[libvirt] [PATCH v2] lxc: fuse mount for /proc/cpuinfo

Cédric Bosdonnat cbosdonnat at suse.com
Thu Sep 3 09:51:16 UTC 2015


We already have a fuse mount to reflect the cgroup memory restrictions
in the container. This commit adds the same for the number of available
CPUs. Only the CPUs listed by virProcessGetAffinity are shown in the
container's cpuinfo.
---
 src/lxc/lxc_container.c |  42 ++++++++++++-------
 src/lxc/lxc_fuse.c      | 106 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 133 insertions(+), 15 deletions(-)

diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index a433552..7ae13a8 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1055,24 +1055,38 @@ static int lxcContainerMountProcFuse(virDomainDefPtr def,
                                      const char *stateDir)
 {
     int ret;
-    char *meminfo_path = NULL;
+    char *src_path = NULL;
+    char *dst_path = NULL;
+    const char *paths[] = {"meminfo", "cpuinfo"};
+    size_t i;
 
-    VIR_DEBUG("Mount /proc/meminfo stateDir=%s", stateDir);
+    for (i = 0; i < 2; i++) {
+        VIR_DEBUG("Mount /proc/%s stateDir=%s", paths[i], stateDir);
+
+        if ((ret = virAsprintf(&src_path,
+                               "/.oldroot/%s/%s.fuse/%s",
+                               stateDir,
+                               def->name,
+                               paths[i])) < 0)
+            return ret;
+
+        if ((ret = virAsprintf(&dst_path,
+                               "/proc/%s",
+                               paths[i])) < 0) {
+            VIR_FREE(src_path);
+            return ret;
+        }
 
-    if ((ret = virAsprintf(&meminfo_path,
-                           "/.oldroot/%s/%s.fuse/meminfo",
-                           stateDir,
-                           def->name)) < 0)
-        return ret;
+        if ((ret = mount(src_path, dst_path,
+                         NULL, MS_BIND, NULL)) < 0) {
+            virReportSystemError(errno,
+                                 _("Failed to mount %s on %s"),
+                                 src_path, dst_path);
+        }
 
-    if ((ret = mount(meminfo_path, "/proc/meminfo",
-                     NULL, MS_BIND, NULL)) < 0) {
-        virReportSystemError(errno,
-                             _("Failed to mount %s on /proc/meminfo"),
-                             meminfo_path);
+        VIR_FREE(src_path);
+        VIR_FREE(dst_path);
     }
-
-    VIR_FREE(meminfo_path);
     return ret;
 }
 #else
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 34a69cc..0d60434 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -42,6 +42,58 @@
 #if WITH_FUSE
 
 static const char *fuse_meminfo_path = "/meminfo";
+static const char *fuse_cpuinfo_path = "/cpuinfo";
+
+static virBufferPtr lxcProcComputeCpuinfo(void) {
+    FILE *fd = NULL;
+    char *line = NULL;
+    size_t n;
+    bool writeProc = false;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    virBufferPtr new_cpuinfo = &buffer;
+    pid_t pid;
+    virBitmapPtr cpuAffinity = NULL;
+
+    fd = fopen("/proc/cpuinfo", "r");
+    if (fd == NULL) {
+        virReportSystemError(errno, "%s", _("Cannot open /proc/cpuinfo"));
+        goto error;
+    }
+
+    pid = getpid();
+    if (!(cpuAffinity = virProcessGetAffinity(pid)))
+        goto error;
+
+    while (getline(&line, &n, fd) > 0) {
+        if (STRPREFIX(line, "processor\t:")) {
+            unsigned long cpuid = 0;
+            char *suffix = NULL;
+            if (virStrToLong_ul(line + 12, &suffix, 10, &cpuid) < 0)
+                goto error;
+
+            if (virBitmapGetBit(cpuAffinity, cpuid, &writeProc) < 0)
+                goto error;
+        }
+
+        if (writeProc) {
+            virBufferAdd(new_cpuinfo, line, -1);
+
+            if (virBufferCheckError(new_cpuinfo) < 0)
+                goto error;
+        }
+    }
+
+ cleanup:
+    VIR_FREE(line);
+    VIR_FORCE_FCLOSE(fd);
+    virBitmapFree(cpuAffinity);
+    return new_cpuinfo;
+
+ error:
+    virBufferFreeAndReset(new_cpuinfo);
+    new_cpuinfo = NULL;
+    goto cleanup;
+}
 
 static int lxcProcGetattr(const char *path, struct stat *stbuf)
 {
@@ -50,6 +102,7 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
     struct stat sb;
     struct fuse_context *context = fuse_get_context();
     virDomainDefPtr def = (virDomainDefPtr)context->private_data;
+    virBufferPtr cpuinfo = NULL;
 
     memset(stbuf, 0, sizeof(struct stat));
     if (virAsprintf(&mempath, "/proc/%s", path) < 0)
@@ -76,12 +129,36 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
         stbuf->st_atime = sb.st_atime;
         stbuf->st_ctime = sb.st_ctime;
         stbuf->st_mtime = sb.st_mtime;
+    } else if (STREQ(path, fuse_cpuinfo_path)) {
+        if (!(cpuinfo = lxcProcComputeCpuinfo())) {
+            res = -EIO;
+            goto cleanup;
+        }
+
+        if (stat(mempath, &sb) < 0) {
+            res = -errno;
+            goto cleanup;
+        }
+
+        stbuf->st_uid = def->idmap.uidmap ? def->idmap.uidmap[0].target : 0;
+        stbuf->st_gid = def->idmap.gidmap ? def->idmap.gidmap[0].target : 0;
+        stbuf->st_mode = sb.st_mode;
+        stbuf->st_nlink = 1;
+        stbuf->st_blksize = sb.st_blksize;
+        stbuf->st_size = virBufferUse(cpuinfo);
+        stbuf->st_blocks = stbuf->st_size / 512;
+        if (stbuf->st_size % 512 != 0)
+            stbuf->st_blocks++;
+        stbuf->st_atime = sb.st_atime;
+        stbuf->st_ctime = sb.st_ctime;
+        stbuf->st_mtime = sb.st_mtime;
     } else {
         res = -ENOENT;
     }
 
  cleanup:
     VIR_FREE(mempath);
+    virBufferFreeAndReset(cpuinfo);
     return res;
 }
 
