Blob Blame History Raw
From ba776c58abac13bd5a539cd128c002284a363f58 Mon Sep 17 00:00:00 2001
Message-Id: <ba776c58abac13bd5a539cd128c002284a363f58.1375465853.git.jdenemar@redhat.com>
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Wed, 31 Jul 2013 19:48:20 +0100
Subject: [PATCH] Enable support for systemd-machined in cgroups creation

https://bugzilla.redhat.com/show_bug.cgi?id=980929

Make the virCgroupNewMachine method try to use systemd-machined
first. If that fails, then fallback to using the traditional
cgroup setup code path.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

(cherry picked from commit 2fe2470181ce3722788fd7125d3f1f9be87e6278)
---
 src/lxc/lxc_process.c  |  10 +--
 src/qemu/qemu_cgroup.c |   1 +
 src/util/vircgroup.c   | 187 ++++++++++++++++++++++++++++++++++++++++++++-----
 src/util/vircgroup.h   |   1 +
 4 files changed, 179 insertions(+), 20 deletions(-)

diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 247e516..0a28305 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -1203,8 +1203,9 @@ int virLXCProcessStart(virConnectPtr conn,
         goto cleanup;
     }
 
-    if (virCgroupNewDetectMachine(vm->def->name, "lxc",
-                                  vm->pid, -1, &priv->cgroup) < 0)
+    if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
+                                  vm->def->resource->partition,
+                                  -1, &priv->cgroup) < 0)
         goto error;
 
     if (!priv->cgroup) {
@@ -1411,8 +1412,9 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm,
         if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm)))
             goto error;
 
