2010-12-16 10:10:54 -06:00
|
|
|
/*
|
|
|
|
* qemu_cgroup.c: QEMU cgroup management
|
|
|
|
*
|
2013-01-09 17:39:18 -06:00
|
|
|
* Copyright (C) 2006-2013 Red Hat, Inc.
|
2010-12-16 10:10:54 -06:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 17:30:55 -05:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 05:06:23 -05:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-12-16 10:10:54 -06:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_cgroup.h"
|
2011-07-20 21:10:31 -05:00
|
|
|
#include "qemu_domain.h"
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
#include "qemu_process.h"
|
2012-12-03 09:03:47 -06:00
|
|
|
#include "vircgroup.h"
|
2012-12-12 11:59:27 -06:00
|
|
|
#include "virlog.h"
|
2012-12-12 12:06:53 -06:00
|
|
|
#include "viralloc.h"
|
2012-12-13 12:21:53 -06:00
|
|
|
#include "virerror.h"
|
2012-12-13 11:44:57 -06:00
|
|
|
#include "virutil.h"
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
#include "domain_audit.h"
|
2010-12-16 10:10:54 -06:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
static const char *const defaultDeviceACL[] = {
|
|
|
|
"/dev/null", "/dev/full", "/dev/zero",
|
|
|
|
"/dev/random", "/dev/urandom",
|
|
|
|
"/dev/ptmx", "/dev/kvm", "/dev/kqemu",
|
2011-03-09 16:05:00 -06:00
|
|
|
"/dev/rtc", "/dev/hpet",
|
2010-12-16 10:10:54 -06:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
#define DEVICE_PTY_MAJOR 136
|
|
|
|
#define DEVICE_SND_MAJOR 116
|
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
bool qemuCgroupControllerActive(virQEMUDriverPtr driver,
|
2011-05-03 15:19:06 -05:00
|
|
|
int controller)
|
2010-12-16 10:10:54 -06:00
|
|
|
{
|
2013-01-10 15:03:14 -06:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
bool ret = false;
|
|
|
|
|
2010-12-16 10:10:54 -06:00
|
|
|
if (driver->cgroup == NULL)
|
2013-01-10 15:03:14 -06:00
|
|
|
goto cleanup;
|
2011-05-03 15:19:06 -05:00
|
|
|
if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST)
|
2013-01-10 15:03:14 -06:00
|
|
|
goto cleanup;
|
2011-06-06 14:07:11 -05:00
|
|
|
if (!virCgroupMounted(driver->cgroup, controller))
|
2013-01-10 15:03:14 -06:00
|
|
|
goto cleanup;
|
|
|
|
if (cfg->cgroupControllers & (1 << controller))
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return ret;
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
|
2011-02-15 20:18:40 -06:00
|
|
|
static int
|
2011-03-08 21:13:18 -06:00
|
|
|
qemuSetupDiskPathAllow(virDomainDiskDefPtr disk,
|
2011-02-15 20:18:40 -06:00
|
|
|
const char *path,
|
|
|
|
size_t depth ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
2010-12-16 10:10:54 -06:00
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData *data = opaque;
|
2010-12-16 10:10:54 -06:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
VIR_DEBUG("Process path %s for disk", path);
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDevicePath(data->cgroup, path,
|
|
|
|
(disk->readonly ? VIR_CGROUP_DEVICE_READ
|
|
|
|
: VIR_CGROUP_DEVICE_RW));
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupPath(data->vm, data->cgroup, "allow", path,
|
|
|
|
disk->readonly ? "r" : "rw", rc);
|
2011-02-16 18:05:54 -06:00
|
|
|
if (rc < 0) {
|
|
|
|
if (rc == -EACCES) { /* Get this for root squash NFS */
|
2010-12-16 10:10:54 -06:00
|
|
|
VIR_DEBUG("Ignoring EACCES for %s", path);
|
|
|
|
} else {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to allow access for disk path %s"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-17 15:22:24 -05:00
|
|
|
int qemuSetupDiskCgroup(virDomainObjPtr vm,
|
2010-12-16 10:10:54 -06:00
|
|
|
virCgroupPtr cgroup,
|
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData data = { vm, cgroup };
|
2010-12-16 10:10:54 -06:00
|
|
|
return virDomainDiskDefForeachPath(disk,
|
|
|
|
true,
|
|
|
|
qemuSetupDiskPathAllow,
|
2011-02-15 20:18:40 -06:00
|
|
|
&data);
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-15 20:18:40 -06:00
|
|
|
static int
|
|
|
|
qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
|
|
|
|
const char *path,
|
|
|
|
size_t depth ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
2010-12-16 10:10:54 -06:00
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData *data = opaque;
|
2010-12-16 10:10:54 -06:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
VIR_DEBUG("Process path %s for disk", path);
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupDenyDevicePath(data->cgroup, path,
|
|
|
|
VIR_CGROUP_DEVICE_RWM);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupPath(data->vm, data->cgroup, "deny", path, "rwm", rc);
|
2011-02-16 18:05:54 -06:00
|
|
|
if (rc < 0) {
|
|
|
|
if (rc == -EACCES) { /* Get this for root squash NFS */
|
2010-12-16 10:10:54 -06:00
|
|
|
VIR_DEBUG("Ignoring EACCES for %s", path);
|
|
|
|
} else {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to deny access for disk path %s"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-17 15:22:24 -05:00
|
|
|
int qemuTeardownDiskCgroup(virDomainObjPtr vm,
|
2010-12-16 10:10:54 -06:00
|
|
|
virCgroupPtr cgroup,
|
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData data = { vm, cgroup };
|
2010-12-16 10:10:54 -06:00
|
|
|
return virDomainDiskDefForeachPath(disk,
|
|
|
|
true,
|
|
|
|
qemuTeardownDiskPathDeny,
|
2011-02-15 20:18:40 -06:00
|
|
|
&data);
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-15 20:18:40 -06:00
|
|
|
static int
|
|
|
|
qemuSetupChardevCgroup(virDomainDefPtr def,
|
|
|
|
virDomainChrDefPtr dev,
|
|
|
|
void *opaque)
|
2010-12-16 10:10:54 -06:00
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData *data = opaque;
|
2010-12-16 10:10:54 -06:00
|
|
|
int rc;
|
|
|
|
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 16:45:01 -06:00
|
|
|
if (dev->source.type != VIR_DOMAIN_CHR_TYPE_DEV)
|
2010-12-16 10:10:54 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 16:45:01 -06:00
|
|
|
VIR_DEBUG("Process path '%s' for disk", dev->source.data.file.path);
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDevicePath(data->cgroup, dev->source.data.file.path,
|
|
|
|
VIR_CGROUP_DEVICE_RW);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupPath(data->vm, data->cgroup, "allow",
|
|
|
|
dev->source.data.file.path, "rw", rc);
|
2011-02-16 18:05:54 -06:00
|
|
|
if (rc < 0) {
|
2010-12-16 10:10:54 -06:00
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to allow device %s for %s"),
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 16:45:01 -06:00
|
|
|
dev->source.data.file.path, def->name);
|
2010-12-16 10:10:54 -06:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-14 16:11:44 -06:00
|
|
|
int qemuSetupHostUsbDeviceCgroup(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
|
2010-12-16 10:10:54 -06:00
|
|
|
const char *path,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData *data = opaque;
|
2010-12-16 10:10:54 -06:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
VIR_DEBUG("Process path '%s' for USB device", path);
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDevicePath(data->cgroup, path,
|
|
|
|
VIR_CGROUP_DEVICE_RW);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupPath(data->vm, data->cgroup, "allow", path, "rw", rc);
|
2011-02-16 18:05:54 -06:00
|
|
|
if (rc < 0) {
|
2010-12-16 10:10:54 -06:00
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to allow device %s"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
int qemuSetupCgroup(virQEMUDriverPtr driver,
|
2012-05-12 07:53:15 -05:00
|
|
|
virDomainObjPtr vm,
|
2012-09-14 02:47:00 -05:00
|
|
|
virBitmapPtr nodemask)
|
2010-12-16 10:10:54 -06:00
|
|
|
{
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
int rc;
|
|
|
|
unsigned int i;
|
2013-01-10 15:03:14 -06:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2010-12-16 10:10:54 -06:00
|
|
|
const char *const *deviceACL =
|
2013-01-10 15:03:14 -06:00
|
|
|
cfg->cgroupDeviceACL ?
|
|
|
|
(const char *const *)cfg->cgroupDeviceACL :
|
2010-12-16 10:10:54 -06:00
|
|
|
defaultDeviceACL;
|
|
|
|
|
|
|
|
if (driver->cgroup == NULL)
|
2013-01-10 15:03:14 -06:00
|
|
|
goto done; /* Not supported, so claim success */
|
2010-12-16 10:10:54 -06:00
|
|
|
|
|
|
|
rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 1);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to create cgroup for %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
2011-02-15 20:18:40 -06:00
|
|
|
qemuCgroupData data = { vm, cgroup };
|
2010-12-16 10:10:54 -06:00
|
|
|
rc = virCgroupDenyAllDevices(cgroup);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroup(vm, cgroup, "deny", "all", rc == 0);
|
2010-12-16 10:10:54 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
if (rc == -EPERM) {
|
2011-05-09 04:24:09 -05:00
|
|
|
VIR_WARN("Group devices ACL is not accessible, disabling whitelisting");
|
2010-12-16 10:10:54 -06:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to deny all devices for %s"), vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->ndisks ; i++) {
|
2013-02-20 16:34:48 -06:00
|
|
|
if (qemuSetupDiskCgroup(vm, cgroup, vm->def->disks[i]) < 0)
|
2010-12-16 10:10:54 -06:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR,
|
|
|
|
VIR_CGROUP_DEVICE_RW);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupMajor(vm, cgroup, "allow", DEVICE_PTY_MAJOR,
|
|
|
|
"pty", "rw", rc == 0);
|
2010-12-16 10:10:54 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc, "%s",
|
|
|
|
_("unable to allow /dev/pts/ devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-02-25 12:55:44 -06:00
|
|
|
if (vm->def->nsounds &&
|
|
|
|
(!vm->def->ngraphics ||
|
|
|
|
((vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
|
2013-01-10 15:03:14 -06:00
|
|
|
cfg->vncAllowHostAudio) ||
|
2011-02-25 12:55:44 -06:00
|
|
|
(vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL)))) {
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR,
|
|
|
|
VIR_CGROUP_DEVICE_RW);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupMajor(vm, cgroup, "allow", DEVICE_SND_MAJOR,
|
|
|
|
"sound", "rw", rc == 0);
|
2010-12-16 10:10:54 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc, "%s",
|
|
|
|
_("unable to allow /dev/snd/ devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; deviceACL[i] != NULL ; i++) {
|
2011-03-08 21:13:18 -06:00
|
|
|
rc = virCgroupAllowDevicePath(cgroup, deviceACL[i],
|
|
|
|
VIR_CGROUP_DEVICE_RW);
|
Move qemu_audit.h helpers into shared code
The LXC and UML drivers can both make use of auditing. Move
the qemu_audit.{c,h} files to src/conf/domain_audit.{c,h}
* src/conf/domain_audit.c: Rename from src/qemu/qemu_audit.c
* src/conf/domain_audit.h: Rename from src/qemu/qemu_audit.h
* src/Makefile.am: Remove qemu_audit.{c,h}, add domain_audit.{c,h}
* src/qemu/qemu_audit.h, src/qemu/qemu_cgroup.c,
src/qemu/qemu_command.c, src/qemu/qemu_driver.c,
src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c,
src/qemu/qemu_process.c: Update for changed audit API names
2011-07-04 05:56:13 -05:00
|
|
|
virDomainAuditCgroupPath(vm, cgroup, "allow", deviceACL[i], "rw", rc);
|
2010-12-16 10:10:54 -06:00
|
|
|
if (rc < 0 &&
|
|
|
|
rc != -ENOENT) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("unable to allow device %s"),
|
|
|
|
deviceACL[i]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainChrDefForeach(vm->def,
|
|
|
|
true,
|
|
|
|
qemuSetupChardevCgroup,
|
2011-02-15 20:18:40 -06:00
|
|
|
&data) < 0)
|
2010-12-16 10:10:54 -06:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->nhostdevs; i++) {
|
|
|
|
virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
|
2013-01-14 16:11:44 -06:00
|
|
|
virUSBDevicePtr usb;
|
2010-12-16 10:10:54 -06:00
|
|
|
|
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
|
|
|
continue;
|
|
|
|
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
|
|
|
|
continue;
|
2012-10-04 09:18:16 -05:00
|
|
|
if (hostdev->missing)
|
|
|
|
continue;
|
2010-12-16 10:10:54 -06:00
|
|
|
|
2013-01-14 16:11:44 -06:00
|
|
|
if ((usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device,
|
|
|
|
NULL)) == NULL)
|
2010-12-16 10:10:54 -06:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-01-14 16:11:44 -06:00
|
|
|
if (virUSBDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup,
|
|
|
|
&data) < 0) {
|
|
|
|
virUSBDeviceFree(usb);
|
2010-12-16 10:10:54 -06:00
|
|
|
goto cleanup;
|
2013-02-05 09:14:46 -06:00
|
|
|
}
|
2013-01-14 16:11:44 -06:00
|
|
|
virUSBDeviceFree(usb);
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-31 22:41:33 -05:00
|
|
|
if (vm->def->blkio.weight != 0) {
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
2011-02-08 00:59:38 -06:00
|
|
|
rc = virCgroupSetBlkioWeight(cgroup, vm->def->blkio.weight);
|
2012-10-17 04:23:12 -05:00
|
|
|
if (rc != 0) {
|
2011-02-08 00:59:38 -06:00
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set io weight for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-03-31 22:41:33 -05:00
|
|
|
} else {
|
2012-07-18 10:22:03 -05:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Block I/O tuning is not available on this host"));
|
2011-11-08 05:00:34 -06:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->def->blkio.ndevices) {
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
|
|
|
for (i = 0; i < vm->def->blkio.ndevices; i++) {
|
|
|
|
virBlkioDeviceWeightPtr dw = &vm->def->blkio.devices[i];
|
qemu: filter blkio 0-device-weight at two other places
filter 0-device-weight when:
- getting blkio parameters with --config
- starting up a domain
When testing with blkio, I found these issues:
(dom is down)
virsh blkiotune dom --device-weights /dev/sda,300,/dev/sdb,500
virsh blkiotune dom --device-weights /dev/sda,300,/dev/sdb,0
virsh blkiotune dom
weight : 800
device_weight : /dev/sda,200,/dev/sdb,0
# issue 1: shows 0 device weight of /dev/sdb that may confuse user
(continued)
virsh start dom
# issue 2: If /dev/sdb doesn't exist, libvirt refuses to bring the
# dom up because it wants to set the device weight to 0 of a
# non-existing device. Since 0 means no weight-limit, we really don't
# have to set it.
2011-11-29 20:11:08 -06:00
|
|
|
if (!dw->weight)
|
|
|
|
continue;
|
2011-11-08 05:00:34 -06:00
|
|
|
rc = virCgroupSetBlkioDeviceWeight(cgroup, dw->path,
|
|
|
|
dw->weight);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set io device weight "
|
|
|
|
"for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
maint: don't permit format strings without %
Any time we have a string with no % passed through gettext, a
translator can inject a % to cause a stack overread. When there
is nothing to format, it's easier to ask for a string that cannot
be used as a formatter, by using a trivial "%s" format instead.
In the past, we have used --disable-nls to catch some of the
offenders, but that doesn't get run very often, and many more
uses have crept in. Syntax check to the rescue!
The syntax check can catch uses such as
virReportError(code,
_("split "
"string"));
by using a sed script to fold context lines into one pattern
space before checking for a string without %.
This patch is just mechanical insertion of %s; there are probably
several messages touched by this patch where we would be better
off giving the user more information than a fixed string.
* cfg.mk (sc_prohibit_diagnostic_without_format): New rule.
* src/datatypes.c (virUnrefConnect, virGetDomain)
(virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface)
(virUnrefInterface, virGetStoragePool, virUnrefStoragePool)
(virGetStorageVol, virUnrefStorageVol, virGetNodeDevice)
(virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter)
(virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper.
* src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters)
(lxcDomainGetBlkioParameters): Likewise.
* src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML)
(virDomainDiskDefParseXML, virDomainGraphicsDefParseXML):
Likewise.
* src/conf/network_conf.c (virNetworkDNSHostsDefParseXML)
(virNetworkDefParseXML): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterIsValidChainName):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple)
(virNWFilterVarAccessParse): Likewise.
* src/libvirt.c (virDomainSave, virDomainSaveFlags)
(virDomainRestore, virDomainRestoreFlags)
(virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML)
(virDomainCoreDump, virDomainGetXMLDesc)
(virDomainMigrateVersion1, virDomainMigrateVersion2)
(virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2)
(virStreamSendAll, virStreamRecvAll)
(virDomainSnapshotGetXMLDesc): Likewise.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterDHCPSnoopReq): Likewise.
* src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise.
* src/openvz/openvz_util.c (openvzKBPerPages): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise.
* src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr)
(qemuBuildCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity):
Likewise.
* src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX)
(virNetSocketSendFD, virNetSocketRecvFD): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskBuildPool): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemProbe)
(virStorageBackendFileSystemBuild): Likewise.
* src/storage/storage_backend_rbd.c
(virStorageBackendRBDOpenRADOSConn): Likewise.
* src/storage/storage_driver.c (storageVolumeResize): Likewise.
* src/test/test_driver.c (testInterfaceChangeBegin)
(testInterfaceChangeCommit, testInterfaceChangeRollback):
Likewise.
* src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise.
* src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr):
Likewise.
* src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk)
(xenFormatXM): Likewise.
2012-07-23 15:33:08 -05:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2012-07-18 10:22:03 -05:00
|
|
|
_("Block I/O tuning is not available on this host"));
|
2011-11-08 05:00:34 -06:00
|
|
|
goto cleanup;
|
2011-02-08 00:59:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-17 11:38:47 -05:00
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
|
|
|
|
unsigned long long hard_limit = vm->def->mem.hard_limit;
|
|
|
|
|
|
|
|
if (!hard_limit) {
|
qemu: Relax hard RSS limit
Currently, if there's no hard memory limit defined for a domain,
libvirt tries to calculate one, based on domain definition and magic
equation and set it upon the domain startup. The rationale behind was,
if there's a memory leak or exploit in qemu, we should prevent the
host system trashing. However, the equation was too tightening, as it
didn't reflect what the kernel counts into the memory used by a
process. Since many hosts do have a swap, nobody hasn't noticed
anything, because if hard memory limit is reached, process can
continue allocating memory on a swap. However, if there is no swap on
the host, the process gets killed by OOM killer. In our case, the qemu
process it is.
To prevent this, we need to relax the hard RSS limit. Moreover, we
should reflect more precisely the kernel way of accounting the memory
for process. That is, even the kernel caches are counted within the
memory used by a process (within cgroups at least). Hence the magic
equation has to be changed:
limit = 1.5 * (domain memory + total video memory) + (32MB for cache
per each disk) + 200MB
2013-01-08 03:15:49 -06:00
|
|
|
/* If there is no hard_limit set, set a reasonable one to avoid
|
2013-01-09 17:39:18 -06:00
|
|
|
* system thrashing caused by exploited qemu. A 'reasonable
|
|
|
|
* limit' has been chosen:
|
qemu: Relax hard RSS limit
Currently, if there's no hard memory limit defined for a domain,
libvirt tries to calculate one, based on domain definition and magic
equation and set it upon the domain startup. The rationale behind was,
if there's a memory leak or exploit in qemu, we should prevent the
host system trashing. However, the equation was too tightening, as it
didn't reflect what the kernel counts into the memory used by a
process. Since many hosts do have a swap, nobody hasn't noticed
anything, because if hard memory limit is reached, process can
continue allocating memory on a swap. However, if there is no swap on
the host, the process gets killed by OOM killer. In our case, the qemu
process it is.
To prevent this, we need to relax the hard RSS limit. Moreover, we
should reflect more precisely the kernel way of accounting the memory
for process. That is, even the kernel caches are counted within the
memory used by a process (within cgroups at least). Hence the magic
equation has to be changed:
limit = 1.5 * (domain memory + total video memory) + (32MB for cache
per each disk) + 200MB
2013-01-08 03:15:49 -06:00
|
|
|
* (1 + k) * (domain memory + total video memory) + (32MB for
|
|
|
|
* cache per each disk) + F
|
|
|
|
* where k = 0.5 and F = 200MB. The cache for disks is important as
|
|
|
|
* kernel cache on the host side counts into the RSS limit. */
|
2012-07-17 11:38:47 -05:00
|
|
|
hard_limit = vm->def->mem.max_balloon;
|
|
|
|
for (i = 0; i < vm->def->nvideos; i++)
|
|
|
|
hard_limit += vm->def->videos[i]->vram;
|
qemu: Relax hard RSS limit
Currently, if there's no hard memory limit defined for a domain,
libvirt tries to calculate one, based on domain definition and magic
equation and set it upon the domain startup. The rationale behind was,
if there's a memory leak or exploit in qemu, we should prevent the
host system trashing. However, the equation was too tightening, as it
didn't reflect what the kernel counts into the memory used by a
process. Since many hosts do have a swap, nobody hasn't noticed
anything, because if hard memory limit is reached, process can
continue allocating memory on a swap. However, if there is no swap on
the host, the process gets killed by OOM killer. In our case, the qemu
process it is.
To prevent this, we need to relax the hard RSS limit. Moreover, we
should reflect more precisely the kernel way of accounting the memory
for process. That is, even the kernel caches are counted within the
memory used by a process (within cgroups at least). Hence the magic
equation has to be changed:
limit = 1.5 * (domain memory + total video memory) + (32MB for cache
per each disk) + 200MB
2013-01-08 03:15:49 -06:00
|
|
|
hard_limit = hard_limit * 1.5 + 204800;
|
|
|
|
hard_limit += vm->def->ndisks * 32768;
|
2012-07-17 11:38:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupSetMemoryHardLimit(cgroup, hard_limit);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set memory hard limit for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (vm->def->mem.soft_limit != 0) {
|
|
|
|
rc = virCgroupSetMemorySoftLimit(cgroup, vm->def->mem.soft_limit);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set memory soft limit for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
2012-07-17 11:38:47 -05:00
|
|
|
}
|
2010-12-16 10:10:54 -06:00
|
|
|
|
2012-07-17 11:38:47 -05:00
|
|
|
if (vm->def->mem.swap_hard_limit != 0) {
|
|
|
|
rc = virCgroupSetMemSwapHardLimit(cgroup, vm->def->mem.swap_hard_limit);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set swap hard limit for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
}
|
2012-07-17 11:38:47 -05:00
|
|
|
} else if (vm->def->mem.hard_limit != 0 ||
|
|
|
|
vm->def->mem.soft_limit != 0 ||
|
|
|
|
vm->def->mem.swap_hard_limit != 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Memory cgroup is not available on this host"));
|
|
|
|
} else {
|
|
|
|
VIR_WARN("Could not autoset a RSS limit for domain %s", vm->def->name);
|
2010-12-16 10:10:54 -06:00
|
|
|
}
|
|
|
|
|
2011-03-31 22:41:33 -05:00
|
|
|
if (vm->def->cputune.shares != 0) {
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
|
2011-03-29 08:41:25 -05:00
|
|
|
rc = virCgroupSetCpuShares(cgroup, vm->def->cputune.shares);
|
2012-10-17 04:23:12 -05:00
|
|
|
if (rc != 0) {
|
2011-03-29 08:41:25 -05:00
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set io cpu shares for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-03-31 22:41:33 -05:00
|
|
|
} else {
|
2012-07-18 10:22:03 -05:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("CPU tuning is not available on this host"));
|
2011-03-29 08:41:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 07:53:15 -05:00
|
|
|
if ((vm->def->numatune.memory.nodemask ||
|
|
|
|
(vm->def->numatune.memory.placement_mode ==
|
|
|
|
VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO)) &&
|
2011-12-20 02:34:59 -06:00
|
|
|
vm->def->numatune.memory.mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT &&
|
|
|
|
qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
|
2012-05-12 07:53:15 -05:00
|
|
|
char *mask = NULL;
|
|
|
|
if (vm->def->numatune.memory.placement_mode ==
|
|
|
|
VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO)
|
2012-09-14 02:47:00 -05:00
|
|
|
mask = virBitmapFormat(nodemask);
|
2012-05-12 07:53:15 -05:00
|
|
|
else
|
2012-09-14 02:47:00 -05:00
|
|
|
mask = virBitmapFormat(vm->def->numatune.memory.nodemask);
|
2011-12-20 02:34:59 -06:00
|
|
|
if (!mask) {
|
2012-07-18 10:22:03 -05:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to convert memory nodemask"));
|
2011-12-20 02:34:59 -06:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupSetCpusetMems(cgroup, mask);
|
|
|
|
VIR_FREE(mask);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to set cpuset.mems for domain %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2010-12-16 10:10:54 -06:00
|
|
|
done:
|
2013-01-10 15:03:14 -06:00
|
|
|
virObjectUnref(cfg);
|
2010-12-16 10:10:54 -06:00
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
2013-01-10 15:03:14 -06:00
|
|
|
virObjectUnref(cfg);
|
2010-12-16 10:10:54 -06:00
|
|
|
if (cgroup) {
|
|
|
|
virCgroupRemove(cgroup);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-07-20 21:10:31 -05:00
|
|
|
int qemuSetupCgroupVcpuBW(virCgroupPtr cgroup, unsigned long long period,
|
|
|
|
long long quota)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned long long old_period;
|
|
|
|
|
|
|
|
if (period == 0 && quota == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (period) {
|
|
|
|
/* get old period, and we can rollback if set quota failed */
|
|
|
|
rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
2011-07-21 04:32:57 -05:00
|
|
|
"%s", _("Unable to get cpu bandwidth period"));
|
2011-07-20 21:10:31 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupSetCpuCfsPeriod(cgroup, period);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
2011-07-21 04:32:57 -05:00
|
|
|
"%s", _("Unable to set cpu bandwidth period"));
|
2011-07-20 21:10:31 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quota) {
|
|
|
|
rc = virCgroupSetCpuCfsQuota(cgroup, quota);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
2011-07-21 04:32:57 -05:00
|
|
|
"%s", _("Unable to set cpu bandwidth quota"));
|
2011-07-20 21:10:31 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (period) {
|
|
|
|
rc = virCgroupSetCpuCfsPeriod(cgroup, old_period);
|
|
|
|
if (rc < 0)
|
2012-07-10 16:43:08 -05:00
|
|
|
virReportSystemError(-rc, "%s",
|
2012-07-05 20:53:11 -05:00
|
|
|
_("Unable to rollback cpu bandwidth period"));
|
2011-07-20 21:10:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:30 -05:00
|
|
|
int qemuSetupCgroupVcpuPin(virCgroupPtr cgroup,
|
|
|
|
virDomainVcpuPinDefPtr *vcpupin,
|
|
|
|
int nvcpupin,
|
|
|
|
int vcpuid)
|
|
|
|
{
|
2012-08-21 04:18:33 -05:00
|
|
|
int i;
|
2012-08-21 04:18:30 -05:00
|
|
|
|
|
|
|
for (i = 0; i < nvcpupin; i++) {
|
|
|
|
if (vcpuid == vcpupin[i]->vcpuid) {
|
2012-10-17 09:39:31 -05:00
|
|
|
return qemuSetupCgroupEmulatorPin(cgroup, vcpupin[i]->cpumask);
|
2012-08-21 04:18:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:33 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuSetupCgroupEmulatorPin(virCgroupPtr cgroup,
|
2012-10-17 09:39:31 -05:00
|
|
|
virBitmapPtr cpumask)
|
2012-08-21 04:18:33 -05:00
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
char *new_cpus = NULL;
|
|
|
|
|
2012-10-17 09:39:31 -05:00
|
|
|
new_cpus = virBitmapFormat(cpumask);
|
2012-08-21 04:18:33 -05:00
|
|
|
if (!new_cpus) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to convert cpu mask"));
|
|
|
|
rc = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupSetCpusetCpus(cgroup, new_cpus);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
"%s",
|
|
|
|
_("Unable to set cpuset.cpus"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:30 -05:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(new_cpus);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
int qemuSetupCgroupForVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm)
|
2011-07-20 21:10:31 -05:00
|
|
|
{
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
virCgroupPtr cgroup_vcpu = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2012-08-21 04:18:30 -05:00
|
|
|
virDomainDefPtr def = vm->def;
|
2011-07-20 21:10:31 -05:00
|
|
|
int rc;
|
2012-09-04 08:26:46 -05:00
|
|
|
unsigned int i, j;
|
2011-07-20 21:10:31 -05:00
|
|
|
unsigned long long period = vm->def->cputune.period;
|
|
|
|
long long quota = vm->def->cputune.quota;
|
|
|
|
|
2012-08-29 08:30:34 -05:00
|
|
|
if ((period || quota) &&
|
2012-08-29 09:08:59 -05:00
|
|
|
(!driver->cgroup ||
|
|
|
|
!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU))) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("cgroup cpu is required for scheduler tuning"));
|
2012-08-21 04:18:41 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-29 09:08:59 -05:00
|
|
|
/* We are trying to setup cgroups for CPU pinning, which can also be done
|
|
|
|
* with virProcessInfoSetAffinity, thus the lack of cgroups is not fatal
|
|
|
|
* here.
|
|
|
|
*/
|
|
|
|
if (driver->cgroup == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2011-07-20 21:10:31 -05:00
|
|
|
rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to find cgroup for %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
|
2012-08-21 04:18:42 -05:00
|
|
|
/* If we don't know VCPU<->PID mapping or all vcpu runs in the same
|
2011-07-21 04:32:57 -05:00
|
|
|
* thread, we cannot control each vcpu.
|
2011-07-20 21:10:31 -05:00
|
|
|
*/
|
2012-08-24 10:31:47 -05:00
|
|
|
VIR_WARN("Unable to get vcpus' pids.");
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return 0;
|
2011-07-20 21:10:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < priv->nvcpupids; i++) {
|
|
|
|
rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 1);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to create vcpu cgroup for %s(vcpu:"
|
|
|
|
" %d)"),
|
|
|
|
vm->def->name, i);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* move the thread for vcpu to sub dir */
|
|
|
|
rc = virCgroupAddTask(cgroup_vcpu, priv->vcpupids[i]);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("unable to add vcpu %d task %d to cgroup"),
|
|
|
|
i, priv->vcpupids[i]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (period || quota) {
|
2012-08-21 04:18:41 -05:00
|
|
|
if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
|
|
|
|
goto cleanup;
|
2011-07-20 21:10:31 -05:00
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:30 -05:00
|
|
|
/* Set vcpupin in cgroup if vcpupin xml is provided */
|
2012-09-04 08:26:46 -05:00
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
|
|
|
|
/* find the right CPU to pin, otherwise
|
|
|
|
* qemuSetupCgroupVcpuPin will fail. */
|
|
|
|
for (j = 0; j < def->cputune.nvcpupin; j++) {
|
|
|
|
if (def->cputune.vcpupin[j]->vcpuid != i)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (qemuSetupCgroupVcpuPin(cgroup_vcpu,
|
|
|
|
def->cputune.vcpupin,
|
|
|
|
def->cputune.nvcpupin,
|
|
|
|
i) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-21 04:18:30 -05:00
|
|
|
|
2011-07-20 21:10:31 -05:00
|
|
|
virCgroupFree(&cgroup_vcpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-08-21 04:18:26 -05:00
|
|
|
if (cgroup_vcpu) {
|
|
|
|
virCgroupRemove(cgroup_vcpu);
|
|
|
|
virCgroupFree(&cgroup_vcpu);
|
|
|
|
}
|
|
|
|
|
2011-07-20 21:10:31 -05:00
|
|
|
if (cgroup) {
|
|
|
|
virCgroupRemove(cgroup);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
int qemuSetupCgroupForEmulator(virQEMUDriverPtr driver,
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
virBitmapPtr nodemask)
|
2012-08-21 04:18:26 -05:00
|
|
|
{
|
2012-10-17 09:39:31 -05:00
|
|
|
virBitmapPtr cpumask = NULL;
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
virBitmapPtr cpumap = NULL;
|
2012-08-21 04:18:26 -05:00
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
virCgroupPtr cgroup_emulator = NULL;
|
2012-08-21 04:18:33 -05:00
|
|
|
virDomainDefPtr def = vm->def;
|
2012-08-21 04:18:42 -05:00
|
|
|
unsigned long long period = vm->def->cputune.emulator_period;
|
|
|
|
long long quota = vm->def->cputune.emulator_quota;
|
2012-08-21 04:18:26 -05:00
|
|
|
int rc, i;
|
|
|
|
|
2012-08-29 09:08:59 -05:00
|
|
|
if ((period || quota) &&
|
|
|
|
(!driver->cgroup ||
|
|
|
|
!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU))) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("cgroup cpu is required for scheduler tuning"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:26 -05:00
|
|
|
if (driver->cgroup == NULL)
|
|
|
|
return 0; /* Not supported, so claim success */
|
|
|
|
|
|
|
|
rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to find cgroup for %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 1);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to create emulator cgroup for %s"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
|
2013-02-27 10:51:04 -06:00
|
|
|
if (i != VIR_CGROUP_CONTROLLER_CPU &&
|
|
|
|
i != VIR_CGROUP_CONTROLLER_CPUACCT &&
|
|
|
|
i != VIR_CGROUP_CONTROLLER_CPUSET)
|
|
|
|
continue;
|
|
|
|
|
2012-08-29 09:08:59 -05:00
|
|
|
if (!qemuCgroupControllerActive(driver, i))
|
2012-08-21 04:18:26 -05:00
|
|
|
continue;
|
|
|
|
rc = virCgroupMoveTask(cgroup, cgroup_emulator, i);
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to move tasks from domain cgroup to "
|
|
|
|
"emulator cgroup in controller %d for %s"),
|
|
|
|
i, vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
|
|
|
|
if (!(cpumap = qemuPrepareCpumap(driver, nodemask)))
|
|
|
|
goto cleanup;
|
|
|
|
cpumask = cpumap;
|
|
|
|
} else if (def->cputune.emulatorpin) {
|
2012-10-17 09:39:31 -05:00
|
|
|
cpumask = def->cputune.emulatorpin->cpumask;
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
} else if (def->cpumask) {
|
2012-10-17 09:39:31 -05:00
|
|
|
cpumask = def->cpumask;
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
}
|
2012-10-17 09:39:31 -05:00
|
|
|
|
|
|
|
if (cpumask) {
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
|
|
|
|
rc = qemuSetupCgroupEmulatorPin(cgroup_emulator, cpumask);
|
|
|
|
if (rc < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
cpumask = NULL; /* sanity */
|
2012-09-06 05:13:52 -05:00
|
|
|
}
|
2012-08-21 04:18:33 -05:00
|
|
|
|
2012-08-21 04:18:42 -05:00
|
|
|
if (period || quota) {
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
|
2012-09-06 05:13:52 -05:00
|
|
|
if ((rc = qemuSetupCgroupVcpuBW(cgroup_emulator, period,
|
|
|
|
quota)) < 0)
|
2012-08-21 04:18:42 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-21 04:18:26 -05:00
|
|
|
virCgroupFree(&cgroup_emulator);
|
|
|
|
virCgroupFree(&cgroup);
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
virBitmapFree(cpumap);
|
2012-08-21 04:18:26 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
cleanup:
|
qemu: Keep the affinity when creating cgroup for emulator thread
When the cpu placement model is "auto", it sets the affinity for
domain process with the advisory nodeset from numad, however,
creating cgroup for the domain process (called emulator thread
in some contexts) later overrides that with pinning it to all
available pCPUs.
How to reproduce:
* Configure the domain with "auto" placement for <vcpu>, e.g.
<vcpu placement='auto'>4</vcpu>
* % virsh start dom
* % cat /proc/$dompid/status
Though the emulator cgroup cause conflicts, but we can't simply
prohibit creating it, as other tunables are still useful, such
as "emulator_period", which is used by API
virDomainSetSchedulerParameter. So this patch doesn't prohibit
creating the emulator cgroup, but inherit the nodeset from numad,
and reset the affinity for domain process.
* src/qemu/qemu_cgroup.h: Modify definition of qemuSetupCgroupForEmulator
to accept the passed nodenet
* src/qemu/qemu_cgroup.c: Set the affinity with the passed nodeset
2012-10-24 04:27:56 -05:00
|
|
|
virBitmapFree(cpumap);
|
|
|
|
|
2012-08-21 04:18:26 -05:00
|
|
|
if (cgroup_emulator) {
|
|
|
|
virCgroupRemove(cgroup_emulator);
|
|
|
|
virCgroupFree(&cgroup_emulator);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cgroup) {
|
|
|
|
virCgroupRemove(cgroup);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2010-12-16 10:10:54 -06:00
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
int qemuRemoveCgroup(virQEMUDriverPtr driver,
|
2010-12-16 10:10:54 -06:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
int quiet)
|
|
|
|
{
|
|
|
|
virCgroupPtr cgroup;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (driver->cgroup == NULL)
|
|
|
|
return 0; /* Not supported, so claim success */
|
|
|
|
|
|
|
|
rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0);
|
|
|
|
if (rc != 0) {
|
|
|
|
if (!quiet)
|
2012-07-18 10:22:03 -05:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to find cgroup for %s"),
|
|
|
|
vm->def->name);
|
2010-12-16 10:10:54 -06:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupRemove(cgroup);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-11-28 10:43:10 -06:00
|
|
|
int qemuAddToCgroup(virQEMUDriverPtr driver,
|
2010-12-16 10:10:54 -06:00
|
|
|
virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (driver->cgroup == NULL)
|
|
|
|
return 0; /* Not supported, so claim success */
|
|
|
|
|
|
|
|
rc = virCgroupForDomain(driver->cgroup, def->name, &cgroup, 0);
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("unable to find cgroup for domain %s"),
|
|
|
|
def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virCgroupAddTask(cgroup, getpid());
|
|
|
|
if (rc != 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("unable to add domain %s task %d to cgroup"),
|
|
|
|
def->name, getpid());
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return ret;
|
|
|
|
}
|