I know it's a POC type series, but figured I'd take a look primarily at
the first 4 patches, learn a bit in the 5th one, and provide some review
feedback in order to help move things along... There's perhaps a few
adjustments in here that could be made into multiple patches.
On 12/20/2017 11:47 AM, Daniel P. Berrange wrote:
Currently the QEMU driver has three ways of setting up cgroups. It
either
skips them entirely (if non-root), or uses systemd-machined, or uses
cgroups directly.
It is further possible to register directly with systemd and bypass
machined. We don't support this by systemd-nsspawn does and we ought
s/by/but/ (I think)
Still a bit odd to add an option that isn't supported unless there was a
plan to add the support when formulating the non POC patches...
to.
This change adds ability to configure the mechanism for registering
resources between all these options explicitly. via
s/. via/ via:/ (e.g. remove the '.' and add ':')
<resource register="none|direct|machined|systemd"/>
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/conf/domain_conf.c | 42 ++++++++++++++++++++++-------
src/conf/domain_conf.h | 12 +++++++++
src/libvirt_private.syms | 2 ++
src/lxc/lxc_cgroup.c | 34 ++++++++++++++++++++++++
src/lxc/lxc_cgroup.h | 3 +++
src/lxc/lxc_process.c | 11 ++++----
src/qemu/qemu_cgroup.c | 69 +++++++++++++++++++++++++++++++++++++++++-------
src/util/vircgroup.c | 55 ++++++++++++++++++++++++--------------
src/util/vircgroup.h | 10 ++++++-
9 files changed, 194 insertions(+), 44 deletions(-)
formatdomain.html.in would need to be augmented to describe the new
attribute.
domaincommon.rng modified to add the new attribute.
A tests either added or existing one adjusted to exhibit the new
attribute option(s).
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 9a62bc472c..fb8e7a0ec7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -910,6 +910,14 @@ VIR_ENUM_IMPL(virDomainHPTResizing,
"required",
);
+VIR_ENUM_IMPL(virDomainResourceRegister,
+ VIR_DOMAIN_RESOURCE_REGISTER_LAST,
+ "default",
+ "none",
+ "cgroup",
+ "machined",
+ "systemd");
+
/* Internal mapping: subset of block job types that can be present in
* <mirror> XML (remaining types are not two-phase). */
VIR_ENUM_DECL(virDomainBlockJob)
@@ -17698,16 +17706,20 @@ virDomainResourceDefParse(xmlNodePtr node,
{
virDomainResourceDefPtr def = NULL;
xmlNodePtr tmp = ctxt->node;
+ char *reg;
= NULL;
ctxt->node = node;
if (VIR_ALLOC(def) < 0)
goto error;
- /* Find out what type of virtualization to use */
- if (!(def->partition = virXPathString("string(./partition)", ctxt))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing resource partition
attribute"));
+ def->partition = virXPathString("string(./partition)", ctxt);
It seems partition is now optional, although formatdomain seems to have
already indicated that... However, that's not a perfect match to
domaincommon.rng where only "respartition" is optional. (This type of
change could perhaps be it's own patch).
+
+ reg = virXMLPropString(node, "register");
+ if (reg != NULL &&
+ (def->reg = virDomainResourceRegisterTypeFromString(reg)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("Invalid register attribute"));
goto error;
}
Need a VIR_FREE(reg); since we haven't GO-ified yet in both error and
normal paths unless this is rewritten a bit...
@@ -25568,11 +25580,23 @@ static void
virDomainResourceDefFormat(virBufferPtr buf,
virDomainResourceDefPtr def)
{
- virBufferAddLit(buf, "<resource>\n");
- virBufferAdjustIndent(buf, 2);
- virBufferEscapeString(buf, "<partition>%s</partition>\n",
def->partition);
- virBufferAdjustIndent(buf, -2);
- virBufferAddLit(buf, "</resource>\n");
+ if (def->reg == VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT &&
+ def->partition == NULL)
+ return;
+
+ virBufferAddLit(buf, "<resource");
+ if (def->reg != VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT)
+ virBufferAsprintf(buf, " register='%s'",
virDomainResourceRegisterTypeToString(def->reg));
+
+ if (def->partition) {
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferEscapeString(buf, "<partition>%s</partition>\n",
def->partition);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</resource>\n");
+ } else {
+ virBufferAddLit(buf, "/>\n");
+ }
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6f7f96b3dd..a7a6628a36 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2145,9 +2145,20 @@ struct _virDomainPanicDef {
void virBlkioDeviceArrayClear(virBlkioDevicePtr deviceWeights,
int ndevices);
+typedef enum {
+ VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT,
+ VIR_DOMAIN_RESOURCE_REGISTER_NONE,
+ VIR_DOMAIN_RESOURCE_REGISTER_CGROUP,
+ VIR_DOMAIN_RESOURCE_REGISTER_MACHINED,
+ VIR_DOMAIN_RESOURCE_REGISTER_SYSTEMD,
+
+ VIR_DOMAIN_RESOURCE_REGISTER_LAST,
+} virDomainResourceRegister;
+
typedef struct _virDomainResourceDef virDomainResourceDef;
typedef virDomainResourceDef *virDomainResourceDefPtr;
struct _virDomainResourceDef {
+ int reg; /* enum virDomainResourceRegister */
char *partition;
};
@@ -3325,6 +3336,7 @@ VIR_ENUM_DECL(virDomainMemorySource)
VIR_ENUM_DECL(virDomainMemoryAllocation)
VIR_ENUM_DECL(virDomainIOMMUModel)
VIR_ENUM_DECL(virDomainShmemModel)
+VIR_ENUM_DECL(virDomainResourceRegister)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d5c3b9abb5..a0fde65dba 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -489,6 +489,8 @@ virDomainRedirdevBusTypeToString;
virDomainRedirdevDefFind;
virDomainRedirdevDefFree;
virDomainRedirdevDefRemove;
+virDomainResourceRegisterTypeFromString;
+virDomainResourceRegisterTypeToString;
virDomainRNGBackendTypeToString;
virDomainRNGDefFree;
virDomainRNGFind;
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 3369801870..7bd479df1b 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -478,6 +478,35 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
return ret;
}
+int virLXCCgroupMode(virDomainResourceRegister reg,
+ virCgroupRegister *cgreg)
+{
+ switch (reg) {
+ case VIR_DOMAIN_RESOURCE_REGISTER_NONE:
+ goto unsupported;
+ case VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT:
+ *cgreg = VIR_CGROUP_REGISTER_DEFAULT;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_MACHINED:
+ *cgreg = VIR_CGROUP_REGISTER_MACHINED;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_CGROUP:
+ *cgreg = VIR_CGROUP_REGISTER_DIRECT;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_SYSTEMD:
+ default:
Use VIR_DOMAIN_RESOURCE_REGISTER_LAST instead of default
+ goto unsupported;
+ }
+
+ return 0;
+
+ unsupported:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Resource register '%s' not available"),
+ virDomainResourceRegisterTypeToString(reg));
+ return -1;
+}
+
virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
pid_t initpid,
@@ -485,11 +514,15 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
int *nicindexes)
{
virCgroupPtr cgroup = NULL;
+ virCgroupRegister reg;
char *machineName = virLXCDomainGetMachineName(def, 0);
if (!machineName)
goto cleanup;
+ if (virLXCCgroupMode(def->resource->reg, ®) < 0)
+ goto cleanup;
+
if (def->resource->partition[0] != '/') {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Resource partition '%s' must start with
'/'"),
@@ -504,6 +537,7 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
initpid,
true,
nnicindexes, nicindexes,
+ ®,
def->resource->partition,
-1,
&cgroup) < 0)
diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h
index e85f21c47d..979d6a154b 100644
--- a/src/lxc/lxc_cgroup.h
+++ b/src/lxc/lxc_cgroup.h
@@ -27,6 +27,9 @@
# include "lxc_fuse.h"
# include "virusb.h"
+int virLXCCgroupMode(virDomainResourceRegister reg,
+ virCgroupRegister *cgreg);
+
virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def,
pid_t initpid,
size_t nnicindexes,
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index efd8a69000..24aa0cb0bf 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -1166,6 +1166,7 @@ virLXCProcessEnsureRootFS(virDomainObjPtr vm)
return -1;
}
+
/**
* virLXCProcessStart:
* @conn: pointer to connection
@@ -1260,13 +1261,13 @@ int virLXCProcessStart(virConnectPtr conn,
if (VIR_ALLOC(res) < 0)
goto cleanup;
- if (VIR_STRDUP(res->partition, "/machine") < 0) {
- VIR_FREE(res);
- goto cleanup;
- }
-
vm->def->resource = res;
}
So the above could be shortened to just:
if (!vm->def->resource &&
VIR_ALLOC(vm->def->resource) < 0)
goto cleanup;
+ if (vm->def->resource->reg !=
VIR_DOMAIN_RESOURCE_REGISTER_NONE &&
+ !vm->def->resource->partition) {
+ if (VIR_STRDUP(vm->def->resource->partition, "/machine") <
0)
+ goto cleanup;
+ }
This could be similar too w/r/t single if condition...
if (virAsprintf(&logfile, "%s/%s.log",
cfg->logDir, vm->def->name) < 0)
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 19252ea239..5167d7fee1 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -834,6 +834,46 @@ qemuSetupCpuCgroup(virDomainObjPtr vm)
}
There could be a helper here that would be callable by qemuConnectCgroup
that would return the @avail value.
+static int qemuGetCgroupMode(virDomainObjPtr vm,
+ virDomainResourceRegister reg,
+ virCgroupRegister *cgreg)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ bool avail = virQEMUDriverIsPrivileged(priv->driver) &&
+ virCgroupAvailable();
+
+ switch (reg) {
+ case VIR_DOMAIN_RESOURCE_REGISTER_NONE:
+ return 0;
+ case VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT:
+ if (!avail)
+ return 0;
+ *cgreg = VIR_CGROUP_REGISTER_DEFAULT;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_MACHINED:
+ if (!avail)
+ goto unsupported;
+ *cgreg = VIR_CGROUP_REGISTER_MACHINED;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_CGROUP:
+ if (!avail)
+ goto unsupported;
+ *cgreg = VIR_CGROUP_REGISTER_DIRECT;
+ break;
+ case VIR_DOMAIN_RESOURCE_REGISTER_SYSTEMD:
+ default:
Use VIR_DOMAIN_RESOURCE_REGISTER_LAST instead of default
+ goto unsupported;
+ }
+
+ return 1;
+
+ unsupported:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Resource register '%s' not available"),
+ virDomainResourceRegisterTypeToString(reg));
+ return -1;
+}
+
static int
qemuInitCgroup(virDomainObjPtr vm,
size_t nnicindexes,
@@ -842,11 +882,17 @@ qemuInitCgroup(virDomainObjPtr vm,
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(priv->driver);
+ virCgroupRegister reg;
+ int rv;
- if (!virQEMUDriverIsPrivileged(priv->driver))
- goto done;
-
- if (!virCgroupAvailable())
+ rv = qemuGetCgroupMode(vm,
+ vm->def->resource ?
+ vm->def->resource->reg :
+ VIR_DOMAIN_RESOURCE_REGISTER_DEFAULT,
+ ®);
+ if (rv < 0)
+ goto cleanup;
+ if (rv == 0)
goto done;
virCgroupFree(&priv->cgroup);
@@ -857,13 +903,12 @@ qemuInitCgroup(virDomainObjPtr vm,
if (VIR_ALLOC(res) < 0)
goto cleanup;
- if (VIR_STRDUP(res->partition, "/machine") < 0) {
- VIR_FREE(res);
- goto cleanup;
- }
-
vm->def->resource = res;
}
Similar to above, we now have:
if (!vm->def->resource &&
VIR_ALLOC(vm->def->resource) < 0)
goto cleanup;
+ if (!vm->def->resource->partition) {
+ if (VIR_STRDUP(vm->def->resource->partition, "/machine") <
0)
+ goto cleanup;
+ }
and similar construct if desired.
if (vm->def->resource->partition[0] != '/') {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -879,6 +924,7 @@ qemuInitCgroup(virDomainObjPtr vm,
vm->pid,
false,
nnicindexes, nicindexes,
+ ®,
vm->def->resource->partition,
cfg->cgroupControllers,
&priv->cgroup) < 0) {
@@ -980,6 +1026,11 @@ qemuConnectCgroup(virDomainObjPtr vm)
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(priv->driver);
int ret = -1;
+ if (vm->def->resource &&
+ vm->def->resource->reg == VIR_DOMAIN_RESOURCE_REGISTER_NONE) {
+ goto done;
+ }
+
The subsequent checks could use the @avail helper mentioned above...
John
if (!virQEMUDriverIsPrivileged(priv->driver))
goto done;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 0a31947b0d..07ffb78c78 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -1733,6 +1733,7 @@ virCgroupNewMachine(const char *name,
bool isContainer,
size_t nnicindexes,
int *nicindexes,
+ virCgroupRegister *reg,
const char *partition,
int controllers,
virCgroupPtr *group)
@@ -1741,28 +1742,42 @@ virCgroupNewMachine(const char *name,
*group = NULL;
- if ((rv = virCgroupNewMachineSystemd(name,
- drivername,
- uuid,
- rootdir,
- pidleader,
- isContainer,
- nnicindexes,
- nicindexes,
- partition,
- controllers,
- group)) == 0)
- return 0;
+ if (*reg == VIR_CGROUP_REGISTER_DEFAULT ||
+ *reg == VIR_CGROUP_REGISTER_MACHINED) {
+ if ((rv = virCgroupNewMachineSystemd(name,
+ drivername,
+ uuid,
+ rootdir,
+ pidleader,
+ isContainer,
+ nnicindexes,
+ nicindexes,
+ partition,
+ controllers,
+ group)) == 0) {
+ *reg = VIR_CGROUP_REGISTER_MACHINED;
+ return 0;
+ }
- if (rv == -1)
- return -1;
+ if (rv == -1)
+ return -1;
+
+ if (*reg == VIR_CGROUP_REGISTER_MACHINED) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("Systemd machined requested, but not
available"));
+ return -1;
+ }
+ }
- return virCgroupNewMachineManual(name,
- drivername,
- pidleader,
- partition,
- controllers,
- group);
+ rv = virCgroupNewMachineManual(name,
+ drivername,
+ pidleader,
+ partition,
+ controllers,
+ group);
+ if (rv == 0)
+ *reg = VIR_CGROUP_REGISTER_DIRECT;
+ return rv;
}
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index d833927678..63ee1aba5c 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -46,7 +46,8 @@ enum {
VIR_CGROUP_CONTROLLER_LAST
};
-VIR_ENUM_DECL(virCgroupController);
+VIR_ENUM_DECL(virCgroupController)
+
/* Items of this enum are used later in virCgroupNew to create
* bit array stored in int. Like this:
* 1 << VIR_CGROUP_CONTROLLER_CPU
@@ -103,6 +104,12 @@ virCgroupNewDetectMachine(const char *name,
virCgroupPtr *group)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+typedef enum {
+ VIR_CGROUP_REGISTER_DEFAULT,
+ VIR_CGROUP_REGISTER_DIRECT,
+ VIR_CGROUP_REGISTER_MACHINED,
+} virCgroupRegister;
+
int virCgroupNewMachine(const char *name,
const char *drivername,
const unsigned char *uuid,
@@ -111,6 +118,7 @@ int virCgroupNewMachine(const char *name,
bool isContainer,
size_t nnicindexes,
int *nicindexes,
+ virCgroupRegister *reg,
const char *partition,
int controllers,
virCgroupPtr *group)