---
src/qemu/qemu_driver.c | 162 +++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 853c84c..0d83c04 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4764,6 +4764,7 @@ static char *qemuGetSchedulerType(virDomainPtr dom,
{
struct qemud_driver *driver = dom->conn->privateData;
char *ret = NULL;
+ char *cfs_period_path = NULL;
qemuDriverLock(driver);
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
@@ -4772,14 +4773,29 @@ static char *qemuGetSchedulerType(virDomainPtr dom,
goto cleanup;
}
- if (nparams)
- *nparams = 1;
+ /* check whether the host supports CFS bandwidth */
+ if (virCgroupPathOfController(driver->cgroup, VIR_CGROUP_CONTROLLER_CPU,
+ "cpu.cfs_period_us", &cfs_period_path) <
0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot get the path of cgroup CPU controller"));
+ goto cleanup;
+ }
+
+ if (nparams) {
+ if (access(cfs_period_path, F_OK) < 0) {
+ *nparams = 1;
+ } else {
+ *nparams = 3;
+ }
+ }
ret = strdup("posix");
if (!ret)
virReportOOMError();
cleanup:
+ VIR_FREE(cfs_period_path);
qemuDriverUnlock(driver);
return ret;
}
@@ -5313,9 +5329,10 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
int i;
virCgroupPtr group = NULL;
virDomainObjPtr vm = NULL;
- virDomainDefPtr persistentDef = NULL;
+ virDomainDefPtr vmdef = NULL;
int ret = -1;
bool isActive;
+ int rc;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG, -1);
@@ -5339,10 +5356,17 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
flags = VIR_DOMAIN_AFFECT_CONFIG;
}
- if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient
domain"));
- 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;
+ }
+
+ /* Make a copy for updated domain. */
+ vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
+ if (!vmdef)
+ goto cleanup;
}
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
@@ -5369,7 +5393,6 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
virTypedParameterPtr param = ¶ms[i];
if (STREQ(param->field, "cpu_shares")) {
- int rc;
if (param->type != VIR_TYPED_PARAM_ULLONG) {
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
_("invalid type for cpu_shares tunable, expected a
'ullong'"));
@@ -5388,19 +5411,53 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- persistentDef = virDomainObjGetPersistentDef(driver->caps, vm);
- if (!persistentDef) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("can't get persistentDef"));
+ vmdef->cputune.shares = params[i].value.ul;
+ }
+ } else if (STREQ(param->field, "cfs_period")) {
+ if (param->type != VIR_TYPED_PARAM_ULLONG) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid type for cfs_period tunable,"
+ " expected a 'ullong'"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ rc = virCgroupSetCpuCfsPeriod(group, params[i].value.ul);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to set cpu bandwidth
period"
+ " tunable"));
goto cleanup;
}
- persistentDef->cputune.shares = params[i].value.ul;
- rc = virDomainSaveConfig(driver->configDir, persistentDef);
- if (rc) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("can't save config"));
+
+ vm->def->cputune.period = params[i].value.ul;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ vmdef->cputune.period = params[i].value.ul;
+ }
+ } else if (STREQ(param->field, "cfs_quota")) {
+ if (param->type != VIR_TYPED_PARAM_LLONG) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("invalid type for cfs_quota tunable,"
+ " expected a 'llong'"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ rc = virCgroupSetCpuCfsQuota(group, params[i].value.l);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to set cpu bandwidth"
+ " tunable"));
goto cleanup;
}
+
+ vm->def->cputune.quota = params[i].value.l;
+ }
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ vmdef->cputune.quota = params[i].value.l;
}
} else {
qemuReportError(VIR_ERR_INVALID_ARG,
@@ -5409,6 +5466,15 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
}
}
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ rc = virDomainSaveConfig(driver->configDir, vmdef);
+ if (rc) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("can't save config"));
+ goto cleanup;
+ }
+ }
+
ret = 0;
cleanup:
@@ -5438,7 +5504,9 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom,
struct qemud_driver *driver = dom->conn->privateData;
virCgroupPtr group = NULL;
virDomainObjPtr vm = NULL;
- unsigned long long val;
+ unsigned long long shares;
+ unsigned long long period;
+ long long quota;
int ret = -1;
int rc;
bool isActive;
@@ -5493,9 +5561,17 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom,
_("can't get persistentDef"));
goto cleanup;
}
- val = persistentDef->cputune.shares;
+ shares = persistentDef->cputune.shares;
+ if (*nparams > 1) {
+ period = persistentDef->cputune.period;
+ quota = persistentDef->cputune.quota;
+ }
} else {
- val = vm->def->cputune.shares;
+ shares = vm->def->cputune.shares;
+ if (*nparams > 1) {
+ period = vm->def->cputune.period;
+ quota = vm->def->cputune.quota;
+ }
}
goto out;
}
@@ -5518,14 +5594,31 @@ qemuGetSchedulerParametersFlags(virDomainPtr dom,
goto cleanup;
}
- rc = virCgroupGetCpuShares(group, &val);
+ rc = virCgroupGetCpuShares(group, &shares);
if (rc != 0) {
virReportSystemError(-rc, "%s",
_("unable to get cpu shares tunable"));
goto cleanup;
}
+
+ if (*nparams > 1) {
+ rc = virCgroupGetCpuCfsPeriod(group, &period);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to get cpu bandwidth period"
+ " tunable"));
+ goto cleanup;
+ }
+
+ rc = virCgroupGetCpuCfsQuota(group, "a);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to get cpu bandwidth tunable"));
+ goto cleanup;
+ }
+ }
out:
- params[0].value.ul = val;
+ params[0].value.ul = shares;
params[0].type = VIR_TYPED_PARAM_ULLONG;
if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -5533,7 +5626,30 @@ out:
goto cleanup;
}
- *nparams = 1;
+ if (*nparams > 1) {
+ params[1].value.ul = period;
+ params[1].type = VIR_TYPED_PARAM_ULLONG;
+ if (virStrcpyStatic(params[1].field, "cfs_period") == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("Field cfs_period too long for destination"));
+ goto cleanup;
+ }
+
+ params[2].value.ul = quota;
+ params[2].type = VIR_TYPED_PARAM_LLONG;
+ if (virStrcpyStatic(params[2].field, "cfs_quota") == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("Field cfs_quota too long for destination"));
+ goto cleanup;
+ }
+
+ *nparams = 3;
+ } else {
+ *nparams = 1;
+ }
+
ret = 0;
cleanup:
--
1.7.1