From mboxrd@z Thu Jan 1 00:00:00 1970 From: Vasileios Almpanis Date: Fri, 7 Aug 2026 11:25:39 +0200 Subject: Re: [Devel] [PATCH VZ10 v5 7/9] ve: Introduce per-VE failcount In-Reply-To: <4ccd2bf8a399dd400c8cff87c01adb0c91294af7.1785669419.git.vladimir.riabchun@virtuozzo.com> References: <4ccd2bf8a399dd400c8cff87c01adb0c91294af7.1785669419.git.vladimir.riabchun@virtuozzo.com> Message-ID: <400e003b-2b6a-43ac-94aa-f78a4fe7d6e2@virtuozzo.com> List-Id: On 8/2/26 1:40 PM, Vladimir Riabchun wrote: > It may be useful to have a history of resource limit hits for every VE, > this may simplify debugging and provide some information about the > resources usage. > > This information is provided by ve.failcount file, any write to it > resets all failcounts. > > To add a new failcounter we need to create a new atomic_t field > name_failcount in ve structure and add a new VE_FC_ENTRY in > ve_failcounts array. > > One change, unrelated to failcounts: aio fields are now initialized > in ve0. > > https://virtuozzo.atlassian.net/browse/VSTOR-135520 > > Feature: per-ve failcounters > Signed-off-by: Vladimir Riabchun > --- > fs/aio.c | 1 + > fs/namespace.c | 2 ++ > include/linux/ve.h | 6 ++++ > kernel/bpf/syscall.c | 1 + > kernel/ve/ve.c | 67 ++++++++++++++++++++++++++++++++++++++++ > net/core/dev.c | 2 ++ > net/core/neighbour.c | 1 + > net/core/net_namespace.c | 4 ++- > 8 files changed, 83 insertions(+), 1 deletion(-) > > diff --git a/fs/aio.c b/fs/aio.c > index cb63416af135..3fa07cc626f8 100644 > --- a/fs/aio.c > +++ b/fs/aio.c > @@ -814,6 +814,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) > spin_lock(&ve->aio_nr_lock); > if (ve->aio_nr + ctx->max_reqs > ve->aio_max_nr || > ve->aio_nr + ctx->max_reqs < ve->aio_nr) { > + atomic_inc(&ve->aio_failcount); > spin_unlock(&ve->aio_nr_lock); > err = -EAGAIN; > goto err_ctx; > diff --git a/fs/namespace.c b/fs/namespace.c > index 2550aeba2f1e..c4e2c7f7f725 100644 > --- a/fs/namespace.c > +++ b/fs/namespace.c > @@ -3283,6 +3283,8 @@ static inline int ve_try_reserve_mount(struct ve_struct *ve) > > if (ret) > get_ve(ve); > + else > + atomic_inc(&ve->mnt_failcount); > return ret; > } > > diff --git a/include/linux/ve.h b/include/linux/ve.h > index 5687faad46ff..9e73527e970e 100644 > --- a/include/linux/ve.h > +++ b/include/linux/ve.h > @@ -72,12 +72,15 @@ struct ve_struct { > struct kmapset_key proc_perms_key; > > atomic_t netns_avail_nr; > + atomic_t netns_failcount; > int netns_max_nr; > > atomic_t netif_avail_nr; > + atomic_t netif_failcount; > int netif_max_nr; > > atomic_t bpf_prog_avail_nr; > + atomic_t bpf_prog_failcount; > int bpf_prog_max_nr; > > atomic64_t _uevent_seqnum; > @@ -86,6 +89,7 @@ struct ve_struct { > > atomic_t arp_neigh_nr; > atomic_t nd_neigh_nr; > + atomic_t neigh_tbl_failcount; > unsigned long meminfo_val; > > /* > @@ -94,6 +98,7 @@ struct ve_struct { > * other containers. > */ > atomic_t mnt_avail_nr; /* number of available VE mounts */ > + atomic_t mnt_failcount; > int mnt_max_nr; > > #ifdef CONFIG_COREDUMP > @@ -121,6 +126,7 @@ struct ve_struct { > spinlock_t aio_nr_lock; > unsigned long aio_nr; > unsigned long aio_max_nr; > + atomic_t aio_failcount; > #endif > struct vfsmount *devtmpfs_mnt; > }; > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c > index ff2a51c59f04..95e806fa19f4 100644 > --- a/kernel/bpf/syscall.c > +++ b/kernel/bpf/syscall.c > @@ -2891,6 +2891,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) > if (!bpf_cap && type == BPF_PROG_TYPE_CGROUP_DEVICE) { > load_ve = get_exec_env(); > if (atomic_dec_if_positive(&load_ve->bpf_prog_avail_nr) < 0) { > + atomic_inc(&load_ve->bpf_prog_failcount); > load_ve = NULL; > err = -ENOSPC; > goto put_token; > diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c > index dc3faa0b1d76..a5c93be759ac 100644 > --- a/kernel/ve/ve.c > +++ b/kernel/ve/ve.c > @@ -99,10 +99,13 @@ struct ve_struct ve0 = { > .features = -1, > .sched_lat_ve.cur = &ve0_lat_stats, > .netns_avail_nr = ATOMIC_INIT(INT_MAX), > + .netns_failcount = ATOMIC_INIT(0), > .netns_max_nr = INT_MAX, > .netif_avail_nr = ATOMIC_INIT(INT_MAX), > + .netif_failcount = ATOMIC_INIT(0), > .netif_max_nr = INT_MAX, > .bpf_prog_avail_nr = ATOMIC_INIT(INT_MAX), > + .bpf_prog_failcount = ATOMIC_INIT(0), > .bpf_prog_max_nr = INT_MAX, > .fsync_enable = FSYNC_FILTERED, > ._randomize_va_space = > @@ -114,8 +117,16 @@ struct ve_struct ve0 = { > > .arp_neigh_nr = ATOMIC_INIT(0), > .nd_neigh_nr = ATOMIC_INIT(0), > + .neigh_tbl_failcount = ATOMIC_INIT(0), > .mnt_avail_nr = ATOMIC_INIT(INT_MAX), > .mnt_max_nr = INT_MAX, > + .mnt_failcount = ATOMIC_INIT(0), > +#ifdef CONFIG_AIO > + .aio_nr_lock = __SPIN_LOCK_UNLOCKED(aio_nr_lock), > + .aio_nr = 0, > + .aio_max_nr = AIO_MAX_NR_DEFAULT, > + .aio_failcount = ATOMIC_INIT(0), > +#endif > .meminfo_val = VE_MEMINFO_SYSTEM, > .umh_running_helpers = ATOMIC_INIT(0), > .umh_helpers_waitq = __WAIT_QUEUE_HEAD_INITIALIZER(ve0.umh_helpers_waitq), > @@ -780,12 +791,15 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_ > ve->fsync_enable = FSYNC_FILTERED; > > atomic_set(&ve->netns_avail_nr, NETNS_MAX_NR_DEFAULT); > + atomic_set(&ve->netns_failcount, 0); > ve->netns_max_nr = NETNS_MAX_NR_DEFAULT; > > atomic_set(&ve->netif_avail_nr, NETIF_MAX_NR_DEFAULT); > + atomic_set(&ve->netif_failcount, 0); > ve->netif_max_nr = NETIF_MAX_NR_DEFAULT; > > atomic_set(&ve->bpf_prog_avail_nr, BPF_PROG_MAX_NR_DEFAULT); > + atomic_set(&ve->bpf_prog_failcount, 0); > ve->bpf_prog_max_nr = BPF_PROG_MAX_NR_DEFAULT; > > err = ve_log_init(ve); > @@ -812,7 +826,9 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_ > > atomic_set(&ve->arp_neigh_nr, 0); > atomic_set(&ve->nd_neigh_nr, 0); > + atomic_set(&ve->neigh_tbl_failcount, 0); > ve->mnt_max_nr = MNT_MAX_NR_DEFAULT; > + atomic_set(&ve->mnt_failcount, 0); > atomic_set(&ve->mnt_avail_nr, MNT_MAX_NR_DEFAULT); > > #ifdef CONFIG_COREDUMP > @@ -825,6 +841,7 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_ > spin_lock_init(&ve->aio_nr_lock); > ve->aio_nr = 0; > ve->aio_max_nr = AIO_MAX_NR_DEFAULT; > + atomic_set(&ve->aio_failcount, 0); > #endif > > return &ve->css; > @@ -1066,6 +1083,50 @@ VE_RESOURCE(mnt); > VE_RESOURCE(netif); > VE_RESOURCE(bpf_prog); > > +static const struct ve_failcount_entry { > + const char *name; > + size_t offset; > +} ve_failcounts[] = { > +#define VE_FC_ENTRY(name) { #name, offsetof(struct ve_struct, name##_failcount) } > + VE_FC_ENTRY(netns), > + VE_FC_ENTRY(mnt), > + VE_FC_ENTRY(netif), > + VE_FC_ENTRY(bpf_prog), > + VE_FC_ENTRY(neigh_tbl), > +#ifdef CONFIG_AIO > + VE_FC_ENTRY(aio), > +#endif > + {} > +}; > + > +static int ve_failcount_read(struct seq_file *sf, void *v) > +{ > + struct ve_struct *ve = css_to_ve(seq_css(sf)); > + struct ve_failcount_entry *entry; > + atomic_t *fc; > + kernel/ve/ve.c: In function ?ve_failcount_read?: kernel/ve/ve.c:1107:20: warning: assignment discards ?const? qualifier from pointer target type [-Wdiscarded-qualifiers] ?1107 |? ? ? ? ?for (entry = ve_failcounts; entry->name; entry++) { ? ? ? |? ? ? ? ? ? ? ? ? ? ^ kernel/ve/ve.c: In function ?ve_failcount_write?: kernel/ve/ve.c:1121:20: warning: assignment discards ?const? qualifier from pointer target type [-Wdiscarded-qualifiers] ?1121 |? ? ? ? ?for (entry = ve_failcounts; entry->name; entry++) { the left-hand pointee must carry all qualifiers of the right-hand pointee according to C11 > + for (entry = ve_failcounts; entry->name; entry++) { > + fc = (void *)ve + entry->offset; > + seq_printf(sf, "%s: %d\n", entry->name, atomic_read(fc)); > + } > + return 0; > +} > + > +static ssize_t ve_failcount_write(struct kernfs_open_file *of, char *buf, > + size_t nbytes, loff_t off) > +{ > + struct ve_struct *ve = css_to_ve(of_css(of)); > + struct ve_failcount_entry *entry; > + atomic_t *fc; > + > + for (entry = ve_failcounts; entry->name; entry++) { > + fc = (void *)ve + entry->offset; > + atomic_set(fc, 0); > + } > + > + return nbytes; > +} > + > static int ve_os_release_read(struct seq_file *sf, void *v) > { > struct cgroup_subsys_state *css = seq_css(sf); > @@ -1603,6 +1664,12 @@ static struct cftype ve_cftypes[] = { > .flags = CFTYPE_NOT_ON_ROOT, > .write_u64 = ve_rpc_kill_write, > }, > + { > + .name = "failcount", > + .flags = CFTYPE_NOT_ON_ROOT, > + .seq_show = ve_failcount_read, > + .write = ve_failcount_write, > + }, > { } > }; > > diff --git a/net/core/dev.c b/net/core/dev.c > index c7dddb200489..05e0b9b6ba23 100644 > --- a/net/core/dev.c > +++ b/net/core/dev.c > @@ -10997,6 +10997,7 @@ int register_netdevice(struct net_device *dev) > > ret = -ENOMEM; > if (atomic_dec_if_positive(&net->owner_ve->netif_avail_nr) < 0) { > + atomic_inc(&net->owner_ve->netif_failcount); > ve_pr_warn_ratelimited(VE_LOG_BOTH, > "CT%s: hits max number of network devices, " > "increase ve::netif_max_nr parameter\n", > @@ -12211,6 +12212,7 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net, > > err = -ENOMEM; > if (atomic_dec_if_positive(&net->owner_ve->netif_avail_nr) < 0) { > + atomic_inc(&net->owner_ve->netif_failcount); > ve_pr_warn_ratelimited(VE_LOG_BOTH, > "CT%s: hits max number of network devices, " > "increase ve::netif_max_nr parameter\n", > diff --git a/net/core/neighbour.c b/net/core/neighbour.c > index f90deb17fb25..57a49d9c98a7 100644 > --- a/net/core/neighbour.c > +++ b/net/core/neighbour.c > @@ -520,6 +520,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, > (glob_entries >= READ_ONCE(tbl->gc_thresh2) && > time_after(now, READ_ONCE(tbl->last_flush) + 5 * HZ))) { > if (!neigh_forced_gc(tbl, ve) && entries >= gc_thresh3) { > + atomic_inc(&ve->neigh_tbl_failcount); > net_info_ratelimited("%s: neighbor table overflow!\n", > tbl->id); > NEIGH_CACHE_STAT_INC(tbl, table_fulls); > diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c > index b3d54cad984a..9a3376d2682f 100644 > --- a/net/core/net_namespace.c > +++ b/net/core/net_namespace.c > @@ -486,8 +486,10 @@ void net_drop_ns(void *p) > #ifdef CONFIG_VE > static int dec_netns_avail(struct ve_struct *ve) > { > - if (atomic_dec_if_positive(&ve->netns_avail_nr) < 0) > + if (atomic_dec_if_positive(&ve->netns_avail_nr) < 0) { > + atomic_inc(&ve->netns_failcount); > return -ENOSPC; > + } > return 0; > } > -- Best regards, Vasileios Almpanis Software Developer, Virtuozzo.