OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 help / color / mirror / Atom feed
From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>, devel@openvz.org
Subject: Re: [Devel] [PATCH VZ10 v9 6/8] ve: Introduce per-VE failcount
Date: Fri, 25 Sep 2026 18:08:05 +0200	[thread overview]
Message-ID: <0a0a8403-3ff0-47b8-b5e4-5a20c7b1ea3b@virtuozzo.com> (raw)
In-Reply-To: <f1cc00374e7290a70a359b760e6255e280d8e5a7.1789491989.git.vladimir.riabchun@virtuozzo.com>


On 9/15/26 19:22, 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 <vladimir.riabchun@virtuozzo.com>
> ---
>  fs/aio.c                 |  1 +
>  fs/namespace.c           |  2 ++
>  include/linux/ve.h       | 16 +++++++++
>  kernel/bpf/syscall.c     |  1 +
>  kernel/ve/ve.c           | 70 ++++++++++++++++++++++++++++++++++++++++
>  net/core/dev.c           | 10 ++----
>  net/core/neighbour.c     |  3 +-
>  net/core/net_namespace.c |  4 ++-
>  8 files changed, 96 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/aio.c b/fs/aio.c
> index cb63416af135..4ae06bcd47f2 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) {
> +		ve_failcount_inc(ve, aio);
>  		spin_unlock(&ve->aio_nr_lock);
>  		err = -EAGAIN;
>  		goto err_ctx;
> diff --git a/fs/namespace.c b/fs/namespace.c
> index 1d6e66cd7174..ea01664ff5f2 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -3380,6 +3380,8 @@ static inline int ve_try_reserve_mount(struct ve_struct *ve)
>  
>  	if (ret)
>  		get_ve(ve);
> +	else
> +		ve_failcount_inc(ve, mnt);
>  	return ret;
>  }

  Now every failed mount produces two ratelimited warnings in the host
  log: the pre-existing one in alloc_vfsmnt()

        pr_warn_ratelimited("CT#%s reached the limit on mounts.\n", ...);

  and the one printed by ve_failcount_inc(). They are ratelimited
  independently, so the log gets both messages for the same event.

  Please drop the alloc_vfsmnt() one in this patch: the
  ve_failcount_inc() message carries strictly more information (it also
  names the counter to look at) and additionally goes to the container
  log.

