From: "Daniel P. Berrange" <berrange(a)redhat.com>
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(a)redhat.com>
---
src/lxc/lxc_process.c | 10 +--
src/qemu/qemu_cgroup.c | 1 +
src/util/vircgroup.c | 187 ++++++++++++++++++++++++++++++++++++++++++++-----
src/util/vircgroup.h | 1 +
src/util/virsystemd.c | 5 +-
5 files changed, 182 insertions(+), 22 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 94f6692..e857362 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
@@ -100,11 +101,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)
@@ -113,6 +116,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;
@@ -140,9 +152,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;
}
}
@@ -151,6 +164,7 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
cleanup:
VIR_FREE(partname);
+ VIR_FREE(scopename);
return valid;
}
@@ -1638,6 +1652,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)
{
@@ -1647,7 +1662,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);
@@ -1657,22 +1672,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)
+/*
+ * Retujrns 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,
@@ -1708,6 +1825,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);
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c
index 251b846..3fd653d 100644
--- a/src/util/virsystemd.c
+++ b/src/util/virsystemd.c
@@ -225,8 +225,9 @@ int virSystemdCreateMachine(const char *name,
iscontainer ? "container" : "vm",
(unsigned int)pidleader,
rootdir ? rootdir : "",
- 1, "Slice", "s",
- slicename) < 0) {
+ 1,
+ "Slice", "s", slicename
+ ) < 0) {
virErrorPtr err = virGetLastError();
if (err->code == VIR_ERR_DBUS_SERVICE &&
STREQ(err->str2, "org.freedesktop.DBus.Error.ServiceUnknown"))
{
--
1.8.1.4