linux-vserver / util-vserver

http://linux-vserver.org/
GNU General Public License v2.0
15 stars 14 forks source link

vserver-stat assembles cgroup paths incorrectly when per_ss==1 and base!="" #32

Open akorn opened 5 years ago

akorn commented 5 years ago

Symptom:

open("/sys/fs/cgroup/vserver//memory/mail/memory.stat", O_RDONLY) = -1 ENOENT (No such file or directory)

It should be accessing /sys/fs/cgroup/memory/vserver/mail/memory.stat instead.

I have a quick and dirty fix:

diff -ru util-vserver.orig/vserver-stat.c util-vserver.mine/vserver-stat.c
--- util-vserver.orig/vserver-stat.c    2018-01-14 13:26:26.000000000 +0100
+++ util-vserver.mine/vserver-stat.c    2019-05-26 13:18:51.742946149 +0200
@@ -307,15 +307,16 @@
     struct vc_sched_info       sched;
     int                                cpu;
     char                       vhi_name[65],
-                               filename[128],
+                               filename[512],
                                cgroup[129],
                                name[129],
+                               base[129]="",
                                buf[30];
     int                                fd;
     ssize_t                    cgroup_len, name_len;
     unsigned long long         rss = 0;
     char                       *endptr;
-    ssize_t                    len;
+    ssize_t                    len, base_len;
     unsigned long long         stime_total, utime_total;
     int                                per_ss = 0;
     FILE                       *fp;
@@ -361,21 +362,21 @@
     }

     if ((fd = open(DEFAULTCONFDIR "/cgroup/base", O_RDONLY)) != -1) {
-      len = read(fd, cgroup + cgroup_len, sizeof(cgroup) - cgroup_len);
-      if (len == -1) {
+      base_len = read(fd, base, sizeof(base));
+      if (base_len == -1) {
         perror("read(cgroup/base)");
         return;
       }
       close(fd);
-      if (len > 0) {
-       while (cgroup[cgroup_len + len - 1] == '\n' || cgroup[cgroup_len + len - 1] == '\r')
-         len--;
-       cgroup_len += len;
-       if (cgroup[cgroup_len - 1] != '/') {
-         cgroup[cgroup_len] = '/';
-         cgroup_len += 1;
+      if (base_len > 0) {
+       while (base[base_len - 1] == '\n' || base[base_len - 1] == '\r') {
+         base_len--;
+        }
+       if (base[base_len - 1] != '/') {
+         base[base_len] = '/';
+         base_len += 1;
        }
-       cgroup[cgroup_len] = 0;
+       base[base_len] = 0;
       }
     }

@@ -429,7 +430,7 @@
       WRITE_MSG(2, "\n");
       return;
     }
-    snprintf(filename, sizeof(filename), "%s%s%s/memory.stat", cgroup, (per_ss ? "/memory" : ""), name);
+    snprintf(filename, sizeof(filename), "%s/%s/%s/%s/memory.stat", cgroup, (per_ss ? "/memory" : ""), base, name);

     if ((fp = fopen(filename, "r")) == NULL)
       perror("open(memory.stat)");

It's cosmetically imperfect because it uses too many / characters in the path to memory.stat, but it works.

akorn commented 4 years ago

The same problem affects the other cgroups too. E.g.

open("/etc/vservers/.defaults/cgroup/mnt", O_RDONLY) = 4
read(4, "/sys/fs/cgroup\n", 129)        = 15
close(4)                                = 0
open("/etc/vservers/.defaults/cgroup/base", O_RDONLY) = 4
read(4, "vserver/\n", 129)              = 9
close(4)                                = 0
access("/etc/vservers/.defaults/cgroup/per-ss", F_OK) = 0
open("/etc/vservers/mail/cgroup/name", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/sys/fs/cgroup///memory/vserver///mail/memory.stat", O_RDONLY) = 4
[...]
open("/sys/fs/cgroup//cpuacct/mail/cpuacct.stat", O_RDONLY) = -1 ENOENT (No such file or directory)

(It should be accessing /sys/fs/cgroup/cpuacct/vserver/mail/cpuacct.stat.)

Replacing the 2nd snprintf() line in vserver-stat.c with

snprintf(filename, sizeof(filename), "%s/%s/%s/%s/cpuacct.stat", cgroup, (per_ss ? "/cpuacct" : ""), base, name);

Fixes it for me.