[libvirt] [PATCH v3 14/16] Track symlinks for co-mounted cgroup controllers

Daniel P. Berrange berrange at redhat.com
Wed Apr 10 10:08:23 UTC 2013


From: "Daniel P. Berrange" <berrange at redhat.com>

If a cgroup controller is co-mounted with another, eg

   /sys/fs/cgroup/cpu,cpuacct

Then it is a requirement that there exist symlinks at

   /sys/fs/cgroup/cpu
   /sys/fs/cgroup/cpuacct

pointing to the real mount point. Add support to virCgroupPtr
to detect and track these symlinks

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/util/vircgroup.c     | 56 ++++++++++++++++++++++++++++++++++++++++++----
 src/util/vircgrouppriv.h |  5 +++++
 tests/vircgroupmock.c    | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/vircgrouptest.c    | 36 +++++++++++++++++++++++-------
 4 files changed, 143 insertions(+), 12 deletions(-)

diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 6202614..14af16e 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -75,6 +75,7 @@ void virCgroupFree(virCgroupPtr *group)
 
     for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
         VIR_FREE((*group)->controllers[i].mountPoint);
+        VIR_FREE((*group)->controllers[i].linkPoint);
         VIR_FREE((*group)->controllers[i].placement);
     }
 
@@ -114,6 +115,14 @@ static int virCgroupCopyMounts(virCgroupPtr group,
 
         if (!group->controllers[i].mountPoint)
             return -ENOMEM;
+
+        if (parent->controllers[i].linkPoint) {
+            group->controllers[i].linkPoint =
+                strdup(parent->controllers[i].linkPoint);
+
+            if (!group->controllers[i].linkPoint)
+                return -ENOMEM;
+        }
     }
     return 0;
 }
@@ -157,9 +166,46 @@ static int virCgroupDetectMounts(virCgroupPtr group)
                  * first entry only
                  */
                 if (typelen == len && STREQLEN(typestr, tmp, len) &&
-                    !group->controllers[i].mountPoint &&
-                    !(group->controllers[i].mountPoint = strdup(entry.mnt_dir)))
-                    goto no_memory;
+                    !group->controllers[i].mountPoint) {
+                    char *linksrc;
+                    struct stat sb;
+                    char *tmp2;
+
+                    if (!(group->controllers[i].mountPoint = strdup(entry.mnt_dir)))
+                        goto no_memory;
+
+                    tmp2 = strrchr(entry.mnt_dir, '/');
+                    if (!tmp2) {
+                        errno = EINVAL;
+                        goto error;
+                    }
+                    *tmp2 = '\0';
+                    /* If it is a co-mount it has a filename like "cpu,cpuacct"
+                     * and we must identify the symlink path */
+                    if (strchr(tmp2 + 1, ',')) {
+                        if (virAsprintf(&linksrc, "%s/%s",
+                                        entry.mnt_dir, typestr) < 0)
+                            goto no_memory;
+                        *tmp2 = '/';
+
+                        if (lstat(linksrc, &sb) < 0) {
+                            if (errno == ENOENT) {
+                                VIR_WARN("Controller %s co-mounted at %s is missing symlink at %s",
+                                         typestr, entry.mnt_dir, linksrc);
+                                VIR_FREE(linksrc);
+                            } else {
+                                goto error;
+                            }
+                        } else {
+                            if (!S_ISLNK(sb.st_mode)) {
+                                VIR_WARN("Expecting a symlink at %s for controller %s",
+                                         linksrc, typestr);
+                            } else {
+                                group->controllers[i].linkPoint = linksrc;
+                            }
+                        }
+                    }
+                }
                 tmp = next;
             }
         }
@@ -170,8 +216,10 @@ static int virCgroupDetectMounts(virCgroupPtr group)
     return 0;
 
 no_memory:
+    errno = ENOENT;
+error:
     VIR_FORCE_FCLOSE(mounts);
-    return -ENOMEM;
+    return -errno;
 }
 
 