@@ -96,6 +173,7 @@ static int lxcProcReaddir(const char *path, void *buf,
     filler(buf, ".", NULL, 0);
     filler(buf, "..", NULL, 0);
     filler(buf, fuse_meminfo_path + 1, NULL, 0);
+    filler(buf, fuse_cpuinfo_path + 1, NULL, 0);
 
     return 0;
 }
@@ -103,7 +181,8 @@ static int lxcProcReaddir(const char *path, void *buf,
 static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED,
                        struct fuse_file_info *fi ATTRIBUTE_UNUSED)
 {
-    if (!STREQ(path, fuse_meminfo_path))
+    if (!STREQ(path, fuse_meminfo_path) &&
+        !STREQ(path, fuse_cpuinfo_path))
         return -ENOENT;
 
     if ((fi->flags & 3) != O_RDONLY)
@@ -234,6 +313,28 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
     return res;
 }
 
+static int lxcProcReadCpuinfo(char *buf, size_t size, off_t offset)
+{
+    virBufferPtr new_cpuinfo = lxcProcComputeCpuinfo();
+    int new_size = -1;
+    int copied = -1;
+
+    if (!new_cpuinfo)
+        goto error;
+
+    copied = size;
+    new_size = virBufferUse(new_cpuinfo);
+
+    if ((new_size - offset) < size)
+        copied = new_size - offset;
+
+    memcpy(buf, virBufferCurrentContent(new_cpuinfo) + offset, copied);
+
+ error:
+    virBufferFreeAndReset(new_cpuinfo);
+    return copied;
+}
+
 static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
                        char *buf ATTRIBUTE_UNUSED,
                        size_t size ATTRIBUTE_UNUSED,
@@ -254,6 +355,9 @@ static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
     if (STREQ(path, fuse_meminfo_path)) {
         if ((res = lxcProcReadMeminfo(hostpath, def, buf, size, offset)) < 0)
             res = lxcProcHostRead(hostpath, buf, size, offset);
+    } else if (STREQ(path, fuse_cpuinfo_path)) {
+        if ((res = lxcProcReadCpuinfo(buf, size, offset)) < 0)
+            res = lxcProcHostRead(hostpath, buf, size, offset);
     }
 
     VIR_FREE(hostpath);
-- 
2.1.4




More information about the libvir-list mailing list