From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list