From e1184bde63a7ed92fb99fc4eba4b4abdf6a01815 Mon Sep 17 00:00:00 2001 Message-Id: From: Pavel Hrdina Date: Mon, 1 Jul 2019 17:06:27 +0200 Subject: [PATCH] vircgroup: extract v1 detect functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Fabiano Fidêncio Reviewed-by: Ján Tomko Signed-off-by: Pavel Hrdina (cherry picked from commit 42a3fcc02bcaec4a0c037a5c59ca63f3fc90e90f) Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1689297 Signed-off-by: Pavel Hrdina Message-Id: <3a918fc4eda51c5e9aff5efc93fe14886470578e.1561993100.git.phrdina@redhat.com> Reviewed-by: Ján Tomko --- src/util/vircgroup.c | 138 ++----------------------------- src/util/vircgroupbackend.h | 14 ++++ src/util/vircgroupv1.c | 158 ++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 130 deletions(-) diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 9d644d37d1..10c99a66fd 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -235,82 +235,6 @@ virCgroupPartitionEscape(char **path) } -static int -virCgroupResolveMountLink(const char *mntDir, - const char *typeStr, - virCgroupControllerPtr controller) -{ - VIR_AUTOFREE(char *) linkSrc = NULL; - VIR_AUTOFREE(char *) tmp = NULL; - char *dirName; - struct stat sb; - - if (VIR_STRDUP(tmp, mntDir) < 0) - return -1; - - dirName = strrchr(tmp, '/'); - if (!dirName) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Missing '/' separator in cgroup mount '%s'"), tmp); - return -1; - } - - if (!strchr(dirName + 1, ',')) - return 0; - - *dirName = '\0'; - if (virAsprintf(&linkSrc, "%s/%s", tmp, typeStr) < 0) - return -1; - *dirName = '/'; - - if (lstat(linkSrc, &sb) < 0) { - if (errno == ENOENT) { - VIR_WARN("Controller %s co-mounted at %s is missing symlink at %s", - typeStr, tmp, linkSrc); - } else { - virReportSystemError(errno, _("Cannot stat %s"), linkSrc); - return -1; - } - } else { - if (!S_ISLNK(sb.st_mode)) { - VIR_WARN("Expecting a symlink at %s for controller %s", - linkSrc, typeStr); - } else { - VIR_STEAL_PTR(controller->linkPoint, linkSrc); - } - } - - return 0; -} - - -static bool -virCgroupMountOptsMatchController(const char *mntOpts, - const char *typeStr) -{ - const char *tmp = mntOpts; - int typeLen = strlen(typeStr); - - while (tmp) { - const char *next = strchr(tmp, ','); - int len; - if (next) { - len = next - tmp; - next++; - } else { - len = strlen(tmp); - } - - if (typeLen == len && STREQLEN(typeStr, tmp, len)) - return true; - - tmp = next; - } - - return false; -} - - /* * Process /proc/mounts figuring out what controllers are * mounted and where @@ -318,7 +242,6 @@ virCgroupMountOptsMatchController(const char *mntOpts, static int virCgroupDetectMounts(virCgroupPtr group) { - size_t i; FILE *mounts = NULL; struct mntent entry; char buf[CGROUP_MAX_VAL]; @@ -331,34 +254,11 @@ virCgroupDetectMounts(virCgroupPtr group) } while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) { - if (STRNEQ(entry.mnt_type, "cgroup")) - continue; - - for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { - const char *typestr = virCgroupControllerTypeToString(i); - - if (virCgroupMountOptsMatchController(entry.mnt_opts, typestr)) { - /* Note that the lines in /proc/mounts have the same - * order than the mount operations, and that there may - * be duplicates due to bind mounts. This means - * that the same mount point may be processed more than - * once. We need to save the results of the last one, - * and we need to be careful to release the memory used - * by previous processing. */ - virCgroupControllerPtr controller = &group->controllers[i]; - - VIR_FREE(controller->mountPoint); - VIR_FREE(controller->linkPoint); - if (VIR_STRDUP(controller->mountPoint, entry.mnt_dir) < 0) - goto cleanup; - - /* If it is a co-mount it has a filename like "cpu,cpuacct" - * and we must identify the symlink path */ - if (virCgroupResolveMountLink(entry.mnt_dir, typestr, - controller) < 0) { - goto cleanup; - } - } + if (group->backend->detectMounts(group, + entry.mnt_type, + entry.mnt_opts, + entry.mnt_dir) < 0) { + goto cleanup; } } @@ -432,7 +332,6 @@ virCgroupDetectPlacement(virCgroupPtr group, pid_t pid, const char *path) { - size_t i; FILE *mapping = NULL; char line[1024]; int ret = -1; @@ -472,30 +371,9 @@ virCgroupDetectPlacement(virCgroupPtr group, controllers++; selfpath++; - for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { - const char *typestr = virCgroupControllerTypeToString(i); - - if (virCgroupMountOptsMatchController(controllers, typestr) && - group->controllers[i].mountPoint != NULL && - group->controllers[i].placement == NULL) { - /* - * selfpath == "/" + path="" -> "/" - * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" - * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" - */ - if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) { - if (VIR_STRDUP(group->controllers[i].placement, - selfpath) < 0) - goto cleanup; - } else { - if (virAsprintf(&group->controllers[i].placement, - "%s%s%s", selfpath, - (STREQ(selfpath, "/") || - STREQ(path, "") ? "" : "/"), - path) < 0) - goto cleanup; - } - } + if (group->backend->detectPlacement(group, path, controllers, + selfpath) < 0) { + goto cleanup; } } diff --git a/src/util/vircgroupbackend.h b/src/util/vircgroupbackend.h index 81ee597fc8..fadc7efdcf 100644 --- a/src/util/vircgroupbackend.h +++ b/src/util/vircgroupbackend.h @@ -45,6 +45,18 @@ typedef int (*virCgroupCopyMountsCB)(virCgroupPtr group, virCgroupPtr parent); +typedef int +(*virCgroupDetectMountsCB)(virCgroupPtr group, + const char *mntType, + const char *mntOpts, + const char *mntDir); + +typedef int +(*virCgroupDetectPlacementCB)(virCgroupPtr group, + const char *path, + const char *controllers, + const char *selfpath); + struct _virCgroupBackend { virCgroupBackendType type; @@ -52,6 +64,8 @@ struct _virCgroupBackend { virCgroupAvailableCB available; virCgroupValidateMachineGroupCB validateMachineGroup; virCgroupCopyMountsCB copyMounts; + virCgroupDetectMountsCB detectMounts; + virCgroupDetectPlacementCB detectPlacement; }; typedef struct _virCgroupBackend virCgroupBackend; typedef virCgroupBackend *virCgroupBackendPtr; diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c index 50b58ab413..bd9f28f6e9 100644 --- a/src/util/vircgroupv1.c +++ b/src/util/vircgroupv1.c @@ -23,6 +23,7 @@ #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R # include #endif +#include #include "internal.h" @@ -38,6 +39,7 @@ #include "virlog.h" #include "virstring.h" #include "virsystemd.h" +#include "virerror.h" VIR_LOG_INIT("util.cgroup"); @@ -181,12 +183,168 @@ virCgroupV1CopyMounts(virCgroupPtr group, } +static int +virCgroupV1ResolveMountLink(const char *mntDir, + const char *typeStr, + virCgroupControllerPtr controller) +{ + VIR_AUTOFREE(char *) linkSrc = NULL; + VIR_AUTOFREE(char *) tmp = NULL; + char *dirName; + struct stat sb; + + if (VIR_STRDUP(tmp, mntDir) < 0) + return -1; + + dirName = strrchr(tmp, '/'); + if (!dirName) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing '/' separator in cgroup mount '%s'"), tmp); + return -1; + } + + if (!strchr(dirName + 1, ',')) + return 0; + + *dirName = '\0'; + if (virAsprintf(&linkSrc, "%s/%s", tmp, typeStr) < 0) + return -1; + *dirName = '/'; + + if (lstat(linkSrc, &sb) < 0) { + if (errno == ENOENT) { + VIR_WARN("Controller %s co-mounted at %s is missing symlink at %s", + typeStr, tmp, linkSrc); + } else { + virReportSystemError(errno, _("Cannot stat %s"), linkSrc); + return -1; + } + } else { + if (!S_ISLNK(sb.st_mode)) { + VIR_WARN("Expecting a symlink at %s for controller %s", + linkSrc, typeStr); + } else { + VIR_STEAL_PTR(controller->linkPoint, linkSrc); + } + } + + return 0; +} + + +static bool +virCgroupV1MountOptsMatchController(const char *mntOpts, + const char *typeStr) +{ + const char *tmp = mntOpts; + int typeLen = strlen(typeStr); + + while (tmp) { + const char *next = strchr(tmp, ','); + int len; + if (next) { + len = next - tmp; + next++; + } else { + len = strlen(tmp); + } + + if (typeLen == len && STREQLEN(typeStr, tmp, len)) + return true; + + tmp = next; + } + + return false; +} + + +static int +virCgroupV1DetectMounts(virCgroupPtr group, + const char *mntType, + const char *mntOpts, + const char *mntDir) +{ + size_t i; + + if (STRNEQ(mntType, "cgroup")) + return 0; + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + const char *typestr = virCgroupV1ControllerTypeToString(i); + + if (virCgroupV1MountOptsMatchController(mntOpts, typestr)) { + /* Note that the lines in /proc/mounts have the same + * order than the mount operations, and that there may + * be duplicates due to bind mounts. This means + * that the same mount point may be processed more than + * once. We need to save the results of the last one, + * and we need to be careful to release the memory used + * by previous processing. */ + virCgroupControllerPtr controller = &group->controllers[i]; + + VIR_FREE(controller->mountPoint); + VIR_FREE(controller->linkPoint); + if (VIR_STRDUP(controller->mountPoint, mntDir) < 0) + return -1; + + /* If it is a co-mount it has a filename like "cpu,cpuacct" + * and we must identify the symlink path */ + if (virCgroupV1ResolveMountLink(mntDir, typestr, controller) < 0) + return -1; + } + } + + return 0; +} + + +static int +virCgroupV1DetectPlacement(virCgroupPtr group, + const char *path, + const char *controllers, + const char *selfpath) +{ + size_t i; + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + const char *typestr = virCgroupV1ControllerTypeToString(i); + + if (virCgroupV1MountOptsMatchController(controllers, typestr) && + group->controllers[i].mountPoint != NULL && + group->controllers[i].placement == NULL) { + /* + * selfpath == "/" + path="" -> "/" + * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" + * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" + */ + if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) { + if (VIR_STRDUP(group->controllers[i].placement, + selfpath) < 0) + return -1; + } else { + if (virAsprintf(&group->controllers[i].placement, + "%s%s%s", selfpath, + (STREQ(selfpath, "/") || + STREQ(path, "") ? "" : "/"), + path) < 0) + return -1; + } + } + } + + return 0; +} + + virCgroupBackend virCgroupV1Backend = { .type = VIR_CGROUP_BACKEND_TYPE_V1, .available = virCgroupV1Available, .validateMachineGroup = virCgroupV1ValidateMachineGroup, .copyMounts = virCgroupV1CopyMounts, + .detectMounts = virCgroupV1DetectMounts, + .detectPlacement = virCgroupV1DetectPlacement, }; -- 2.22.0