[Devel] [PATCH vz9 24/27] vecalls: Introduce VZCTL_GET_CPU_STAT ioctl

Nikita Yushchenko nikita.yushchenko at virtuozzo.com
Wed Oct 6 11:57:36 MSK 2021


From: Konstantin Khorenko <khorenko at virtuozzo.com>

This vzctl ioctl still used by vzstat utility and dispatcher/libvirt
statistics reporting.
>From one point of view almost all data can be get from cpu cgroup of a
Container (missing data can be exported additionally),
but statistics is gathered often and ioctl is faster and requires less
cpu power => let it be for now.

The current patch is based on following vz7 commits:
  ecdce58b214c ("sched: Export per task_group statistics_work")
  a58fb58bff1c ("Use ve init task's css instead of opening cgroup via vfs")
  75fc174adc36 ("sched: Port cpustat related patches")

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
Reviewed-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

+++
sched: Uninline css_tg()

Compilation with custom config fails:

kernel/ve/ve.c: In function ‘ve_get_cpu_avenrun’:
kernel/ve/ve.c:1679:27: error: inlining failed in call to always_inline ‘css_tg’: function body not available
 inline struct task_group *css_tg(struct cgroup_subsys_state *css);
                           ^~~~~~
kernel/ve/ve.c:1690:7: note: called from here
  tg = css_tg(css);
       ^~~~~~~~~~~

We may remove "inline" attribute, as compiler is clever enough
to make itself inlining in kernel/sched/sched.c.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
Reviewed-by: Evgenii Shatokhin <eshatokhin at virtuozzo.com>

(cherry-picked from vz8 commit e5e88546c0ab ("vecalls: Introduce
VZCTL_GET_CPU_STAT ioctl"))

Signed-off-by: Nikita Yushchenko <nikita.yushchenko at virtuozzo.com>
---
 include/linux/ve.h  |  2 ++
 kernel/time/time.c  |  1 +
 kernel/ve/ve.c      | 18 +++++++++++++
 kernel/ve/vecalls.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+)

diff --git a/include/linux/ve.h b/include/linux/ve.h
index e7b5be193442..c9e823f2c5c0 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -201,10 +201,12 @@ struct seq_file;
 #if defined(CONFIG_VE) && defined(CONFIG_CGROUP_SCHED)
 int ve_show_cpu_stat(struct ve_struct *ve, struct seq_file *p);
 int ve_show_loadavg(struct ve_struct *ve, struct seq_file *p);
+int ve_get_cpu_avenrun(struct ve_struct *ve, unsigned long *avenrun);
 int ve_get_cpu_stat(struct ve_struct *ve, struct kernel_cpustat *kstat);
 #else
 static inline int ve_show_cpu_stat(struct ve_struct *ve, struct seq_file *p) { return -ENOSYS; }
 static inline int ve_show_loadavg(struct ve_struct *ve, struct seq_file *p) { return -ENOSYS; }
+static inline int ve_get_cpu_avenrun(struct ve_struct *ve, unsigned long *avenrun) { return -ENOSYS; }
 static inline int ve_get_cpu_stat(struct ve_struct *ve, struct kernel_cpustat *kstat) { return -ENOSYS; }
 #endif
 
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 29923b20e0e4..f56853a94b5b 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -686,6 +686,7 @@ u64 nsec_to_clock_t(u64 x)
 	return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
 #endif
 }
+EXPORT_SYMBOL(nsec_to_clock_t);
 
 u64 jiffies64_to_nsecs(u64 j)
 {
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 105e4deae29b..47fbd6fd4d80 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -1492,6 +1492,24 @@ int ve_show_loadavg(struct ve_struct *ve, struct seq_file *p)
 	return err;
 }
 
