Blame SOURCES/libvirt-vircgroup-introduce-nested-cgroup-to-properly-work-with-systemd.patch

7548c0
From 2593f2e4626fbb6dfef2317bceea4d1b8275f9d8 Mon Sep 17 00:00:00 2001
7548c0
Message-Id: <2593f2e4626fbb6dfef2317bceea4d1b8275f9d8@dist-git>
7548c0
From: Pavel Hrdina <phrdina@redhat.com>
7548c0
Date: Fri, 19 Feb 2021 13:33:59 +0100
7548c0
Subject: [PATCH] vircgroup: introduce nested cgroup to properly work with
7548c0
 systemd
7548c0
MIME-Version: 1.0
7548c0
Content-Type: text/plain; charset=UTF-8
7548c0
Content-Transfer-Encoding: 8bit
7548c0
7548c0
When running on host with systemd we register VMs with machined.
7548c0
In this case systemd creates the root VM cgroup for us. This has some
7548c0
implications where one of them is that systemd owns all files inside
7548c0
the root VM cgroup and we should not touch them.
7548c0
7548c0
We already use DBus calls for some of the APIs but for the remaining
7548c0
ones we will continue accessing the files directly. Systemd doesn't
7548c0
support threaded cgroups so we need to do this.
7548c0
7548c0
The reason why we don't use DBus for most of the APIs is that we already
7548c0
have a code that works with files and we would have to check if systemd
7548c0
supports each API.
7548c0
7548c0
This change introduces new topology on systemd hosts:
7548c0
7548c0
$ROOT
7548c0
  |
7548c0
  +- machine.slice
7548c0
     |
7548c0
     +- machine-qemu\x2d1\x2dvm1.scope
7548c0
        |
7548c0
        +- libvirt
7548c0
           |
7548c0
           +- emulator
7548c0
           +- vcpu0
7548c0
           +- vcpu0
7548c0
7548c0
compared to the previous topology:
7548c0
7548c0
$ROOT
7548c0
  |
7548c0
  +- machine.slice
7548c0
     |
7548c0
     +- machine-qemu\x2d1\x2dvm1.scope
7548c0
        |
7548c0
        +- emulator
7548c0
        +- vcpu0
7548c0
        +- vcpu0
7548c0
7548c0
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
7548c0
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
7548c0
(cherry picked from commit 184245f53b94fc84f727eb6e8a2aa52df02d69c0)
7548c0
7548c0
Conflicts:
7548c0
    src/util/vircgroup.c
7548c0
        - missing upstream g_free and g_autofree rewrite
7548c0
7548c0
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463
7548c0
7548c0
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
7548c0
Message-Id: <51312c8b520e4ed794f8cd8a77b77c228387bb15.1613737828.git.phrdina@redhat.com>
7548c0
Reviewed-by: Ján Tomko <jtomko@redhat.com>
7548c0
---
7548c0
 docs/cgroups.html.in     |  29 +++--
7548c0
 src/util/vircgroup.c     | 256 +++++++++++++++++++++++++++++++--------
7548c0
 src/util/vircgrouppriv.h |   4 +
7548c0
 src/util/vircgroupv1.c   |  15 ++-
7548c0
 src/util/vircgroupv2.c   |   6 +
7548c0
 5 files changed, 245 insertions(+), 65 deletions(-)
7548c0
7548c0
diff --git a/docs/cgroups.html.in b/docs/cgroups.html.in
7548c0
index 78dede1bba..412a9360ff 100644
7548c0
--- a/docs/cgroups.html.in
7548c0
+++ b/docs/cgroups.html.in
7548c0
@@ -117,21 +117,27 @@ $ROOT
7548c0
       |
7548c0
       +- machine-qemu\x2d1\x2dvm1.scope
7548c0
       |   |
7548c0
-      |   +- emulator
7548c0
-      |   +- vcpu0
7548c0
-      |   +- vcpu1
7548c0
+      |   +- libvirt
7548c0
+      |       |
7548c0
+      |       +- emulator
7548c0
+      |       +- vcpu0
7548c0
+      |       +- vcpu1
7548c0
       |
7548c0
       +- machine-qemu\x2d2\x2dvm2.scope
7548c0
       |   |
7548c0
-      |   +- emulator
7548c0
-      |   +- vcpu0
7548c0
-      |   +- vcpu1
7548c0
+      |   +- libvirt
7548c0
+      |       |
7548c0
+      |       +- emulator
7548c0
+      |       +- vcpu0
7548c0
+      |       +- vcpu1
7548c0
       |
7548c0
       +- machine-qemu\x2d3\x2dvm3.scope
7548c0
       |   |
7548c0
-      |   +- emulator
7548c0
-      |   +- vcpu0
7548c0
-      |   +- vcpu1
7548c0
+      |   +- libvirt
7548c0
+      |       |
7548c0
+      |       +- emulator
7548c0
+      |       +- vcpu0
7548c0
+      |       +- vcpu1
7548c0
       |
7548c0
       +- machine-engineering.slice
7548c0
       |   |
7548c0
@@ -148,6 +154,11 @@ $ROOT
7548c0
           +- machine-lxc\x2d33333\x2dcontainer3.scope
7548c0
     
7548c0
 
7548c0
+    

7548c0
+      Prior libvirt 7.1.0 the topology doesn't have extra
7548c0
+      libvirt directory.
7548c0
+    

7548c0
+
7548c0
     

Non-systemd cgroups layout

7548c0
 
7548c0
     

7548c0
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
7548c0
index 8f5bcd94f4..d0f867ba7f 100644
7548c0
--- a/src/util/vircgroup.c
7548c0
+++ b/src/util/vircgroup.c
7548c0
@@ -639,6 +639,22 @@ virCgroupMakeGroup(virCgroupPtr parent,
7548c0
 }
7548c0
 
7548c0
 