>  
> diff --git a/include/linux/ve.h b/include/linux/ve.h
> index fabc608e31f5..065129b42768 100644
> --- a/include/linux/ve.h
> +++ b/include/linux/ve.h
> @@ -80,12 +80,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;
> @@ -94,6 +97,7 @@ struct ve_struct {
>  
>  	atomic_t		arp_neigh_nr;
>  	atomic_t		nd_neigh_nr;
> +	atomic_t		neigh_tbl_failcount;
>  	unsigned long		meminfo_val;
>  
>  	/*
> @@ -102,6 +106,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
> @@ -129,6 +134,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;
>  };
> @@ -151,6 +157,16 @@ extern int nr_ve;
>  #define BPF_PROG_MAX_NR_DEFAULT	256	/* number of loaded BPF progs per-VE */
>  #define MNT_MAX_NR_DEFAULT	4096	/* number of mounts per-VE */
>  
> +#define ve_failcount_inc(ve, name)					\
> +do {									\
> +	struct ve_struct *__ve = (ve);					\
> +									\
> +	atomic_inc(&__ve->name##_failcount);				\
> +	ve_pr_warn_ratelimited(VE_LOG_BOTH, "CT%s: hits the " #name	\
> +		" limit, see the '" #name "' counter in ve.failcount "	\
> +		"of the container's ve cgroup\n", ve_name(__ve));	\
> +} while (0)
> +
>  #ifdef CONFIG_VE
>  static inline void ve_set_state(struct ve_struct *ve, int new_state)
>  {
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index c94d4240e3d3..8498bc9df7ea 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) {
> +			ve_failcount_inc(load_ve, bpf_prog);
>  			load_ve = NULL;
>  			err = -ENOSPC;
>  			goto put_token;
> diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
> index 5ebdb4b7baa7..9261565208e6 100644
> --- a/kernel/ve/ve.c
> +++ b/kernel/ve/ve.c
> @@ -100,10 +100,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	=
> @@ -115,8 +118,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,
>  #ifdef CONFIG_X86
>  	.umh_running_helpers	= ATOMIC_INIT(0),
> @@ -787,12 +798,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);
> @@ -821,7 +835,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
> @@ -834,6 +850,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;
> @@ -1074,6 +1091,53 @@ 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));
> +	const struct ve_failcount_entry *entry;
> +	atomic_t *fc;
> +
> +	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));
> +	const struct ve_failcount_entry *entry;
> +	atomic_t *fc;
> +
> +	if (!ve_is_super(get_exec_env()) && !ve->is_pseudosuper)
> +		return -EPERM;
> +
> +	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);
> @@ -1613,6 +1677,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..7632ad1fd015 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -10997,10 +10997,7 @@ int register_netdevice(struct net_device *dev)
>  
>  	ret = -ENOMEM;
>  	if (atomic_dec_if_positive(&net->owner_ve->netif_avail_nr) < 0) {
> -		ve_pr_warn_ratelimited(VE_LOG_BOTH,
> -			"CT%s: hits max number of network devices, "
> -			"increase ve::netif_max_nr parameter\n",
> -			ve_name(net->owner_ve));
> +		ve_failcount_inc(net->owner_ve, netif);
>  		return ret;
>  	}
>  
> @@ -12211,10 +12208,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) {
> -		ve_pr_warn_ratelimited(VE_LOG_BOTH,
> -			"CT%s: hits max number of network devices, "
> -			"increase ve::netif_max_nr parameter\n",
> -			ve_name(net->owner_ve));
> +		ve_failcount_inc(net->owner_ve, netif);
>  		goto out;
>  	}
>  	atomic_inc(&dev_net(dev)->owner_ve->netif_avail_nr);
> diff --git a/net/core/neighbour.c b/net/core/neighbour.c
> index f90deb17fb25..c7d5e6df50c2 100644
> --- a/net/core/neighbour.c
> +++ b/net/core/neighbour.c
> @@ -520,8 +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) {
> -			net_info_ratelimited("%s: neighbor table overflow!\n",
> -					     tbl->id);
> +			ve_failcount_inc(ve, neigh_tbl);
>  			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
>  			goto out_entries;
>  		}
> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
> index b3d54cad984a..328e1c96b6f4 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) {
> +		ve_failcount_inc(ve, netns);
>  		return -ENOSPC;
> +	}
>  	return 0;
>  }
>  

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  parent reply	other threads:[~2026-09-25 16:09 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15 17:22 [Devel] [PATCH VZ10 v9 0/8] Add per-VE failcount support Vladimir Riabchun
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 1/8] ve/ve.{h, c}: Farewell to spaces as indents Vladimir Riabchun
2026-09-25 15:55   ` Konstantin Khorenko
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 2/8] ve/fs: Rework per-ve mount count Vladimir Riabchun
2026-09-18 13:22   ` Vladimir Riabchun
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 3/8] selftests/ve: Update ve_ns_owner_test Vladimir Riabchun
2026-09-18 13:28   ` Vladimir Riabchun
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 4/8] ve: Move from global VE mounts limit to per-VE limit Vladimir Riabchun
2026-09-18 14:29   ` Vladimir Riabchun
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 5/8] ve/ve.c: Generate VE resource accessors using macros Vladimir Riabchun
2026-09-18 14:36   ` Vladimir Riabchun
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 6/8] ve: Introduce per-VE failcount Vladimir Riabchun
2026-09-18 14:42   ` Vladimir Riabchun
2026-09-25 16:02   ` Konstantin Khorenko
2026-09-25 16:08   ` Konstantin Khorenko [this message]
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 7/8] ve/printk: Don't use ve log outside task context Vladimir Riabchun
2026-09-18 14:50   ` Vladimir Riabchun
2026-09-22 11:21   ` Vladimir Riabchun
2026-09-25 16:02     ` Konstantin Khorenko
2026-09-15 17:22 ` [Devel] [PATCH VZ10 v9 8/8] selftests/ve: Add mount accounting selftest Vladimir Riabchun
2026-09-18 15:06   ` Vladimir Riabchun
2026-09-25 16:04   ` Konstantin Khorenko
2026-09-16 12:30 ` [Devel] [PATCH VZ10 v9 0/8] Add per-VE failcount support Vasileios Almpanis
2026-09-16 17:30 ` Konstantin Khorenko
2026-09-18 15:07   ` Vladimir Riabchun
2026-09-18 16:02   ` Vladimir Riabchun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0a0a8403-3ff0-47b8-b5e4-5a20c7b1ea3b@virtuozzo.com \
    --to=khorenko@virtuozzo.com \
    --cc=devel@openvz.org \
    --cc=vladimir.riabchun@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox