c480ed
From 4a7aa0ff6839fd9ccefce19d63c48beed32ee7f1 Mon Sep 17 00:00:00 2001
c480ed
Message-Id: <4a7aa0ff6839fd9ccefce19d63c48beed32ee7f1@dist-git>
c480ed
From: Pavel Hrdina <phrdina@redhat.com>
c480ed
Date: Mon, 1 Jul 2019 17:07:25 +0200
c480ed
Subject: [PATCH] vircgroup: introduce virCgroupV2MakeGroup
c480ed
MIME-Version: 1.0
c480ed
Content-Type: text/plain; charset=UTF-8
c480ed
Content-Transfer-Encoding: 8bit
c480ed
c480ed
When creating cgroup hierarchy we need to enable controllers in the
c480ed
parent cgroup in order to be usable.  That means writing "+{controller}"
c480ed
into cgroup.subtree_control file.  We can enable only controllers that
c480ed
are enabled for parent cgroup, that means we need to do that for the
c480ed
whole cgroup tree.
c480ed
c480ed
Cgroups for threads needs to be handled differently in cgroup v2.  There
c480ed
are two types of controllers:
c480ed
c480ed
    - domain controllers: these cannot be enabled for threads
c480ed
    - threaded controllers: these can be enabled for threads
c480ed
c480ed
In addition there are multiple types of cgroups:
c480ed
c480ed
    - domain: normal cgroup
c480ed
    - domain threaded: a domain cgroup that serves as root for threaded
c480ed
                       cgroups
c480ed
    - domain invalid: invalid cgroup, can be changed into threaded, this
c480ed
                      is the default state if you create subgroup inside
c480ed
                      domain threaded group or threaded group
c480ed
    - threaded: threaded cgroup which can have domain threaded or
c480ed
                threaded as parent group
c480ed
c480ed
In order to create threaded cgroup it's sufficient to write "threaded"
c480ed
into cgroup.type file, it will automatically make parent cgroup
c480ed
"domain threaded" if it was only "domain".  In case the parent cgroup
c480ed
is already "domain threaded" or "threaded" it will modify only the type
c480ed
of current cgroup.  After that we can enable threaded controllers.
c480ed
c480ed
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
c480ed
(cherry picked from commit 89f52abd07d3f991ddd22990e5d61338ff350a99)
c480ed
c480ed
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1689297
c480ed
c480ed
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
c480ed
Message-Id: <165b3b0f0fd1e5a4b52e4b9e86e4137b3598f7ee.1561993100.git.phrdina@redhat.com>
c480ed
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c480ed
---
c480ed
 src/util/vircgroup.c        |  2 +-
c480ed
 src/util/vircgroupbackend.h |  1 +
c480ed
 src/util/vircgroupv2.c      | 76 +++++++++++++++++++++++++++++++++++++
c480ed
 3 files changed, 78 insertions(+), 1 deletion(-)
c480ed
c480ed
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
c480ed
index 42930582db..a859628241 100644
c480ed
--- a/src/util/vircgroup.c
c480ed
+++ b/src/util/vircgroup.c
c480ed
@@ -942,7 +942,7 @@ virCgroupNewThread(virCgroupPtr domain,
c480ed
     if (virCgroupNew(-1, name, domain, controllers, group) < 0)
c480ed
         return -1;
c480ed
 
c480ed
-    if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_NONE) < 0) {
c480ed
+    if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_THREAD) < 0) {
c480ed
         virCgroupFree(group);
c480ed
         return -1;
c480ed
     }
c480ed
diff --git a/src/util/vircgroupbackend.h b/src/util/vircgroupbackend.h
c480ed
index b1f19233e4..86d1539e07 100644
c480ed
--- a/src/util/vircgroupbackend.h
c480ed
+++ b/src/util/vircgroupbackend.h
c480ed
@@ -33,6 +33,7 @@ typedef enum {
c480ed
                                        * before creating subcgroups and
c480ed
                                        * attaching tasks
c480ed
                                        */
c480ed
+    VIR_CGROUP_THREAD = 1 << 1, /* cgroup v2 handles threads differently */
c480ed
 } virCgroupBackendFlags;
c480ed
 
c480ed
 typedef enum {
c480ed
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
c480ed
index 6695901766..cf8bd01317 100644
c480ed
--- a/src/util/vircgroupv2.c
c480ed
+++ b/src/util/vircgroupv2.c
c480ed
@@ -338,6 +338,81 @@ virCgroupV2PathOfController(virCgroupPtr group,
c480ed
 }
c480ed
 
c480ed
 
c480ed
+static int
c480ed
+virCgroupV2EnableController(virCgroupPtr parent,
c480ed
+                            int controller)
c480ed
+{
c480ed
+    VIR_AUTOFREE(char *) val = NULL;
c480ed
+
c480ed
+    if (virAsprintf(&val, "+%s",
c480ed
+                    virCgroupV2ControllerTypeToString(controller)) < 0) {
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    if (virCgroupSetValueStr(parent, controller,
c480ed
+                             "cgroup.subtree_control", val) < 0) {
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virCgroupV2MakeGroup(virCgroupPtr parent ATTRIBUTE_UNUSED,
c480ed
+                     virCgroupPtr group,
c480ed
+                     bool create,
c480ed
+                     unsigned int flags)
c480ed
+{
c480ed
+    VIR_AUTOFREE(char *) path = NULL;
c480ed
+    int controller;
c480ed
+
c480ed
+    VIR_DEBUG("Make group %s", group->path);
c480ed
+
c480ed
+    controller = virCgroupV2GetAnyController(group);
c480ed
+    if (virCgroupV2PathOfController(group, controller, "", &path) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    VIR_DEBUG("Make controller %s", path);
c480ed
+
c480ed
+    if (!virFileExists(path) &&
c480ed
+        (!create || (mkdir(path, 0755) < 0 && errno != EEXIST))) {
c480ed
+        virReportSystemError(errno, _("Failed to create v2 cgroup '%s'"),
c480ed
+                             group->path);
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    if (create) {
c480ed
+        if (flags & VIR_CGROUP_THREAD) {
c480ed
+            if (virCgroupSetValueStr(group, VIR_CGROUP_CONTROLLER_CPU,
c480ed
+                                     "cgroup.type", "threaded") < 0) {
c480ed
+                return -1;
c480ed
+            }
c480ed
+
c480ed
+            if (virCgroupV2EnableController(parent,
c480ed
+                                            VIR_CGROUP_CONTROLLER_CPU) < 0) {
c480ed
+                return -1;
c480ed
+            }
c480ed
+        } else {
c480ed
+            size_t i;
c480ed
+            for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
c480ed
+                if (!virCgroupV2HasController(parent, i))
c480ed
+                    continue;
c480ed
+
c480ed
+                /* Controllers that are implicitly enabled if available. */
c480ed
+                if (i == VIR_CGROUP_CONTROLLER_CPUACCT)
c480ed
+                    continue;
c480ed
+
c480ed
+                if (virCgroupV2EnableController(parent, i) < 0)
c480ed
+                    return -1;
c480ed
+            }
c480ed
+        }
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
 virCgroupBackend virCgroupV2Backend = {
c480ed
     .type = VIR_CGROUP_BACKEND_TYPE_V2,
c480ed
 
c480ed
@@ -353,6 +428,7 @@ virCgroupBackend virCgroupV2Backend = {
c480ed
     .hasController = virCgroupV2HasController,
c480ed
     .getAnyController = virCgroupV2GetAnyController,
c480ed
     .pathOfController = virCgroupV2PathOfController,
c480ed
+    .makeGroup = virCgroupV2MakeGroup,
c480ed
 };
c480ed
 
c480ed
 
c480ed
-- 
c480ed
2.22.0
c480ed