7548c0
+static bool
7548c0
+virCgroupExists(virCgroupPtr group)
7548c0
+{
7548c0
+    size_t i;
7548c0
+
7548c0
+    for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
7548c0
+        if (group->backends[i] &&
7548c0
+            !group->backends[i]->exists(group)) {
7548c0
+            return false;
7548c0
+        }
7548c0
+    }
7548c0
+
7548c0
+    return true;
7548c0
+}
7548c0
+
7548c0
+
7548c0
 /**
7548c0
  * virCgroupNew:
7548c0
  * @path: path for the new group
7548c0
@@ -695,10 +711,11 @@ virCgroupAddTaskInternal(virCgroupPtr group,
7548c0
                          unsigned int flags)
7548c0
 {
7548c0
     size_t i;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
 
7548c0
     for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
7548c0
-        if (group->backends[i] &&
7548c0
-            group->backends[i]->addTask(group, pid, flags) < 0) {
7548c0
+        if (parent->backends[i] &&
7548c0
+            parent->backends[i]->addTask(parent, pid, flags) < 0) {
7548c0
             return -1;
7548c0
         }
7548c0
     }
7548c0
@@ -871,6 +888,30 @@ virCgroupNewPartition(const char *path,
7548c0
 }
7548c0
 
7548c0
 
7548c0
+static int
7548c0
+virCgroupNewNested(virCgroupPtr parent,
7548c0
+                   int controllers,
7548c0
+                   bool create,
7548c0
+                   pid_t pid,
7548c0
+                   virCgroupPtr *nested)
7548c0
+{
7548c0
+    virCgroupPtr new = NULL;
7548c0
+
7548c0
+    if (virCgroupNew(-1, "libvirt", parent, controllers, &new) < 0)
7548c0
+        return -1;
7548c0
+
7548c0
+    if (create) {
7548c0
+        if (virCgroupMakeGroup(parent, new, create, pid, VIR_CGROUP_NONE) < 0) {
7548c0
+            virCgroupFree(&new;;
7548c0
+            return -1;
7548c0
+        }
7548c0
+    }
7548c0
+
7548c0
+    *nested = g_steal_pointer(&new;;
7548c0
+    return 0;
7548c0
+}
7548c0
+
7548c0
+
7548c0
 /**
7548c0
 * virCgroupNewSelf:
7548c0
 *
7548c0
@@ -954,6 +995,7 @@ virCgroupNewThread(virCgroupPtr domain,
7548c0
                    virCgroupPtr *group)
7548c0
 {
7548c0
     g_autofree char *name = NULL;
7548c0
+    virCgroupPtr parent = NULL;
7548c0
     int controllers;
7548c0
 
7548c0
     switch (nameval) {
7548c0
@@ -976,10 +1018,12 @@ virCgroupNewThread(virCgroupPtr domain,
7548c0
                    (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
7548c0
                    (1 << VIR_CGROUP_CONTROLLER_CPUSET));
7548c0
 
7548c0
-    if (virCgroupNew(-1, name, domain, controllers, group) < 0)
7548c0
+    parent = virCgroupGetNested(domain);
7548c0
+
7548c0
+    if (virCgroupNew(-1, name, parent, controllers, group) < 0)
7548c0
         return -1;
7548c0
 
7548c0
-    if (virCgroupMakeGroup(domain, *group, create, -1, VIR_CGROUP_THREAD) < 0) {
7548c0
+    if (virCgroupMakeGroup(parent, *group, create, -1, VIR_CGROUP_THREAD) < 0) {
7548c0
         virCgroupFree(group);
7548c0
         return -1;
7548c0
     }
7548c0
@@ -1009,6 +1053,7 @@ virCgroupNewDetectMachine(const char *name,
7548c0
                           virCgroupPtr *group)
7548c0
 {
7548c0
     size_t i;
7548c0
+    virCgroupPtr nested = NULL;
7548c0
 
7548c0
     if (virCgroupNewDetect(pid, controllers, group) < 0) {
7548c0
         if (virCgroupNewIgnoreError())
7548c0
@@ -1032,6 +1077,14 @@ virCgroupNewDetectMachine(const char *name,
7548c0
     if (virSystemdHasMachined() == 0 && !(*group)->unitName)
7548c0
         return -1;
7548c0
 
7548c0
+    if (virCgroupNewNested((*group), controllers, false, -1, &nested) < 0)
7548c0
+        return -1;
7548c0
+
7548c0
+    if (virCgroupExists(nested))
7548c0
+        (*group)->nested = g_steal_pointer(&nested);
7548c0
+
7548c0
+    virCgroupFree(&nested);
7548c0
+
7548c0
     return 0;
7548c0
 }
7548c0
 
7548c0
@@ -1107,6 +1160,7 @@ virCgroupNewMachineSystemd(const char *name,
7548c0
 {
7548c0
     int rv;
7548c0
     virCgroupPtr init;
7548c0
+    virCgroupPtr nested = NULL;
7548c0
     g_autofree char *path = NULL;
7548c0
     size_t i;
7548c0
 
7548c0
@@ -1157,6 +1211,13 @@ virCgroupNewMachineSystemd(const char *name,
7548c0
         return -1;
7548c0
     }
7548c0
 
7548c0
+    if (virCgroupNewNested((*group), controllers, true, pidleader, &nested) < 0) {
7548c0
+        virCgroupFree(group);
7548c0
+        return -1;
7548c0
+    }
7548c0
+
7548c0
+    (*group)->nested = nested;
7548c0
+
7548c0
     if (virCgroupAddProcess(*group, pidleader) < 0) {
7548c0
         virErrorPtr saved;
7548c0
 
7548c0
@@ -1349,7 +1410,9 @@ virCgroupGetBlkioIoServiced(virCgroupPtr group,
7548c0
                             long long *requests_read,
7548c0
                             long long *requests_write)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioIoServiced, -1,
7548c0
                             bytes_read, bytes_write,
7548c0
                             requests_read, requests_write);
7548c0
@@ -1376,7 +1439,9 @@ virCgroupGetBlkioIoDeviceServiced(virCgroupPtr group,
7548c0
                                   long long *requests_read,
7548c0
                                   long long *requests_write)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioIoDeviceServiced, -1,
7548c0
                             path, bytes_read, bytes_write,
7548c0
                             requests_read, requests_write);
7548c0
@@ -1427,7 +1492,9 @@ virCgroupSetBlkioDeviceReadIops(virCgroupPtr group,
7548c0
                                 const char *path,
7548c0
                                 unsigned int riops)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             setBlkioDeviceReadIops, -1, path, riops);
7548c0
 }
7548c0
 
7548c0
@@ -1445,7 +1512,9 @@ virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group,
7548c0
                                  const char *path,
7548c0
                                  unsigned int wiops)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             setBlkioDeviceWriteIops, -1, path, wiops);
7548c0
 }
7548c0
 
7548c0
@@ -1463,7 +1532,9 @@ virCgroupSetBlkioDeviceReadBps(virCgroupPtr group,
7548c0
                                const char *path,
7548c0
                                unsigned long long rbps)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             setBlkioDeviceReadBps, -1, path, rbps);
7548c0
 }
7548c0
 
7548c0
@@ -1480,7 +1551,9 @@ virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group,
7548c0
                                 const char *path,
7548c0
                                 unsigned long long wbps)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             setBlkioDeviceWriteBps, -1, path, wbps);
7548c0
 }
7548c0
 
7548c0
@@ -1516,7 +1589,9 @@ virCgroupGetBlkioDeviceReadIops(virCgroupPtr group,
7548c0
                                 const char *path,
7548c0
                                 unsigned int *riops)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioDeviceReadIops, -1, path, riops);
7548c0
 }
7548c0
 
7548c0
@@ -1533,7 +1608,9 @@ virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group,
7548c0
                                  const char *path,
7548c0
                                  unsigned int *wiops)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioDeviceWriteIops, -1, path, wiops);
7548c0
 }
7548c0
 
7548c0
@@ -1550,7 +1627,9 @@ virCgroupGetBlkioDeviceReadBps(virCgroupPtr group,
7548c0
                                const char *path,
7548c0
                                unsigned long long *rbps)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioDeviceReadBps, -1, path, rbps);
7548c0
 }
7548c0
 
7548c0
@@ -1567,7 +1646,9 @@ virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group,
7548c0
                                 const char *path,
7548c0
                                 unsigned long long *wbps)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO,
7548c0
                             getBlkioDeviceWriteBps, -1, path, wbps);
7548c0
 }
7548c0
 
7548c0
@@ -1600,7 +1681,9 @@ virCgroupGetBlkioDeviceWeight(virCgroupPtr group,
7548c0
 int
7548c0
 virCgroupSetMemory(virCgroupPtr group, unsigned long long kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             setMemory, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1627,7 +1710,9 @@ virCgroupGetMemoryStat(virCgroupPtr group,
7548c0
                        unsigned long long *inactiveFile,
7548c0
                        unsigned long long *unevictable)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemoryStat, -1, cache,
7548c0
                             activeAnon, inactiveAnon,
7548c0
                             activeFile, inactiveFile,
7548c0
@@ -1646,7 +1731,9 @@ virCgroupGetMemoryStat(virCgroupPtr group,
7548c0
 int
7548c0
 virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemoryUsage, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1662,7 +1749,9 @@ virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb)
7548c0
 int
7548c0
 virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             setMemoryHardLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1678,7 +1767,9 @@ virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 int
7548c0
 virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemoryHardLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1694,7 +1785,9 @@ virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 int
7548c0
 virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             setMemorySoftLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1710,7 +1803,9 @@ virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 int
7548c0
 virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemorySoftLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1726,7 +1821,9 @@ virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 int
7548c0
 virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             setMemSwapHardLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1742,7 +1839,9 @@ virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb)
7548c0
 int
7548c0
 virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemSwapHardLimit, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1758,7 +1857,9 @@ virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb)
7548c0
 int
7548c0
 virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY,
7548c0
                             getMemSwapUsage, -1, kb);
7548c0
 }
7548c0
 
7548c0
@@ -1774,7 +1875,9 @@ virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb)
7548c0
 int
7548c0
 virCgroupSetCpusetMems(virCgroupPtr group, const char *mems)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             setCpusetMems, -1, mems);
7548c0
 }
7548c0
 
7548c0
@@ -1790,7 +1893,9 @@ virCgroupSetCpusetMems(virCgroupPtr group, const char *mems)
7548c0
 int
7548c0
 virCgroupGetCpusetMems(virCgroupPtr group, char **mems)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             getCpusetMems, -1, mems);
7548c0
 }
7548c0
 
7548c0
@@ -1806,7 +1911,9 @@ virCgroupGetCpusetMems(virCgroupPtr group, char **mems)
7548c0
 int
7548c0
 virCgroupSetCpusetMemoryMigrate(virCgroupPtr group, bool migrate)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             setCpusetMemoryMigrate, -1, migrate);
7548c0
 }
7548c0
 
7548c0
@@ -1822,7 +1929,9 @@ virCgroupSetCpusetMemoryMigrate(virCgroupPtr group, bool migrate)
7548c0
 int
7548c0
 virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             getCpusetMemoryMigrate, -1, migrate);
7548c0
 }
7548c0
 
7548c0
@@ -1838,7 +1947,9 @@ virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate)
7548c0
 int
7548c0
 virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             setCpusetCpus, -1, cpus);
7548c0
 }
7548c0
 
7548c0
@@ -1854,7 +1965,9 @@ virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus)
7548c0
 int
7548c0
 virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET,
7548c0
                             getCpusetCpus, -1, cpus);
7548c0
 }
7548c0
 
7548c0
@@ -1869,7 +1982,9 @@ virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus)
7548c0
 int
7548c0
 virCgroupDenyAllDevices(virCgroupPtr group)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             denyAllDevices, -1);
7548c0
 }
7548c0
 
7548c0
@@ -1890,7 +2005,9 @@ virCgroupDenyAllDevices(virCgroupPtr group)
7548c0
 int
7548c0
 virCgroupAllowAllDevices(virCgroupPtr group, int perms)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             allowAllDevices, -1, perms);
7548c0
 }
7548c0
 
7548c0
@@ -1910,7 +2027,9 @@ int
7548c0
 virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor,
7548c0
                      int perms)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             allowDevice, -1, type, major, minor, perms);
7548c0
 }
7548c0
 
7548c0
@@ -1936,6 +2055,7 @@ virCgroupAllowDevicePath(virCgroupPtr group,
7548c0
                          bool ignoreEacces)
7548c0
 {
7548c0
     struct stat sb;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
 
7548c0
     if (stat(path, &sb) < 0) {
7548c0
         if (errno == EACCES && ignoreEacces)
7548c0
@@ -1950,7 +2070,7 @@ virCgroupAllowDevicePath(virCgroupPtr group,
7548c0
     if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
7548c0
         return 1;
7548c0
 
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             allowDevice, -1,
7548c0
                             S_ISCHR(sb.st_mode) ? 'c' : 'b',
7548c0
                             major(sb.st_rdev),
7548c0
@@ -1974,7 +2094,9 @@ int
7548c0
 virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor,
7548c0
                     int perms)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             denyDevice, -1, type, major, minor, perms);
7548c0
 }
7548c0
 
7548c0
@@ -2000,6 +2122,7 @@ virCgroupDenyDevicePath(virCgroupPtr group,
7548c0
                         bool ignoreEacces)
7548c0
 {
7548c0
     struct stat sb;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
 
7548c0
     if (stat(path, &sb) < 0) {
7548c0
         if (errno == EACCES && ignoreEacces)
7548c0
@@ -2014,7 +2137,7 @@ virCgroupDenyDevicePath(virCgroupPtr group,
7548c0
     if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
7548c0
         return 1;
7548c0
 
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES,
7548c0
                             denyDevice, -1,
7548c0
                             S_ISCHR(sb.st_mode) ? 'c' : 'b',
7548c0
                             major(sb.st_rdev),
7548c0
@@ -2282,7 +2405,9 @@ virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
7548c0
 int
7548c0
 virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU,
7548c0
                             setCpuCfsPeriod, -1, cfs_period);
7548c0
 }
7548c0
 
7548c0
@@ -2298,7 +2423,9 @@ virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period)
7548c0
 int
7548c0
 virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU,
7548c0
                             getCpuCfsPeriod, -1, cfs_period);
7548c0
 }
7548c0
 
7548c0
@@ -2315,7 +2442,9 @@ virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period)
7548c0
 int
7548c0
 virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU,
7548c0
                             setCpuCfsQuota, -1, cfs_quota);
7548c0
 }
7548c0
 
7548c0
@@ -2323,7 +2452,9 @@ virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota)
7548c0
 int
7548c0
 virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
                             getCpuacctPercpuUsage, -1, usage);
7548c0
 }
7548c0
 
7548c0
@@ -2669,7 +2800,9 @@ virCgroupKillPainfully(virCgroupPtr group)
7548c0
 int
7548c0
 virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU,
7548c0
                             getCpuCfsQuota, -1, cfs_quota);
7548c0
 }
7548c0
 
7548c0
@@ -2677,7 +2810,9 @@ virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota)
7548c0
 int
7548c0
 virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
                             getCpuacctUsage, -1, usage);
7548c0
 }
7548c0
 
7548c0
@@ -2686,7 +2821,9 @@ int
7548c0
 virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
7548c0
                         unsigned long long *sys)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT,
7548c0
                             getCpuacctStat, -1, user, sys);
7548c0
 }
7548c0
 
7548c0
@@ -2694,7 +2831,9 @@ virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user,
7548c0
 int
7548c0
 virCgroupSetFreezerState(virCgroupPtr group, const char *state)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_FREEZER,
7548c0
                             setFreezerState, -1, state);
7548c0
 }
7548c0
 
7548c0
@@ -2702,7 +2841,9 @@ virCgroupSetFreezerState(virCgroupPtr group, const char *state)
7548c0
 int
7548c0
 virCgroupGetFreezerState(virCgroupPtr group, char **state)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_FREEZER,
7548c0
                             getFreezerState, -1, state);
7548c0
 }
7548c0
 
7548c0
@@ -2712,10 +2853,11 @@ virCgroupBindMount(virCgroupPtr group, const char *oldroot,
7548c0
                    const char *mountopts)
7548c0
 {
7548c0
     size_t i;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(group);
7548c0
 
7548c0
     for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
7548c0
-        if (group->backends[i] &&
7548c0
-            group->backends[i]->bindMount(group, oldroot, mountopts) < 0) {
7548c0
+        if (parent->backends[i] &&
7548c0
+            parent->backends[i]->bindMount(parent, oldroot, mountopts) < 0) {
7548c0
             return -1;
7548c0
         }
7548c0
     }
7548c0
@@ -2730,10 +2872,11 @@ int virCgroupSetOwner(virCgroupPtr cgroup,
7548c0
                       int controllers)
7548c0
 {
7548c0
     size_t i;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(cgroup);
7548c0
 
7548c0
     for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
7548c0
-        if (cgroup->backends[i] &&
7548c0
-            cgroup->backends[i]->setOwner(cgroup, uid, gid, controllers) < 0) {
7548c0
+        if (parent->backends[i] &&
7548c0
+            parent->backends[i]->setOwner(parent, uid, gid, controllers) < 0) {
7548c0
             return -1;
7548c0
         }
7548c0
     }
7548c0
@@ -2752,7 +2895,9 @@ int virCgroupSetOwner(virCgroupPtr cgroup,
7548c0
 bool
7548c0
 virCgroupSupportsCpuBW(virCgroupPtr cgroup)
7548c0
 {
7548c0
-    VIR_CGROUP_BACKEND_CALL(cgroup, VIR_CGROUP_CONTROLLER_CPU,
7548c0
+    virCgroupPtr parent = virCgroupGetNested(cgroup);
7548c0
+
7548c0
+    VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU,
7548c0
                             supportsCpuBW, false);
7548c0
 }
7548c0
 
7548c0
@@ -2760,10 +2905,11 @@ int
7548c0
 virCgroupHasEmptyTasks(virCgroupPtr cgroup, int controller)
7548c0
 {
7548c0
     size_t i;
7548c0
+    virCgroupPtr parent = virCgroupGetNested(cgroup);
7548c0
 
7548c0
     for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) {
7548c0
-        if (cgroup->backends[i]) {
7548c0
-            int rc = cgroup->backends[i]->hasEmptyTasks(cgroup, controller);
7548c0
+        if (parent->backends[i]) {
7548c0
+            int rc = parent->backends[i]->hasEmptyTasks(parent, controller);
7548c0
             if (rc <= 0)
7548c0
                 return rc;
7548c0
         }
7548c0
@@ -3565,6 +3711,7 @@ virCgroupFree(virCgroupPtr *group)
7548c0
     VIR_FREE((*group)->unified.mountPoint);
7548c0
     VIR_FREE((*group)->unified.placement);
7548c0
     VIR_FREE((*group)->unitName);
7548c0
+    VIR_FREE((*group)->nested);
7548c0
 
7548c0
     VIR_FREE((*group)->path);
7548c0
     VIR_FREE(*group);
7548c0
@@ -3577,9 +3724,12 @@ virCgroupDelThread(virCgroupPtr cgroup,
7548c0
                    int idx)
7548c0
 {
7548c0
     virCgroupPtr new_cgroup = NULL;
7548c0
+    virCgroupPtr parent = NULL;
7548c0
 
7548c0
     if (cgroup) {
7548c0
-        if (virCgroupNewThread(cgroup, nameval, idx, false, &new_cgroup) < 0)
7548c0
+        parent = virCgroupGetNested(cgroup);
7548c0
+
7548c0
+        if (virCgroupNewThread(parent, nameval, idx, false, &new_cgroup) < 0)
7548c0
             return -1;
7548c0
 
7548c0
         /* Remove the offlined cgroup */
