[Devel] [PATCH hci-8.1 v10 07/13] ve: introduce per-VE failcounter infrastructure

Konstantin Khorenko khorenko at virtuozzo.com
Fri Sep 25 19:53:28 MSK 2026


From: Vladimir Riabchun <vladimir.riabchun at virtuozzo.com>

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. The counters themselves come in the follow-up
patches, one per resource.

The neighbour table overflow will not be counted for now: neigh_alloc
can run in softirq context, where ve log must not be used, and
ve_failcount_inc writes to it. The neigh_tbl counter will be added
together with the ve_printk softirq fix (VSTOR-146839).

https://virtuozzo.atlassian.net/browse/VSTOR-135520

Feature: per-ve failcounters
Signed-off-by: Vladimir Riabchun <vladimir.riabchun at virtuozzo.com>
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 include/linux/ve.h | 10 ++++++++++
 kernel/ve/ve.c     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/include/linux/ve.h b/include/linux/ve.h
index fabc608e31f51..546060eddc765 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -151,6 +151,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/ve/ve.c b/kernel/ve/ve.c
index c4e5c000bc427..f915f86e7471e 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -1079,6 +1079,45 @@ 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) }
+	{}
+};
+
+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);
@@ -1618,6 +1657,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,
+	},
 	{ }
 };
 

-- 
2.43.0



More information about the Devel mailing list