---
src/qemu/qemu_cgroup.c | 14 ++
src/qemu/qemu_driver.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 321 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 49307b2..99714ab 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -381,6 +381,20 @@ int qemuSetupCgroup(struct qemud_driver *driver,
vm->def->name);
goto cleanup;
}
+ rc = virCgroupSetCpusetHardwall(cgroup, vm->def->numatune.strict);
+ if (rc != 0) {
+ virReportSystemError(-rc,
+ _("Unable to set cpuset.mem_hardwall for domain
%s"),
+ vm->def->name);
+ goto cleanup;
+ }
+ rc = virCgroupSetCpusetMemExclusive(cgroup,
vm->def->numatune.exclusive);
+ if (rc != 0) {
+ virReportSystemError(-rc,
+ _("Unable to set cpuset.mem_exclusive for
domain %s"),
+ vm->def->name);
+ goto cleanup;
+ }
} else {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unable to set numa for domain %s since cpuset cgroup
is "
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5e49ff4..be9697c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -94,6 +94,8 @@
#define QEMU_NB_MEM_PARAM 3
+#define QEMU_NB_NUMA_PARAM 2
+
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
@@ -6518,6 +6520,309 @@ cleanup:
return ret;
}
+static int qemuDomainSetNumaParameters(virDomainPtr dom,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ int i;
+ virDomainDefPtr persistentDef = NULL;
+ virCgroupPtr group = NULL;
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+ bool isActive;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (vm == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("No such domain %s"), dom->uuid);
+ goto cleanup;
+ }
+
+ isActive = virDomainObjIsActive(vm);
+
+ if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ flags = VIR_DOMAIN_AFFECT_LIVE;
+ else
+ flags = VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ if (!isActive) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cgroup cpuset controller is not
mounted"));
+ goto cleanup;
+ }
+
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) !=
0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot find cgroup for domain %s"),
vm->def->name);
+ goto cleanup;
+ }
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!vm->persistent) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot change persistent config of a transient
domain"));
+ goto cleanup;
+ }
+ if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
+ goto cleanup;
+ }
+
+ ret = 0;
+ for (i = 0; i < nparams; i++) {
+ virTypedParameterPtr param = ¶ms[i];
+
+ if (STREQ(param->field, VIR_DOMAIN_NUMA_STRICT)) {
+ int rc;
+ if (param->type != VIR_TYPED_PARAM_ULLONG) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid type for numa strict tunable, expected a
'ullong'"));
+ ret = -1;
+ continue;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ rc = virCgroupSetCpusetHardwall(group, params[i].value.i);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to set memory hard_limit
tunable"));
+ ret = -1;
+ }
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ persistentDef->numatune.strict = params[i].value.i;
+ }
+ } else if (STREQ(param->field, VIR_DOMAIN_NUMA_EXCLUSIVE)) {
+ int rc;
+ if (param->type != VIR_TYPED_PARAM_ULLONG) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid type for numa strict tunable, expected a
'ullong'"));
+ ret = -1;
+ continue;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ rc = virCgroupSetCpusetMemExclusive(group, params[i].value.i);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to set memory hard_limit
tunable"));
+ ret = -1;
+ }
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ persistentDef->numatune.exclusive = params[i].value.i;
+ }
+ } else {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Parameter `%s' not supported"),
param->field);
+ ret = -1;
+ }
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
+ ret = -1;
+ }
+
+cleanup:
+ virCgroupFree(&group);
+ if (vm)
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
+ return ret;
+}
+
+static int qemuDomainGetNumaParameters(virDomainPtr dom,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ int i;
+ virCgroupPtr group = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainDefPtr persistentDef = NULL;
+ unsigned long long val;
+ int ret = -1;
+ int rc;
+ bool isActive;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ qemuDriverLock(driver);
+
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (vm == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("No such domain %s"), dom->uuid);
+ goto cleanup;
+ }
+
+ isActive = virDomainObjIsActive(vm);
+
+ if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ flags = VIR_DOMAIN_AFFECT_LIVE;
+ else
+ flags = VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ if (!isActive) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cgroup memory controller is not
mounted"));
+ goto cleanup;
+ }
+
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) !=
0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot find cgroup for domain %s"),
vm->def->name);
+ goto cleanup;
+ }
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!vm->persistent) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot change persistent config of a transient
domain"));
+ goto cleanup;
+ }
+ if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
+ goto cleanup;
+ }
+
+ if ((*nparams) == 0) {
+ *nparams = QEMU_NB_NUMA_PARAM;
+ ret = 0;
+ goto cleanup;
+ }
+
+ if ((*nparams) < QEMU_NB_NUMA_PARAM) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("Invalid parameter count"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ for (i = 0; i < *nparams; i++) {
+ virMemoryParameterPtr param = ¶ms[i];
+ val = 0;
+ param->value.ul = 0;
+ param->type = VIR_TYPED_PARAM_ULLONG;
+
+ switch (i) {
+ case 0: /* fill numa strict here */
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_NUMA_STRICT) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field numa strict too long
for destination"));
+ goto cleanup;
+ }
+ param->value.i = persistentDef->numatune.strict;
+ break;
+
+ case 1:
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_NUMA_EXCLUSIVE) == NULL)
{
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field numa exclusive too long
for destination"));
+ goto cleanup;
+ }
+ param->value.i = persistentDef->numatune.exclusive;
+ break;
+
+ default:
+ break;
+ /* should not hit here */
+ }
+ }
+ goto out;
+ }
+
+ for (i = 0; i < QEMU_NB_NUMA_PARAM; i++) {
+ virTypedParameterPtr param = ¶ms[i];
+ val = 0;
+ param->value.ul = 0;
+ param->type = VIR_TYPED_PARAM_ULLONG;
+
+ /* Coverity does not realize that if we get here, group is set. */
+ sa_assert(group);
+
+ switch (i) {
+ case 0: /* fill numa strict here */
+ rc = virCgroupGetCpusetHardwall(group, &val);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to get numa strict"));
+ goto cleanup;
+ }
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_NUMA_STRICT) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field numa strict too long for
destination"));
+ goto cleanup;
+ }
+ param->value.ul = val;
+ break;
+
+ case 1: /* file numa exclusive here */
+ rc = virCgroupGetCpusetMemExclusive(group, &val);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to get numa exclusive"));
+ goto cleanup;
+ }
+ if (virStrcpyStatic(param->field, VIR_DOMAIN_NUMA_EXCLUSIVE) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field numa exclusive too long for
destination"));
+ goto cleanup;
+ }
+ param->value.ul = val;
+ break;
+
+ default:
+ break;
+ /* should not hit here */
+ }
+ }
+
+out:
+ *nparams = QEMU_NB_NUMA_PARAM;
+ ret = 0;
+
+cleanup:
+ if (group)
+ virCgroupFree(&group);
+ if (vm)
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
+ return ret;
+}
+
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
unsigned long long period, long long quota)
@@ -10904,6 +11209,8 @@ static virDriver qemuDriver = {
.domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
.domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
.domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
+ .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.8 */
+ .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.8 */
};
--
1.7.3.1