7548c0
diff --git a/src/util/vircgrouppriv.h b/src/util/vircgrouppriv.h
7548c0
index b4a9e0b379..104d74e4d7 100644
7548c0
--- a/src/util/vircgrouppriv.h
7548c0
+++ b/src/util/vircgrouppriv.h
7548c0
@@ -69,8 +69,12 @@ struct _virCgroup {
7548c0
     virCgroupV2Controller unified;
7548c0
 
7548c0
     char *unitName;
7548c0
+    virCgroupPtr nested;
7548c0
 };
7548c0
 
7548c0
+#define virCgroupGetNested(cgroup) \
7548c0
+    (cgroup->nested ? cgroup->nested : cgroup)
7548c0
+
7548c0
 #define virCgroupSetValueDBus(unitName, key, ...) \
7548c0
     ({ \
7548c0
         int __ret = -1; \
7548c0
diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c
7548c0
index 57d617cb69..49a2cb023e 100644
7548c0
--- a/src/util/vircgroupv1.c
7548c0
+++ b/src/util/vircgroupv1.c
7548c0
@@ -338,6 +338,8 @@ virCgroupV1DetectPlacement(virCgroupPtr group,
7548c0
 
7548c0
     for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
7548c0
         const char *typestr = virCgroupV1ControllerTypeToString(i);
7548c0
+        g_autofree char* placement = NULL;
7548c0
+        char *tmp = NULL;
7548c0
 
7548c0
         if (!virCgroupV1MountOptsMatchController(controllers, typestr))
7548c0
             continue;
7548c0
@@ -348,17 +350,24 @@ virCgroupV1DetectPlacement(virCgroupPtr group,
7548c0
         if (group->legacy[i].placement)
7548c0
             continue;
7548c0
 
7548c0
+        /* On systemd we create a nested cgroup for some cgroup tasks
7548c0
+         * but the placement should point to the root cgroup. */
7548c0
+        placement = g_strdup(selfpath);
7548c0
+        tmp = g_strrstr(placement, "/libvirt");
7548c0
+        if (tmp)
7548c0
+            *tmp = '\0';
7548c0
+
7548c0
         /*
7548c0
          * selfpath == "/" + path="" -> "/"
7548c0
          * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service"
7548c0
          * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo"
7548c0
          */
7548c0
         if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) {
7548c0
-            group->legacy[i].placement = g_strdup(selfpath);
7548c0
+            group->legacy[i].placement = g_strdup(placement);
7548c0
         } else {
7548c0
-            bool delim = STREQ(selfpath, "/") || STREQ(path, "");
7548c0
+            bool delim = STREQ(placement, "/") || STREQ(path, "");
7548c0
 
7548c0
-            group->legacy[i].placement = g_strdup_printf("%s%s%s", selfpath,
7548c0
+            group->legacy[i].placement = g_strdup_printf("%s%s%s", placement,
7548c0
                                                          delim ? "" : "/",
7548c0
                                                          path);
7548c0
         }
7548c0
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
7548c0
index d15e2354cf..a14fc669fb 100644
7548c0
--- a/src/util/vircgroupv2.c
7548c0
+++ b/src/util/vircgroupv2.c
7548c0
@@ -210,6 +210,12 @@ virCgroupV2DetectPlacement(virCgroupPtr group,
7548c0
     if (tmp)
7548c0
         *tmp = '\0';
7548c0
 
7548c0
+    /* On systemd we create a nested cgroup for some cgroup tasks
7548c0
+     * but the placement should point to the root cgroup. */
7548c0
+    tmp = g_strrstr(placement, "/libvirt");
7548c0
+    if (tmp)
7548c0
+        *tmp = '\0';
7548c0
+
7548c0
     /*
7548c0
      * selfpath == "/" + path="" -> "/"
7548c0
      * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service"
7548c0
-- 
7548c0
2.30.0
7548c0