This patch sets up the cgroups for QEMU instances. It creates a cgroup
when starting a guest, uses an exec hook to place the process into the
correct cgroup, and cleans up empty cgroup when the QEMU process shuts
down.
Daniel
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -68,6 +68,7 @@
#include "memory.h"
#include "uuid.h"
#include "domain_conf.h"
+#include "cgroup.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -1134,6 +1135,79 @@ static int qemudNextFreeVNCPort(struct q
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
const char *name);
+static int qemuSetupCgroup(virConnectPtr conn,
+ struct qemud_driver *driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ virCgroupPtr cgroup = NULL;
+
+ if (virCgroupHaveSupport() != 0)
+ return 0; /* Not supported, so claim success */
+
+ if (virCgroupForDomain(vm->def, "qemu", &cgroup) !=0 ) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to create cgroup for %s\n"),
+ vm->def->name);
+ goto cleanup;
+ }
+
+ virCgroupFree(&cgroup);
+ return 0;
+
+cleanup:
+ if (cgroup) {
+ virCgroupRemove(cgroup);
+ virCgroupFree(&cgroup);
+ }
+ return -1;
+}
+
+
+static int qemuRemoveCgroup(virConnectPtr conn,
+ struct qemud_driver *driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ virCgroupPtr cgroup;
+
+ if (virCgroupHaveSupport() != 0)
+ return 0; /* Not supported, so claim success */
+
+ if (virCgroupForDomain(vm->def, "qemu", &cgroup) != 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s\n"),
+ vm->def->name);
+ return -1;
+ }
+
+ virCgroupRemove(cgroup);
+ virCgroupFree(&cgroup);
+ return 0;
+}
+
+static int qemuAddToCgroup(void *data)
+{
+ virDomainDefPtr def = data;
+ virCgroupPtr cgroup = NULL;
+
+ if (virCgroupHaveSupport() != 0)
+ return 0; /* Not supported, so claim success */
+
+ if (virCgroupForDomain(def, "qemu", &cgroup) != 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s\n"),
+ def->name);
+ return -1;
+ }
+
+ if (virCgroupAddTask(cgroup, getpid()) < 0) {
+ virCgroupFree(&cgroup);
+ return -1;
+ }
+
+ virCgroupFree(&cgroup);
+ return 0;
+}
+
static int qemudStartVMDaemon(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm,
@@ -1160,6 +1234,8 @@ static int qemudStartVMDaemon(virConnect
return -1;
}
+ qemuRemoveCgroup(conn, driver, vm);
+
if (vm->def->graphics &&
vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
vm->def->graphics->data.vnc.autoport) {
@@ -1185,8 +1261,11 @@ static int qemudStartVMDaemon(virConnect
emulator = vm->def->emulator;
if (!emulator)
emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
- if (!emulator)
- return -1;
+ if (!emulator) {
+ close(vm->logfile);
+ vm->logfile = -1;
+ return -1;
+ }
/* Make sure the binary we are about to try exec'ing exists.
* Technically we could catch the exec() failure, but that's
@@ -1196,6 +1275,8 @@ static int qemudStartVMDaemon(virConnect
virReportSystemError(conn, errno,
_("Cannot find QEMU binary %s"),
emulator);
+ close(vm->logfile);
+ vm->logfile = -1;
return -1;
}
@@ -1205,7 +1286,14 @@ static int qemudStartVMDaemon(virConnect
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Cannot determine QEMU argv syntax %s"),
emulator);
- return -1;
+ close(vm->logfile);
+ vm->logfile = -1;
+ return -1;
+ }
+
+ if (qemuSetupCgroup(conn, driver, vm) < 0) {
+ close(vm->logfile);
+ vm->logfile = -1;
}
vm->def->id = driver->nextvmid++;
@@ -1249,9 +1337,10 @@ static int qemudStartVMDaemon(virConnect
for (i = 0 ; i < ntapfds ; i++)
FD_SET(tapfds[i], &keepfd);
- ret = virExec(conn, argv, progenv, &keepfd, &child,
- stdin_fd, &vm->logfile, &vm->logfile,
- VIR_EXEC_NONBLOCK | VIR_EXEC_DAEMON);
+ ret = virExecWithHook(conn, argv, progenv, &keepfd, &child,
+ stdin_fd, &vm->logfile, &vm->logfile,
+ VIR_EXEC_NONBLOCK | VIR_EXEC_DAEMON,
+ qemuAddToCgroup, vm->def);
/* wait for qemu process to to show up */
if (ret == 0) {
@@ -1278,6 +1367,8 @@ static int qemudStartVMDaemon(virConnect
"%s", _("Unable to daemonize QEMU
process"));
ret = -1;
}
+ } else {
+ qemuRemoveCgroup(conn, driver, vm);
}
if (ret == 0) {
@@ -1315,7 +1406,7 @@ static int qemudStartVMDaemon(virConnect
}
-static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
+static void qemudShutdownVMDaemon(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm) {
if (!virDomainIsActive(vm))
@@ -1351,6 +1442,9 @@ static void qemudShutdownVMDaemon(virCon
qemudLog(QEMUD_WARN, _("Failed to remove domain status for %s"),
vm->def->name);
}
+
+ qemuRemoveCgroup(conn, driver, vm);
+
vm->pid = -1;
vm->def->id = -1;
vm->state = VIR_DOMAIN_SHUTOFF;
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|