[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v2 RESEND 2/2] cgroup: refactor virCgroup



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 = &params[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, &quota);
+        rc = lxcGetVcpuBWLive(vm->cgroup, &period, &quota);
         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, &quota);
+        rc = qemuGetVcpusBWLive(vm, vm->cgroup, &period, &quota);
         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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]