This patch adds a new structure, virCgroupItem, to represent a cgroup directory(named cgroup item). cgroup directory is created when needed and removed if no one is using it. --- src/conf/domain_conf.h | 5 + src/libvirt_private.syms | 7 +- src/lxc/lxc_cgroup.c | 40 +- src/lxc/lxc_cgroup.h | 2 +- src/lxc/lxc_controller.c | 31 +- src/lxc/lxc_driver.c | 177 +++---- src/lxc/lxc_process.c | 19 +- src/qemu/qemu_cgroup.c | 162 +++--- src/qemu/qemu_cgroup.h | 3 +- src/qemu/qemu_driver.c | 350 +++++-------- src/qemu/qemu_hotplug.c | 21 +- src/qemu/qemu_migration.c | 20 +- src/qemu/qemu_process.c | 7 +- src/util/vircgroup.c | 1253 +++++++++++++++++++++------------------------ src/util/vircgroup.h | 19 +- 15 files changed, 915 insertions(+), 1201 deletions(-) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index dc411e4..395a653 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -47,6 +47,7 @@ # include "device_conf.h" # include "virbitmap.h" # include "virstoragefile.h" +# include "vircgroup.h" /* forward declarations of all device types, required by * virDomainDeviceDef @@ -1888,6 +1889,10 @@ struct _virDomainObj { void (*privateDataFreeFunc)(void *); int taint; + + virCgroupPtr cgroup; + virCgroupPtr *vcpuCgroups; + virCgroupPtr cgroupEmulator; }; typedef struct _virDomainObjList virDomainObjList; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 57e3eb4..50a668a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -85,10 +85,6 @@ virCgroupDenyAllDevices; virCgroupDenyDevice; virCgroupDenyDeviceMajor; virCgroupDenyDevicePath; -virCgroupForDomain; -virCgroupForDriver; -virCgroupForEmulator; -virCgroupForVcpu; virCgroupFree; virCgroupGetAppRoot; virCgroupGetBlkioWeight; @@ -109,10 +105,11 @@ virCgroupGetMemSwapUsage; virCgroupKill; virCgroupKillPainfully; virCgroupKillRecursive; +virCgroupMakePath; virCgroupMounted; virCgroupMoveTask; +virCgroupNew; virCgroupPathOfController; -virCgroupRemove; virCgroupSetBlkioDeviceWeight; virCgroupSetBlkioWeight; virCgroupSetCpuCfsPeriod; diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index a075335..04b2513 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -242,7 +242,7 @@ int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo) int ret; virCgroupPtr cgroup; - ret = virCgroupGetAppRoot(&cgroup); + ret = virCgroupGetAppRoot(&cgroup, true); if (ret < 0) { virReportSystemError(-ret, "%s", _("Unable to get cgroup for container")); @@ -472,53 +472,29 @@ cleanup: } -int virLXCCgroupSetup(virDomainDefPtr def) +int virLXCCgroupSetup(virCgroupPtr cgroup, virDomainDefPtr def) { - virCgroupPtr driver = NULL; - virCgroupPtr cgroup = NULL; - int ret = -1; int rc; - rc = virCgroupForDriver("lxc", &driver, 1, 0); - if (rc != 0) { - virReportSystemError(-rc, "%s", - _("Unable to get cgroup for driver")); - goto cleanup; - } - - rc = virCgroupForDomain(driver, def->name, &cgroup, 1); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to create cgroup for domain %s"), - def->name); - goto cleanup; - } - if (virLXCCgroupSetupCpuTune(def, cgroup) < 0) - goto cleanup; + return -1; if (virLXCCgroupSetupBlkioTune(def, cgroup) < 0) - goto cleanup; + return -1; if (virLXCCgroupSetupMemTune(def, cgroup) < 0) - goto cleanup; + return -1; if (virLXCCgroupSetupDeviceACL(def, cgroup) < 0) - goto cleanup; + return -1; rc = virCgroupAddTask(cgroup, getpid()); if (rc != 0) { virReportSystemError(-rc, _("Unable to add task %d to cgroup for domain %s"), getpid(), def->name); - goto cleanup; + return -1; } - ret = 0; - -cleanup: - virCgroupFree(&cgroup); - virCgroupFree(&driver); - - return ret; + return 0; } diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h index fff554b..3b3541a 100644 --- a/src/lxc/lxc_cgroup.h +++ b/src/lxc/lxc_cgroup.h @@ -26,7 +26,7 @@ # include "lxc_fuse.h" # include "virusb.h" -int virLXCCgroupSetup(virDomainDefPtr def); +int virLXCCgroupSetup(virCgroupPtr cgroup, virDomainDefPtr def); int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo); int diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 2673f72..4a7a63b 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -130,6 +130,8 @@ struct _virLXCController { int timerShutdown; virLXCFusePtr fuse; + + virCgroupPtr cgroup; }; #include "lxc_controller_dispatch.h" @@ -272,6 +274,8 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl) VIR_FREE(ctrl->devptmx); + virCgroupFree(&ctrl->cgroup); + virDomainDefFree(ctrl->def); VIR_FREE(ctrl->name); @@ -548,6 +552,31 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) return 0; } +static int virLXCControllerSetupCgroup(virLXCControllerPtr ctrl) +{ + virCgroupPtr appCgroup = NULL; + int rc; + + rc = virCgroupGetAppRoot(&appCgroup, true); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for libvirt")); + goto cleanup; + } + + rc = virCgroupNew("lxc", appCgroup, &ctrl->cgroup); + if (rc != 0) { + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for driver")); + goto cleanup; + } + + rc = virLXCCgroupSetup(ctrl->cgroup, ctrl->def); + +cleanup: + virCgroupFree(&appCgroup); + return rc; +} /** * virLXCControllerSetupResourceLimits @@ -567,7 +596,7 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) if (virLXCControllerSetupNUMAPolicy(ctrl) < 0) return -1; - return virLXCCgroupSetup(ctrl->def); + return virLXCControllerSetupCgroup(ctrl); } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 671b19d..b265095 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -527,7 +527,6 @@ static int lxcDomainGetInfo(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; - virCgroupPtr cgroup = NULL; int ret = -1, rc; lxcDriverLock(driver); @@ -543,22 +542,16 @@ static int lxcDomainGetInfo(virDomainPtr dom, info->state = virDomainObjGetState(vm, NULL); - if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) { + if (!virDomainObjIsActive(vm) || vm->cgroup == NULL) { info->cpuTime = 0; info->memory = vm->def->mem.cur_balloon; } else { - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get cgroup for %s"), vm->def->name); - goto cleanup; - } - - if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) { + if (virCgroupGetCpuacctUsage(vm->cgroup, &(info->cpuTime)) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Cannot read cputime for domain")); goto cleanup; } - if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) { + if ((rc = virCgroupGetMemoryUsage(vm->cgroup, &(info->memory))) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Cannot read memory usage for domain")); if (rc == -ENOENT) { @@ -576,8 +569,6 @@ static int lxcDomainGetInfo(virDomainPtr dom, cleanup: lxcDriverUnlock(driver); - if (cgroup) - virCgroupFree(&cgroup); if (vm) virObjectUnlock(vm); return ret; @@ -708,7 +699,6 @@ cleanup: static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; - virCgroupPtr cgroup = NULL; int ret = -1; lxcDriverLock(driver); @@ -734,19 +724,13 @@ static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { goto cleanup; } - if (driver->cgroup == NULL) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cgroups must be configured on the host")); goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get cgroup for %s"), vm->def->name); - goto cleanup; - } - - if (virCgroupSetMemory(cgroup, newmem) < 0) { + if (virCgroupSetMemory(vm->cgroup, newmem) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to set memory for domain")); goto cleanup; @@ -757,8 +741,6 @@ static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { cleanup: if (vm) virObjectUnlock(vm); - if (cgroup) - virCgroupFree(&cgroup); return ret; } @@ -770,7 +752,6 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr cgroup = NULL; virDomainObjPtr vm = NULL; int ret = -1; int rc; @@ -797,7 +778,7 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -808,21 +789,21 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, virTypedParameterPtr param = ¶ms[i]; if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { - rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul); + rc = virCgroupSetMemoryHardLimit(vm->cgroup, params[i].value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set memory hard_limit tunable")); ret = -1; } } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { - rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul); + rc = virCgroupSetMemorySoftLimit(vm->cgroup, params[i].value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set memory soft_limit tunable")); ret = -1; } } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) { - rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul); + rc = virCgroupSetMemSwapHardLimit(vm->cgroup, params[i].value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set swap_hard_limit tunable")); @@ -832,8 +813,6 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, } cleanup: - if (cgroup) - virCgroupFree(&cgroup); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -848,7 +827,6 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr cgroup = NULL; virDomainObjPtr vm = NULL; unsigned long long val; int ret = -1; @@ -874,7 +852,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to get cgroup for %s"), vm->def->name); goto cleanup; @@ -886,7 +864,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, switch (i) { case 0: /* fill memory hard limit here */ - rc = virCgroupGetMemoryHardLimit(cgroup, &val); + rc = virCgroupGetMemoryHardLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get memory hard limit")); @@ -897,7 +875,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, goto cleanup; break; case 1: /* fill memory soft limit here */ - rc = virCgroupGetMemorySoftLimit(cgroup, &val); + rc = virCgroupGetMemorySoftLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get memory soft limit")); @@ -908,7 +886,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, goto cleanup; break; case 2: /* fill swap hard limit here */ - rc = virCgroupGetMemSwapHardLimit(cgroup, &val); + rc = virCgroupGetMemSwapHardLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get swap hard limit")); @@ -932,8 +910,6 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, ret = 0; cleanup: - if (cgroup) - virCgroupFree(&cgroup); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -1408,6 +1384,7 @@ static int lxcStartup(bool privileged, virStateInhibitCallback callback ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { + virCgroupPtr appCgroup = NULL; char *ld; int rc; @@ -1452,15 +1429,19 @@ static int lxcStartup(bool privileged, lxc_driver->log_libvirtd = 0; /* by default log to container logfile */ lxc_driver->have_netns = lxcCheckNetNsSupport(); - rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1); - if (rc < 0) { - char buf[1024] ATTRIBUTE_UNUSED; - VIR_DEBUG("Unable to create cgroup for LXC driver: %s", - virStrerror(-rc, buf, sizeof(buf))); - /* Don't abort startup. We will explicitly report to - * the user when they try to start a VM - */ + rc = virCgroupGetAppRoot(&appCgroup, privileged); + if (appCgroup) { + rc = virCgroupNew("lxc", appCgroup, &lxc_driver->cgroup); + if (rc < 0) { + char buf[1024]; + VIR_DEBUG("Unable to create cgroup for LXC driver: %s", + virStrerror(-rc, buf, sizeof(buf))); + /* Don't abort startup. We will explicitly report to + * the user when they try to start a VM + */ + } } + virCgroupFree(&appCgroup); /* Call function to load lxc driver configuration information */ if (lxcLoadDriverConfig(lxc_driver) < 0) @@ -1565,6 +1546,7 @@ static int lxcShutdown(void) VIR_FREE(lxc_driver->autostartDir); VIR_FREE(lxc_driver->stateDir); VIR_FREE(lxc_driver->logDir); + virCgroupFree(&lxc_driver->cgroup); lxcDriverUnlock(lxc_driver); virMutexDestroy(&lxc_driver->lock); VIR_FREE(lxc_driver); @@ -1754,7 +1736,6 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr vmdef = NULL; int ret = -1; @@ -1799,7 +1780,7 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, "%s", _("cgroup CPU controller is not mounted")); goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); @@ -1812,7 +1793,7 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = virCgroupSetCpuShares(group, params[i].value.ul); + rc = virCgroupSetCpuShares(vm->cgroup, params[i].value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set cpu shares tunable")); @@ -1827,7 +1808,7 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, } } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = lxcSetVcpuBWLive(group, params[i].value.ul, 0); + rc = lxcSetVcpuBWLive(vm->cgroup, params[i].value.ul, 0); if (rc != 0) goto cleanup; @@ -1840,7 +1821,7 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, } } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = lxcSetVcpuBWLive(group, 0, params[i].value.l); + rc = lxcSetVcpuBWLive(vm->cgroup, 0, params[i].value.l); if (rc != 0) goto cleanup; @@ -1871,7 +1852,6 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, cleanup: virDomainDefFree(vmdef); - virCgroupFree(&group); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -1893,7 +1873,6 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, unsigned int flags) { virLXCDriverPtr driver = dom->conn->privateData; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef; unsigned long long shares = 0; @@ -1943,13 +1922,13 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } - rc = virCgroupGetCpuShares(group, &shares); + rc = virCgroupGetCpuShares(vm->cgroup, &shares); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get cpu shares tunable")); @@ -1957,7 +1936,7 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, } if (*nparams > 1 && cpu_bw_status) { - rc = lxcGetVcpuBWLive(group, &period, "a); + rc = lxcGetVcpuBWLive(vm->cgroup, &period, "a); if (rc != 0) goto cleanup; } @@ -1990,7 +1969,6 @@ out: ret = 0; cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -2014,7 +1992,6 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; int ret = -1; @@ -2048,7 +2025,7 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -2066,7 +2043,7 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, goto cleanup; } - rc = virCgroupSetBlkioWeight(group, params[i].value.ui); + rc = virCgroupSetBlkioWeight(vm->cgroup, params[i].value.ui); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set blkio weight tunable")); @@ -2099,7 +2076,6 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, ret = 0; cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -2116,7 +2092,6 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, { virLXCDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; unsigned int val; @@ -2153,7 +2128,7 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -2165,7 +2140,7 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, switch (i) { case 0: /* fill blkio weight here */ - rc = virCgroupGetBlkioWeight(group, &val); + rc = virCgroupGetBlkioWeight(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get blkio weight")); @@ -2207,8 +2182,6 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, ret = 0; cleanup: - if (group) - virCgroupFree(&group); if (vm) virObjectUnlock(vm); lxcDriverUnlock(driver); @@ -2378,7 +2351,7 @@ cleanup: return ret; } -static int lxcFreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm) +static int lxcFreezeContainer(virDomainObjPtr vm) { int timeout = 1000; /* In milliseconds */ int check_interval = 1; /* In milliseconds */ @@ -2388,8 +2361,7 @@ static int lxcFreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm) char *state = NULL; virCgroupPtr cgroup = NULL; - if (!(driver->cgroup && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0)) + if (!vm->cgroup) return -1; /* From here on, we know that cgroup != NULL. */ @@ -2496,7 +2468,7 @@ static int lxcDomainSuspend(virDomainPtr dom) } if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) { - if (lxcFreezeContainer(driver, vm) < 0) { + if (lxcFreezeContainer(vm) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Suspend operation failed")); goto cleanup; @@ -2521,18 +2493,15 @@ cleanup: return ret; } -static int lxcUnfreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm) +static int lxcUnfreezeContainer(virDomainObjPtr vm) { int ret; - virCgroupPtr cgroup = NULL; - if (!(driver->cgroup && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0)) + if (!(vm->cgroup)) return -1; - ret = virCgroupSetFreezerState(cgroup, "THAWED"); + ret = virCgroupSetFreezerState(vm->cgroup, "THAWED"); - virCgroupFree(&cgroup); return ret; } @@ -2561,7 +2530,7 @@ static int lxcDomainResume(virDomainPtr dom) } if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) { - if (lxcUnfreezeContainer(driver, vm) < 0) { + if (lxcUnfreezeContainer(vm) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Resume operation failed")); goto cleanup; @@ -3104,7 +3073,6 @@ lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainDiskDefPtr def = dev->data.disk; - virCgroupPtr group = NULL; int ret = -1; char *dst = NULL; struct stat sb; @@ -3195,13 +3163,13 @@ lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } - if (virCgroupAllowDevicePath(group, def->src, + if (virCgroupAllowDevicePath(vm->cgroup, def->src, (def->readonly ? VIR_CGROUP_DEVICE_READ : VIR_CGROUP_DEVICE_RW) | @@ -3219,8 +3187,6 @@ lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver, cleanup: def->src = tmpsrc; virDomainAuditDisk(vm, NULL, def->src, "attach", ret == 0); - if (group) - virCgroupFree(&group); if (dst && created && ret < 0) unlink(dst); return ret; @@ -3374,7 +3340,6 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver, mode_t mode; bool created = false; virUSBDevicePtr usb = NULL; - virCgroupPtr group = NULL; if (virDomainHostdevFind(vm->def, def, NULL) >= 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", @@ -3415,7 +3380,7 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -3462,7 +3427,7 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver, if (virUSBDeviceFileIterate(usb, virLXCSetupHostUsbDeviceCgroup, - &group) < 0) + &vm->cgroup) < 0) goto cleanup; ret = 0; @@ -3473,7 +3438,6 @@ cleanup: unlink(dstfile); virUSBDeviceFree(usb); - virCgroupFree(&group); VIR_FREE(src); VIR_FREE(dstfile); VIR_FREE(dstdir); @@ -3489,7 +3453,6 @@ lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevDefPtr def = dev->data.hostdev; - virCgroupPtr group = NULL; int ret = -1; char *dst = NULL; char *vroot = NULL; @@ -3564,13 +3527,13 @@ lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } - if (virCgroupAllowDevicePath(group, def->source.caps.u.storage.block, + if (virCgroupAllowDevicePath(vm->cgroup, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RW | VIR_CGROUP_DEVICE_MKNOD) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -3585,8 +3548,6 @@ lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver, cleanup: virDomainAuditHostdev(vm, def, "attach", ret == 0); - if (group) - virCgroupFree(&group); if (dst && created && ret < 0) unlink(dst); VIR_FREE(dst); @@ -3602,7 +3563,6 @@ lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevDefPtr def = dev->data.hostdev; - virCgroupPtr group = NULL; int ret = -1; char *dst = NULL; char *vroot = NULL; @@ -3677,13 +3637,13 @@ lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } - if (virCgroupAllowDevicePath(group, def->source.caps.u.misc.chardev, + if (virCgroupAllowDevicePath(vm->cgroup, def->source.caps.u.misc.chardev, VIR_CGROUP_DEVICE_RW | VIR_CGROUP_DEVICE_MKNOD) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -3698,8 +3658,6 @@ lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver, cleanup: virDomainAuditHostdev(vm, def, "attach", ret == 0); - if (group) - virCgroupFree(&group); if (dst && created && ret < 0) unlink(dst); VIR_FREE(dst); @@ -3822,7 +3780,6 @@ lxcDomainDetachDeviceDiskLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainDiskDefPtr def = NULL; - virCgroupPtr group = NULL; int i, ret = -1; char *dst = NULL; @@ -3854,7 +3811,7 @@ lxcDomainDetachDeviceDiskLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -3869,7 +3826,7 @@ lxcDomainDetachDeviceDiskLive(virLXCDriverPtr driver, } virDomainAuditDisk(vm, def->src, NULL, "detach", true); - if (virCgroupDenyDevicePath(group, def->src, VIR_CGROUP_DEVICE_RWM) != 0) + if (virCgroupDenyDevicePath(vm->cgroup, def->src, VIR_CGROUP_DEVICE_RWM) != 0) VIR_WARN("cannot deny device %s for domain %s", def->src, vm->def->name); @@ -3880,8 +3837,6 @@ lxcDomainDetachDeviceDiskLive(virLXCDriverPtr driver, cleanup: VIR_FREE(dst); - if (group) - virCgroupFree(&group); return ret; } @@ -3959,7 +3914,6 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevDefPtr def = NULL; - virCgroupPtr group = NULL; int idx, ret = -1; char *dst = NULL; char *vroot; @@ -3993,7 +3947,7 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -4014,7 +3968,7 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, if (virUSBDeviceFileIterate(usb, virLXCTeardownHostUsbDeviceCgroup, - &group) < 0) + &vm->cgroup) < 0) VIR_WARN("cannot deny device %s for domain %s", dst, vm->def->name); @@ -4028,7 +3982,6 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, cleanup: virUSBDeviceFree(usb); VIR_FREE(dst); - virCgroupFree(&group); return ret; } @@ -4040,7 +3993,6 @@ lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevDefPtr def = NULL; - virCgroupPtr group = NULL; int i, ret = -1; char *dst = NULL; @@ -4072,7 +4024,7 @@ lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -4087,7 +4039,8 @@ lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver, } virDomainAuditHostdev(vm, def, "detach", true); - if (virCgroupDenyDevicePath(group, def->source.caps.u.storage.block, VIR_CGROUP_DEVICE_RWM) != 0) + if (virCgroupDenyDevicePath(vm->cgroup, def->source.caps.u.storage.block, + VIR_CGROUP_DEVICE_RWM) != 0) VIR_WARN("cannot deny device %s for domain %s", def->source.caps.u.storage.block, vm->def->name); @@ -4098,8 +4051,6 @@ lxcDomainDetachDeviceHostdevStorageLive(virLXCDriverPtr driver, cleanup: VIR_FREE(dst); - if (group) - virCgroupFree(&group); return ret; } @@ -4111,7 +4062,6 @@ lxcDomainDetachDeviceHostdevMiscLive(virLXCDriverPtr driver, { virLXCDomainObjPrivatePtr priv = vm->privateData; virDomainHostdevDefPtr def = NULL; - virCgroupPtr group = NULL; int i, ret = -1; char *dst = NULL; @@ -4143,7 +4093,7 @@ lxcDomainDetachDeviceHostdevMiscLive(virLXCDriverPtr driver, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (vm->cgroup == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -4158,7 +4108,8 @@ lxcDomainDetachDeviceHostdevMiscLive(virLXCDriverPtr driver, } virDomainAuditHostdev(vm, def, "detach", true); - if (virCgroupDenyDevicePath(group, def->source.caps.u.misc.chardev, VIR_CGROUP_DEVICE_RWM) != 0) + if (virCgroupDenyDevicePath(vm->cgroup, def->source.caps.u.misc.chardev, + VIR_CGROUP_DEVICE_RWM) != 0) VIR_WARN("cannot deny device %s for domain %s", def->source.caps.u.misc.chardev, vm->def->name); @@ -4169,8 +4120,6 @@ lxcDomainDetachDeviceHostdevMiscLive(virLXCDriverPtr driver, cleanup: VIR_FREE(dst); - if (group) - virCgroupFree(&group); return ret; } diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index aaa81a7..397ba1b 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -218,7 +218,6 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, virDomainObjPtr vm, virDomainShutoffReason reason) { - virCgroupPtr cgroup; int i; virLXCDomainObjPrivatePtr priv = vm->privateData; virNetDevVPortProfilePtr vport = NULL; @@ -276,11 +275,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, virDomainConfVMNWFilterTeardown(vm); - if (driver->cgroup && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - } + virCgroupFree(&vm->cgroup); /* now that we know it's stopped call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { @@ -685,7 +680,6 @@ int virLXCProcessStop(virLXCDriverPtr driver, virDomainObjPtr vm, virDomainShutoffReason reason) { - virCgroupPtr group = NULL; int rc; VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d", @@ -707,8 +701,8 @@ int virLXCProcessStop(virLXCDriverPtr driver, VIR_FREE(vm->def->seclabels[0]->imagelabel); } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { - rc = virCgroupKillPainfully(group); + if (vm->cgroup) { + rc = virCgroupKillPainfully(vm->cgroup); if (rc < 0) { virReportSystemError(-rc, "%s", _("Failed to kill container PIDs")); @@ -732,7 +726,6 @@ int virLXCProcessStop(virLXCDriverPtr driver, rc = 0; cleanup: - virCgroupFree(&group); return rc; } @@ -945,6 +938,12 @@ int virLXCProcessStart(virConnectPtr conn, return -1; } + if (virCgroupNew(vm->def->name, driver->cgroup, &vm->cgroup) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unable to find cgroup for domain")); + return -1; + } + if (virFileMakePath(driver->logDir) < 0) { virReportSystemError(errno, _("Cannot create log directory '%s'"), diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 4fde1af..cd7ec33 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -210,7 +210,7 @@ int qemuSetupCgroup(virQEMUDriverPtr driver, if (driver->cgroup == NULL) goto done; /* Not supported, so claim success */ - rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 1); + rc = virCgroupNew(vm->def->name, driver->cgroup, &vm->cgroup); if (rc != 0) { virReportSystemError(-rc, _("Unable to create cgroup for %s"), @@ -218,6 +218,17 @@ int qemuSetupCgroup(virQEMUDriverPtr driver, goto cleanup; } + rc = virCgroupMakePath(vm->cgroup); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to create cgroup path for %s"), + vm->def->name); + virCgroupFree(&vm->cgroup); + goto cleanup; + } + + cgroup = vm->cgroup; + if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { qemuCgroupData data = { vm, cgroup }; rc = virCgroupDenyAllDevices(cgroup); @@ -445,15 +456,10 @@ int qemuSetupCgroup(virQEMUDriverPtr driver, } done: virObjectUnref(cfg); - virCgroupFree(&cgroup); return 0; cleanup: virObjectUnref(cfg); - if (cgroup) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - } return -1; } @@ -550,7 +556,6 @@ cleanup: int qemuSetupCgroupForVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm) { - virCgroupPtr cgroup = NULL; virCgroupPtr cgroup_vcpu = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; virDomainDefPtr def = vm->def; @@ -558,6 +563,7 @@ int qemuSetupCgroupForVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm) unsigned int i, j; unsigned long long period = vm->def->cputune.period; long long quota = vm->def->cputune.quota; + char *vcpuName = NULL; if ((period || quota) && (!driver->cgroup || @@ -571,35 +577,39 @@ int qemuSetupCgroupForVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm) * with virProcessInfoSetAffinity, thus the lack of cgroups is not fatal * here. */ - if (driver->cgroup == NULL) + if (vm->cgroup == NULL) return 0; - rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to find cgroup for %s"), - vm->def->name); - goto cleanup; - } - if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) { /* If we don't know VCPU<->PID mapping or all vcpu runs in the same * thread, we cannot control each vcpu. */ VIR_WARN("Unable to get vcpus' pids."); - virCgroupFree(&cgroup); return 0; } + if (VIR_ALLOC_N(vm->vcpuCgroups, priv->nvcpupids) < 0) { + virReportOOMError(); + goto cleanup; + } + for (i = 0; i < priv->nvcpupids; i++) { - rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 1); - if (rc < 0) { + if (virAsprintf(&vcpuName, "vcpu%d", i) < 0) + goto cleanup; + + if ((rc = virCgroupNew(vcpuName, vm->cgroup, &vm->vcpuCgroups[i])) < 0) { virReportSystemError(-rc, _("Unable to create vcpu cgroup for %s(vcpu:" " %d)"), vm->def->name, i); + goto cleanup; } + VIR_FREE(vcpuName); + } + + for (i = 0; i < priv->nvcpupids; i++) { + cgroup_vcpu = vm->vcpuCgroups[i]; /* move the thread for vcpu to sub dir */ rc = virCgroupAddTask(cgroup_vcpu, priv->vcpupids[i]); @@ -632,24 +642,17 @@ int qemuSetupCgroupForVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm) break; } } - - virCgroupFree(&cgroup_vcpu); } - virCgroupFree(&cgroup); return 0; cleanup: - if (cgroup_vcpu) { - virCgroupRemove(cgroup_vcpu); - virCgroupFree(&cgroup_vcpu); - } - - if (cgroup) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); + if (vm->vcpuCgroups) { + for (i = 0; i < priv->nvcpupids; i++) { + if (vm->vcpuCgroups[i]) + virCgroupFree(&vm->vcpuCgroups[i]); + } } - return -1; } @@ -659,8 +662,6 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, { virBitmapPtr cpumask = NULL; virBitmapPtr cpumap = NULL; - virCgroupPtr cgroup = NULL; - virCgroupPtr cgroup_emulator = NULL; virDomainDefPtr def = vm->def; unsigned long long period = vm->def->cputune.emulator_period; long long quota = vm->def->cputune.emulator_quota; @@ -674,20 +675,12 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, return -1; } - if (driver->cgroup == NULL) - return 0; /* Not supported, so claim success */ + if (vm->cgroup == NULL) + return 0; - rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0); + rc = virCgroupNew("emulator", vm->cgroup, &vm->cgroupEmulator); if (rc != 0) { virReportSystemError(-rc, - _("Unable to find cgroup for %s"), - vm->def->name); - goto cleanup; - } - - rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 1); - if (rc < 0) { - virReportSystemError(-rc, _("Unable to create emulator cgroup for %s"), vm->def->name); goto cleanup; @@ -696,7 +689,7 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { if (!qemuCgroupControllerActive(driver, i)) continue; - rc = virCgroupMoveTask(cgroup, cgroup_emulator, i); + rc = virCgroupMoveTask(vm->cgroup, vm->cgroupEmulator, i); if (rc < 0) { virReportSystemError(-rc, _("Unable to move tasks from domain cgroup to " @@ -718,7 +711,7 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, if (cpumask) { if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) { - rc = qemuSetupCgroupEmulatorPin(cgroup_emulator, cpumask); + rc = qemuSetupCgroupEmulatorPin(vm->cgroupEmulator, cpumask); if (rc < 0) goto cleanup; } @@ -727,86 +720,61 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, if (period || quota) { if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) { - if ((rc = qemuSetupCgroupVcpuBW(cgroup_emulator, period, + if ((rc = qemuSetupCgroupVcpuBW(vm->cgroupEmulator, period, quota)) < 0) goto cleanup; } } - virCgroupFree(&cgroup_emulator); - virCgroupFree(&cgroup); virBitmapFree(cpumap); return 0; cleanup: virBitmapFree(cpumap); - if (cgroup_emulator) { - virCgroupRemove(cgroup_emulator); - virCgroupFree(&cgroup_emulator); - } - - if (cgroup) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - } + if (vm->cgroupEmulator) + virCgroupFree(&vm->cgroupEmulator); return rc; } -int qemuRemoveCgroup(virQEMUDriverPtr driver, +int qemuRemoveCgroup(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr vm, - int quiet) + int quiet ATTRIBUTE_UNUSED) { - virCgroupPtr cgroup; - int rc; + qemuDomainObjPrivatePtr priv = vm->privateData; + int i; - if (driver->cgroup == NULL) - return 0; /* Not supported, so claim success */ + if (vm->cgroup) + virCgroupFree(&vm->cgroup); - rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0); - if (rc != 0) { - if (!quiet) - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find cgroup for %s"), - vm->def->name); - return rc; + if (vm->cgroupEmulator) + virCgroupFree(&vm->cgroupEmulator); + + if (vm->vcpuCgroups) { + for (i = 0; i < priv->nvcpupids; i++) { + if (vm->vcpuCgroups[i]) + virCgroupFree(&vm->vcpuCgroups[i]); + } } - rc = virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - return rc; + return 0; } -int qemuAddToCgroup(virQEMUDriverPtr driver, - virDomainDefPtr def) +int qemuAddToCgroup(virDomainObjPtr vm) { - virCgroupPtr cgroup = NULL; int ret = -1; - int rc; - if (driver->cgroup == NULL) + if (vm->cgroup == NULL) return 0; /* Not supported, so claim success */ - rc = virCgroupForDomain(driver->cgroup, def->name, &cgroup, 0); - if (rc != 0) { - virReportSystemError(-rc, - _("unable to find cgroup for domain %s"), - def->name); - goto cleanup; - } - - rc = virCgroupAddTask(cgroup, getpid()); - if (rc != 0) { - virReportSystemError(-rc, + ret = virCgroupAddTask(vm->cgroup, getpid()); + if (ret != 0) { + virReportSystemError(-ret, _("unable to add domain %s task %d to cgroup"), - def->name, getpid()); - goto cleanup; + vm->def->name, getpid()); + return -1; } - ret = 0; - -cleanup: - virCgroupFree(&cgroup); - return ret; + return 0; } diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h index a677d07..ea6d69f 100644 --- a/src/qemu/qemu_cgroup.h +++ b/src/qemu/qemu_cgroup.h @@ -63,7 +63,6 @@ int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver, int qemuRemoveCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm, int quiet); -int qemuAddToCgroup(virQEMUDriverPtr driver, - virDomainDefPtr def); +int qemuAddToCgroup(virDomainObjPtr vm); #endif /* __QEMU_CGROUP_H__ */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 979a027..fab0b1d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -662,6 +662,7 @@ qemuStartup(bool privileged, char *membase = NULL; char *mempath = NULL; virQEMUDriverConfigPtr cfg; + virCgroupPtr appCgroup = NULL; if (VIR_ALLOC(qemu_driver) < 0) return -1; @@ -732,11 +733,18 @@ qemuStartup(bool privileged, goto error; } - rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1); + rc = virCgroupGetAppRoot(&appCgroup, privileged); + if (rc < 0) { + VIR_INFO("Unable to create cgroup for libvirt: %s", + virStrerror(-rc, ebuf, sizeof(ebuf))); + goto error; + } + rc = virCgroupNew("qemu", appCgroup, &qemu_driver->cgroup); if (rc < 0) { VIR_INFO("Unable to create cgroup for driver: %s", virStrerror(-rc, ebuf, sizeof(ebuf))); } + virCgroupFree(&appCgroup); qemu_driver->qemuImgBinary = virFindFileInPath("kvm-img"); if (!qemu_driver->qemuImgBinary) @@ -3615,9 +3623,8 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, int vcpus = oldvcpus; pid_t *cpupids = NULL; int ncpupids; - virCgroupPtr cgroup = NULL; virCgroupPtr cgroup_vcpu = NULL; - bool cgroup_available = false; + char *vcpuName = NULL; qemuDomainObjEnterMonitor(driver, vm); @@ -3680,15 +3687,14 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, goto cleanup; } - cgroup_available = (virCgroupForDomain(driver->cgroup, vm->def->name, - &cgroup, 0) == 0); - if (nvcpus > oldvcpus) { for (i = oldvcpus; i < nvcpus; i++) { - if (cgroup_available) { + if (vm->cgroup) { int rv = -1; /* Create cgroup for the onlined vcpu */ - rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 1); + if (virAsprintf(&vcpuName, "cpu%d", i) < 0) + goto cleanup; + rv = virCgroupNew(vcpuName, vm->cgroup,&cgroup_vcpu); if (rv < 0) { virReportSystemError(-rv, _("Unable to create vcpu cgroup for %s(vcpu:" @@ -3697,13 +3703,15 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, goto cleanup; } + VIR_FREE(vcpuName); + /* Add vcpu thread to the cgroup */ rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]); if (rv < 0) { virReportSystemError(-rv, _("unable to add vcpu %d task %d to cgroup"), i, cpupids[i]); - virCgroupRemove(cgroup_vcpu); + virCgroupFree(&cgroup_vcpu); goto cleanup; } } @@ -3731,7 +3739,7 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, vcpupin->vcpuid = i; vm->def->cputune.vcpupin[vm->def->cputune.nvcpupin++] = vcpupin; - if (cgroup_available) { + if (cgroup_vcpu) { if (qemuSetupCgroupVcpuPin(cgroup_vcpu, vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin, i) < 0) { @@ -3752,28 +3760,13 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, } } } - - virCgroupFree(&cgroup_vcpu); } } else { for (i = oldvcpus - 1; i >= nvcpus; i--) { virDomainVcpuPinDefPtr vcpupin = NULL; - if (cgroup_available) { - int rv = -1; - - rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0); - if (rv < 0) { - virReportSystemError(-rv, - _("Unable to access vcpu cgroup for %s(vcpu:" - " %d)"), - vm->def->name, i); - goto cleanup; - } - - /* Remove cgroup for the offlined vcpu */ - virCgroupRemove(cgroup_vcpu); - virCgroupFree(&cgroup_vcpu); + if (vm->cgroup) { + /* XXX: remove cgroup for vcpu */ } /* Free vcpupin setting */ @@ -3793,10 +3786,6 @@ cleanup: vm->def->vcpus = vcpus; VIR_FREE(cpupids); virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1); - if (cgroup) - virCgroupFree(&cgroup); - if (cgroup_vcpu) - virCgroupFree(&cgroup_vcpu); return ret; unsupported: @@ -3996,7 +3985,8 @@ qemuDomainPinVcpuFlags(virDomainPtr dom, /* Configure the corresponding cpuset cgroup before set affinity. */ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) { - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup_dom, 0) == 0 && +#if 0 /* XXX */ + if (vm->cgroup && virCgroupForVcpu(cgroup_dom, vcpu, &cgroup_vcpu, 0) == 0 && qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) { virReportError(VIR_ERR_OPERATION_INVALID, @@ -4004,6 +3994,7 @@ qemuDomainPinVcpuFlags(virDomainPtr dom, " for vcpu %d"), vcpu); goto cleanup; } +#endif } else { if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, @@ -4180,8 +4171,6 @@ qemuDomainPinEmulator(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; - virCgroupPtr cgroup_dom = NULL; - virCgroupPtr cgroup_emulator = NULL; pid_t pid; virDomainDefPtr persistentDef = NULL; int ret = -1; @@ -4246,16 +4235,13 @@ qemuDomainPinEmulator(virDomainPtr dom, * Configure the corresponding cpuset cgroup. * If no cgroup for domain or hypervisor exists, do nothing. */ - if (virCgroupForDomain(driver->cgroup, vm->def->name, - &cgroup_dom, 0) == 0) { - if (virCgroupForEmulator(cgroup_dom, &cgroup_emulator, 0) == 0) { - if (qemuSetupCgroupEmulatorPin(cgroup_emulator, - newVcpuPin[0]->cpumask) < 0) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("failed to set cpuset.cpus in cgroup" - " for emulator threads")); - goto cleanup; - } + if (vm->cgroupEmulator) { + if (qemuSetupCgroupEmulatorPin(vm->cgroupEmulator, + newVcpuPin[0]->cpumask) < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("failed to set cpuset.cpus in cgroup" + " for emulator threads")); + goto cleanup; } } } else { @@ -4317,10 +4303,6 @@ qemuDomainPinEmulator(virDomainPtr dom, ret = 0; cleanup: - if (cgroup_emulator) - virCgroupFree(&cgroup_emulator); - if (cgroup_dom) - virCgroupFree(&cgroup_dom); virBitmapFree(pcpumap); if (vm) @@ -5788,7 +5770,6 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn, virDomainDeviceDefPtr dev) { virDomainDiskDefPtr disk = dev->data.disk; - virCgroupPtr cgroup = NULL; int ret = -1; if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) { @@ -5807,13 +5788,7 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn, goto end; if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find cgroup for %s"), - vm->def->name); - goto end; - } - if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0) + if (vm->cgroup && qemuSetupDiskCgroup(vm, vm->cgroup, disk) < 0) goto end; } switch (disk->device) { @@ -5848,8 +5823,8 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn, break; } - if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0) + if (ret != 0 && vm->cgroup) { + if (qemuTeardownDiskCgroup(vm, vm->cgroup, disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(disk->src)); } @@ -5866,8 +5841,6 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn, } end: - if (cgroup) - virCgroupFree(&cgroup); return ret; } @@ -6051,21 +6024,13 @@ qemuDomainChangeDiskMediaLive(virDomainObjPtr vm, bool force) { virDomainDiskDefPtr disk = dev->data.disk; - virCgroupPtr cgroup = NULL; int ret = -1; if (qemuDomainDetermineDiskChain(driver, disk, false) < 0) goto end; if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - if (virCgroupForDomain(driver->cgroup, - vm->def->name, &cgroup, 0) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to find cgroup for %s"), - vm->def->name); - goto end; - } - if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0) + if (vm->cgroup && qemuSetupDiskCgroup(vm, vm->cgroup, disk) < 0) goto end; } @@ -6083,14 +6048,12 @@ qemuDomainChangeDiskMediaLive(virDomainObjPtr vm, break; } - if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0) + if (ret != 0 && vm->cgroup) { + if (qemuTeardownDiskCgroup(vm, vm->cgroup, disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(disk->src)); } end: - if (cgroup) - virCgroupFree(&cgroup); return ret; } @@ -6884,7 +6847,6 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; int ret = -1; @@ -6920,7 +6882,7 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); @@ -6942,7 +6904,7 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, continue; } - rc = virCgroupSetBlkioWeight(group, params[i].value.ui); + rc = virCgroupSetBlkioWeight(vm->cgroup, params[i].value.ui); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set blkio weight tunable")); @@ -6960,7 +6922,7 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, continue; } for (j = 0; j < ndevices; j++) { - rc = virCgroupSetBlkioDeviceWeight(group, + rc = virCgroupSetBlkioDeviceWeight(vm->cgroup, devices[j].path, devices[j].weight); if (rc < 0) { @@ -7023,7 +6985,6 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, } cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7039,7 +7000,6 @@ qemuDomainGetBlkioParameters(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; int i, j; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; unsigned int val; @@ -7082,7 +7042,7 @@ qemuDomainGetBlkioParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -7096,7 +7056,7 @@ qemuDomainGetBlkioParameters(virDomainPtr dom, switch (i) { case 0: /* fill blkio weight here */ - rc = virCgroupGetBlkioWeight(group, &val); + rc = virCgroupGetBlkioWeight(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get blkio weight")); @@ -7209,8 +7169,6 @@ qemuDomainGetBlkioParameters(virDomainPtr dom, ret = 0; cleanup: - if (group) - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7226,7 +7184,6 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, virQEMUDriverPtr driver = dom->conn->privateData; int i; virDomainDefPtr persistentDef = NULL; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virTypedParameterPtr hard_limit = NULL; virTypedParameterPtr swap_hard_limit = NULL; @@ -7273,7 +7230,7 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -7301,7 +7258,7 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, if (flags & VIR_DOMAIN_AFFECT_LIVE) { /* Get current swap hard limit */ - rc = virCgroupGetMemSwapHardLimit(group, &val); + rc = virCgroupGetMemSwapHardLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get swap hard limit")); @@ -7336,7 +7293,7 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = virCgroupSetMemoryHardLimit(group, param->value.ul); + rc = virCgroupSetMemoryHardLimit(vm->cgroup, param->value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set memory hard_limit tunable")); @@ -7349,7 +7306,7 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, } } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = virCgroupSetMemorySoftLimit(group, param->value.ul); + rc = virCgroupSetMemorySoftLimit(vm->cgroup, param->value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set memory soft_limit tunable")); @@ -7362,7 +7319,7 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, } } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - rc = virCgroupSetMemSwapHardLimit(group, param->value.ul); + rc = virCgroupSetMemSwapHardLimit(vm->cgroup, param->value.ul); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to set swap_hard_limit tunable")); @@ -7381,7 +7338,6 @@ qemuDomainSetMemoryParameters(virDomainPtr dom, } cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7397,7 +7353,6 @@ qemuDomainGetMemoryParameters(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; int ret = -1; @@ -7431,7 +7386,7 @@ qemuDomainGetMemoryParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; @@ -7491,7 +7446,7 @@ qemuDomainGetMemoryParameters(virDomainPtr dom, switch (i) { case 0: /* fill memory hard limit here */ - rc = virCgroupGetMemoryHardLimit(group, &val); + rc = virCgroupGetMemoryHardLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get memory hard limit")); @@ -7504,7 +7459,7 @@ qemuDomainGetMemoryParameters(virDomainPtr dom, break; case 1: /* fill memory soft limit here */ - rc = virCgroupGetMemorySoftLimit(group, &val); + rc = virCgroupGetMemorySoftLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get memory soft limit")); @@ -7517,7 +7472,7 @@ qemuDomainGetMemoryParameters(virDomainPtr dom, break; case 2: /* fill swap hard limit here */ - rc = virCgroupGetMemSwapHardLimit(group, &val); + rc = virCgroupGetMemSwapHardLimit(vm->cgroup, &val); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get swap hard limit")); @@ -7541,8 +7496,6 @@ out: ret = 0; cleanup: - if (group) - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7558,7 +7511,6 @@ qemuDomainSetNumaParameters(virDomainPtr dom, virQEMUDriverPtr driver = dom->conn->privateData; int i; virDomainDefPtr persistentDef = NULL; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; int ret = -1; virQEMUDriverConfigPtr cfg = NULL; @@ -7595,7 +7547,7 @@ qemuDomainSetNumaParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); @@ -7653,7 +7605,7 @@ qemuDomainSetNumaParameters(virDomainPtr dom, continue; } - if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) { + if ((rc = virCgroupSetCpusetMems(vm->cgroup, nodeset_str) != 0)) { virReportSystemError(-rc, "%s", _("unable to set numa tunable")); virBitmapFree(nodeset); @@ -7693,7 +7645,6 @@ qemuDomainSetNumaParameters(virDomainPtr dom, } cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7709,7 +7660,6 @@ qemuDomainGetNumaParameters(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef = NULL; char *nodeset = NULL; @@ -7752,7 +7702,7 @@ qemuDomainGetNumaParameters(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); @@ -7780,7 +7730,7 @@ qemuDomainGetNumaParameters(virDomainPtr dom, if (!nodeset) nodeset = strdup(""); } else { - rc = virCgroupGetCpusetMems(group, &nodeset); + rc = virCgroupGetCpusetMems(vm->cgroup, &nodeset); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get numa nodeset")); @@ -7807,7 +7757,6 @@ qemuDomainGetNumaParameters(virDomainPtr dom, cleanup: VIR_FREE(nodeset); - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -7815,13 +7764,11 @@ cleanup: } static int -qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup, +qemuSetVcpusBWLive(virDomainObjPtr vm, unsigned long long period, long long quota) { int i; qemuDomainObjPrivatePtr priv = vm->privateData; - virCgroupPtr cgroup_vcpu = NULL; - int rc; if (period == 0 && quota == 0) return 0; @@ -7832,36 +7779,23 @@ qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup, */ if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) { for (i = 0; i < priv->nvcpupids; i++) { - rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0); - if (rc < 0) { - virReportSystemError(-rc, - _("Unable to find vcpu cgroup for %s(vcpu:" - " %d)"), - vm->def->name, i); + if (vm->vcpuCgroups[i] && + qemuSetupCgroupVcpuBW(vm->vcpuCgroups[i], period, quota) < 0) goto cleanup; - } - - if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0) - goto cleanup; - - virCgroupFree(&cgroup_vcpu); } } return 0; cleanup: - virCgroupFree(&cgroup_vcpu); return -1; } static int -qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup, +qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, unsigned long long period, long long quota) { qemuDomainObjPrivatePtr priv = vm->privateData; - virCgroupPtr cgroup_emulator = NULL; - int rc; if (period == 0 && quota == 0) return 0; @@ -7870,23 +7804,17 @@ qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup, return 0; } - rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0); - if (rc < 0) { - virReportSystemError(-rc, - _("Unable to find emulator cgroup for %s"), - vm->def->name); - goto cleanup; + if (!vm->cgroupEmulator) { + virReportError(VIR_ERR_NO_SUPPORT, + _("Unable to find emulator cgroup for %s"), + vm->def->name); + return -1; } - if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0) - goto cleanup; + if (qemuSetupCgroupVcpuBW(vm->cgroupEmulator, period, quota) < 0) + return -1; - virCgroupFree(&cgroup_emulator); return 0; - -cleanup: - virCgroupFree(&cgroup_emulator); - return -1; } #define SCHED_RANGE_CHECK(VAR, NAME, MIN, MAX) \ @@ -7906,7 +7834,6 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; int i; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr vmdef = NULL; unsigned long long value_ul; @@ -7960,7 +7887,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, "%s", _("cgroup CPU controller is not mounted")); goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); @@ -7975,7 +7902,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) { if (flags & VIR_DOMAIN_AFFECT_LIVE) { - if ((rc = virCgroupSetCpuShares(group, value_ul))) { + if ((rc = virCgroupSetCpuShares(vm->cgroup, value_ul))) { virReportSystemError(-rc, "%s", _("unable to set cpu shares tunable")); goto cleanup; @@ -7991,7 +7918,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD); if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) { - if ((rc = qemuSetVcpusBWLive(vm, group, value_ul, 0))) + if ((rc = qemuSetVcpusBWLive(vm, value_ul, 0))) goto cleanup; vm->def->cputune.period = value_ul; @@ -8005,7 +7932,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA); if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) { - if ((rc = qemuSetVcpusBWLive(vm, group, 0, value_l))) + if ((rc = qemuSetVcpusBWLive(vm, 0, value_l))) goto cleanup; vm->def->cputune.quota = value_l; @@ -8019,7 +7946,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD); if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) { - if ((rc = qemuSetEmulatorBandwidthLive(vm, group, value_ul, 0))) + if ((rc = qemuSetEmulatorBandwidthLive(vm, value_ul, 0))) goto cleanup; vm->def->cputune.emulator_period = value_ul; @@ -8033,7 +7960,7 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA); if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) { - if ((rc = qemuSetEmulatorBandwidthLive(vm, group, 0, value_l))) + if ((rc = qemuSetEmulatorBandwidthLive(vm, 0, value_l))) goto cleanup; vm->def->cputune.emulator_quota = value_l; @@ -8061,7 +7988,6 @@ qemuSetSchedulerParametersFlags(virDomainPtr dom, cleanup: virDomainDefFree(vmdef); - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -8108,52 +8034,39 @@ static int qemuGetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup, unsigned long long *period, long long *quota) { - virCgroupPtr cgroup_vcpu = NULL; qemuDomainObjPrivatePtr priv = NULL; - int rc; - int ret = -1; priv = vm->privateData; if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) { /* We do not create sub dir for each vcpu */ - rc = qemuGetVcpuBWLive(cgroup, period, quota); - if (rc < 0) - goto cleanup; + if (qemuGetVcpuBWLive(cgroup, period, quota) < 0) + return -1; if (*quota > 0) *quota /= vm->def->vcpus; - goto out; + + return 0; } /* get period and quota for vcpu0 */ - rc = virCgroupForVcpu(cgroup, 0, &cgroup_vcpu, 0); - if (!cgroup_vcpu) { - virReportSystemError(-rc, - _("Unable to find vcpu cgroup for %s(vcpu: 0)"), - vm->def->name); - goto cleanup; + if (!vm->vcpuCgroups[0]) { + virReportError(VIR_ERR_NO_SUPPORT, + _("Unable to find vcpu cgroup for %s(vcpu: 0)"), + vm->def->name); + return -1; } - rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota); - if (rc < 0) - goto cleanup; - -out: - ret = 0; + if (qemuGetVcpuBWLive(vm->vcpuCgroups[0], period, quota) < 0) + return -1; -cleanup: - virCgroupFree(&cgroup_vcpu); - return ret; + return 0; } static int -qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup, +qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, unsigned long long *period, long long *quota) { - virCgroupPtr cgroup_emulator = NULL; qemuDomainObjPrivatePtr priv = NULL; - int rc; - int ret = -1; priv = vm->privateData; if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) { @@ -8164,23 +8077,17 @@ qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup, } /* get period and quota for emulator */ - rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0); - if (!cgroup_emulator) { - virReportSystemError(-rc, - _("Unable to find emulator cgroup for %s"), - vm->def->name); - goto cleanup; + if (!vm->cgroupEmulator) { + virReportError(VIR_ERR_NO_SUPPORT, + _("Unable to find emulator cgroup for %s"), + vm->def->name); + return -1; } - rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota); - if (rc < 0) - goto cleanup; - - ret = 0; + if (qemuGetVcpuBWLive(vm->cgroupEmulator, period, quota) < 0) + return -1; -cleanup: - virCgroupFree(&cgroup_emulator); - return ret; + return 0; } static int @@ -8190,7 +8097,6 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom, unsigned int flags) { virQEMUDriverPtr driver = dom->conn->privateData; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; unsigned long long shares; unsigned long long period; @@ -8248,13 +8154,13 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } - rc = virCgroupGetCpuShares(group, &shares); + rc = virCgroupGetCpuShares(vm->cgroup, &shares); if (rc != 0) { virReportSystemError(-rc, "%s", _("unable to get cpu shares tunable")); @@ -8262,13 +8168,13 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom, } if (*nparams > 1 && cpu_bw_status) { - rc = qemuGetVcpusBWLive(vm, group, &period, "a); + rc = qemuGetVcpusBWLive(vm, vm->cgroup, &period, "a); if (rc != 0) goto cleanup; } if (*nparams > 3 && cpu_bw_status) { - rc = qemuGetEmulatorBandwidthLive(vm, group, &emulator_period, + rc = qemuGetEmulatorBandwidthLive(vm, &emulator_period, &emulator_quota); if (rc != 0) goto cleanup; @@ -8321,7 +8227,6 @@ out: ret = 0; cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); @@ -11022,7 +10927,6 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver, int i; bool persist = false; bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0; - virCgroupPtr cgroup = NULL; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); if (!virDomainObjIsActive(vm)) { @@ -11032,7 +10936,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver, } if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) { + !vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -11075,7 +10979,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver, } } - ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, cgroup, + ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, vm->cgroup, &snap->def->disks[i], vm->def->disks[i], persistDisk, actions, @@ -11104,7 +11008,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver, persistDisk = vm->newDef->disks[indx]; } - qemuDomainSnapshotUndoSingleDiskActive(driver, vm, cgroup, + qemuDomainSnapshotUndoSingleDiskActive(driver, vm, vm->cgroup, snap->def->dom->disks[i], vm->def->disks[i], persistDisk, @@ -11115,8 +11019,6 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver, qemuDomainObjExitMonitorWithDriver(driver, vm); cleanup: - virCgroupFree(&cgroup); - if (ret == 0 || !qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) { if (virDomainSaveStatus(driver->caps, cfg->stateDir, vm) < 0 || (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0)) @@ -12922,7 +12824,7 @@ qemuDomainBlockPivot(virConnectPtr conn, * we know for sure that there is a backing chain. */ if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW && qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) { + !vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -12943,7 +12845,7 @@ qemuDomainBlockPivot(virConnectPtr conn, if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW && (virDomainLockDiskAttach(driver->lockManager, cfg->uri, vm, disk) < 0 || - (cgroup && qemuSetupDiskCgroup(vm, cgroup, disk) < 0) || + (cgroup && qemuSetupDiskCgroup(vm, vm->cgroup, disk) < 0) || virSecurityManagerSetImageLabel(driver->securityManager, vm->def, disk) < 0)) { disk->src = oldsrc; @@ -12987,8 +12889,6 @@ qemuDomainBlockPivot(virConnectPtr conn, disk->mirroring = false; cleanup: - if (cgroup) - virCgroupFree(&cgroup); if (resume && virDomainObjIsActive(vm) && qemuProcessStartCPUs(driver, vm, conn, VIR_DOMAIN_RUNNING_UNPAUSED, @@ -13220,7 +13120,6 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path, struct stat st; bool need_unlink = false; char *mirror = NULL; - virCgroupPtr cgroup = NULL; virQEMUDriverConfigPtr cfg = NULL; /* Preliminaries: find the disk we are editing, sanity checks */ @@ -13237,7 +13136,7 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path, goto cleanup; } if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) { + !vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -13344,9 +13243,9 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path, goto endjob; } - if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest, + if (qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, dest, VIR_DISK_CHAIN_READ_WRITE) < 0) { - qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest, + qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, dest, VIR_DISK_CHAIN_NO_ACCESS); goto endjob; } @@ -13358,7 +13257,7 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path, virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0); qemuDomainObjExitMonitor(driver, vm); if (ret < 0) { - qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest, + qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, dest, VIR_DISK_CHAIN_NO_ACCESS); goto endjob; } @@ -13380,8 +13279,6 @@ endjob: } cleanup: - if (cgroup) - virCgroupFree(&cgroup); VIR_FREE(device); if (vm) virObjectUnlock(vm); @@ -13437,7 +13334,6 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base, virStorageFileMetadataPtr top_meta = NULL; const char *top_parent = NULL; const char *base_canon = NULL; - virCgroupPtr cgroup = NULL; bool clean_access = false; virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1); @@ -13522,17 +13418,17 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base, * operation succeeds, but doing that requires tracking the * operation in XML across libvirtd restarts. */ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) { + !vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); goto endjob; } clean_access = true; - if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon, + if (qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, base_canon, VIR_DISK_CHAIN_READ_WRITE) < 0 || (top_parent && top_parent != disk->src && - qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, + qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, top_parent, VIR_DISK_CHAIN_READ_WRITE) < 0)) goto endjob; @@ -13546,15 +13442,13 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base, endjob: if (ret < 0 && clean_access) { /* Revert access to read-only, if possible. */ - qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon, + qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, base_canon, VIR_DISK_CHAIN_READ_ONLY); if (top_parent && top_parent != disk->src) - qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, + qemuDomainPrepareDiskChainElement(driver, vm, vm->cgroup, disk, top_parent, VIR_DISK_CHAIN_READ_ONLY); } - if (cgroup) - virCgroupFree(&cgroup); if (qemuDomainObjEndJob(driver, vm) == 0) { vm = NULL; goto cleanup; @@ -14246,28 +14140,27 @@ qemuDomainGetTotalcpuStats(virCgroupPtr group, * s3 = t03 + t13 */ static int -getSumVcpuPercpuStats(virCgroupPtr group, - unsigned int nvcpu, +getSumVcpuPercpuStats(virDomainObjPtr vm, unsigned long long *sum_cpu_time, unsigned int num) { int ret = -1; int i; char *buf = NULL; - virCgroupPtr group_vcpu = NULL; + qemuDomainObjPrivatePtr priv = vm->privateData; - for (i = 0; i < nvcpu; i++) { + for (i = 0; i < priv->nvcpupids; i++) { char *pos; unsigned long long tmp; int j; - if (virCgroupForVcpu(group, i, &group_vcpu, 0) < 0) { + if (!vm->vcpuCgroups[i]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("error accessing cgroup cpuacct for vcpu")); goto cleanup; } - if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0) + if (virCgroupGetCpuacctPercpuUsage(vm->vcpuCgroups[i], &buf) < 0) goto cleanup; pos = buf; @@ -14280,13 +14173,11 @@ getSumVcpuPercpuStats(virCgroupPtr group, sum_cpu_time[j] += tmp; } - virCgroupFree(&group_vcpu); VIR_FREE(buf); } ret = 0; cleanup: - virCgroupFree(&group_vcpu); VIR_FREE(buf); return ret; } @@ -14306,7 +14197,6 @@ qemuDomainGetPercpuStats(virDomainObjPtr vm, unsigned long long *sum_cpu_time = NULL; unsigned long long *sum_cpu_pos; unsigned int n = 0; - qemuDomainObjPrivatePtr priv = vm->privateData; virTypedParameterPtr ent; int param_idx; unsigned long long cpu_time; @@ -14373,7 +14263,7 @@ qemuDomainGetPercpuStats(virDomainObjPtr vm, virReportOOMError(); goto cleanup; } - if (getSumVcpuPercpuStats(group, priv->nvcpupids, sum_cpu_time, n) < 0) + if (getSumVcpuPercpuStats(vm, sum_cpu_time, n) < 0) goto cleanup; sum_cpu_pos = sum_cpu_time; @@ -14406,7 +14296,6 @@ qemuDomainGetCPUStats(virDomainPtr domain, unsigned int flags) { virQEMUDriverPtr driver = domain->conn->privateData; - virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; int ret = -1; bool isActive; @@ -14435,19 +14324,18 @@ qemuDomainGetCPUStats(virDomainPtr domain, goto cleanup; } - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } if (start_cpu == -1) - ret = qemuDomainGetTotalcpuStats(group, params, nparams); + ret = qemuDomainGetTotalcpuStats(vm->cgroup, params, nparams); else - ret = qemuDomainGetPercpuStats(vm, group, params, nparams, + ret = qemuDomainGetPercpuStats(vm, vm->cgroup, params, nparams, start_cpu, ncpus); cleanup: - virCgroupFree(&group); if (vm) virObjectUnlock(vm); qemuDriverUnlock(driver); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 98912bf..224ed77 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1117,11 +1117,10 @@ int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, } if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - virCgroupPtr cgroup = NULL; virUSBDevicePtr usb; qemuCgroupData data; - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -1134,7 +1133,7 @@ int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, goto error; data.vm = vm; - data.cgroup = cgroup; + data.cgroup = vm->cgroup; if (virUSBDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup, &data) < 0) { virUSBDeviceFree(usb); @@ -2012,7 +2011,6 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver, int i, ret = -1; virDomainDiskDefPtr detach = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; - virCgroupPtr cgroup = NULL; char *drivestr = NULL; i = qemuFindDisk(vm->def, dev->data.disk->dst); @@ -2033,7 +2031,7 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver, } if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -2094,8 +2092,8 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver, vm->def, dev->data.disk) < 0) VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); - if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(vm, cgroup, dev->data.disk) < 0) + if (vm->cgroup != NULL) { + if (qemuTeardownDiskCgroup(vm, vm->cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -2106,7 +2104,6 @@ int qemuDomainDetachPciDiskDevice(virQEMUDriverPtr driver, ret = 0; cleanup: - virCgroupFree(&cgroup); VIR_FREE(drivestr); return ret; } @@ -2118,7 +2115,6 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, int i, ret = -1; virDomainDiskDefPtr detach = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; - virCgroupPtr cgroup = NULL; char *drivestr = NULL; i = qemuFindDisk(vm->def, dev->data.disk->dst); @@ -2146,7 +2142,7 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, } if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); @@ -2186,8 +2182,8 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, vm->def, dev->data.disk) < 0) VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); - if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(vm, cgroup, dev->data.disk) < 0) + if (vm->cgroup != NULL) { + if (qemuTeardownDiskCgroup(vm, vm->cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -2199,7 +2195,6 @@ int qemuDomainDetachDiskDevice(virQEMUDriverPtr driver, cleanup: VIR_FREE(drivestr); - virCgroupFree(&cgroup); return ret; } diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a75fb4e..5d69b71 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3605,7 +3605,6 @@ qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm, enum qemuDomainAsyncJob asyncJob) { qemuDomainObjPrivatePtr priv = vm->privateData; - virCgroupPtr cgroup = NULL; int ret = -1; int rc; bool restoreLabel = false; @@ -3641,20 +3640,16 @@ qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm, * that botches pclose. */ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) { - if (virCgroupForDomain(driver->cgroup, vm->def->name, - &cgroup, 0) != 0) { + if (!vm->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to find cgroup for %s"), vm->def->name); goto cleanup; } - rc = virCgroupAllowDevicePath(cgroup, path, + rc = virCgroupAllowDevicePath(vm->cgroup, path, VIR_CGROUP_DEVICE_RW); - virDomainAuditCgroupPath(vm, cgroup, "allow", path, "rw", rc); - if (rc == 1) { - /* path was not a device, no further need for cgroup */ - virCgroupFree(&cgroup); - } else if (rc < 0) { + virDomainAuditCgroupPath(vm, vm->cgroup, "allow", path, "rw", rc); + if (rc < 0) { virReportSystemError(-rc, _("Unable to allow device %s for %s"), path, vm->def->name); @@ -3754,14 +3749,13 @@ cleanup: vm->def, path) < 0) VIR_WARN("failed to restore save state label on %s", path); - if (cgroup != NULL) { - rc = virCgroupDenyDevicePath(cgroup, path, + if (vm->cgroup != NULL) { + rc = virCgroupDenyDevicePath(vm->cgroup, path, VIR_CGROUP_DEVICE_RWM); - virDomainAuditCgroupPath(vm, cgroup, "deny", path, "rwm", rc); + virDomainAuditCgroupPath(vm, vm->cgroup, "deny", path, "rwm", rc); if (rc < 0) VIR_WARN("Unable to deny device %s for %s %d", path, vm->def->name, rc); - virCgroupFree(&cgroup); } return ret; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 30f923a..84300c1 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2744,7 +2744,7 @@ static int qemuProcessHook(void *data) * memory allocation is on the correct NUMA node */ VIR_DEBUG("Moving process to cgroup"); - if (qemuAddToCgroup(h->driver, h->vm->def) < 0) + if (qemuAddToCgroup(h->vm) < 0) goto cleanup; /* This must be done after cgroup placement to avoid resetting CPU @@ -3641,11 +3641,6 @@ int qemuProcessStart(virConnectPtr conn, } } - /* Ensure no historical cgroup for this VM is lying around bogus - * settings */ - VIR_DEBUG("Ensuring no historical cgroup is lying around"); - qemuRemoveCgroup(driver, vm, 1); - for (i = 0 ; i < vm->def->ngraphics; ++i) { virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 71d46c5..90ff97c 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -37,6 +37,7 @@ #include <libgen.h> #include <dirent.h> +#include "virobject.h" #include "internal.h" #include "virutil.h" #include "viralloc.h" @@ -45,6 +46,7 @@ #include "virfile.h" #include "virhash.h" #include "virhashcode.h" +#include "virthread.h" #define CGROUP_MAX_VAL 512 @@ -58,12 +60,91 @@ struct virCgroupController { char *placement; }; -struct virCgroup { +struct _virCgroupItem; +typedef struct _virCgroupItem virCgroupItem; +typedef virCgroupItem *virCgroupItemPtr; + +struct _virCgroupItem { + virObjectLockable object; + + char *name; char *path; + bool created; /* the path is created or not */ + + virCgroupItemPtr next; + virCgroupItemPtr parent; + virCgroupItemPtr children; + + int type; struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST]; }; +struct virCgroup { + virCgroupItemPtr items[VIR_CGROUP_CONTROLLER_LAST]; +}; + +static virClassPtr cgroupItemClass; + +static void cgroupItemDispose(void *obj); + +static int virCgroupItemOnceInit(void) +{ + if (!(cgroupItemClass = virClassNew(virClassForObjectLockable(), + "cgroupItem", + sizeof(virCgroupItem), + cgroupItemDispose))) + return -1; + + return 0; +} +VIR_ONCE_GLOBAL_INIT(virCgroupItem); + +static virCgroupItemPtr rootCgroupItems[VIR_CGROUP_CONTROLLER_LAST]; + +static virCgroupItemPtr virCgroupItemRootNew(int type); +static int virCgroupDetectMounts(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST]); +static int virCgroupDetectPlacement(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST]); + +static int virCgroupControllersInit(struct virCgroupController (*controllers)[VIR_CGROUP_CONTROLLER_LAST]) +{ + int rc; + int i; + + rc = virCgroupDetectMounts(controllers); + if (rc < 0) { + VIR_ERROR(_("Failed to initialize cgroup controllers")); + return rc; + } + + rc = virCgroupDetectPlacement(controllers); + + if (rc == 0) { + /* Check that for every mounted controller, we found our placement */ + for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { + if (!(*controllers)[i].mountPoint) + continue; + + if (!(*controllers)[i].placement) { + VIR_ERROR(_("Could not find placement for controller %s at %s"), + virCgroupControllerTypeToString(i), + (*controllers)[i].placement); + rc = -ENOENT; + break; + } + + VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i, + virCgroupControllerTypeToString(i), + (*controllers)[i].mountPoint, + (*controllers)[i].placement); + } + } else { + VIR_ERROR(_("Failed to initialize cgroup controllers")); + } + + return rc; +} + typedef enum { VIR_CGROUP_NONE = 0, /* create subdir under each cgroup if possible. */ VIR_CGROUP_MEM_HIERACHY = 1 << 0, /* call virCgroupSetMemoryUseHierarchy @@ -74,25 +155,377 @@ typedef enum { * cpuacct and cpuset if possible. */ } virCgroupFlags; +static virCgroupItemPtr virCgroupItemRootNew(int type) +{ + virCgroupItemPtr rootItem = NULL; + + if (type >= VIR_CGROUP_CONTROLLER_LAST || type < 0) + return NULL; + + if (virCgroupItemInitialize() < 0) + return NULL; + + if (!(rootItem = virObjectNew(cgroupItemClass))) + return NULL; + + if (virCgroupControllersInit(&rootItem->controllers) != 0) { + virObjectUnref(rootItem); + rootItem = NULL; + return NULL; + } + + rootItem->name = strdup("/"); + rootItem->next = NULL; + rootItem->parent = NULL; + rootItem->children = NULL; + rootItem->created = 1; + rootItem->type = type; + if (virAsprintf(&rootItem->path, "%s%s", + rootItem->controllers[rootItem->type].mountPoint, + rootItem->controllers[rootItem->type].placement) < 0) { + virObjectUnref(rootItem); + rootItem = NULL; + } + + return rootItem; +} + +static virCgroupItemPtr virCgroupHasChildByName(virCgroupItemPtr item, + const char *name) +{ + virCgroupItemPtr child; + + virObjectLock(item); + + child = item->children; + + while (child) { + if (STREQ(child->name, name)) { + virObjectRef(child); + goto out; + } + + child = child->next; + } + +out: + virObjectUnlock(item); + return child; +} + +static virCgroupItemPtr virCgroupItemNew(const char *name, + virCgroupItemPtr parent) +{ + virCgroupItemPtr cgroupItem = NULL; + virCgroupItemPtr *next = NULL; + + if (!parent) + return NULL; + + if (virCgroupItemInitialize() < 0) + return NULL; + + cgroupItem = virCgroupHasChildByName(parent, name); + if (cgroupItem) + return cgroupItem; + + if (!(cgroupItem = virObjectNew(cgroupItemClass))) + return NULL; + + cgroupItem->name = strdup(name); + cgroupItem->parent = parent; + cgroupItem->next = NULL; + cgroupItem->children = NULL; + cgroupItem->created = false; + cgroupItem->type = parent->type; + + if (virAsprintf(&cgroupItem->path, "%s/%s", + parent->path, + cgroupItem->name) == -1) { + virObjectUnref(cgroupItem); + cgroupItem = NULL; + return NULL; + } + + virObjectRef(parent); + + virObjectLock(parent); + + next = &parent->children; + + while (*next) + next = &(*next)->next; + + *next = cgroupItem; + + virObjectUnlock(parent); + + return cgroupItem; +} + +static void virCgroupItemFree(virCgroupItemPtr *cgroupItem) +{ + if (!virObjectUnref(*cgroupItem)) + *cgroupItem = NULL; +} + +static void cgroupItemDispose(void *obj) +{ + virCgroupItemPtr cgroupItem = obj; + virCgroupItemPtr parent = cgroupItem->parent; + virCgroupItemPtr *next; + + sa_assert(cgroupItem->children == NULL); + + if (cgroupItem->created && + access(cgroupItem->path, F_OK) == 0) + rmdir(cgroupItem->path); + VIR_FREE(cgroupItem->path); + + if (parent) { + virObjectLock(parent); + + next = &parent->children; + + while (*next && *next != cgroupItem) + next = &(*next)->next; + + if (*next == cgroupItem) { + *next = cgroupItem->next; + cgroupItem->next = NULL; + cgroupItem->parent = NULL; + } else { + /* BUG */ + } + + virObjectUnlock(parent); + virObjectUnref(parent); + } + + VIR_FREE(cgroupItem->name); +} + +static int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem, + const char *key, + char **path); + +static int virCgroupItemGetValueStr(virCgroupItemPtr cgroupItem, + const char *key, + char **value) +{ + int rc; + char *keypath = NULL; + + *value = NULL; + + rc = virCgroupItemKeyPath(cgroupItem, key, &keypath); + if (rc != 0) + return rc; + + VIR_DEBUG("Get value %s", keypath); + + rc = virFileReadAll(keypath, 1024*1024, value); + if (rc < 0) { + rc = -errno; + VIR_DEBUG("Failed to read %s: %m\n", keypath); + } else { + /* Terminated with '\n' has sometimes harmful effects to the caller */ + if ((*value)[rc - 1] == '\n') + (*value)[rc - 1] = '\0'; + + rc = 0; + } + + VIR_FREE(keypath); + + return rc; +} + +static int virCgroupItemSetValueStr(virCgroupItemPtr cgroupItem, + const char *key, + const char *value) +{ + int rc = 0; + char *keypath = NULL; + + rc = virCgroupItemKeyPath(cgroupItem, key, &keypath); + if (rc != 0) + return rc; + + VIR_DEBUG("Set value '%s' to '%s'", keypath, value); + rc = virFileWriteStr(keypath, value, 0); + if (rc < 0) { + rc = -errno; + VIR_DEBUG("Failed to write value '%s': %m", value); + } else { + rc = 0; + } + + VIR_FREE(keypath); + return rc; +} + +static int virCgroupRemoveRecursively(char *grppath); +static int virCgroupItemCpusetInherit(virCgroupItemPtr cgroupItem); +static int virCgroupItemSetMemoryUseHierarchy(virCgroupItemPtr item); + +static int virCgroupItemMakePath(virCgroupItemPtr cgroupItem) +{ + int ret = 0; + + if (!cgroupItem->created && access(cgroupItem->path, F_OK) == 0) { + VIR_WARN(_("removing historical cgroup directory: %s"), + cgroupItem->path); + + if (virCgroupRemoveRecursively(cgroupItem->path) != 0) { + VIR_WARN(_("failed to remove historical cgroup directory: %s"), + cgroupItem->path); + } + } + + cgroupItem->created = true; + + if (access(cgroupItem->path, F_OK) != 0) { + if (cgroupItem->parent && + (ret = virCgroupItemMakePath(cgroupItem->parent)) < 0) + return ret; + + if (mkdir(cgroupItem->path, 0755) < 0) { + return -errno; + } + + if (cgroupItem->type == VIR_CGROUP_CONTROLLER_CPUSET) + virCgroupItemCpusetInherit(cgroupItem); + + if (cgroupItem->type == VIR_CGROUP_CONTROLLER_MEMORY) + virCgroupItemSetMemoryUseHierarchy(cgroupItem); + } + + return ret; +} + +static int virCgroupItemPath(virCgroupItemPtr cgroupItem, + bool create, + char **path) +{ + if (path) { + if (virAsprintf(path, "%s", cgroupItem->path) == -1) + return -ENOMEM; + } + + if (create && virCgroupItemMakePath(cgroupItem) < 0) { + if (path) + VIR_FREE(*path); + + return -1; + } + + return 0; +} + +static int virCgroupItemKeyPath(virCgroupItemPtr cgroupItem, + const char *key, + char **path) +{ + int ret = 0; + char *cgroupItemPath = NULL; + + ret = virCgroupItemPath(cgroupItem, true, &cgroupItemPath); + if (ret < 0) + return ret; + + if (virAsprintf(path, "%s/%s", cgroupItemPath, key) == -1) + ret = -ENOMEM; + + VIR_FREE(cgroupItemPath); + return ret; +} + +int virCgroupMakePath(virCgroupPtr cgroup) +{ + int i; + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + if (virCgroupItemPath(cgroup->items[i], true, NULL) != 0) + return -1; + } + + return 0; +} + +int virCgroupNew(const char *name, virCgroupPtr parent, virCgroupPtr *cgroup) +{ + virCgroupPtr newCgroup = NULL; + virCgroupItemPtr *parentCgroupItems; + int ret = -1; + int i = 0; + + if (VIR_ALLOC(newCgroup) < 0) { + ret = -ENOMEM; + goto error; + } + + if (!parent) { + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + if (!rootCgroupItems[i]) + rootCgroupItems[i] = virCgroupItemRootNew(i); + if (!rootCgroupItems[i]) + goto error; + virObjectRef(rootCgroupItems[i]); + } + + parentCgroupItems = rootCgroupItems; + } else { + parentCgroupItems = parent->items; + } + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + newCgroup->items[i] = virCgroupItemNew(name, parentCgroupItems[i]); + if (!newCgroup->items[i]) + goto error; + } + + *cgroup = newCgroup; + newCgroup = NULL; + ret = 0; + +error: + if (!parent) { + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + if (rootCgroupItems[i]) + virCgroupItemFree(&rootCgroupItems[i]); + } + } + + if (newCgroup) { + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + if (newCgroup->items[i]) + virCgroupItemFree(&newCgroup->items[i]); + } + VIR_FREE(newCgroup); + } + + return ret; +} + /** * virCgroupFree: * * @group: The group structure to free */ -void virCgroupFree(virCgroupPtr *group) +void virCgroupFree(virCgroupPtr *cgroup) { int i; - if (*group == NULL) + if (!cgroup || !*cgroup) return; - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - VIR_FREE((*group)->controllers[i].mountPoint); - VIR_FREE((*group)->controllers[i].placement); + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + virCgroupItemFree(&(*cgroup)->items[i]); } - VIR_FREE((*group)->path); - VIR_FREE(*group); + VIR_FREE(*cgroup); + *cgroup = NULL; } /** @@ -103,12 +536,17 @@ void virCgroupFree(virCgroupPtr *group) * * Returns true if a cgroup is subsystem is mounted. */ -bool virCgroupMounted(virCgroupPtr cgroup, int controller) +bool virCgroupMounted(virCgroupPtr cgroup ATTRIBUTE_UNUSED, + int controller) { - return cgroup->controllers[controller].mountPoint != NULL; + if (rootCgroupItems[controller] && + rootCgroupItems[controller]->controllers[controller].mountPoint) + return true; + return false; } #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R + /* * Process /proc/mounts figuring out what controllers are * mounted and where @@ -134,6 +572,7 @@ static int virCgroupDetectMounts(struct virCgroupController (*controllers)[VIR_C const char *typestr = virCgroupControllerTypeToString(i); int typelen = strlen(typestr); char *tmp = entry.mnt_opts; + (*controllers)[i].type = i; while (tmp) { char *next = strchr(tmp, ','); int len; @@ -184,24 +623,24 @@ static int virCgroupDetectPlacement(struct virCgroupController (*cgroupControlle } while (fgets(line, sizeof(line), mapping) != NULL) { - char *controllers = strchr(line, ':'); - char *path = controllers ? strchr(controllers+1, ':') : NULL; + char *controllersStr = strchr(line, ':'); + char *path = controllersStr ? strchr(controllersStr+1, ':') : NULL; char *nl = path ? strchr(path, '\n') : NULL; - if (!controllers || !path) + if (!controllersStr || !path) continue; if (nl) *nl = '\0'; *path = '\0'; - controllers++; + controllersStr++; path++; for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { const char *typestr = virCgroupControllerTypeToString(i); int typelen = strlen(typestr); - char *tmp = controllers; + char *tmp = controllersStr; while (tmp) { char *next = strchr(tmp, ','); int len; @@ -230,57 +669,8 @@ no_memory: } -static int virCgroupDetect(virCgroupPtr group) -{ - int any = 0; - int rc; - int i; - - rc = virCgroupDetectMounts(&group->controllers); - if (rc < 0) { - VIR_ERROR(_("Failed to detect mounts for %s"), group->path); - return rc; - } - - /* Check that at least 1 controller is available */ - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - if (group->controllers[i].mountPoint != NULL) - any = 1; - } - if (!any) - return -ENXIO; - - - rc = virCgroupDetectPlacement(&group->controllers); - - if (rc == 0) { - /* Check that for every mounted controller, we found our placement */ - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - if (!group->controllers[i].mountPoint) - continue; - - if (!group->controllers[i].placement) { - VIR_ERROR(_("Could not find placement for controller %s at %s"), - virCgroupControllerTypeToString(i), - group->controllers[i].placement); - rc = -ENOENT; - break; - } - - VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i, - virCgroupControllerTypeToString(i), - group->controllers[i].mountPoint, - group->controllers[i].placement); - } - } else { - VIR_ERROR(_("Failed to detect mapping for %s"), group->path); - } - - return rc; -} #endif - int virCgroupPathOfController(virCgroupPtr group, int controller, const char *key, @@ -289,8 +679,7 @@ int virCgroupPathOfController(virCgroupPtr group, if (controller == -1) { int i; for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - if (group->controllers[i].mountPoint && - group->controllers[i].placement) { + if (virCgroupMounted(group, i)) { controller = i; break; } @@ -299,47 +688,22 @@ int virCgroupPathOfController(virCgroupPtr group, if (controller == -1) return -ENOSYS; - if (group->controllers[controller].mountPoint == NULL) - return -ENOENT; - - if (group->controllers[controller].placement == NULL) - return -ENOENT; - - if (virAsprintf(path, "%s%s%s/%s", - group->controllers[controller].mountPoint, - group->controllers[controller].placement, - STREQ(group->path, "/") ? "" : group->path, + if (virAsprintf(path, "%s%s%s", + group->items[controller]->path, + key ? "/" : "", key ? key : "") == -1) return -ENOMEM; return 0; } - static int virCgroupSetValueStr(virCgroupPtr group, int controller, const char *key, const char *value) { - int rc = 0; - char *keypath = NULL; - - rc = virCgroupPathOfController(group, controller, key, &keypath); - if (rc != 0) - return rc; - - VIR_DEBUG("Set value '%s' to '%s'", keypath, value); - rc = virFileWriteStr(keypath, value, 0); - if (rc < 0) { - rc = -errno; - VIR_DEBUG("Failed to write value '%s': %m", value); - } else { - rc = 0; - } - - VIR_FREE(keypath); - - return rc; + return virCgroupItemSetValueStr(group->items[controller], + key, value); } static int virCgroupGetValueStr(virCgroupPtr group, @@ -347,34 +711,8 @@ static int virCgroupGetValueStr(virCgroupPtr group, const char *key, char **value) { - int rc; - char *keypath = NULL; - - *value = NULL; - - rc = virCgroupPathOfController(group, controller, key, &keypath); - if (rc != 0) { - VIR_DEBUG("No path of %s, %s", group->path, key); - return rc; - } - - VIR_DEBUG("Get value %s", keypath); - - rc = virFileReadAll(keypath, 1024*1024, value); - if (rc < 0) { - rc = -errno; - VIR_DEBUG("Failed to read %s: %m\n", keypath); - } else { - /* Terminated with '\n' has sometimes harmful effects to the caller */ - if ((*value)[rc - 1] == '\n') - (*value)[rc - 1] = '\0'; - - rc = 0; - } - - VIR_FREE(keypath); - - return rc; + return virCgroupItemGetValueStr(group->items[controller], + key, value); } static int virCgroupSetValueU64(virCgroupPtr group, @@ -395,8 +733,6 @@ static int virCgroupSetValueU64(virCgroupPtr group, return rc; } - - static int virCgroupSetValueI64(virCgroupPtr group, int controller, const char *key, @@ -441,248 +777,88 @@ static int virCgroupGetValueU64(virCgroupPtr group, unsigned long long int *value) { char *strval = NULL; - int rc = 0; - - rc = virCgroupGetValueStr(group, controller, key, &strval); - if (rc != 0) - goto out; - - if (virStrToLong_ull(strval, NULL, 10, value) < 0) - rc = -EINVAL; -out: - VIR_FREE(strval); - - return rc; -} - - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group) -{ - int i; - int rc = 0; - const char *inherit_values[] = { - "cpuset.cpus", - "cpuset.mems", - }; - - VIR_DEBUG("Setting up inheritance %s -> %s", parent->path, group->path); - for (i = 0; i < ARRAY_CARDINALITY(inherit_values) ; i++) { - char *value; - - rc = virCgroupGetValueStr(parent, - VIR_CGROUP_CONTROLLER_CPUSET, - inherit_values[i], - &value); - if (rc != 0) { - VIR_ERROR(_("Failed to get %s %d"), inherit_values[i], rc); - break; - } - - VIR_DEBUG("Inherit %s = %s", inherit_values[i], value); - - rc = virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_CPUSET, - inherit_values[i], - value); - VIR_FREE(value); - - if (rc != 0) { - VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc); - break; - } - } - - return rc; -} - -static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group) -{ - int rc = 0; - unsigned long long value; - const char *filename = "memory.use_hierarchy"; - - rc = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - filename, &value); - if (rc != 0) { - VIR_ERROR(_("Failed to read %s/%s (%d)"), group->path, filename, rc); - return rc; - } - - /* Setting twice causes error, so if already enabled, skip setting */ - if (value == 1) - return 0; - - VIR_DEBUG("Setting up %s/%s", group->path, filename); - rc = virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - filename, 1); - - if (rc != 0) { - VIR_ERROR(_("Failed to set %s/%s (%d)"), group->path, filename, rc); - } - - return rc; -} - -static int virCgroupMakeGroup(virCgroupPtr parent, - virCgroupPtr group, - bool create, - unsigned int flags) -{ - int i; - int rc = 0; - - VIR_DEBUG("Make group %s", group->path); - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - char *path = NULL; - - /* Skip over controllers that aren't mounted */ - if (!group->controllers[i].mountPoint) - continue; - - /* We need to control cpu bandwidth for each vcpu now */ - if ((flags & VIR_CGROUP_VCPU) && - (i != VIR_CGROUP_CONTROLLER_CPU && - i != VIR_CGROUP_CONTROLLER_CPUACCT && - i != VIR_CGROUP_CONTROLLER_CPUSET)) { - /* treat it as unmounted and we can use virCgroupAddTask */ - VIR_FREE(group->controllers[i].mountPoint); - continue; - } - - rc = virCgroupPathOfController(group, i, "", &path); - if (rc < 0) - return rc; - /* As of Feb 2011, clang can't see that the above function - * call did not modify group. */ - sa_assert(group->controllers[i].mountPoint); - - VIR_DEBUG("Make controller %s", path); - if (access(path, F_OK) != 0) { - if (!create || - mkdir(path, 0755) < 0) { - /* With a kernel that doesn't support multi-level directory - * for blkio controller, libvirt will fail and disable all - * other controllers even though they are available. So - * treat blkio as unmounted if mkdir fails. */ - if (i == VIR_CGROUP_CONTROLLER_BLKIO) { - rc = 0; - VIR_FREE(group->controllers[i].mountPoint); - VIR_FREE(path); - continue; - } else { - rc = -errno; - VIR_FREE(path); - break; - } - } - if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL && - (i == VIR_CGROUP_CONTROLLER_CPUSET || - STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) { - rc = virCgroupCpuSetInherit(parent, group); - if (rc != 0) { - VIR_FREE(path); - break; - } - } - /* - * Note that virCgroupSetMemoryUseHierarchy should always be - * called prior to creating subcgroups and attaching tasks. - */ - if ((flags & VIR_CGROUP_MEM_HIERACHY) && - (group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) && - (i == VIR_CGROUP_CONTROLLER_MEMORY || - STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) { - rc = virCgroupSetMemoryUseHierarchy(group); - if (rc != 0) { - VIR_FREE(path); - break; - } - } - } + int rc = 0; - VIR_FREE(path); - } + rc = virCgroupGetValueStr(group, controller, key, &strval); + if (rc != 0) + goto out; + + if (virStrToLong_ull(strval, NULL, 10, value) < 0) + rc = -EINVAL; +out: + VIR_FREE(strval); return rc; } - -static int virCgroupNew(const char *path, - virCgroupPtr *group) +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +static int virCgroupItemCpusetInherit(virCgroupItemPtr cgroupItem) { + int i; + char *value; int rc = 0; - char *typpath = NULL; - - VIR_DEBUG("New group %s", path); - *group = NULL; - - if (VIR_ALLOC((*group)) != 0) { - rc = -ENOMEM; - goto err; - } + const char *inherit_values[] = { + "cpuset.cpus", + "cpuset.mems", + }; - if (!((*group)->path = strdup(path))) { - rc = -ENOMEM; - goto err; - } + for (i = 0; i < ARRAY_CARDINALITY(inherit_values) ; i++) { + rc = virCgroupItemGetValueStr(cgroupItem->parent, + inherit_values[i], + &value); + if (rc != 0) { + VIR_ERROR(_("Failed to get %s %d"), inherit_values[i], rc); + break; + } - rc = virCgroupDetect(*group); - if (rc < 0) - goto err; + VIR_DEBUG("Inherit %s = %s", inherit_values[i], value); - return rc; -err: - virCgroupFree(group); - *group = NULL; + rc = virCgroupItemSetValueStr(cgroupItem, + inherit_values[i], + value); + VIR_FREE(value); - VIR_FREE(typpath); + if (rc != 0) { + VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc); + break; + } + } return rc; } -static int virCgroupAppRoot(bool privileged, - virCgroupPtr *group, - bool create) +static int virCgroupItemSetMemoryUseHierarchy(virCgroupItemPtr item) { - virCgroupPtr rootgrp = NULL; - int rc; + int rc = 0; + char *value = NULL; + const char *filename = "memory.use_hierarchy"; - rc = virCgroupNew("/", &rootgrp); - if (rc != 0) + rc = virCgroupItemGetValueStr(item, + filename, &value); + if (rc != 0) { + VIR_ERROR(_("Failed to read %s/%s (%d)"), item->path, filename, rc); return rc; + } - if (privileged) { - rc = virCgroupNew("/libvirt", group); - } else { - char *rootname; - char *username; - username = virGetUserName(getuid()); - if (!username) { - rc = -ENOMEM; - goto cleanup; - } - rc = virAsprintf(&rootname, "/libvirt-%s", username); - VIR_FREE(username); - if (rc < 0) { - rc = -ENOMEM; - goto cleanup; - } - - rc = virCgroupNew(rootname, group); - VIR_FREE(rootname); + /* Setting twice causes error, so if already enabled, skip setting */ + if (STREQ(value, "1")) { + rc = 0; + goto out; } - if (rc != 0) - goto cleanup; - rc = virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE); + VIR_DEBUG("Setting up %s/%s", item->path, filename); + rc = virCgroupItemSetValueStr(item, + filename, "1"); -cleanup: - virCgroupFree(&rootgrp); + if (rc != 0) { + VIR_ERROR(_("Failed to set %s/%s (%d)"), item->path, filename, rc); + } + +out: + VIR_FREE(value); return rc; } + #endif #if defined _DIRENT_HAVE_D_TYPE @@ -743,43 +919,6 @@ static int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) #endif /** - * virCgroupRemove: - * - * @group: The group to be removed - * - * It first removes all child groups recursively - * in depth first order and then removes @group - * because the presence of the child groups - * prevents removing @group. - * - * Returns: 0 on success - */ -int virCgroupRemove(virCgroupPtr group) -{ - int rc = 0; - int i; - char *grppath = NULL; - - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - /* Skip over controllers not mounted */ - if (!group->controllers[i].mountPoint) - continue; - - if (virCgroupPathOfController(group, - i, - NULL, - &grppath) != 0) - continue; - - VIR_DEBUG("Removing cgroup %s and all child cgroups", grppath); - rc = virCgroupRemoveRecursively(grppath); - VIR_FREE(grppath); - } - - return rc; -} - -/** * virCgroupAddTask: * * @group: The cgroup to add a task to @@ -794,7 +933,7 @@ int virCgroupAddTask(virCgroupPtr group, pid_t pid) for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { /* Skip over controllers not mounted */ - if (!group->controllers[i].mountPoint) + if (!virCgroupMounted(group, i)) continue; rc = virCgroupSetValueU64(group, i, "tasks", (unsigned long long)pid); @@ -819,7 +958,7 @@ int virCgroupAddTaskController(virCgroupPtr group, pid_t pid, int controller) if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST) return -EINVAL; - if (!group->controllers[controller].mountPoint) + if (!virCgroupMounted(group, controller)) return -EINVAL; return virCgroupSetValueU64(group, controller, "tasks", @@ -882,12 +1021,6 @@ int virCgroupMoveTask(virCgroupPtr src_group, virCgroupPtr dest_group, controller > VIR_CGROUP_CONTROLLER_BLKIO) return -EINVAL; - if (!src_group->controllers[controller].mountPoint || - !dest_group->controllers[controller].mountPoint) { - VIR_WARN("no vm cgroup in controller %d", controller); - return 0; - } - rc = virCgroupGetValueStr(src_group, controller, "tasks", &content); if (rc != 0) return rc; @@ -908,226 +1041,39 @@ cleanup: err = virCgroupAddTaskStrController(src_group, content, controller); if (err != 0) VIR_ERROR(_("Cannot recover cgroup %s from %s"), - src_group->controllers[controller].mountPoint, - dest_group->controllers[controller].mountPoint); + src_group->items[controller]->path, + dest_group->items[controller]->path); VIR_FREE(content); return rc; } -/** - * virCgroupForDriver: - * - * @name: name of this driver (e.g., xen, qemu, lxc) - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForDriver(const char *name, - virCgroupPtr *group, - bool privileged, - bool create) -{ - int rc; - char *path = NULL; - virCgroupPtr rootgrp = NULL; - - rc = virCgroupAppRoot(privileged, &rootgrp, create); - if (rc != 0) - goto out; - - if (virAsprintf(&path, "%s/%s", rootgrp->path, name) < 0) { - rc = -ENOMEM; - goto out; - } - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - rc = virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE); - if (rc != 0) - virCgroupFree(group); - } - -out: - virCgroupFree(&rootgrp); - - return rc; -} -#else -int virCgroupForDriver(const char *name ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool privileged ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - /* Claim no support */ - return -ENXIO; -} -#endif - -/** -* virCgroupGetAppRoot: -* -* @group: Pointer to returned virCgroupPtr -* -* Returns 0 on success -*/ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupGetAppRoot(virCgroupPtr *group) -{ - return virCgroupNew("/", group); -} -#else -int virCgroupGetAppRoot(virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForDomain: - * - * @driver: group for driver owning the domain - * @name: name of the domain - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForDomain(virCgroupPtr driver, - const char *name, - virCgroupPtr *group, - bool create) -{ - int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - - if (virAsprintf(&path, "%s/%s", driver->path, name) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - /* - * Create a cgroup with memory.use_hierarchy enabled to - * surely account memory usage of lxc with ns subsystem - * enabled. (To be exact, memory and ns subsystems are - * enabled at the same time.) - * - * The reason why doing it here, not a upper group, say - * a group for driver, is to avoid overhead to track - * cumulative usage that we don't need. - */ - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_MEM_HIERACHY); - if (rc != 0) - virCgroupFree(group); - } - - return rc; -} -#else -int virCgroupForDomain(virCgroupPtr driver ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForVcpu: - * - * @driver: group for the domain - * @vcpuid: id of the vcpu - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForVcpu(virCgroupPtr driver, - int vcpuid, - virCgroupPtr *group, - bool create) +int virCgroupGetAppRoot(virCgroupPtr *cgroup, bool privileged) { + char *name = NULL; + char *user = NULL; int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - if (virAsprintf(&path, "%s/vcpu%d", driver->path, vcpuid) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); + if (privileged) + name = strdup("libvirt"); + else { + user = virGetUserName(getuid()); + if (!user) { + return -ENOMEM; + } - if (rc == 0) { - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); - if (rc != 0) - virCgroupFree(group); + if (virAsprintf(&name, "libvirt-%s", user) < 0) { + VIR_FREE(user); + return -ENOMEM; + } } - return rc; -} -#else -int virCgroupForVcpu(virCgroupPtr driver ATTRIBUTE_UNUSED, - int vcpuid ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForEmulator: - * - * @driver: group for the domain - * @group: Pointer to returned virCgroupPtr - * - * Returns: 0 on success or -errno on failure - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForEmulator(virCgroupPtr driver, - virCgroupPtr *group, - bool create) -{ - int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - - if (virAsprintf(&path, "%s/emulator", driver->path) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); - if (rc != 0) - virCgroupFree(group); - } + rc = virCgroupNew(name, NULL, cgroup); + VIR_FREE(name); return rc; } -#else -int virCgroupForEmulator(virCgroupPtr driver ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif /** * virCgroupSetBlkioWeight: * @@ -1861,21 +1807,20 @@ int virCgroupGetFreezerState(virCgroupPtr group, char **state) #if defined HAVE_KILL && defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -static int virCgroupKillInternal(virCgroupPtr group, int signum, virHashTablePtr pids) +static int virCgroupItemKillInternal(virCgroupItemPtr item, + int signum, + virHashTablePtr pids) { - int rc; + int rc = -1; int killedAny = 0; char *keypath = NULL; bool done = false; FILE *fp = NULL; - VIR_DEBUG("group=%p path=%s signum=%d pids=%p", - group, group->path, signum, pids); + VIR_DEBUG("cgroupItem=%p signum=%d pids=%p", + item, signum, pids); - rc = virCgroupPathOfController(group, -1, "tasks", &keypath); - if (rc != 0) { - VIR_DEBUG("No path of %s, tasks", group->path); + if (virAsprintf(&keypath, "%s/tasks", item->path) < 0) return rc; - } /* PIDs may be forking as we kill them, so loop * until there are no new PIDs found @@ -1927,7 +1872,6 @@ cleanup: return rc; } - static uint32_t virCgroupPidCode(const void *name, uint32_t seed) { unsigned long pid_value = (unsigned long)(intptr_t)name; @@ -1942,15 +1886,8 @@ static void *virCgroupPidCopy(const void *name) return (void*)name; } -/* - * Returns - * < 0 : errno that occurred - * 0 : no PIDs killed - * 1 : at least one PID killed - */ -int virCgroupKill(virCgroupPtr group, int signum) +static int virCgroupItemKill(virCgroupItemPtr item, int signum) { - VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); int rc; /* The 'tasks' file in cgroups can contain duplicated * pids, so we use a hash to track which we've already @@ -1963,82 +1900,65 @@ int virCgroupKill(virCgroupPtr group, int signum) virCgroupPidCopy, NULL); - rc = virCgroupKillInternal(group, signum, pids); + rc = virCgroupItemKillInternal(item, signum, pids); virHashFree(pids); return rc; } - -static int virCgroupKillRecursiveInternal(virCgroupPtr group, int signum, virHashTablePtr pids, bool dormdir) +/* + * Returns + * < 0 : errno that occurred + * 0 : no PIDs killed + * 1 : at least one PID killed + */ +int virCgroupKill(virCgroupPtr group, int signum) { int rc; - int killedAny = 0; - char *keypath = NULL; - DIR *dp; - virCgroupPtr subgroup = NULL; - struct dirent *ent; - VIR_DEBUG("group=%p path=%s signum=%d pids=%p", group, group->path, signum, pids); - - rc = virCgroupPathOfController(group, -1, "", &keypath); - if (rc != 0) { - VIR_DEBUG("No path of %s, tasks", group->path); - return rc; - } + int i; - if ((rc = virCgroupKillInternal(group, signum, pids)) != 0) - return rc; + VIR_DEBUG("group=%p signum=%d", group, signum); - VIR_DEBUG("Iterate over children of %s", keypath); - if (!(dp = opendir(keypath))) { - rc = -errno; - return rc; + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + rc = virCgroupItemKill(group->items[i], signum); + if (rc < 0) + break; } - while ((ent = readdir(dp))) { - char *subpath; + return rc; +} - if (STREQ(ent->d_name, ".")) - continue; - if (STREQ(ent->d_name, "..")) - continue; - if (ent->d_type != DT_DIR) - continue; +static int virCgroupItemKillRecursiveInternal(virCgroupItemPtr item, + int signum, + virHashTablePtr pids) +{ + int rc; + int killedAny = 0; + virCgroupItemPtr child = NULL; - VIR_DEBUG("Process subdir %s", ent->d_name); - if (virAsprintf(&subpath, "%s/%s", group->path, ent->d_name) < 0) { - rc = -ENOMEM; - goto cleanup; - } + if ((rc = virCgroupItemKillInternal(item, signum, pids)) < 0) + return rc; - if ((rc = virCgroupNew(subpath, &subgroup)) != 0) - goto cleanup; + VIR_DEBUG("Iterate over children of %s", item->path); - if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids, true)) < 0) - goto cleanup; + child = item->children; + while (child) { + rc = virCgroupItemKillRecursiveInternal(child, signum, pids); if (rc == 1) killedAny = 1; - if (dormdir) - virCgroupRemove(subgroup); - - virCgroupFree(&subgroup); + child = child->next; } rc = killedAny; -cleanup: - virCgroupFree(&subgroup); - closedir(dp); - return rc; } -int virCgroupKillRecursive(virCgroupPtr group, int signum) +static int virCgroupItemKillRecursive(virCgroupItemPtr item, int signum) { int rc; - VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); virHashTablePtr pids = virHashCreateFull(100, NULL, virCgroupPidCode, @@ -2046,19 +1966,30 @@ int virCgroupKillRecursive(virCgroupPtr group, int signum) virCgroupPidCopy, NULL); - rc = virCgroupKillRecursiveInternal(group, signum, pids, false); + rc = virCgroupItemKillRecursiveInternal(item, signum, pids); virHashFree(pids); return rc; } +int virCgroupKillRecursive(virCgroupPtr group, int signum) +{ + int rc; + int i; + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + rc = virCgroupItemKillRecursive(group->items[i], signum); + } + + return rc; +} int virCgroupKillPainfully(virCgroupPtr group) { int i; int rc; - VIR_DEBUG("cgroup=%p path=%s", group, group->path); + VIR_DEBUG("cgroup=%p", group); for (i = 0 ; i < 15 ; i++) { int signum; if (i == 0) diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h index 2ed6ff9..0ccca23 100644 --- a/src/util/vircgroup.h +++ b/src/util/vircgroup.h @@ -49,21 +49,7 @@ int virCgroupForDriver(const char *name, bool privileged, bool create); -int virCgroupGetAppRoot(virCgroupPtr *group); - -int virCgroupForDomain(virCgroupPtr driver, - const char *name, - virCgroupPtr *group, - bool create); - -int virCgroupForVcpu(virCgroupPtr driver, - int vcpuid, - virCgroupPtr *group, - bool create); - -int virCgroupForEmulator(virCgroupPtr driver, - virCgroupPtr *group, - bool create); +int virCgroupGetAppRoot(virCgroupPtr *group, bool privileged); int virCgroupPathOfController(virCgroupPtr group, int controller, @@ -159,6 +145,7 @@ int virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus); int virCgroupRemove(virCgroupPtr group); +int virCgroupNew(const char *name, virCgroupPtr parent, virCgroupPtr *cgroup); void virCgroupFree(virCgroupPtr *group); bool virCgroupMounted(virCgroupPtr cgroup, int controller); @@ -166,4 +153,6 @@ int virCgroupKill(virCgroupPtr group, int signum); int virCgroupKillRecursive(virCgroupPtr group, int signum); int virCgroupKillPainfully(virCgroupPtr group); +int virCgroupMakePath(virCgroupPtr cgroup); + #endif /* __VIR_CGROUP_H__ */ -- 1.8.0.1.240.ge8a1f5a -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list