+struct task_group *css_tg(struct cgroup_subsys_state *css);
+int get_avenrun_tg(struct task_group *tg, unsigned long *loads,
+		   unsigned long offset, int shift);
+
+int ve_get_cpu_avenrun(struct ve_struct *ve, unsigned long *avnrun)
+{
+	struct cgroup_subsys_state *css;
+	struct task_group *tg;
+	int err;
+
+	css = ve_get_init_css(ve, cpu_cgrp_id);
+	tg = css_tg(css);
+	err = get_avenrun_tg(tg, avnrun, 0, 0);
+	css_put(css);
+	return err;
+}
+EXPORT_SYMBOL(ve_get_cpu_avenrun);
+
 int cpu_cgroup_get_stat(struct cgroup_subsys_state *cpu_css,
 			struct cgroup_subsys_state *cpuacct_css,
 			struct kernel_cpustat *kstat);
diff --git a/kernel/ve/vecalls.c b/kernel/ve/vecalls.c
index d4ae92505bc1..6bb9d477275d 100644
--- a/kernel/ve/vecalls.c
+++ b/kernel/ve/vecalls.c
@@ -24,6 +24,8 @@
 #include <linux/seq_file.h>
 #include <linux/rcupdate.h>
 #include <linux/mount.h>
+#include <linux/jiffies.h>
+#include <linux/sched/loadavg.h>
 #include <generated/utsrelease.h>
 
 #include <linux/ve.h>
@@ -32,6 +34,62 @@
 #include <linux/veowner.h>
 #include <linux/device_cgroup.h>
 
+static int fill_cpu_stat(envid_t veid, struct vz_cpu_stat __user *buf)
+{
+	struct ve_struct *ve;
+	struct vz_cpu_stat *vstat;
+	int retval;
+	int i;
+	unsigned long tmp;
+	unsigned long avnrun[3];
+	struct kernel_cpustat kstat;
+
+	if (!ve_is_super(get_exec_env()) && (veid != get_exec_env()->veid))
+		return -EPERM;
+	ve = get_ve_by_id(veid);
+	if (!ve)
+		return -ESRCH;
+
+	retval = -ENOMEM;
+	vstat = kzalloc(sizeof(*vstat), GFP_KERNEL);
+	if (!vstat)
+		goto out_put_ve;
+
+	retval = ve_get_cpu_stat(ve, &kstat);
+	if (retval)
+		goto out_free;
+
+	retval = ve_get_cpu_avenrun(ve, avnrun);
+	if (retval)
+		goto out_free;
+
+	vstat->user_jif	  = (unsigned long)nsec_to_clock_t(
+					   kstat.cpustat[CPUTIME_USER]);
+	vstat->nice_jif   = (unsigned long)nsec_to_clock_t(
+					   kstat.cpustat[CPUTIME_NICE]);
+	vstat->system_jif = (unsigned long)nsec_to_clock_t(
+					   kstat.cpustat[CPUTIME_SYSTEM]);
+	vstat->idle_clk   = kstat.cpustat[CPUTIME_IDLE];
+	vstat->uptime_clk = ve_get_uptime(ve);
+
+	vstat->uptime_jif = (unsigned long)jiffies_64_to_clock_t(
+			    get_jiffies_64() - ve->start_jiffies);
+	for (i = 0; i < 3; i++) {
+		tmp = avnrun[i] + (FIXED_1/200);
+		vstat->avenrun[i].val_int = LOAD_INT(tmp);
+		vstat->avenrun[i].val_frac = LOAD_FRAC(tmp);
+	}
+
+	retval = 0;
+	if (copy_to_user(buf, vstat, sizeof(*vstat)))
+		retval = -EFAULT;
+out_free:
+	kfree(vstat);
+out_put_ve:
+	put_ve(ve);
+	return retval;
+}
+
 /**********************************************************************
  **********************************************************************
  *
@@ -360,6 +418,14 @@ int vzcalls_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	err = -ENOTTY;
 	switch(cmd) {
+	    case VZCTL_GET_CPU_STAT: {
+			struct vzctl_cpustatctl s;
+			err = -EFAULT;
+			if (copy_from_user(&s, (void __user *)arg, sizeof(s)))
+				break;
+			err = fill_cpu_stat(s.veid, s.cpustat);
+		}
+		break;
 	    case VZCTL_VE_CONFIGURE:
 		err = ve_configure_ioctl((struct vzctl_ve_configure *)arg);
 		break;
-- 
2.30.2



More information about the Devel mailing list