-        if (virCgroupNewDetectMachine(vm->def->name, "lxc",
-                                      vm->pid, -1, &priv->cgroup) < 0)
+        if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
+                                      vm->def->resource->partition,
+                                      -1, &priv->cgroup) < 0)
             goto error;
 
         if (!priv->cgroup) {
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 9f6b251..787ddeb 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -707,6 +707,7 @@ qemuConnectCgroup(virQEMUDriverPtr driver,
     if (virCgroupNewDetectMachine(vm->def->name,
                                   "qemu",
                                   vm->pid,
+                                  vm->def->resource->partition,
                                   cfg->cgroupControllers,
                                   &priv->cgroup) < 0)
         goto cleanup;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index a70bb98..cfb4b3f 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -50,6 +50,7 @@
 #include "virhash.h"
 #include "virhashcode.h"
 #include "virstring.h"
+#include "virsystemd.h"
 
 #define CGROUP_MAX_VAL 512
 
@@ -102,11 +103,13 @@ static bool
 virCgroupValidateMachineGroup(virCgroupPtr group,
                               const char *name,
                               const char *drivername,
+                              const char *partition,
                               bool stripEmulatorSuffix)
 {
     size_t i;
     bool valid = false;
     char *partname;
+    char *scopename;
 
     if (virAsprintf(&partname, "%s.libvirt-%s",
                     name, drivername) < 0)
@@ -115,6 +118,15 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
     if (virCgroupPartitionEscape(&partname) < 0)
         goto cleanup;
 
+    if (!partition)
+        partition = "/machine";
+
+    if (!(scopename = virSystemdMakeScopeName(name, drivername, partition)))
+        goto cleanup;
+
+    if (virCgroupPartitionEscape(&scopename) < 0)
+        goto cleanup;
+
     for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
         char *tmp;
 
@@ -142,9 +154,10 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
         tmp++;
 
         if (STRNEQ(tmp, name) &&
-            STRNEQ(tmp, partname)) {
-            VIR_DEBUG("Name '%s' for controller '%s' does not match '%s' or '%s'",
-                      tmp, virCgroupControllerTypeToString(i), name, partname);
+            STRNEQ(tmp, partname) &&
+            STRNEQ(tmp, scopename)) {
+            VIR_DEBUG("Name '%s' for controller '%s' does not match '%s', '%s' or '%s'",
+                      tmp, virCgroupControllerTypeToString(i), name, partname, scopename);
             goto cleanup;
         }
     }
@@ -153,6 +166,7 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
 
  cleanup:
     VIR_FREE(partname);
+    VIR_FREE(scopename);
     return valid;
 }
 #else
@@ -1649,6 +1663,7 @@ int virCgroupNewDetect(pid_t pid ATTRIBUTE_UNUSED,
 int virCgroupNewDetectMachine(const char *name,
                               const char *drivername,
                               pid_t pid,
+                              const char *partition,
                               int controllers,
                               virCgroupPtr *group)
 {
@@ -1658,7 +1673,7 @@ int virCgroupNewDetectMachine(const char *name,
         return -1;
     }
 
-    if (!virCgroupValidateMachineGroup(*group, name, drivername, true)) {
+    if (!virCgroupValidateMachineGroup(*group, name, drivername, partition, true)) {
         VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
                   name, drivername);
         virCgroupFree(group);
@@ -1668,22 +1683,124 @@ int virCgroupNewDetectMachine(const char *name,
     return 0;
 }
 
-int virCgroupNewMachine(const char *name,
-                        const char *drivername,
-                        bool privileged ATTRIBUTE_UNUSED,
-                        const unsigned char *uuid ATTRIBUTE_UNUSED,
-                        const char *rootdir ATTRIBUTE_UNUSED,
-                        pid_t pidleader ATTRIBUTE_UNUSED,
-                        bool isContainer ATTRIBUTE_UNUSED,
-                        const char *partition,
-                        int controllers,
-                        virCgroupPtr *group)
+/*
+ * Returns 0 on success, -1 on fatal error, -2 on systemd not available
+ */
+static int
+virCgroupNewMachineSystemd(const char *name,
+                           const char *drivername,
+                           bool privileged,
+                           const unsigned char *uuid,
+                           const char *rootdir,
+                           pid_t pidleader,
+                           bool isContainer,
+                           const char *partition,
+                           int controllers,
+                           virCgroupPtr *group)
 {
-    virCgroupPtr parent = NULL;
     int ret = -1;
+    int rv;
+    virCgroupPtr init, parent = NULL;
+    char *path = NULL;
+    char *offset;
+
+    VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
+    if ((rv = virSystemdCreateMachine(name,
+                                      drivername,
+                                      privileged,
+                                      uuid,
+                                      rootdir,
+                                      pidleader,
+                                      isContainer,
+                                      partition)) < 0)
+        return rv;
+
+    if (controllers != -1)
+        controllers |= (1 << VIR_CGROUP_CONTROLLER_SYSTEMD);
+
+    VIR_DEBUG("Detecting systemd placement");
+    if (virCgroupNewDetect(pidleader,
+                           controllers,
+                           &init) < 0)
+        return -1;
 
-    *group = NULL;
+    path = init->controllers[VIR_CGROUP_CONTROLLER_SYSTEMD].placement;
+    init->controllers[VIR_CGROUP_CONTROLLER_SYSTEMD].placement = NULL;
+    virCgroupFree(&init);
+
+    if (!path || STREQ(path, "/") || path[0] != '/') {
+        VIR_DEBUG("Systemd didn't setup its controller");
+        ret = -2;
+        goto cleanup;
+    }
+
+    offset = path;
+
+    if (virCgroupNew(pidleader,
+                     "",
+                     NULL,
+                     controllers,
+                     &parent) < 0)
+        goto cleanup;
+
+
+    for (;;) {
+        virCgroupPtr tmp;
+        char *t = strchr(offset + 1, '/');
+        if (t)
+            *t = '\0';
+
+        if (virCgroupNew(pidleader,
+                         path,
+                         parent,
+                         controllers,
+                         &tmp) < 0)
+            goto cleanup;
+
+        if (virCgroupMakeGroup(parent, tmp, true, VIR_CGROUP_NONE) < 0) {
+            virCgroupFree(&tmp);
+            goto cleanup;
+        }
+        if (t) {
+            *t = '/';
+            offset = t;
+            virCgroupFree(&parent);
+            parent = tmp;
+        } else {
+            *group = tmp;
+            break;
+        }
+    }
+
+    if (virCgroupAddTask(*group, pidleader) < 0) {
+        virErrorPtr saved = virSaveLastError();
+        virCgroupRemove(*group);
+        virCgroupFree(group);
+        if (saved) {
+            virSetError(saved);
+            virFreeError(saved);
+        }
+    }
+
+    ret = 0;
+ cleanup:
+    virCgroupFree(&parent);
+    VIR_FREE(path);
+    return ret;
+}
 
+static int
+virCgroupNewMachineManual(const char *name,
+                          const char *drivername,
+                          pid_t pidleader,
+                          const char *partition,
+                          int controllers,
+                          virCgroupPtr *group)
+{
+    virCgroupPtr parent = NULL;
+    int ret = -1;
+
+    VIR_DEBUG("Fallback to non-systemd setup");
     if (virCgroupNewPartition(partition,
                               STREQ(partition, "/machine"),
                               controllers,
@@ -1719,6 +1836,44 @@ cleanup:
     return ret;
 }
 
+int virCgroupNewMachine(const char *name,
+                        const char *drivername,
+                        bool privileged,
+                        const unsigned char *uuid,
+                        const char *rootdir,
+                        pid_t pidleader,
+                        bool isContainer,
+                        const char *partition,
+                        int controllers,
+                        virCgroupPtr *group)
+{
+    int rv;
+
+    *group = NULL;
+
+    if ((rv = virCgroupNewMachineSystemd(name,
+                                         drivername,
+                                         privileged,
+                                         uuid,
+                                         rootdir,
+                                         pidleader,
+                                         isContainer,
+                                         partition,
+                                         controllers,
+                                         group)) == 0)
+        return 0;
+
+    if (rv == -1)
+        return -1;
+
+    return virCgroupNewMachineManual(name,
+                                     drivername,
+                                     pidleader,
+                                     partition,
+                                     controllers,
+                                     group);
+}
+
 bool virCgroupNewIgnoreError(void)
 {
     if (virLastErrorIsSystemErrno(ENXIO) ||
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index e579f41..d7ce892 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -83,6 +83,7 @@ int virCgroupNewDetect(pid_t pid,
 int virCgroupNewDetectMachine(const char *name,
                               const char *drivername,
                               pid_t pid,
+                              const char *partition,
                               int controllers,
                               virCgroupPtr *group);
 
-- 
1.8.3.2