diff --git a/src/util/vircgrouppriv.h b/src/util/vircgrouppriv.h
index cc8cc0b..582be79 100644
--- a/src/util/vircgrouppriv.h
+++ b/src/util/vircgrouppriv.h
@@ -34,6 +34,11 @@
 struct virCgroupController {
     int type;
     char *mountPoint;
+    /* If mountPoint holds several controllers co-mounted,
+     * then linkPoint is path of the symlink to the mountPoint
+     * for just the one controller
+     */
+    char *linkPoint;
     char *placement;
 };
 
diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c
index e50f7e0..32f074b 100644
--- a/tests/vircgroupmock.c
+++ b/tests/vircgroupmock.c
@@ -32,6 +32,8 @@
 static int (*realopen)(const char *path, int flags, ...);
 static FILE *(*realfopen)(const char *path, const char *mode);
 static int (*realaccess)(const char *path, int mode);
+static int (*reallstat)(const char *path, struct stat *sb);
+static int (*real__lxstat)(int ver, const char *path, struct stat *sb);
 static int (*realmkdir)(const char *path, mode_t mode);
 static char *fakesysfsdir;
 
@@ -314,8 +316,18 @@ static void init_syms(void)
         }                                                               \
     } while (0)
 
+#define LOAD_SYM_ALT(name1, name2)                                      \
+    do {                                                                \
+        if (!(real ## name1 = dlsym(RTLD_NEXT, #name1)) &&              \
+            !(real ## name2 = dlsym(RTLD_NEXT, #name2))) {              \
+            fprintf(stderr, "Cannot find real '%s' or '%s' symbol\n", #name1, #name2); \
+            abort();                                                    \
+        }                                                               \
+    } while (0)
+
     LOAD_SYM(fopen);
     LOAD_SYM(access);
+    LOAD_SYM_ALT(lstat, __lxstat);
     LOAD_SYM(mkdir);
     LOAD_SYM(open);
 }
@@ -399,6 +411,52 @@ int access(const char *path, int mode)
     return ret;
 }
 
+int __lxstat(int ver, const char *path, struct stat *sb)
+{
+    int ret;
+
+    init_syms();
+
+    if (STRPREFIX(path, SYSFS_PREFIX)) {
+        init_sysfs();
+        char *newpath;
+        if (asprintf(&newpath, "%s/%s",
+                     fakesysfsdir,
+                     path + strlen(SYSFS_PREFIX)) < 0) {
+            errno = ENOMEM;
+            return -1;
+        }
+        ret = real__lxstat(ver, newpath, sb);
+        free(newpath);
+    } else {
+        ret = real__lxstat(ver, path, sb);
+    }
+    return ret;
+}
+
+int lstat(const char *path, struct stat *sb)
+{
+    int ret;
+
+    init_syms();
+
+    if (STRPREFIX(path, SYSFS_PREFIX)) {
+        init_sysfs();
+        char *newpath;
+        if (asprintf(&newpath, "%s/%s",
+                     fakesysfsdir,
+                     path + strlen(SYSFS_PREFIX)) < 0) {
+            errno = ENOMEM;
+            return -1;
+        }
+        ret = reallstat(newpath, sb);
+        free(newpath);
+    } else {
+        ret = reallstat(path, sb);
+    }
+    return ret;
+}
+
 int mkdir(const char *path, mode_t mode)
 {
     int ret;
diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c
index 4f76a06..4b8ca61 100644
--- a/tests/vircgrouptest.c
+++ b/tests/vircgrouptest.c
@@ -36,6 +36,7 @@
 static int validateCgroup(virCgroupPtr cgroup,
                           const char *expectPath,
                           const char **expectMountPoint,
+                          const char **expectLinkPoint,
                           const char **expectPlacement)
 {
     int i;
@@ -55,6 +56,14 @@ static int validateCgroup(virCgroupPtr cgroup,
                     virCgroupControllerTypeToString(i));
             return -1;
         }
+        if (STRNEQ_NULLABLE(expectLinkPoint[i],
+                            cgroup->controllers[i].linkPoint)) {
+            fprintf(stderr, "Wrong link '%s', expected '%s' for '%s'\n",
+                    cgroup->controllers[i].linkPoint,
+                    expectLinkPoint[i],
+                    virCgroupControllerTypeToString(i));
+            return -1;
+        }
         if (STRNEQ_NULLABLE(expectPlacement[i],
                             cgroup->controllers[i].placement)) {
             fprintf(stderr, "Wrong placement '%s', expected '%s' for '%s'\n",
@@ -87,6 +96,17 @@ const char *mountsFull[VIR_CGROUP_CONTROLLER_LAST] = {
     [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup/blkio",
 };
 
+const char *links[VIR_CGROUP_CONTROLLER_LAST] = {
+    [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu",
+    [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpuacct",
+    [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
+    [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
+    [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+    [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
+    [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
+};
+
+
 static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED)
 {
     virCgroupPtr cgroup = NULL;
@@ -106,7 +126,7 @@ static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED)
         goto cleanup;
     }
 
-    ret = validateCgroup(cgroup, "", mountsFull, placement);
+    ret = validateCgroup(cgroup, "", mountsFull, links, placement);
 
 cleanup:
     virCgroupFree(&cgroup);
@@ -168,14 +188,14 @@ static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED)
         fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
         goto cleanup;
     }
-    ret = validateCgroup(cgroup, "libvirt/lxc", mountsSmall, placementSmall);
+    ret = validateCgroup(cgroup, "libvirt/lxc", mountsSmall, links, placementSmall);
     virCgroupFree(&cgroup);
 
     if ((rv = virCgroupNewDriver("lxc", true, -1, &cgroup)) != 0) {
         fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
         goto cleanup;
     }
-    ret = validateCgroup(cgroup, "libvirt/lxc", mountsFull, placementFull);
+    ret = validateCgroup(cgroup, "libvirt/lxc", mountsFull, links, placementFull);
 
 cleanup:
     virCgroupFree(&cgroup);
@@ -209,7 +229,7 @@ static int testCgroupNewForDriverDomain(const void *args ATTRIBUTE_UNUSED)
         goto cleanup;
     }
 
-    ret = validateCgroup(domaincgroup, "libvirt/lxc/wibble", mountsFull, placement);
+    ret = validateCgroup(domaincgroup, "libvirt/lxc/wibble", mountsFull, links, placement);
 
 cleanup:
     virCgroupFree(&drivercgroup);
@@ -272,14 +292,14 @@ static int testCgroupNewForPartition(const void *args ATTRIBUTE_UNUSED)
         fprintf(stderr, "Cannot create /virtualmachines cgroup: %d\n", -rv);
         goto cleanup;
     }
-    ret = validateCgroup(cgroup, "/virtualmachines", mountsSmall, placementSmall);
+    ret = validateCgroup(cgroup, "/virtualmachines", mountsSmall, links, placementSmall);
     virCgroupFree(&cgroup);
 
     if ((rv = virCgroupNewPartition("/virtualmachines", true, -1, &cgroup)) != 0) {
         fprintf(stderr, "Cannot create /virtualmachines cgroup: %d\n", -rv);
         goto cleanup;
     }
-    ret = validateCgroup(cgroup, "/virtualmachines", mountsFull, placementFull);
+    ret = validateCgroup(cgroup, "/virtualmachines", mountsFull, links, placementFull);
 
 cleanup:
     virCgroupFree(&cgroup);
@@ -324,7 +344,7 @@ static int testCgroupNewForPartitionNested(const void *args ATTRIBUTE_UNUSED)
         goto cleanup;
     }
 
-    ret = validateCgroup(cgroup, "/users/berrange", mountsFull, placementFull);
+    ret = validateCgroup(cgroup, "/users/berrange", mountsFull, links, placementFull);
 
 cleanup:
     virCgroupFree(&cgroup);
@@ -359,7 +379,7 @@ static int testCgroupNewForPartitionDomain(const void *args ATTRIBUTE_UNUSED)
         goto cleanup;
     }
 
-    ret = validateCgroup(domaincgroup, "/production/foo.lxc.libvirt", mountsFull, placement);
+    ret = validateCgroup(domaincgroup, "/production/foo.lxc.libvirt", mountsFull, links, placement);
 
 cleanup:
     virCgroupFree(&partitioncgroup);
-- 
1.8.1.4




More information about the libvir-list mailing list