[libvirt] [PATCH 09/10] Implement virDomain{G, S}etNumaParameters for the qemu driver

Hu Tao hutao at cn.fujitsu.com
Thu Nov 3 11:55:24 UTC 2011


---
 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 = &params[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 = &params[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 = &params[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




More information about the libvir-list mailing list