[libvirt] [PATCH v3] systemd: Modernize machine naming
by Martin Kletzander
So, systemd-machined has this philosophy that machine names are like
hostnames and hence should follow the same rules. But we always allowed
international characters in domain names. Thus we need to modify the
machine name we are passing to systemd.
In order to change some machine names that we will be passing to systemd,
we also need to call TerminateMachine at the end of a lifetime of a
domain. Even for domains that were started with older libvirt. That
can be achieved thanks to virSystemdGetMachineNameByPID(). And because
we can change machine names, we can get rid of the inconsistent and
pointless escaping of domain names when creating machine names.
So this patch modifies the naming in the following way. It creates the
name as <drivername>-<id>-<name> where invalid hostname characters are
stripped out of the name and if the resulting name is longer, it
truncates it to 64 characters. That way we can start domains we
couldn't start before. Well, at least on systemd.
To make it work all together, the machineName (which is needed only with
systemd) is saved in domain's private data. That way the generation is
moved to the driver and we don't need to pass various unnecessary
arguments to cgroup functions.
The only thing this complicates a bit is the scope generation when
validating a cgroup where we must check both old and new naming, so a
slight modification was needed there.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1282846
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/lxc/lxc_cgroup.c | 13 +++++++--
src/lxc/lxc_domain.h | 1 +
src/lxc/lxc_process.c | 20 +++++++++----
src/qemu/qemu_cgroup.c | 28 +++++++++++++-----
src/qemu/qemu_cgroup.h | 2 +-
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_process.c | 4 +--
src/util/vircgroup.c | 59 ++++++++++++++++++++++++--------------
src/util/vircgroup.h | 12 ++++----
src/util/virsystemd.c | 75 +++++++++++++++++++++++++++++++++----------------
src/util/virsystemd.h | 13 ++++-----
tests/virsystemdtest.c | 67 +++++++++++++++++++++++++------------------
12 files changed, 191 insertions(+), 104 deletions(-)
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index ad254e4934fc..31489466cfbf 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -29,6 +29,7 @@
#include "viralloc.h"
#include "vircgroup.h"
#include "virstring.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -483,6 +484,13 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
int *nicindexes)
{
virCgroupPtr cgroup = NULL;
+ char *machineName = virSystemdMakeMachineName("lxc",
+ def->id,
+ def->name,
+ true);
+
+ if (!machineName)
+ goto cleanup;
if (def->resource->partition[0] != '/') {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -491,9 +499,8 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
goto cleanup;
}
- if (virCgroupNewMachine(def->name,
+ if (virCgroupNewMachine(machineName,
"lxc",
- true,
def->uuid,
NULL,
initpid,
@@ -517,6 +524,8 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
}
cleanup:
+ VIR_FREE(machineName);
+
return cgroup;
}
diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h
index 2119c7899007..39c6e7def9ce 100644
--- a/src/lxc/lxc_domain.h
+++ b/src/lxc/lxc_domain.h
@@ -64,6 +64,7 @@ struct _virLXCDomainObjPrivate {
pid_t initpid;
virCgroupPtr cgroup;
+ char *machineName;
};
extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace;
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index f7e2b810b74b..9b3981eab20d 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -233,8 +233,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
* properly. See https://bugs.freedesktop.org/show_bug.cgi?id=68370 for
* the bug we are working around here.
*/
- virSystemdTerminateMachine(vm->def->name, "lxc", true);
-
+ virCgroupTerminateMachine(priv->machineName);
/* The "release" hook cleans up additional resources */
if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
@@ -1494,8 +1493,9 @@ int virLXCProcessStart(virConnectPtr conn,
* point so lets detect that first, since it gives us a
* more reliable way to kill everything off if something
* goes wrong from here onwards ... */
- if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
- -1, &priv->cgroup) < 0)
+ if (virCgroupNewDetectMachine(vm->def->name, "lxc",
+ vm->def->id, true,
+ vm->pid, -1, &priv->cgroup) < 0)
goto cleanup;
if (!priv->cgroup) {
@@ -1505,6 +1505,11 @@ int virLXCProcessStart(virConnectPtr conn,
goto cleanup;
}
+ /* Get the machine name so we can properly delete it through
+ * systemd later */
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
/* And we can get the first monitor connection now too */
if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) {
/* Intentionally overwrite the real monitor error message,
@@ -1677,8 +1682,8 @@ 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->def->id, true,
+ vm->pid, -1, &priv->cgroup) < 0)
goto error;
if (!priv->cgroup) {
@@ -1688,6 +1693,9 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm,
goto error;
}
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
if (virLXCUpdateActiveUSBHostdevs(driver, vm->def) < 0)
goto error;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index e41f4617c455..12c81d9eb70b 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -36,6 +36,7 @@
#include "virfile.h"
#include "virtypedparam.h"
#include "virnuma.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -772,9 +773,19 @@ qemuInitCgroup(virQEMUDriverPtr driver,
goto cleanup;
}
- if (virCgroupNewMachine(vm->def->name,
+ /*
+ * We need to do this because of systemd-machined, because
+ * CreateMachine requires the name to be a valid hostname.
+ */
+ priv->machineName = virSystemdMakeMachineName("qemu",
+ vm->def->id,
+ vm->def->name,
+ virQEMUDriverIsPrivileged(driver));
+ if (!priv->machineName)
+ goto cleanup;
+
+ if (virCgroupNewMachine(priv->machineName,
"qemu",
- true,
vm->def->uuid,
NULL,
vm->pid,
@@ -888,11 +899,17 @@ qemuConnectCgroup(virQEMUDriverPtr driver,
if (virCgroupNewDetectMachine(vm->def->name,
"qemu",
+ vm->def->id,
+ virQEMUDriverIsPrivileged(driver),
vm->pid,
cfg->cgroupControllers,
&priv->cgroup) < 0)
goto cleanup;
+ priv->machineName = virSystemdGetMachineNameByPID(vm->pid);
+ if (!priv->machineName)
+ virResetLastError();
+
qemuRestoreCgroupState(vm);
done:
@@ -1264,17 +1281,14 @@ qemuSetupCgroupForIOThreads(virDomainObjPtr vm)
}
int
-qemuRemoveCgroup(virQEMUDriverPtr driver,
- virDomainObjPtr vm)
+qemuRemoveCgroup(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
if (priv->cgroup == NULL)
return 0; /* Not supported, so claim success */
- if (virCgroupTerminateMachine(vm->def->name,
- "qemu",
- virQEMUDriverIsPrivileged(driver)) < 0) {
+ if (virCgroupTerminateMachine(priv->machineName) < 0) {
if (!virCgroupNewIgnoreError())
VIR_DEBUG("Failed to terminate cgroup for %s", vm->def->name);
}
diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
index 2bcf071d3792..347d126f7394 100644
--- a/src/qemu/qemu_cgroup.h
+++ b/src/qemu/qemu_cgroup.h
@@ -56,7 +56,7 @@ int qemuSetupCgroupCpusetCpus(virCgroupPtr cgroup, virBitmapPtr cpumask);
int qemuSetupCgroupForVcpu(virDomainObjPtr vm);
int qemuSetupCgroupForIOThreads(virDomainObjPtr vm);
int qemuSetupCgroupForEmulator(virDomainObjPtr vm);
-int qemuRemoveCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm);
+int qemuRemoveCgroup(virDomainObjPtr vm);
int qemuAddToCgroup(virDomainObjPtr vm);
#endif /* __QEMU_CGROUP_H__ */
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 6a8cf705d8af..ab798faf0fb0 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -203,6 +203,7 @@ struct _qemuDomainObjPrivate {
bool signalIOError; /* true if the domain condition should be signalled on
I/O error */
+ char *machineName;
};
# define QEMU_DOMAIN_DISK_PRIVATE(disk) \
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 7b09ba73896b..b3f8c93d1a93 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4610,7 +4610,7 @@ qemuProcessLaunch(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);
+ qemuRemoveCgroup(vm);
VIR_DEBUG("Setting up ports for graphics");
if (qemuProcessSetupGraphics(driver, vm) < 0)
@@ -5405,7 +5405,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
}
retry:
- if ((ret = qemuRemoveCgroup(driver, vm)) < 0) {
+ if ((ret = qemuRemoveCgroup(vm)) < 0) {
if (ret == -EBUSY && (retries++ < 5)) {
usleep(200*1000);
goto retry;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index da0df7ae7a5e..e62793e31e2f 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -243,12 +243,17 @@ static bool
virCgroupValidateMachineGroup(virCgroupPtr group,
const char *name,
const char *drivername,
+ int id,
+ bool privileged,
bool stripEmulatorSuffix)
{
size_t i;
bool valid = false;
- char *partname;
- char *scopename;
+ char *partname = NULL;
+ char *scopename_old = NULL;
+ char *scopename_new = NULL;
+ char *machinename = virSystemdMakeMachineName(drivername, id,
+ name, privileged);
if (virAsprintf(&partname, "%s.libvirt-%s",
name, drivername) < 0)
@@ -257,10 +262,21 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
if (virCgroupPartitionEscape(&partname) < 0)
goto cleanup;
- if (!(scopename = virSystemdMakeScopeName(name, drivername)))
+ if (!(scopename_old = virSystemdMakeScopeName(name, drivername, true)))
goto cleanup;
- if (virCgroupPartitionEscape(&scopename) < 0)
+ /* We should keep trying even if this failed */
+ if (!machinename)
+ virResetLastError();
+ else if (!(scopename_new = virSystemdMakeScopeName(machinename,
+ drivername, false)))
+ goto cleanup;
+
+ if (virCgroupPartitionEscape(&scopename_old) < 0)
+ goto cleanup;
+
+ if (scopename_new &&
+ virCgroupPartitionEscape(&scopename_new) < 0)
goto cleanup;
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
@@ -290,12 +306,15 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
tmp++;
if (STRNEQ(tmp, name) &&
+ STRNEQ_NULLABLE(tmp, machinename) &&
STRNEQ(tmp, partname) &&
- STRNEQ(tmp, scopename)) {
+ STRNEQ(tmp, scopename_old) &&
+ STRNEQ_NULLABLE(tmp, scopename_new)) {
VIR_DEBUG("Name '%s' for controller '%s' does not match "
- "'%s', '%s' or '%s'",
+ "'%s', '%s', '%s', '%s' or '%s'",
tmp, virCgroupControllerTypeToString(i),
- name, partname, scopename);
+ name, machinename, partname,
+ scopename_old, scopename_new);
goto cleanup;
}
}
@@ -304,7 +323,9 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
cleanup:
VIR_FREE(partname);
- VIR_FREE(scopename);
+ VIR_FREE(scopename_old);
+ VIR_FREE(scopename_new);
+ VIR_FREE(machinename);
return valid;
}
@@ -1555,6 +1576,8 @@ virCgroupNewDetect(pid_t pid,
int
virCgroupNewDetectMachine(const char *name,
const char *drivername,
+ int id,
+ bool privileged,
pid_t pid,
int controllers,
virCgroupPtr *group)
@@ -1565,7 +1588,8 @@ virCgroupNewDetectMachine(const char *name,
return -1;
}
- if (!virCgroupValidateMachineGroup(*group, name, drivername, true)) {
+ if (!virCgroupValidateMachineGroup(*group, name, drivername,
+ id, privileged, true)) {
VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
name, drivername);
virCgroupFree(group);
@@ -1582,7 +1606,6 @@ virCgroupNewDetectMachine(const char *name,
static int
virCgroupNewMachineSystemd(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -1602,7 +1625,6 @@ virCgroupNewMachineSystemd(const char *name,
VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
if ((rv = virSystemdCreateMachine(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
@@ -1690,11 +1712,9 @@ virCgroupNewMachineSystemd(const char *name,
/*
* Returns 0 on success, -1 on fatal error
*/
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virCgroupTerminateMachine(const char *name)
{
- return virSystemdTerminateMachine(name, drivername, privileged);
+ return virSystemdTerminateMachine(name);
}
@@ -1749,7 +1769,6 @@ virCgroupNewMachineManual(const char *name,
int
virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -1766,7 +1785,6 @@ virCgroupNewMachine(const char *name,
if ((rv = virCgroupNewMachineSystemd(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
@@ -4241,6 +4259,8 @@ virCgroupNewDetect(pid_t pid ATTRIBUTE_UNUSED,
int
virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
+ int id ATTRIBUTE_UNUSED,
+ bool privileged ATTRIBUTE_UNUSED,
pid_t pid ATTRIBUTE_UNUSED,
int controllers ATTRIBUTE_UNUSED,
virCgroupPtr *group ATTRIBUTE_UNUSED)
@@ -4251,9 +4271,7 @@ virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED,
}
-int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED,
- const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED)
+int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED)
{
virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
@@ -4264,7 +4282,6 @@ int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED,
int
virCgroupNewMachine(const char *name ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED,
const unsigned char *uuid ATTRIBUTE_UNUSED,
const char *rootdir ATTRIBUTE_UNUSED,
pid_t pidleader ATTRIBUTE_UNUSED,
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index d754b1f3bd7a..bec88dc84e72 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -91,13 +91,15 @@ int virCgroupNewDetect(pid_t pid,
int virCgroupNewDetectMachine(const char *name,
const char *drivername,
+ int id,
+ bool privileged,
pid_t pid,
int controllers,
- virCgroupPtr *group);
+ virCgroupPtr *group)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -110,10 +112,8 @@ int virCgroupNewMachine(const char *name,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
ATTRIBUTE_NONNULL(4);
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virCgroupTerminateMachine(const char *name)
+ ATTRIBUTE_NONNULL(1);
bool virCgroupNewIgnoreError(void);
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c
index 9e85e24b2c4b..37007aa915ec 100644
--- a/src/util/virsystemd.c
+++ b/src/util/virsystemd.c
@@ -27,6 +27,7 @@
#include "virsystemd.h"
#include "viratomic.h"
+#include "virbuffer.h"
#include "virdbus.h"
#include "virstring.h"
#include "viralloc.h"
@@ -78,15 +79,17 @@ static void virSystemdEscapeName(virBufferPtr buf,
#undef VALID_CHARS
}
-
char *virSystemdMakeScopeName(const char *name,
- const char *drivername)
+ const char *drivername,
+ bool legacy_behaviour)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "machine-");
- virSystemdEscapeName(&buf, drivername);
- virBufferAddLit(&buf, "\\x2d");
+ if (legacy_behaviour) {
+ virSystemdEscapeName(&buf, drivername);
+ virBufferAddLit(&buf, "\\x2d");
+ }
virSystemdEscapeName(&buf, name);
virBufferAddLit(&buf, ".scope");
@@ -113,10 +116,42 @@ char *virSystemdMakeSliceName(const char *partition)
return virBufferContentAndReset(&buf);
}
+#define HOSTNAME_CHARS \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"
+
+static void
+virSystemdAppendValidMachineName(virBufferPtr buf,
+ const char *name)
+{
+ bool skip_dot = false;
+
+ for (; *name; name++) {
+ if (strlen(virBufferCurrentContent(buf)) >= 64)
+ break;
+
+ if (*name == '.') {
+ if (!skip_dot)
+ virBufferAddChar(buf, *name);
+ skip_dot = true;
+ continue;
+ }
+
+ skip_dot = false;
+
+ if (!strchr(HOSTNAME_CHARS, *name))
+ continue;
+
+ virBufferAddChar(buf, *name);
+ }
+}
+
+#undef HOSTNAME_CHARS
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
- bool privileged)
+char *
+virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
+ bool privileged)
{
char *machinename = NULL;
char *username = NULL;
@@ -131,7 +166,8 @@ char *virSystemdMakeMachineName(const char *name,
virBufferAsprintf(&buf, "%s-%s-", username, drivername);
}
- virSystemdEscapeName(&buf, name);
+ virBufferAsprintf(&buf, "%d-", id);
+ virSystemdAppendValidMachineName(&buf, name);
machinename = virBufferContentAndReset(&buf);
cleanup:
@@ -212,7 +248,6 @@ virSystemdGetMachineNameByPID(pid_t pid)
*/
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -223,7 +258,6 @@ int virSystemdCreateMachine(const char *name,
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
char *creatorname = NULL;
char *slicename = NULL;
static int hasCreateWithNetwork = 1;
@@ -239,8 +273,6 @@ int virSystemdCreateMachine(const char *name,
return -1;
ret = -1;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
if (virAsprintf(&creatorname, "libvirt-%s", drivername) < 0)
goto cleanup;
@@ -318,7 +350,7 @@ int virSystemdCreateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"CreateMachineWithNetwork",
"sayssusa&ia(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
@@ -360,7 +392,7 @@ int virSystemdCreateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"CreateMachine",
"sayssusa(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
@@ -381,20 +413,19 @@ int virSystemdCreateMachine(const char *name,
cleanup:
VIR_FREE(creatorname);
- VIR_FREE(machinename);
VIR_FREE(slicename);
return ret;
}
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virSystemdTerminateMachine(const char *name)
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
virError error;
+ if (!name)
+ return 0;
+
memset(&error, 0, sizeof(error));
ret = virDBusIsServiceEnabled("org.freedesktop.machine1");
@@ -409,9 +440,6 @@ int virSystemdTerminateMachine(const char *name,
if (!(conn = virDBusGetSystemBus()))
goto cleanup;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
-
/*
* The systemd DBus API we're invoking has the
* following signature
@@ -431,7 +459,7 @@ int virSystemdTerminateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"TerminateMachine",
"s",
- machinename) < 0)
+ name) < 0)
goto cleanup;
if (error.code == VIR_ERR_ERROR &&
@@ -446,7 +474,6 @@ int virSystemdTerminateMachine(const char *name,
cleanup:
virResetError(&error);
- VIR_FREE(machinename);
return ret;
}
diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h
index a13a4c0c48be..93b0aae7e15f 100644
--- a/src/util/virsystemd.h
+++ b/src/util/virsystemd.h
@@ -25,16 +25,17 @@
# include "internal.h"
char *virSystemdMakeScopeName(const char *name,
- const char *drivername);
+ const char *drivername,
+ bool legacy_behaviour);
char *virSystemdMakeSliceName(const char *partition);
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
+char *virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
bool privileged);
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -43,9 +44,7 @@ int virSystemdCreateMachine(const char *name,
int *nicindexes,
const char *partition);
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged);
+int virSystemdTerminateMachine(const char *name);
void virSystemdNotifyStartup(void);
diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c
index 3a3cd9968032..46452dd7436a 100644
--- a/tests/virsystemdtest.c
+++ b/tests/virsystemdtest.c
@@ -166,7 +166,6 @@ static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED)
};
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
@@ -182,9 +181,7 @@ static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED)
static int testTerminateContainer(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "lxc",
- true) < 0) {
+ if (virSystemdTerminateMachine("lxc-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate LXC machine\n");
return -1;
}
@@ -202,7 +199,6 @@ static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED)
};
if (virSystemdCreateMachine("demo",
"qemu",
- false,
uuid,
NULL,
123,
@@ -218,9 +214,7 @@ static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED)
static int testTerminateMachine(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "qemu",
- false) < 0) {
+ if (virSystemdTerminateMachine("test-qemu-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate KVM machine\n");
return -1;
}
@@ -242,7 +236,6 @@ static int testCreateNoSystemd(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -277,7 +270,6 @@ static int testCreateSystemdNotRunning(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -312,7 +304,6 @@ static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -348,7 +339,6 @@ static int testCreateNetwork(const void *opaque ATTRIBUTE_UNUSED)
size_t nnicindexes = ARRAY_CARDINALITY(nicindexes);
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
@@ -385,6 +375,8 @@ testGetMachineName(const void *opaque ATTRIBUTE_UNUSED)
struct testNameData {
const char *name;
const char *expected;
+ int id;
+ bool legacy;
};
static int
@@ -394,7 +386,7 @@ testScopeName(const void *opaque)
int ret = -1;
char *actual = NULL;
- if (!(actual = virSystemdMakeScopeName(data->name, "lxc")))
+ if (!(actual = virSystemdMakeScopeName(data->name, "lxc", data->legacy)))
goto cleanup;
if (STRNEQ(actual, data->expected)) {
@@ -417,7 +409,8 @@ testMachineName(const void *opaque)
int ret = -1;
char *actual = NULL;
- if (!(actual = virSystemdMakeMachineName(data->name, "qemu", true)))
+ if (!(actual = virSystemdMakeMachineName("qemu", data->id,
+ data->name, true)))
goto cleanup;
if (STRNEQ(actual, data->expected)) {
@@ -518,6 +511,12 @@ mymain(void)
{
int ret = 0;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ /* The one we use in tests quite often */
+ if (virUUIDParse("c7a5fdbd-edaf-9455-926a-d65c16db1809", uuid) < 0)
+ return EXIT_FAILURE;
+
if (virtTestRun("Test create container ", testCreateContainer, NULL) < 0)
ret = -1;
if (virtTestRun("Test terminate container ", testTerminateContainer, NULL) < 0)
@@ -538,35 +537,47 @@ mymain(void)
if (virtTestRun("Test getting machine name ", testGetMachineName, NULL) < 0)
ret = -1;
-# define TEST_SCOPE(name, unitname) \
+# define TEST_SCOPE(_name, unitname, _legacy) \
do { \
struct testNameData data = { \
- name, unitname \
+ .name = _name, .expected = unitname, .legacy = _legacy, \
}; \
if (virtTestRun("Test scopename", testScopeName, &data) < 0) \
ret = -1; \
} while (0)
- TEST_SCOPE("demo", "machine-lxc\\x2ddemo.scope");
- TEST_SCOPE("demo-name", "machine-lxc\\x2ddemo\\x2dname.scope");
- TEST_SCOPE("demo!name", "machine-lxc\\x2ddemo\\x21name.scope");
- TEST_SCOPE(".demo", "machine-lxc\\x2d\\x2edemo.scope");
- TEST_SCOPE("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
+# define TEST_SCOPE_OLD(name, unitname) \
+ TEST_SCOPE(name, unitname, true)
+# define TEST_SCOPE_NEW(name, unitname) \
+ TEST_SCOPE(name, unitname, false)
+
+ TEST_SCOPE_OLD("demo", "machine-lxc\\x2ddemo.scope");
+ TEST_SCOPE_OLD("demo-name", "machine-lxc\\x2ddemo\\x2dname.scope");
+ TEST_SCOPE_OLD("demo!name", "machine-lxc\\x2ddemo\\x21name.scope");
+ TEST_SCOPE_OLD(".demo", "machine-lxc\\x2d\\x2edemo.scope");
+ TEST_SCOPE_OLD("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
+
+ TEST_SCOPE_NEW("qemu-3-demo", "machine-qemu\\x2d3\\x2ddemo.scope");
-# define TEST_MACHINE(name, machinename) \
+# define TEST_MACHINE(_name, _id, machinename) \
do { \
struct testNameData data = { \
- name, machinename \
+ .name = _name, .expected = machinename, .id = _id, \
}; \
if (virtTestRun("Test scopename", testMachineName, &data) < 0) \
ret = -1; \
} while (0)
- TEST_MACHINE("demo", "qemu-demo");
- TEST_MACHINE("demo-name", "qemu-demo\\x2dname");
- TEST_MACHINE("demo!name", "qemu-demo\\x21name");
- TEST_MACHINE(".demo", "qemu-\\x2edemo");
- TEST_MACHINE("bull\U0001f4a9", "qemu-bull\\xf0\\x9f\\x92\\xa9");
+ TEST_MACHINE("demo", 1, "qemu-1-demo");
+ TEST_MACHINE("demo-name", 2, "qemu-2-demo-name");
+ TEST_MACHINE("demo!name", 3, "qemu-3-demoname");
+ TEST_MACHINE(".demo", 4, "qemu-4-.demo");
+ TEST_MACHINE("bull\U0001f4a9", 5, "qemu-5-bull");
+ TEST_MACHINE("demo..name", 6, "qemu-6-demo.name");
+ TEST_MACHINE("12345678901234567890123456789012345678901234567890123456789", 7,
+ "qemu-7-123456789012345678901234567890123456789012345678901234567");
+ TEST_MACHINE("123456789012345678901234567890123456789012345678901234567890", 8,
+ "qemu-8-123456789012345678901234567890123456789012345678901234567");
# define TESTS_PM_SUPPORT_HELPER(name, function) \
do { \
--
2.7.0
8 years, 7 months
[libvirt] [PATCH 0/3] Fix domains with non-ASCII (or long) names on systemd
by Martin Kletzander
Well, try starting such domain. More info in patches.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1282846
Martin Kletzander (3):
Revert "systemd: Escape only needed characters for machined"
systemd: Add virSystemdGetMachineNameByPID
systemd: Modernize machine naming
src/libvirt_private.syms | 1 +
src/lxc/lxc_cgroup.c | 13 +++-
src/lxc/lxc_domain.c | 1 +
src/lxc/lxc_domain.h | 1 +
src/lxc/lxc_process.c | 19 ++++--
src/qemu/qemu_cgroup.c | 27 +++++---
src/qemu/qemu_cgroup.h | 2 +-
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_process.c | 4 +-
src/util/vircgroup.c | 25 ++++----
src/util/vircgroup.h | 12 ++--
src/util/virsystemd.c | 156 ++++++++++++++++++++++++++++++++++++-----------
src/util/virsystemd.h | 13 ++--
tests/virsystemdtest.c | 81 ++++++++++++++++++------
15 files changed, 262 insertions(+), 95 deletions(-)
--
2.7.0
8 years, 7 months
[libvirt] [PATCH] logical: Clarify pieces of lvs regex
by John Ferlan
Rather than have a unwieldy regex string - split it up into its components
each having it's own #define and then combine in a different #define
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/storage/storage_backend_logical.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index eb22fd0..ba26223 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -312,6 +312,34 @@ virStorageBackendLogicalMakeVol(char **const groups,
return ret;
}
+#define VIR_STORAGE_VOL_LOGICAL_PREFIX_REGEX "^\\s*"
+#define VIR_STORAGE_VOL_LOGICAL_LV_NAME_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_ORIGIN_REGEX "(\\S*)#"
+#define VIR_STORAGE_VOL_LOGICAL_UUID_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_DEVICES_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_STRIPES_REGEX "([0-9]+)#"
+#define VIR_STORAGE_VOL_LOGICAL_SEG_SIZE_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_VG_EXTENT_SIZE_REGEX "([0-9]+)#"
+#define VIR_STORAGE_VOL_LOGICAL_SIZE_REGEX "([0-9]+)#"
+#define VIR_STORAGE_VOL_LOGICAL_LV_ATTR_REGEX "(\\S+)#"
+#define VIR_STORAGE_VOL_LOGICAL_SUFFIX_REGEX "?\\s*$"
+
+#define VIR_STORAGE_VOL_LOGICAL_REGEX_COUNT 10
+#define VIR_STORAGE_VOL_LOGICAL_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_PREFIX_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_LV_NAME_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_ORIGIN_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_UUID_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_DEVICES_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_SEGTYPE_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_STRIPES_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_SEG_SIZE_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_VG_EXTENT_SIZE_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_SIZE_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_LV_ATTR_REGEX \
+ VIR_STORAGE_VOL_LOGICAL_SUFFIX_REGEX
+
static int
virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
virStorageVolDefPtr vol)
@@ -342,10 +370,10 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
* striped, so "," is not a suitable separator either (rhbz 727474).
*/
const char *regexes[] = {
- "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#([0-9]+)#(\\S+)#?\\s*$"
+ VIR_STORAGE_VOL_LOGICAL_REGEX
};
int vars[] = {
- 10
+ VIR_STORAGE_VOL_LOGICAL_REGEX_COUNT
};
int ret = -1;
virCommandPtr cmd;
--
2.5.0
8 years, 7 months
[libvirt] [PATCH 1/2] storage: zfs: enable on Linux
by Roman Bogorodskiy
ZFS-on-Linux implementation of ZFS starting with version 0.6.4
contains all the features we use, so there's no reason to limit
libvirt ZFS storage backend to FreeBSD only.
There's still one difference between these implementations: ZFS on
FreeBSD requires to set 'volmode' option to 'dev' when creating
volumes, while ZFS-on-Linux does not need that.
Handle it by checking if 'volmode' option is needed by parsing usage
information of the 'zfs get' command.
---
configure.ac | 8 ------
src/storage/storage_backend_zfs.c | 51 +++++++++++++++++++++++++++++++++++++--
2 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/configure.ac b/configure.ac
index a566f5b..d768341 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2005,14 +2005,6 @@ if test "$with_storage_gluster" = "yes"; then
fi
AM_CONDITIONAL([WITH_STORAGE_GLUSTER], [test "$with_storage_gluster" = "yes"])
-if test "$with_storage_zfs" = "check"; then
- with_storage_zfs=$with_freebsd
-fi
-
-if test "$with_storage_zfs" = "yes" && test "$with_freebsd" = "no"; then
- AC_MSG_ERROR([The ZFS storage driver can be enabled on FreeBSD only.])
-fi
-
if test "$with_storage_zfs" = "yes" ||
test "$with_storage_zfs" = "check"; then
AC_PATH_PROG([ZFS], [zfs], [], [$PATH:/sbin:/usr/sbin])
diff --git a/src/storage/storage_backend_zfs.c b/src/storage/storage_backend_zfs.c
index cb2662a..6bf7963 100644
--- a/src/storage/storage_backend_zfs.c
+++ b/src/storage/storage_backend_zfs.c
@@ -39,6 +39,47 @@ VIR_LOG_INIT("storage.storage_backend_zfs");
* for size, show just a number instead of 2G etc
*/
+/**
+ * virStorageBackendZFSVolModeNeeded:
+ *
+ * Checks if it's necessary to specify 'volmode' (i.e. that
+ * we're working with BSD ZFS implementation).
+ *
+ * Returns 1 if 'volmode' is need, 0 if not needed, -1 on error
+ */
+static int
+virStorageBackendZFSVolModeNeeded(void)
+{
+ virCommandPtr cmd = NULL;
+ int ret = -1, exit = -1;
+ char *error = NULL;
+
+ /* 'zfs get' without arguments prints out
+ * usage information to stderr, including
+ * list of supported options, and exits with
+ * exit code 2
+ */
+ cmd = virCommandNewArgList(ZFS, "get", NULL);
+ virCommandAddEnvString(cmd, "LC_ALL=C");
+ virCommandSetErrorBuffer(cmd, &error);
+
+ ret = virCommandRun(cmd, &exit);
+ if ((ret < 0) || (exit != 2)) {
+ VIR_WARN("Command 'zfs get' either failed "
+ "to run or exited with unexpected status");
+ goto cleanup;
+ }
+
+ if (strstr(error, " volmode "))
+ ret = 1;
+ else
+ ret = 0;
+
+ cleanup:
+ virCommandFree(cmd);
+ VIR_FREE(error);
+ return ret;
+}
static int
virStorageBackendZFSCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
@@ -258,6 +299,7 @@ virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
{
virCommandPtr cmd = NULL;
int ret = -1;
+ int volmode_needed = -1;
vol->type = VIR_STORAGE_VOL_BLOCK;
@@ -273,6 +315,9 @@ virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
if (VIR_STRDUP(vol->key, vol->target.path) < 0)
goto cleanup;
+ volmode_needed = virStorageBackendZFSVolModeNeeded();
+ if (volmode_needed < 0)
+ goto cleanup;
/**
* $ zfs create -o volmode=dev -V 10240K test/volname
*
@@ -281,8 +326,10 @@ virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
* will lookup vfs.zfs.vol.mode sysctl value
* -V -- tells to create a volume with the specified size
*/
- cmd = virCommandNewArgList(ZFS, "create", "-o", "volmode=dev",
- "-V", NULL);
+ cmd = virCommandNewArgList(ZFS, "create", NULL);
+ if (volmode_needed)
+ virCommandAddArgList(cmd, "-o", "volmode=dev", NULL);
+ virCommandAddArg(cmd, "-V");
virCommandAddArgFormat(cmd, "%lluK",
VIR_DIV_UP(vol->target.capacity, 1024));
virCommandAddArgFormat(cmd, "%s/%s",
--
1.9.1
8 years, 7 months
[libvirt] virStream: this function is not supported by the connection driver
by Wido den Hollander
Hi,
I'm trying to implement the volUpload and volDownload functions for the
RBD storage driver but I keep getting this:
2016-01-30 18:56:11.675+0000: 6447: debug :
virStorageBackendRBDVolDownload:1395 : Read 4096 bytes at offset 0 from
RBD image libvirt/wido1
2016-01-30 18:56:11.675+0000: 6447: debug : virStreamSend:168 :
stream=0x7fe780000930, data=0x7fe780062df0, nbytes=4096
2016-01-30 18:56:11.675+0000: 6447: error : virStreamSend:186 : this
function is not supported by the connection driver: virStreamSend
I reference to the stream with virStreamRef(stream); and then I use
virStreamSend() to write data to the stream, but that fails.
I've looked through the source and couldn't find anything what might be
the issue.
Libvirt is running locally on my system and I'm using qemu:///system to
connect locally with virsh.
Do I need to initialize the stream in any way before I can write data to it?
Wido
8 years, 7 months
[libvirt] [PATCH RFC 0/2] conf: add net device prefix capability
by Joao Martins
Hey,
Back in the pre 1.3.0 release [0] we had a regression when migrating
domains in libxl (introduced by the reverted commit d2e5538b1).
The chosen solution to address this problem was to introduce a
capability to be used by the virDomainNetDefFormat() and
virDomainNetDefParseXML() routines. This series implements this,
and I would ask if it's in line with what you had in mind by
exposing as a hypervisor capability?
For the purposes of RFC and compability with other drivers I left
the hardcoded checking of VIR_NET_GENERATED_PREFIX plus checking a
prefix registered by the driver.
Having this series and the reverted commit applied, I can
successfully migrate a domain without seeing the same interface
name on both source and destination node.
Thoughts?
Thanks!
Joao
[0] https://www.redhat.com/archives/libvir-list/2015-December/msg00279.html
Joao Martins (2):
conf: add net device prefix to capabilities
libxl: set net device prefix
src/conf/capabilities.c | 21 +++++++++++++++++++++
src/conf/capabilities.h | 4 ++++
src/conf/domain_conf.c | 20 +++++++++++++++-----
src/conf/domain_conf.h | 2 ++
src/libvirt_private.syms | 1 +
src/libxl/libxl_conf.c | 3 +++
src/libxl/libxl_conf.h | 4 ++++
src/network/bridge_driver.c | 2 +-
8 files changed, 51 insertions(+), 6 deletions(-)
--
2.1.4
8 years, 7 months
[libvirt] [PATCH v2 0/4] Export remote typed params methods internally via util
by Erik Skultety
Erik Skultety (4):
util: Introduce virTypedParameterRemote datatype
util: Export remoteDeserializeTypedParameters internally via util
util: Export remoteFreeTypedParameters internally via util
util: Export remoteSerializeTypedParameters internally via util
daemon/remote.c | 316 ++++++++++-------------------------------
src/libvirt_private.syms | 3 +
src/remote/remote_driver.c | 342 +++++++++++----------------------------------
src/rpc/gendispatch.pl | 26 ++--
src/util/virtypedparam.c | 246 ++++++++++++++++++++++++++++++++
src/util/virtypedparam.h | 39 ++++++
6 files changed, 459 insertions(+), 513 deletions(-)
--
2.4.3
8 years, 7 months
[libvirt] [PATCH v2] systemd: Modernize machine naming
by Martin Kletzander
So, systemd-machined has this philosophy that machine names are like
hostnames and hence should follow the same rules. But we always allowed
international characters in domain names. Thus we need to modify the
machine name we are passing to systemd.
In order to change some machinenames that we will be passing to systemd,
we also need to call TerminateMachine at the end of a lifetime of a
domain. Even for domains that were started with older libvirt. That
can be achieved thanks to virSystemdGetMachineNameByPID(). And because
we can change machine names, we can get rid of the inconsistent and
pointless escaping of domain names when creating machine names.
So this patch modifies the naming in the following way. It creates the
name as <drivername>-<id>-<name> where invalid hostname characters are
stripped out of the name and if the resulting name is longer, it
truncates it to 64 characters. That way we can start domains we
couldn't start before. Well, at least on systemd.
To make it work all together, the machineName (which is needed only for
systemd) is saved in domain's private data. That way the generation is
moved to the driver and we don't need to pass various unnecessary
arguments to cgroup functions.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1282846
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/lxc/lxc_cgroup.c | 13 ++++++++--
src/lxc/lxc_domain.c | 1 +
src/lxc/lxc_domain.h | 1 +
src/lxc/lxc_process.c | 19 +++++++++-----
src/qemu/qemu_cgroup.c | 27 ++++++++++++++------
src/qemu/qemu_cgroup.h | 2 +-
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_process.c | 4 +--
src/util/vircgroup.c | 25 +++++++++---------
src/util/vircgroup.h | 12 ++++-----
src/util/virsystemd.c | 67 ++++++++++++++++++++++++++++++++++---------------
src/util/virsystemd.h | 11 ++++----
tests/virsystemdtest.c | 45 +++++++++++++++++----------------
14 files changed, 145 insertions(+), 84 deletions(-)
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index ad254e4934fc..31489466cfbf 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -29,6 +29,7 @@
#include "viralloc.h"
#include "vircgroup.h"
#include "virstring.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -483,6 +484,13 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
int *nicindexes)
{
virCgroupPtr cgroup = NULL;
+ char *machineName = virSystemdMakeMachineName("lxc",
+ def->id,
+ def->name,
+ true);
+
+ if (!machineName)
+ goto cleanup;
if (def->resource->partition[0] != '/') {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -491,9 +499,8 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
goto cleanup;
}
- if (virCgroupNewMachine(def->name,
+ if (virCgroupNewMachine(machineName,
"lxc",
- true,
def->uuid,
NULL,
initpid,
@@ -517,6 +524,8 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
}
cleanup:
+ VIR_FREE(machineName);
+
return cgroup;
}
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c
index c3f7a564b36b..6732e934453f 100644
--- a/src/lxc/lxc_domain.c
+++ b/src/lxc/lxc_domain.c
@@ -28,6 +28,7 @@
#include "virerror.h"
#include <libxml/xpathInternals.h>
#include "virstring.h"
+#include "vircgroup.h"
#include "virutil.h"
#include "virfile.h"
diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h
index 2119c7899007..39c6e7def9ce 100644
--- a/src/lxc/lxc_domain.h
+++ b/src/lxc/lxc_domain.h
@@ -64,6 +64,7 @@ struct _virLXCDomainObjPrivate {
pid_t initpid;
virCgroupPtr cgroup;
+ char *machineName;
};
extern virDomainXMLNamespace virLXCDriverDomainXMLNamespace;
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index f7e2b810b74b..b14b69da4a16 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -233,8 +233,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
* properly. See https://bugs.freedesktop.org/show_bug.cgi?id=68370 for
* the bug we are working around here.
*/
- virSystemdTerminateMachine(vm->def->name, "lxc", true);
-
+ virCgroupTerminateMachine(priv->machineName);
/* The "release" hook cleans up additional resources */
if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
@@ -1494,8 +1493,8 @@ int virLXCProcessStart(virConnectPtr conn,
* point so lets detect that first, since it gives us a
* more reliable way to kill everything off if something
* goes wrong from here onwards ... */
- if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid,
- -1, &priv->cgroup) < 0)
+ if (virCgroupNewDetectMachine(vm->def->name, vm->def->uuid, "lxc",
+ vm->pid, -1, &priv->cgroup) < 0)
goto cleanup;
if (!priv->cgroup) {
@@ -1505,6 +1504,11 @@ int virLXCProcessStart(virConnectPtr conn,
goto cleanup;
}
+ /* Get the machine name so we can properly delete it through
+ * systemd later */
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
/* And we can get the first monitor connection now too */
if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) {
/* Intentionally overwrite the real monitor error message,
@@ -1677,8 +1681,8 @@ 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, vm->def->uuid, "lxc",
+ vm->pid, -1, &priv->cgroup) < 0)
goto error;
if (!priv->cgroup) {
@@ -1688,6 +1692,9 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm,
goto error;
}
+ if (!(priv->machineName = virSystemdGetMachineNameByPID(vm->pid)))
+ virResetLastError();
+
if (virLXCUpdateActiveUSBHostdevs(driver, vm->def) < 0)
goto error;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index e41f4617c455..705594d93dc5 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -36,6 +36,7 @@
#include "virfile.h"
#include "virtypedparam.h"
#include "virnuma.h"
+#include "virsystemd.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -772,9 +773,19 @@ qemuInitCgroup(virQEMUDriverPtr driver,
goto cleanup;
}
- if (virCgroupNewMachine(vm->def->name,
+ /*
+ * We need to do this because of systemd-machined, because
+ * CreateMachine requires the name to be a valid hostname.
+ */
+ priv->machineName = virSystemdMakeMachineName("qemu",
+ vm->def->id,
+ vm->def->name,
+ virQEMUDriverIsPrivileged(driver));
+ if (!priv->machineName)
+ goto cleanup;
+
+ if (virCgroupNewMachine(priv->machineName,
"qemu",
- true,
vm->def->uuid,
NULL,
vm->pid,
@@ -887,12 +898,17 @@ qemuConnectCgroup(virQEMUDriverPtr driver,
virCgroupFree(&priv->cgroup);
if (virCgroupNewDetectMachine(vm->def->name,
+ vm->def->uuid,
"qemu",
vm->pid,
cfg->cgroupControllers,
&priv->cgroup) < 0)
goto cleanup;
+ priv->machineName = virSystemdGetMachineNameByPID(vm->pid);
+ if (!priv->machineName)
+ virResetLastError();
+
qemuRestoreCgroupState(vm);
done:
@@ -1264,17 +1280,14 @@ qemuSetupCgroupForIOThreads(virDomainObjPtr vm)
}
int
-qemuRemoveCgroup(virQEMUDriverPtr driver,
- virDomainObjPtr vm)
+qemuRemoveCgroup(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
if (priv->cgroup == NULL)
return 0; /* Not supported, so claim success */
- if (virCgroupTerminateMachine(vm->def->name,
- "qemu",
- virQEMUDriverIsPrivileged(driver)) < 0) {
+ if (virCgroupTerminateMachine(priv->machineName) < 0) {
if (!virCgroupNewIgnoreError())
VIR_DEBUG("Failed to terminate cgroup for %s", vm->def->name);
}
diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
index 2bcf071d3792..347d126f7394 100644
--- a/src/qemu/qemu_cgroup.h
+++ b/src/qemu/qemu_cgroup.h
@@ -56,7 +56,7 @@ int qemuSetupCgroupCpusetCpus(virCgroupPtr cgroup, virBitmapPtr cpumask);
int qemuSetupCgroupForVcpu(virDomainObjPtr vm);
int qemuSetupCgroupForIOThreads(virDomainObjPtr vm);
int qemuSetupCgroupForEmulator(virDomainObjPtr vm);
-int qemuRemoveCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm);
+int qemuRemoveCgroup(virDomainObjPtr vm);
int qemuAddToCgroup(virDomainObjPtr vm);
#endif /* __QEMU_CGROUP_H__ */
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 189552045177..09ad2f75916f 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -39,6 +39,7 @@
#include "virtime.h"
#include "virstoragefile.h"
#include "virstring.h"
+#include "virsystemd.h"
#include "virthreadjob.h"
#include "viratomic.h"
#include "virprocess.h"
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 6a8cf705d8af..ab798faf0fb0 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -203,6 +203,7 @@ struct _qemuDomainObjPrivate {
bool signalIOError; /* true if the domain condition should be signalled on
I/O error */
+ char *machineName;
};
# define QEMU_DOMAIN_DISK_PRIVATE(disk) \
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 7b09ba73896b..b3f8c93d1a93 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4610,7 +4610,7 @@ qemuProcessLaunch(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);
+ qemuRemoveCgroup(vm);
VIR_DEBUG("Setting up ports for graphics");
if (qemuProcessSetupGraphics(driver, vm) < 0)
@@ -5405,7 +5405,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
}
retry:
- if ((ret = qemuRemoveCgroup(driver, vm)) < 0) {
+ if ((ret = qemuRemoveCgroup(vm)) < 0) {
if (ret == -EBUSY && (retries++ < 5)) {
usleep(200*1000);
goto retry;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index da0df7ae7a5e..4aed5d20b818 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -43,6 +43,7 @@
#include "vircgrouppriv.h"
#include "virutil.h"
+#include "viruuid.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
@@ -243,12 +244,14 @@ static bool
virCgroupValidateMachineGroup(virCgroupPtr group,
const char *name,
const char *drivername,
+ const unsigned char *uuid,
bool stripEmulatorSuffix)
{
size_t i;
bool valid = false;
char *partname;
char *scopename;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
if (virAsprintf(&partname, "%s.libvirt-%s",
name, drivername) < 0)
@@ -263,6 +266,8 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
if (virCgroupPartitionEscape(&scopename) < 0)
goto cleanup;
+ virUUIDFormat(uuid, uuidstr);
+
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
char *tmp;
@@ -290,6 +295,7 @@ virCgroupValidateMachineGroup(virCgroupPtr group,
tmp++;
if (STRNEQ(tmp, name) &&
+ STRNEQ(tmp, uuidstr) &&
STRNEQ(tmp, partname) &&
STRNEQ(tmp, scopename)) {
VIR_DEBUG("Name '%s' for controller '%s' does not match "
@@ -1554,6 +1560,7 @@ virCgroupNewDetect(pid_t pid,
*/
int
virCgroupNewDetectMachine(const char *name,
+ const unsigned char *uuid,
const char *drivername,
pid_t pid,
int controllers,
@@ -1565,7 +1572,7 @@ virCgroupNewDetectMachine(const char *name,
return -1;
}
- if (!virCgroupValidateMachineGroup(*group, name, drivername, true)) {
+ if (!virCgroupValidateMachineGroup(*group, name, drivername, uuid, true)) {
VIR_DEBUG("Failed to validate machine name for '%s' driver '%s'",
name, drivername);
virCgroupFree(group);
@@ -1582,7 +1589,6 @@ virCgroupNewDetectMachine(const char *name,
static int
virCgroupNewMachineSystemd(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -1602,7 +1608,6 @@ virCgroupNewMachineSystemd(const char *name,
VIR_DEBUG("Trying to setup machine '%s' via systemd", name);
if ((rv = virSystemdCreateMachine(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
@@ -1690,11 +1695,9 @@ virCgroupNewMachineSystemd(const char *name,
/*
* Returns 0 on success, -1 on fatal error
*/
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virCgroupTerminateMachine(const char *name)
{
- return virSystemdTerminateMachine(name, drivername, privileged);
+ return virSystemdTerminateMachine(name);
}
@@ -1749,7 +1752,6 @@ virCgroupNewMachineManual(const char *name,
int
virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -1766,7 +1768,6 @@ virCgroupNewMachine(const char *name,
if ((rv = virCgroupNewMachineSystemd(name,
drivername,
- privileged,
uuid,
rootdir,
pidleader,
@@ -4240,6 +4241,7 @@ virCgroupNewDetect(pid_t pid ATTRIBUTE_UNUSED,
int
virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED,
+ const unsigned char *uuid ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
pid_t pid ATTRIBUTE_UNUSED,
int controllers ATTRIBUTE_UNUSED,
@@ -4251,9 +4253,7 @@ virCgroupNewDetectMachine(const char *name ATTRIBUTE_UNUSED,
}
-int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED,
- const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED)
+int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED)
{
virReportSystemError(ENXIO, "%s",
_("Control groups not supported on this platform"));
@@ -4264,7 +4264,6 @@ int virCgroupTerminateMachine(const char *name ATTRIBUTE_UNUSED,
int
virCgroupNewMachine(const char *name ATTRIBUTE_UNUSED,
const char *drivername ATTRIBUTE_UNUSED,
- bool privileged ATTRIBUTE_UNUSED,
const unsigned char *uuid ATTRIBUTE_UNUSED,
const char *rootdir ATTRIBUTE_UNUSED,
pid_t pidleader ATTRIBUTE_UNUSED,
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index d754b1f3bd7a..dd4cb719f1f1 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -90,14 +90,16 @@ int virCgroupNewDetect(pid_t pid,
virCgroupPtr *group);
int virCgroupNewDetectMachine(const char *name,
+ const unsigned char *uuid,
const char *drivername,
pid_t pid,
int controllers,
- virCgroupPtr *group);
+ virCgroupPtr *group)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ ATTRIBUTE_NONNULL(3);
int virCgroupNewMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -110,10 +112,8 @@ int virCgroupNewMachine(const char *name,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
ATTRIBUTE_NONNULL(4);
-int virCgroupTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virCgroupTerminateMachine(const char *name)
+ ATTRIBUTE_NONNULL(1);
bool virCgroupNewIgnoreError(void);
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c
index 9e85e24b2c4b..5c6cd872bee0 100644
--- a/src/util/virsystemd.c
+++ b/src/util/virsystemd.c
@@ -25,6 +25,8 @@
# include <systemd/sd-daemon.h>
#endif
+#include "internal.h"
+
#include "virsystemd.h"
#include "viratomic.h"
#include "virdbus.h"
@@ -33,6 +35,7 @@
#include "virutil.h"
#include "virlog.h"
#include "virerror.h"
+#include "viruuid.h"
#define VIR_FROM_THIS VIR_FROM_SYSTEMD
@@ -113,10 +116,42 @@ char *virSystemdMakeSliceName(const char *partition)
return virBufferContentAndReset(&buf);
}
+#define HOSTNAME_CHARS \
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
- bool privileged)
+static void
+virSystemdAppendValidMachineName(virBufferPtr buf,
+ const char *name)
+{
+ bool skip_dot = false;
+
+ for (; *name; name++) {
+ if (strlen(virBufferCurrentContent(buf)) >= 64)
+ break;
+
+ if (*name == '.') {
+ if (!skip_dot)
+ virBufferAddChar(buf, *name);
+ skip_dot = true;
+ continue;
+ }
+
+ skip_dot = false;
+
+ if (!strchr(HOSTNAME_CHARS, *name))
+ continue;
+
+ virBufferAddChar(buf, *name);
+ }
+}
+
+#undef HOSTNAME_CHARS
+
+char *
+virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
+ bool privileged)
{
char *machinename = NULL;
char *username = NULL;
@@ -131,7 +166,8 @@ char *virSystemdMakeMachineName(const char *name,
virBufferAsprintf(&buf, "%s-%s-", username, drivername);
}
- virSystemdEscapeName(&buf, name);
+ virBufferAsprintf(&buf, "%d-", id);
+ virSystemdAppendValidMachineName(&buf, name);
machinename = virBufferContentAndReset(&buf);
cleanup:
@@ -212,7 +248,6 @@ virSystemdGetMachineNameByPID(pid_t pid)
*/
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -223,7 +258,6 @@ int virSystemdCreateMachine(const char *name,
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
char *creatorname = NULL;
char *slicename = NULL;
static int hasCreateWithNetwork = 1;
@@ -239,8 +273,6 @@ int virSystemdCreateMachine(const char *name,
return -1;
ret = -1;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
if (virAsprintf(&creatorname, "libvirt-%s", drivername) < 0)
goto cleanup;
@@ -318,7 +350,7 @@ int virSystemdCreateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"CreateMachineWithNetwork",
"sayssusa&ia(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
@@ -360,7 +392,7 @@ int virSystemdCreateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"CreateMachine",
"sayssusa(sv)",
- machinename,
+ name,
16,
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
@@ -381,20 +413,19 @@ int virSystemdCreateMachine(const char *name,
cleanup:
VIR_FREE(creatorname);
- VIR_FREE(machinename);
VIR_FREE(slicename);
return ret;
}
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged)
+int virSystemdTerminateMachine(const char *name)
{
int ret;
DBusConnection *conn;
- char *machinename = NULL;
virError error;
+ if (!name)
+ return 0;
+
memset(&error, 0, sizeof(error));
ret = virDBusIsServiceEnabled("org.freedesktop.machine1");
@@ -409,9 +440,6 @@ int virSystemdTerminateMachine(const char *name,
if (!(conn = virDBusGetSystemBus()))
goto cleanup;
- if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged)))
- goto cleanup;
-
/*
* The systemd DBus API we're invoking has the
* following signature
@@ -431,7 +459,7 @@ int virSystemdTerminateMachine(const char *name,
"org.freedesktop.machine1.Manager",
"TerminateMachine",
"s",
- machinename) < 0)
+ name) < 0)
goto cleanup;
if (error.code == VIR_ERR_ERROR &&
@@ -446,7 +474,6 @@ int virSystemdTerminateMachine(const char *name,
cleanup:
virResetError(&error);
- VIR_FREE(machinename);
return ret;
}
diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h
index a13a4c0c48be..9042b5f31263 100644
--- a/src/util/virsystemd.h
+++ b/src/util/virsystemd.h
@@ -23,18 +23,19 @@
# define __VIR_SYSTEMD_H__
# include "internal.h"
+# include "virbuffer.h"
char *virSystemdMakeScopeName(const char *name,
const char *drivername);
char *virSystemdMakeSliceName(const char *partition);
-char *virSystemdMakeMachineName(const char *name,
- const char *drivername,
+char *virSystemdMakeMachineName(const char *drivername,
+ int id,
+ const char *name,
bool privileged);
int virSystemdCreateMachine(const char *name,
const char *drivername,
- bool privileged,
const unsigned char *uuid,
const char *rootdir,
pid_t pidleader,
@@ -43,9 +44,7 @@ int virSystemdCreateMachine(const char *name,
int *nicindexes,
const char *partition);
-int virSystemdTerminateMachine(const char *name,
- const char *drivername,
- bool privileged);
+int virSystemdTerminateMachine(const char *name);
void virSystemdNotifyStartup(void);
diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c
index 3a3cd9968032..d7fccf92bc24 100644
--- a/tests/virsystemdtest.c
+++ b/tests/virsystemdtest.c
@@ -166,7 +166,6 @@ static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED)
};
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
@@ -182,9 +181,7 @@ static int testCreateContainer(const void *opaque ATTRIBUTE_UNUSED)
static int testTerminateContainer(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "lxc",
- true) < 0) {
+ if (virSystemdTerminateMachine("lxc-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate LXC machine\n");
return -1;
}
@@ -202,7 +199,6 @@ static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED)
};
if (virSystemdCreateMachine("demo",
"qemu",
- false,
uuid,
NULL,
123,
@@ -218,9 +214,7 @@ static int testCreateMachine(const void *opaque ATTRIBUTE_UNUSED)
static int testTerminateMachine(const void *opaque ATTRIBUTE_UNUSED)
{
- if (virSystemdTerminateMachine("demo",
- "qemu",
- false) < 0) {
+ if (virSystemdTerminateMachine("test-qemu-demo") < 0) {
fprintf(stderr, "%s", "Failed to terminate KVM machine\n");
return -1;
}
@@ -242,7 +236,6 @@ static int testCreateNoSystemd(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -277,7 +270,6 @@ static int testCreateSystemdNotRunning(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -312,7 +304,6 @@ static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED)
if ((rv = virSystemdCreateMachine("demo",
"qemu",
- true,
uuid,
NULL,
123,
@@ -348,7 +339,6 @@ static int testCreateNetwork(const void *opaque ATTRIBUTE_UNUSED)
size_t nnicindexes = ARRAY_CARDINALITY(nicindexes);
if (virSystemdCreateMachine("demo",
"lxc",
- true,
uuid,
"/proc/123/root",
123,
@@ -385,6 +375,7 @@ testGetMachineName(const void *opaque ATTRIBUTE_UNUSED)
struct testNameData {
const char *name;
const char *expected;
+ int id;
};
static int
@@ -417,7 +408,8 @@ testMachineName(const void *opaque)
int ret = -1;
char *actual = NULL;
- if (!(actual = virSystemdMakeMachineName(data->name, "qemu", true)))
+ if (!(actual = virSystemdMakeMachineName("qemu", data->id,
+ data->name, true)))
goto cleanup;
if (STRNEQ(actual, data->expected)) {
@@ -518,6 +510,12 @@ mymain(void)
{
int ret = 0;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ /* The one we use in tests quite often */
+ if (virUUIDParse("c7a5fdbd-edaf-9455-926a-d65c16db1809", uuid) < 0)
+ return EXIT_FAILURE;
+
if (virtTestRun("Test create container ", testCreateContainer, NULL) < 0)
ret = -1;
if (virtTestRun("Test terminate container ", testTerminateContainer, NULL) < 0)
@@ -541,7 +539,7 @@ mymain(void)
# define TEST_SCOPE(name, unitname) \
do { \
struct testNameData data = { \
- name, unitname \
+ name, unitname, 0, \
}; \
if (virtTestRun("Test scopename", testScopeName, &data) < 0) \
ret = -1; \
@@ -553,20 +551,25 @@ mymain(void)
TEST_SCOPE(".demo", "machine-lxc\\x2d\\x2edemo.scope");
TEST_SCOPE("bull💩", "machine-lxc\\x2dbull\\xf0\\x9f\\x92\\xa9.scope");
-# define TEST_MACHINE(name, machinename) \
+# define TEST_MACHINE(name, id, machinename) \
do { \
struct testNameData data = { \
- name, machinename \
+ name, machinename, id, \
}; \
if (virtTestRun("Test scopename", testMachineName, &data) < 0) \
ret = -1; \
} while (0)
- TEST_MACHINE("demo", "qemu-demo");
- TEST_MACHINE("demo-name", "qemu-demo\\x2dname");
- TEST_MACHINE("demo!name", "qemu-demo\\x21name");
- TEST_MACHINE(".demo", "qemu-\\x2edemo");
- TEST_MACHINE("bull\U0001f4a9", "qemu-bull\\xf0\\x9f\\x92\\xa9");
+ TEST_MACHINE("demo", 1, "qemu-1-demo");
+ TEST_MACHINE("demo-name", 2, "qemu-2-demo-name");
+ TEST_MACHINE("demo!name", 3, "qemu-3-demoname");
+ TEST_MACHINE(".demo", 4, "qemu-4-.demo");
+ TEST_MACHINE("bull\U0001f4a9", 5, "qemu-5-bull");
+ TEST_MACHINE("demo..name", 6, "qemu-6-demo.name");
+ TEST_MACHINE("12345678901234567890123456789012345678901234567890123456789", 7,
+ "qemu-7-123456789012345678901234567890123456789012345678901234567");
+ TEST_MACHINE("123456789012345678901234567890123456789012345678901234567890", 8,
+ "qemu-8-123456789012345678901234567890123456789012345678901234567");
# define TESTS_PM_SUPPORT_HELPER(name, function) \
do { \
--
2.7.0
8 years, 7 months
[libvirt] [PATCH v3] qemu: qemuDomainRename and virDomainObjListNumOfDomains ABBA deadlock fix
by Nikolay Shirokovskiy
A pretty nasty deadlock occurs while trying to rename a VM in parallel
with virDomainObjListNumOfDomains.
The short description of the problem is as follows:
Thread #1:
qemuDomainRename:
------> aquires domain lock by qemuDomObjFromDomain
---------> waits for domain list lock in any of the listed functions:
- virDomainObjListFindByName
- virDomainObjListRenameAddNew
- virDomainObjListRenameRemove
Thread #2:
virDomainObjListNumOfDomains:
------> aquires domain list lock
---------> waits for domain lock in virDomainObjListCount
Introduce generic virDomainObjListRename function for renaming domains.
It aquires list lock in right order to avoid deadlock. Callback is used
to make driver specific domain updates.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
src/conf/virdomainobjlist.c | 98 +++++++++++++++++++-----------
src/conf/virdomainobjlist.h | 16 +++--
src/libvirt_private.syms | 3 +-
src/qemu/qemu_driver.c | 142 ++++++++++++++++++++------------------------
4 files changed, 142 insertions(+), 117 deletions(-)
diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
index 7568f93..1f7ddaf 100644
--- a/src/conf/virdomainobjlist.c
+++ b/src/conf/virdomainobjlist.c
@@ -313,40 +313,6 @@ virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
}
-int
-virDomainObjListRenameAddNew(virDomainObjListPtr doms,
- virDomainObjPtr vm,
- const char *name)
-{
- int ret = -1;
- virObjectLock(doms);
-
- /* Add new name into the hash table of domain names. */
- if (virHashAddEntry(doms->objsName, name, vm) < 0)
- goto cleanup;
-
- /* Okay, this is crazy. virHashAddEntry() does not increment
- * the refcounter of @vm, but virHashRemoveEntry() does
- * decrement it. We need to work around it. */
- virObjectRef(vm);
-
- ret = 0;
- cleanup:
- virObjectUnlock(doms);
- return ret;
-}
-
-
-int
-virDomainObjListRenameRemove(virDomainObjListPtr doms, const char *name)
-{
- virObjectLock(doms);
- virHashRemoveEntry(doms->objsName, name);
- virObjectUnlock(doms);
- return 0;
-}
-
-
/*
* The caller must hold a lock on the driver owning 'doms',
* and must also have locked 'dom', to ensure no one else
@@ -372,6 +338,70 @@ void virDomainObjListRemove(virDomainObjListPtr doms,
}
+/*
+ * The caller must hold a lock on dom. Callbacks should not sleep/wait othewise
+ * operations on all domains will be blocked as the callback is called with
+ * domains lock hold. Domain lock is dropped/reaquired during this operation
+ * thus domain consistency must not rely on this lock solely.
+ */
+
+int
+virDomainObjListRename(virDomainObjListPtr doms,
+ virDomainObjPtr dom,
+ const char *new_name,
+ unsigned int flags,
+ virDomainObjListRenameCallback callback,
+ void *opaque)
+{
+ int ret = -1;
+ char *old_name = NULL;
+ int rc;
+
+ /* doms and dom locks must be attained in right order thus relock dom. */
+ /* dom reference is touched for the benefit of those callers that
+ * hold a lock on dom but not refcount it. */
+ virObjectRef(dom);
+ virObjectUnlock(dom);
+ virObjectLock(doms);
+ virObjectLock(dom);
+ virObjectUnref(dom);
+
+ if (STREQ(dom->def->name, new_name)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Can't rename domain to itself"));
+ goto cleanup;
+ }
+
+ if (virHashLookup(doms->objsName, new_name) != NULL) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("domain with name '%s' already exists"),
+ new_name);
+ goto cleanup;
+ }
+
+ if (VIR_STRDUP(old_name, dom->def->name) < 0)
+ goto cleanup;
+
+ if (virHashAddEntry(doms->objsName, new_name, dom) < 0)
+ goto cleanup;
+
+ /* Okay, this is crazy. virHashAddEntry() does not increment
+ * the refcounter of @dom, but virHashRemoveEntry() does
+ * decrement it. We need to work around it. */
+ virObjectRef(dom);
+
+ rc = callback(dom, new_name, flags, opaque);
+ virHashRemoveEntry(doms->objsName, rc < 0 ? new_name : old_name);
+ if (rc < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virObjectUnlock(doms);
+ VIR_FREE(old_name);
+ return ret;
+}
+
/* The caller must hold lock on 'doms' in addition to 'virDomainObjListRemove'
* requirements
*
diff --git a/src/conf/virdomainobjlist.h b/src/conf/virdomainobjlist.h
index f479598..c0f856c 100644
--- a/src/conf/virdomainobjlist.h
+++ b/src/conf/virdomainobjlist.h
@@ -51,11 +51,17 @@ virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
unsigned int flags,
virDomainDefPtr *oldDef);
-int virDomainObjListRenameAddNew(virDomainObjListPtr doms,
- virDomainObjPtr vm,
- const char *name);
-int virDomainObjListRenameRemove(virDomainObjListPtr doms,
- const char *name);
+typedef int (*virDomainObjListRenameCallback)(virDomainObjPtr dom,
+ const char *new_name,
+ unsigned int flags,
+ void *opaque);
+int virDomainObjListRename(virDomainObjListPtr doms,
+ virDomainObjPtr dom,
+ const char *new_name,
+ unsigned int flags,
+ virDomainObjListRenameCallback callback,
+ void *opaque);
+
void virDomainObjListRemove(virDomainObjListPtr doms,
virDomainObjPtr dom);
void virDomainObjListRemoveLocked(virDomainObjListPtr doms,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3d0ec9d..3ef3468 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -893,8 +893,7 @@ virDomainObjListNew;
virDomainObjListNumOfDomains;
virDomainObjListRemove;
virDomainObjListRemoveLocked;
-virDomainObjListRenameAddNew;
-virDomainObjListRenameRemove;
+virDomainObjListRename;
# cpu/cpu.h
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index abcdbe6..c0e750d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -19976,14 +19976,14 @@ qemuDomainSetUserPassword(virDomainPtr dom,
}
-static int qemuDomainRename(virDomainPtr dom,
- const char *new_name,
- unsigned int flags)
+static int
+qemuDomainRenameCallback(virDomainObjPtr vm,
+ const char *new_name,
+ unsigned int flags,
+ void *opaque)
{
- virQEMUDriverPtr driver = dom->conn->privateData;
+ virQEMUDriverPtr driver = opaque;
virQEMUDriverConfigPtr cfg = NULL;
- virDomainObjPtr vm = NULL;
- virDomainObjPtr tmp_dom = NULL;
virObjectEventPtr event_new = NULL;
virObjectEventPtr event_old = NULL;
int ret = -1;
@@ -19993,73 +19993,16 @@ static int qemuDomainRename(virDomainPtr dom,
virCheckFlags(0, ret);
- if (!(vm = qemuDomObjFromDomain(dom)))
- goto cleanup;
-
- if (virDomainRenameEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
cfg = virQEMUDriverGetConfig(driver);
- if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
- goto cleanup;
-
- if (virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot rename active domain"));
- goto endjob;
- }
-
- if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot rename a transient domain"));
- goto endjob;
- }
-
- if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain has to be shutoff before renaming"));
- goto endjob;
- }
-
- if (virDomainSnapshotObjListNum(vm->snapshots, NULL, 0) > 0) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot rename domain with snapshots"));
- goto endjob;
- }
-
- if (STREQ(vm->def->name, new_name)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("Can't rename domain to itself"));
- goto endjob;
- }
-
- /*
- * This is a rather racy check, but still better than reporting
- * internal error. And since new_name != name here, there's no
- * deadlock imminent.
- */
- tmp_dom = virDomainObjListFindByName(driver->domains, new_name);
- if (tmp_dom) {
- virObjectUnlock(tmp_dom);
- virObjectUnref(tmp_dom);
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("domain with name '%s' already exists"),
- new_name);
- goto endjob;
- }
-
if (VIR_STRDUP(new_dom_name, new_name) < 0)
- goto endjob;
+ goto cleanup;
if (!(old_dom_cfg_file = virDomainConfigFile(cfg->configDir,
vm->def->name))) {
- goto endjob;
+ goto cleanup;
}
- if (virDomainObjListRenameAddNew(driver->domains, vm, new_name) < 0)
- goto endjob;
-
event_old = virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_UNDEFINED,
VIR_DOMAIN_EVENT_UNDEFINED_RENAMED);
@@ -20080,21 +20023,12 @@ static int qemuDomainRename(virDomainPtr dom,
goto rollback;
}
- /* Remove old domain name from table. */
- virDomainObjListRenameRemove(driver->domains, old_dom_name);
-
event_new = virDomainEventLifecycleNewFromObj(vm,
VIR_DOMAIN_EVENT_DEFINED,
VIR_DOMAIN_EVENT_DEFINED_RENAMED);
-
- /* Success, domain has been renamed. */
ret = 0;
- endjob:
- qemuDomainObjEndJob(driver, vm);
-
cleanup:
- virDomainObjEndAPI(&vm);
VIR_FREE(old_dom_cfg_file);
VIR_FREE(old_dom_name);
VIR_FREE(new_dom_name);
@@ -20109,9 +20043,65 @@ static int qemuDomainRename(virDomainPtr dom,
vm->def->name = old_dom_name;
old_dom_name = NULL;
}
+ goto cleanup;
+}
- virDomainObjListRenameRemove(driver->domains, new_name);
- goto endjob;
+static int qemuDomainRename(virDomainPtr dom,
+ const char *new_name,
+ unsigned int flags)
+{
+ virQEMUDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, ret);
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+ goto cleanup;
+
+ if (virDomainRenameEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ if (virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot rename active domain"));
+ goto endjob;
+ }
+
+ if (!vm->persistent) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot rename a transient domain"));
+ goto endjob;
+ }
+
+ if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain has to be shutoff before renaming"));
+ goto endjob;
+ }
+
+ if (virDomainSnapshotObjListNum(vm->snapshots, NULL, 0) > 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot rename domain with snapshots"));
+ goto endjob;
+ }
+
+ if (virDomainObjListRename(driver->domains, vm, new_name, flags,
+ qemuDomainRenameCallback, driver) < 0)
+ goto endjob;
+
+ /* Success, domain has been renamed. */
+ ret = 0;
+
+ endjob:
+ qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
}
static virHypervisorDriver qemuHypervisorDriver = {
--
1.8.3.1
8 years, 7 months
[libvirt] [PATCH 0/5] Export remote typed params methods internally via util
by Erik Skultety
Erik Skultety (5):
cfg.mk: Adjust sc_prohibit_int_ijk to support 'exempt from
syntax-check'
util: Introduce virTypedParameterRemote datatype
util: Export remoteDeserializeTypedParameters internally via util
util: Export remoteFreeTypedParameters internally via util
util: Export remoteSerializeTypedParameters internally via util
cfg.mk | 3 +-
daemon/remote.c | 218 ++++++---------------------------------
src/libvirt_private.syms | 3 +
src/remote/remote_driver.c | 196 +++---------------------------------
src/rpc/gendispatch.pl | 9 +-
src/util/virtypedparam.c | 246 +++++++++++++++++++++++++++++++++++++++++++++
src/util/virtypedparam.h | 40 ++++++++
7 files changed, 341 insertions(+), 374 deletions(-)
--
2.4.3
8 years, 7 months