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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list