util/vircgroup.c uses a lot of macros to detect if cgroup is supported by the system or not. These macros are pretty smart and allow to keep code compact, however the downside of that is that it's getting harder to navigate through the cgroup code. So re-organise macros in a more simple fashion, i.e. just explicitly provide functional and stub implementation for every public function. --- src/util/vircgroup.c | 984 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 648 insertions(+), 336 deletions(-) diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index cfb4b3f..45db658 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -61,6 +61,13 @@ VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST, "freezer", "blkio", "net_cls", "perf_event", "name=systemd"); +#if defined(__linux__) && defined(HAVE_MNTENT_H) && defined(HAVE_GETMNTENT_R) \ + && defined(_DIRENT_HAVE_D_TYPE) && defined(major) && defined(minor) +# define VIR_CGROUP_SUPPORTED +#endif + +#if defined(VIR_CGROUP_SUPPORTED) + typedef enum { VIR_CGROUP_NONE = 0, /* create subdir under each cgroup if possible. */ VIR_CGROUP_MEM_HIERACHY = 1 << 0, /* call virCgroupSetMemoryUseHierarchy @@ -72,7 +79,6 @@ typedef enum { bool virCgroupAvailable(void) { bool ret = false; -#ifdef HAVE_GETMNTENT_R FILE *mounts = NULL; struct mntent entry; char buf[CGROUP_MAX_VAL]; @@ -91,11 +97,9 @@ bool virCgroupAvailable(void) } VIR_FORCE_FCLOSE(mounts); -#endif return ret; } -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R static int virCgroupPartitionEscape(char **path); @@ -169,16 +173,6 @@ virCgroupValidateMachineGroup(virCgroupPtr group, VIR_FREE(scopename); return valid; } -#else -static bool -virCgroupValidateMachineGroup(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - const char *drivername ATTRIBUTE_UNUSED, - bool stripEmulatorSuffix ATTRIBUTE_UNUSED) -{ - return true; -} -#endif /** * virCgroupFree: @@ -220,7 +214,6 @@ bool virCgroupHasController(virCgroupPtr cgroup, int controller) return cgroup->controllers[controller].mountPoint != NULL; } -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R static int virCgroupCopyMounts(virCgroupPtr group, virCgroupPtr parent) { @@ -339,7 +332,6 @@ error: return -1; } - static int virCgroupCopyPlacement(virCgroupPtr group, const char *path, virCgroupPtr parent) @@ -374,7 +366,6 @@ static int virCgroupCopyPlacement(virCgroupPtr group, return 0; } - /* * virCgroupDetectPlacement: * @group: the group to process @@ -599,8 +590,6 @@ static int virCgroupDetect(virCgroupPtr group, return 0; } -#endif - int virCgroupPathOfController(virCgroupPtr group, int controller, @@ -651,7 +640,6 @@ int virCgroupPathOfController(virCgroupPtr group, return 0; } - static int virCgroupSetValueStr(virCgroupPtr group, int controller, const char *key, @@ -727,8 +715,6 @@ static int virCgroupSetValueU64(virCgroupPtr group, return ret; } - - static int virCgroupSetValueI64(virCgroupPtr group, int controller, const char *key, @@ -797,8 +783,6 @@ cleanup: return ret; } - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group) { size_t i; @@ -993,9 +977,7 @@ error: return -1; } -#endif -#if defined _DIRENT_HAVE_D_TYPE int virCgroupRemoveRecursively(char *grppath) { DIR *grpdir; @@ -1044,14 +1026,6 @@ int virCgroupRemoveRecursively(char *grppath) return rc; } -#else -int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif /** * virCgroupRemove: @@ -1101,7 +1075,6 @@ int virCgroupRemove(virCgroupPtr group) return rc; } - /** * virCgroupAddTask: * @@ -1252,8 +1225,6 @@ cleanup: return ret; } - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R static int virCgroupPartitionNeedsEscaping(const char *path) { FILE *fp = NULL; @@ -1445,18 +1416,6 @@ cleanup: VIR_FREE(newpath); return ret; } -#else -int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED, - int controllers ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif - /** * virCgroupNewSelf: @@ -1484,7 +1443,6 @@ int virCgroupNewSelf(virCgroupPtr *group) * * Returns 0 on success, or -1 on error */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R int virCgroupNewDomainPartition(virCgroupPtr partition, const char *driver, const char *name, @@ -1526,18 +1484,6 @@ cleanup: VIR_FREE(grpname); return ret; } -#else -int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED, - const char *driver ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif /** * virCgroupNewVcpu: @@ -1549,7 +1495,6 @@ int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED, * * Returns 0 on success, or -1 on error */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R int virCgroupNewVcpu(virCgroupPtr domain, int vcpuid, bool create, @@ -1580,17 +1525,6 @@ cleanup: VIR_FREE(name); return ret; } -#else -int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED, - int vcpuid ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif /** * virCgroupNewEmulator: @@ -1601,7 +1535,6 @@ int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED, * * Returns: 0 on success or -1 on error */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R int virCgroupNewEmulator(virCgroupPtr domain, bool create, virCgroupPtr *group) @@ -1626,36 +1559,13 @@ int virCgroupNewEmulator(virCgroupPtr domain, cleanup: return ret; } -#else -int virCgroupNewEmulator(virCgroupPtr domain ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif - - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R int virCgroupNewDetect(pid_t pid, int controllers, virCgroupPtr *group) { return virCgroupNew(pid, "", NULL, controllers, group); } -#else -int virCgroupNewDetect(pid_t pid ATTRIBUTE_UNUSED, - int controllers ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENXIO, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif /* * Returns 0 on success (but @group may be NULL), -1 on fatal error @@ -1941,7 +1851,6 @@ int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) * * Returns: 0 on success, -1 on error */ -#if defined(major) && defined(minor) int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, const char *path, unsigned int weight) @@ -1982,17 +1891,6 @@ int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, VIR_FREE(str); return ret; } -#else -int -virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - unsigned int weight ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif /** * virCgroupSetMemory: @@ -2364,7 +2262,6 @@ cleanup: * Returns: 0 on success, 1 if path exists but is not a device, or * -1 on error */ -#if defined(major) && defined(minor) int virCgroupAllowDevicePath(virCgroupPtr group, const char *path, int perms) { struct stat sb; @@ -2385,17 +2282,6 @@ int virCgroupAllowDevicePath(virCgroupPtr group, const char *path, int perms) minor(sb.st_rdev), perms); } -#else -int virCgroupAllowDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - int perms ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif - /** * virCgroupDenyDevice: @@ -2468,7 +2354,6 @@ cleanup: return ret; } -#if defined(major) && defined(minor) int virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms) { struct stat sb; @@ -2489,16 +2374,6 @@ int virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms) minor(sb.st_rdev), perms); } -#else -int virCgroupDenyDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - int perms ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares) { @@ -2609,63 +2484,6 @@ int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage) "cpuacct.usage_percpu", usage); } -#ifdef _SC_CLK_TCK -int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, - unsigned long long *sys) -{ - char *str; - char *p; - int ret = -1; - static double scale = -1.0; - - if (virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, - "cpuacct.stat", &str) < 0) - return -1; - - if (!(p = STRSKIP(str, "user ")) || - virStrToLong_ull(p, &p, 10, user) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Cannot parse user stat '%s'"), - p); - goto cleanup; - } - if (!(p = STRSKIP(p, "\nsystem ")) || - virStrToLong_ull(p, NULL, 10, sys) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Cannot parse sys stat '%s'"), - p); - goto cleanup; - } - /* times reported are in system ticks (generally 100 Hz), but that - * rate can theoretically vary between machines. Scale things - * into approximate nanoseconds. */ - if (scale < 0) { - long ticks_per_sec = sysconf(_SC_CLK_TCK); - if (ticks_per_sec == -1) { - virReportSystemError(errno, "%s", - _("Cannot determine system clock HZ")); - goto cleanup; - } - scale = 1000000000.0 / ticks_per_sec; - } - *user *= scale; - *sys *= scale; - - ret = 0; -cleanup: - VIR_FREE(str); - return ret; -} -#else -int virCgroupGetCpuacctStat(virCgroupPtr group ATTRIBUTE_UNUSED, - unsigned long long *user ATTRIBUTE_UNUSED, - unsigned long long *sys ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Control groups not supported on this platform")); - return -1; -} -#endif int virCgroupSetFreezerState(virCgroupPtr group, const char *state) { @@ -2681,53 +2499,614 @@ int virCgroupGetFreezerState(virCgroupPtr group, char **state) "freezer.state", state); } +static char *virCgroupIdentifyRoot(virCgroupPtr group) +{ + char *ret = NULL; + size_t i; -#if defined HAVE_KILL && defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -/* - * Returns 1 if some PIDs are killed, 0 if none are killed, or -1 on error - */ -static int virCgroupKillInternal(virCgroupPtr group, int signum, virHashTablePtr pids) + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + char *tmp; + if (!group->controllers[i].mountPoint) + continue; + if (!(tmp = strrchr(group->controllers[i].mountPoint, '/'))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find directory separator in %s"), + group->controllers[i].mountPoint); + return NULL; + } + + if (VIR_STRNDUP(ret, group->controllers[i].mountPoint, + tmp - group->controllers[i].mountPoint) < 0) + return NULL; + return ret; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find any mounted controllers")); + return NULL; +} + + +int virCgroupIsolateMount(virCgroupPtr group, const char *oldroot, + const char *mountopts) { int ret = -1; - bool killedAny = false; - char *keypath = NULL; - bool done = false; - FILE *fp = NULL; - VIR_DEBUG("group=%p path=%s signum=%d pids=%p", - group, group->path, signum, pids); + size_t i; + char *opts = NULL; + char *root = NULL; - if (virCgroupPathOfController(group, -1, "tasks", &keypath) < 0) + if (!(root = virCgroupIdentifyRoot(group))) return -1; - /* PIDs may be forking as we kill them, so loop - * until there are no new PIDs found - */ - while (!done) { - done = true; - if (!(fp = fopen(keypath, "r"))) { - if (errno == ENOENT) { - VIR_DEBUG("No file %s, assuming done", keypath); - killedAny = false; - goto done; - } - - virReportSystemError(errno, - _("Failed to read %s"), - keypath); - goto cleanup; - } else { - while (!feof(fp)) { - unsigned long pid_value; - if (fscanf(fp, "%lu", &pid_value) != 1) { - if (feof(fp)) - break; - virReportSystemError(errno, - _("Failed to read %s"), - keypath); - goto cleanup; - } - if (virHashLookup(pids, (void*)pid_value)) - continue; + VIR_DEBUG("Mounting cgroups at '%s'", root); + + if (virFileMakePath(root) < 0) { + virReportSystemError(errno, + _("Unable to create directory %s"), + root); + goto cleanup; + } + + if (virAsprintf(&opts, + "mode=755,size=65536%s", mountopts) < 0) + goto cleanup; + + if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC, opts) < 0) { + virReportSystemError(errno, + _("Failed to mount %s on %s type %s"), + "tmpfs", root, "tmpfs"); + goto cleanup; + } + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + if (!group->controllers[i].mountPoint) + continue; + + if (!virFileExists(group->controllers[i].mountPoint)) { + char *src; + if (virAsprintf(&src, "%s%s%s", + oldroot, + group->controllers[i].mountPoint, + group->controllers[i].placement) < 0) + goto cleanup; + + VIR_DEBUG("Create mount point '%s'", group->controllers[i].mountPoint); + if (virFileMakePath(group->controllers[i].mountPoint) < 0) { + virReportSystemError(errno, + _("Unable to create directory %s"), + group->controllers[i].mountPoint); + VIR_FREE(src); + goto cleanup; + } + + if (mount(src, group->controllers[i].mountPoint, NULL, MS_BIND, NULL) < 0) { + virReportSystemError(errno, + _("Failed to bind cgroup '%s' on '%s'"), + src, group->controllers[i].mountPoint); + VIR_FREE(src); + goto cleanup; + } + + VIR_FREE(src); + } + + if (group->controllers[i].linkPoint) { + VIR_DEBUG("Link mount point '%s' to '%s'", + group->controllers[i].mountPoint, + group->controllers[i].linkPoint); + if (symlink(group->controllers[i].mountPoint, + group->controllers[i].linkPoint) < 0) { + virReportSystemError(errno, + _("Unable to symlink directory %s to %s"), + group->controllers[i].mountPoint, + group->controllers[i].linkPoint); + return -1; + } + } + } + ret = 0; + +cleanup: + VIR_FREE(root); + VIR_FREE(opts); + return ret; +} + +#else /* !(VIR_CGROUP_SUPPORTED) */ +bool virCgroupAvailable(void) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return false; +} + +void virCgroupFree(virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); +} + +int virCgroupNewSelf(virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED, + const char *drivername ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED, + const char *partition ATTRIBUTE_UNUSED, + int controllers ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetMemoryHardLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetMemoryHardLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetMemorySoftLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetMemorySoftLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetMemSwapHardLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetMemSwapHardLimit(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetMemSwapUsage(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetMemoryUsage(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long *kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetMemory(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long kb ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetCpusetMems(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *mems ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpusetMems(virCgroupPtr group ATTRIBUTE_UNUSED, + char **mems ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetCpusetCpus(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *cpus ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpusetCpus(virCgroupPtr group ATTRIBUTE_UNUSED, + char **cpus ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupDenyAllDevices(virCgroupPtr group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupDenyDeviceMajor(virCgroupPtr group ATTRIBUTE_UNUSED, + char type ATTRIBUTE_UNUSED, + int major ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupDenyDevice(virCgroupPtr group ATTRIBUTE_UNUSED, + char type ATTRIBUTE_UNUSED, + int major ATTRIBUTE_UNUSED, + int minor ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetCpuCfsPeriod(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long cfs_period ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpuCfsPeriod(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *cfs_period ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetCpuCfsQuota(virCgroupPtr group ATTRIBUTE_UNUSED, + long long cfs_quota ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpuCfsQuota(virCgroupPtr group ATTRIBUTE_UNUSED, + long long *cfs_quota ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetCpuShares(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long shares ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpuShares(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *shares ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group ATTRIBUTE_UNUSED, + char **usage ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetCpuacctUsage(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *usage ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupSetBlkioWeight(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned int weight ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupAllowDevice(virCgroupPtr group ATTRIBUTE_UNUSED, + char type ATTRIBUTE_UNUSED, + int major ATTRIBUTE_UNUSED, + int minor ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupAllowDeviceMajor(virCgroupPtr group ATTRIBUTE_UNUSED, + char type ATTRIBUTE_UNUSED, + int major ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupAddTask(virCgroupPtr group ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupMoveTask(virCgroupPtr src_group ATTRIBUTE_UNUSED, + virCgroupPtr dest_group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupAddTaskController(virCgroupPtr group ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED, + int controller ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetBlkioWeight(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned int *weight ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewMachine(const char *name ATTRIBUTE_UNUSED, + const char *drivername ATTRIBUTE_UNUSED, + bool privileged ATTRIBUTE_UNUSED, + const unsigned char *uuid ATTRIBUTE_UNUSED, + const char *rootdir ATTRIBUTE_UNUSED, + pid_t pidleader ATTRIBUTE_UNUSED, + bool isContainer ATTRIBUTE_UNUSED, + const char *partition ATTRIBUTE_UNUSED, + int controllers ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +bool virCgroupNewIgnoreError(void) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return false; +} + +int virCgroupRemove(virCgroupPtr group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewPartition(const char *path ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED, + int controllers ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewDomainPartition(virCgroupPtr partition ATTRIBUTE_UNUSED, + const char *driver ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewVcpu(virCgroupPtr domain ATTRIBUTE_UNUSED, + int vcpuid ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewEmulator(virCgroupPtr domain ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupNewDetect(pid_t pid ATTRIBUTE_UNUSED, + int controllers ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENXIO, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int +virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + unsigned int weight ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupAllowDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} +int virCgroupDenyDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupPathOfController(virCgroupPtr group ATTRIBUTE_UNUSED, + int controller ATTRIBUTE_UNUSED, + const char *key ATTRIBUTE_UNUSED, + char **path ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +bool virCgroupHasController(virCgroupPtr cgroup ATTRIBUTE_UNUSED, + int controller ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; + +} + +int virCgroupSetFreezerState(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *state ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupGetFreezerState(virCgroupPtr group ATTRIBUTE_UNUSED, + char **state ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} + +int virCgroupIsolateMount(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *oldroot ATTRIBUTE_UNUSED, + const char *mountopts ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Control groups not supported on this platform")); + return -1; +} +#endif /* VIR_CGROUP_SUPPORTED */ + +#if defined(VIR_CGROUP_SUPPORTED) && defined(HAVE_KILL) +/* + * Returns 1 if some PIDs are killed, 0 if none are killed, or -1 on error + */ +static int virCgroupKillInternal(virCgroupPtr group, int signum, virHashTablePtr pids) +{ + int ret = -1; + bool killedAny = false; + char *keypath = NULL; + bool done = false; + FILE *fp = NULL; + VIR_DEBUG("group=%p path=%s signum=%d pids=%p", + group, group->path, signum, pids); + + if (virCgroupPathOfController(group, -1, "tasks", &keypath) < 0) + return -1; + + /* PIDs may be forking as we kill them, so loop + * until there are no new PIDs found + */ + while (!done) { + done = true; + if (!(fp = fopen(keypath, "r"))) { + if (errno == ENOENT) { + VIR_DEBUG("No file %s, assuming done", keypath); + killedAny = false; + goto done; + } + + virReportSystemError(errno, + _("Failed to read %s"), + keypath); + goto cleanup; + } else { + while (!feof(fp)) { + unsigned long pid_value; + if (fscanf(fp, "%lu", &pid_value) != 1) { + if (feof(fp)) + break; + virReportSystemError(errno, + _("Failed to read %s"), + keypath); + goto cleanup; + } + if (virHashLookup(pids, (void*)pid_value)) + continue; VIR_DEBUG("pid=%lu", pid_value); /* Cgroups is a Linux concept, so this cast is safe. */ @@ -2800,7 +3179,6 @@ int virCgroupKill(virCgroupPtr group, int signum) return ret; } - static int virCgroupKillRecursiveInternal(virCgroupPtr group, int signum, virHashTablePtr pids, bool dormdir) { int ret = -1; @@ -2911,7 +3289,7 @@ int virCgroupKillPainfully(virCgroupPtr group) return ret; } -#else /* !(HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R) */ +#else /* !(VIR_CGROUP_SUPPORTED, HAVE_KILL) */ int virCgroupKill(virCgroupPtr group ATTRIBUTE_UNUSED, int signum ATTRIBUTE_UNUSED) { @@ -2933,128 +3311,62 @@ int virCgroupKillPainfully(virCgroupPtr group ATTRIBUTE_UNUSED) _("Control groups not supported on this platform")); return -1; } -#endif /* HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R */ - -#ifdef __linux__ -static char *virCgroupIdentifyRoot(virCgroupPtr group) -{ - char *ret = NULL; - size_t i; - - for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { - char *tmp; - if (!group->controllers[i].mountPoint) - continue; - if (!(tmp = strrchr(group->controllers[i].mountPoint, '/'))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not find directory separator in %s"), - group->controllers[i].mountPoint); - return NULL; - } - - if (VIR_STRNDUP(ret, group->controllers[i].mountPoint, - tmp - group->controllers[i].mountPoint) < 0) - return NULL; - return ret; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Could not find any mounted controllers")); - return NULL; -} - +#endif /* VIR_CGROUP_SUPPORTED, HAVE_KILL */ -int virCgroupIsolateMount(virCgroupPtr group, const char *oldroot, - const char *mountopts) +#if defined(VIR_CGROUP_SUPPORTED) && defined(_SC_CLK_TCK) +int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, + unsigned long long *sys) { + char *str; + char *p; int ret = -1; - size_t i; - char *opts = NULL; - char *root = NULL; + static double scale = -1.0; - if (!(root = virCgroupIdentifyRoot(group))) + if (virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, + "cpuacct.stat", &str) < 0) return -1; - VIR_DEBUG("Mounting cgroups at '%s'", root); - - if (virFileMakePath(root) < 0) { - virReportSystemError(errno, - _("Unable to create directory %s"), - root); + if (!(p = STRSKIP(str, "user ")) || + virStrToLong_ull(p, &p, 10, user) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot parse user stat '%s'"), + p); goto cleanup; } - - if (virAsprintf(&opts, - "mode=755,size=65536%s", mountopts) < 0) - goto cleanup; - - if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC, opts) < 0) { - virReportSystemError(errno, - _("Failed to mount %s on %s type %s"), - "tmpfs", root, "tmpfs"); + if (!(p = STRSKIP(p, "\nsystem ")) || + virStrToLong_ull(p, NULL, 10, sys) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot parse sys stat '%s'"), + p); goto cleanup; } - - for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { - if (!group->controllers[i].mountPoint) - continue; - - if (!virFileExists(group->controllers[i].mountPoint)) { - char *src; - if (virAsprintf(&src, "%s%s%s", - oldroot, - group->controllers[i].mountPoint, - group->controllers[i].placement) < 0) - goto cleanup; - - VIR_DEBUG("Create mount point '%s'", group->controllers[i].mountPoint); - if (virFileMakePath(group->controllers[i].mountPoint) < 0) { - virReportSystemError(errno, - _("Unable to create directory %s"), - group->controllers[i].mountPoint); - VIR_FREE(src); - goto cleanup; - } - - if (mount(src, group->controllers[i].mountPoint, NULL, MS_BIND, NULL) < 0) { - virReportSystemError(errno, - _("Failed to bind cgroup '%s' on '%s'"), - src, group->controllers[i].mountPoint); - VIR_FREE(src); - goto cleanup; - } - - VIR_FREE(src); - } - - if (group->controllers[i].linkPoint) { - VIR_DEBUG("Link mount point '%s' to '%s'", - group->controllers[i].mountPoint, - group->controllers[i].linkPoint); - if (symlink(group->controllers[i].mountPoint, - group->controllers[i].linkPoint) < 0) { - virReportSystemError(errno, - _("Unable to symlink directory %s to %s"), - group->controllers[i].mountPoint, - group->controllers[i].linkPoint); - return -1; - } + /* times reported are in system ticks (generally 100 Hz), but that + * rate can theoretically vary between machines. Scale things + * into approximate nanoseconds. */ + if (scale < 0) { + long ticks_per_sec = sysconf(_SC_CLK_TCK); + if (ticks_per_sec == -1) { + virReportSystemError(errno, "%s", + _("Cannot determine system clock HZ")); + goto cleanup; } + scale = 1000000000.0 / ticks_per_sec; } - ret = 0; + *user *= scale; + *sys *= scale; + ret = 0; cleanup: - VIR_FREE(root); - VIR_FREE(opts); + VIR_FREE(str); return ret; } -#else /* __linux__ */ -int virCgroupIsolateMount(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *oldroot ATTRIBUTE_UNUSED, - const char *mountopts ATTRIBUTE_UNUSED) +#else +int virCgroupGetCpuacctStat(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *user ATTRIBUTE_UNUSED, + unsigned long long *sys ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Control groups not supported on this platform")); return -1; } -#endif /* __linux__ */ +#endif -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list