* src/qemu_driver.c: Add driver methods qemuGetSchedulerType,
qemuGetSchedulerParameters, qemuSetSchedulerParameters
* src/lxc_driver.c: Fix to use unsigned long long consistently
for schedular parameters
* src/cgroup.h, src/cgroup.c: Fix cpu_shares to take unsigned
long long
* src/util.c, src/util.h, src/libvirt_private.syms: Add a
virStrToDouble helper
* src/virsh.c: Fix handling of --set arg to schedinfo command
to honour the designated data type of each schedular tunable
as declared by the driver
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/cgroup.c | 10 +-
src/cgroup.h | 4 +-
src/libvirt_private.syms | 1 +
src/lxc_driver.c | 9 ++-
src/qemu_driver.c | 151 +++++++++++++++++++++++++++++-
src/util.c | 20 ++++
src/util.h | 3 +
src/virsh.c | 232 +++++++++++++++++++++++++---------------------
8 files changed, 314 insertions(+), 116 deletions(-)
diff --git a/src/cgroup.c b/src/cgroup.c
index d3d45d2..1a80a20 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -790,23 +790,23 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group,
return rc;
}
-int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares)
+int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
{
return virCgroupSetValueU64(group,
VIR_CGROUP_CONTROLLER_CPU,
- "cpu.shares", (uint64_t)shares);
+ "cpu.shares", shares);
}
-int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares)
+int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
{
return virCgroupGetValueU64(group,
VIR_CGROUP_CONTROLLER_CPU,
- "cpu.shares", (uint64_t *)shares);
+ "cpu.shares", shares);
}
int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
{
return virCgroupGetValueU64(group,
VIR_CGROUP_CONTROLLER_CPUACCT,
- "cpuacct.usage", (uint64_t *)usage);
+ "cpuacct.usage", usage);
}
diff --git a/src/cgroup.h b/src/cgroup.h
index dbb444b..f452e2d 100644
--- a/src/cgroup.h
+++ b/src/cgroup.h
@@ -39,8 +39,8 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group,
char type,
int major);
-int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares);
-int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares);
+int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares);
+int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares);
int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0e9c9f7..22fb083 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -348,6 +348,7 @@ virStrToLong_i;
virStrToLong_ll;
virStrToLong_ull;
virStrToLong_ui;
+virStrToDouble;
virFileLinkPointsTo;
virFileResolveLink;
saferead;
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
index ff35845..843b066 100644
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -1355,9 +1355,14 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
for (i = 0; i < nparams; i++) {
virSchedParameterPtr param = ¶ms[i];
+ if (param->type != VIR_DOMAIN_SCHED_FIELD_ULLONG) {
+ lxcError(NULL, domain, VIR_ERR_INVALID_ARG,
+ _("invalid type for cpu_shares tunable, expected a
'ullong'"));
+ goto cleanup;
+ }
if (STREQ(param->field, "cpu_shares")) {
- if (virCgroupSetCpuShares(group, params[i].value.ui) != 0)
+ if (virCgroupSetCpuShares(group, params[i].value.ul) != 0)
goto cleanup;
} else {
lxcError(NULL, domain, VIR_ERR_INVALID_ARG,
@@ -1381,7 +1386,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
lxc_driver_t *driver = domain->conn->privateData;
virCgroupPtr group = NULL;
virDomainObjPtr vm = NULL;
- unsigned long val;
+ unsigned long long val;
int ret = -1;
if (driver->cgroup == NULL)
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 39ad47e..6c8370c 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -5275,6 +5275,151 @@ cleanup:
return ret;
}
+
+static char *qemuGetSchedulerType(virDomainPtr dom,
+ int *nparams)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ char *ret;
+
+ if (driver->cgroup == NULL) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ __FUNCTION__);
+ return NULL;
+ }
+
+ if (nparams)
+ *nparams = 1;
+
+ ret = strdup("posix");
+ if (!ret)
+ virReportOOMError(dom->conn);
+ return ret;
+}
+
+static int qemuSetSchedulerParameters(virDomainPtr dom,
+ virSchedParameterPtr params,
+ int nparams)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ int i;
+ virCgroupPtr group = NULL;
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+
+ if (driver->cgroup == NULL) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ __FUNCTION__);
+ return -1;
+ }
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (vm == NULL) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("No such domain %s"), dom->uuid);
+ goto cleanup;
+ }
+
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
{
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot find cgroup for domain %s"),
vm->def->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < nparams; i++) {
+ virSchedParameterPtr param = ¶ms[i];
+
+ if (STREQ(param->field, "cpu_shares")) {
+ int rc;
+ if (param->type != VIR_DOMAIN_SCHED_FIELD_ULLONG) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+ _("invalid type for cpu_shares tunable, expected a
'ullong'"));
+ goto cleanup;
+ }
+
+ rc = virCgroupSetCpuShares(group, params[i].value.ul);
+ if (rc != 0) {
+ virReportSystemError(dom->conn, -rc, "%s",
+ _("unable to set cpu shares tunable"));
+ goto cleanup;
+ }
+ } else {
+ qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
+ _("Invalid parameter `%s'"),
param->field);
+ goto cleanup;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ virCgroupFree(&group);
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int qemuGetSchedulerParameters(virDomainPtr dom,
+ virSchedParameterPtr params,
+ int *nparams)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virCgroupPtr group = NULL;
+ virDomainObjPtr vm = NULL;
+ unsigned long long val;
+ int ret = -1;
+ int rc;
+
+ if (driver->cgroup == NULL) {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ __FUNCTION__);
+ return -1;
+ }
+
+ if ((*nparams) != 1) {
+ qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
+ "%s", _("Invalid parameter count"));
+ return -1;
+ }
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (vm == NULL) {
+ qemudReportError(dom->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("No such domain %s"), dom->uuid);
+ goto cleanup;
+ }
+
+ if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
{
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot find cgroup for domain %s"),
vm->def->name);
+ goto cleanup;
+ }
+
+ rc = virCgroupGetCpuShares(group, &val);
+ if (rc != 0) {
+ virReportSystemError(dom->conn, -rc, "%s",
+ _("unable to get cpu shares tunable"));
+ goto cleanup;
+ }
+ params[0].value.ul = val;
+ strncpy(params[0].field, "cpu_shares", sizeof(params[0].field));
+ params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
+
+ ret = 0;
+
+cleanup:
+ virCgroupFree(&group);
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+
/* This uses the 'info blockstats' monitor command which was
* integrated into both qemu & kvm in late 2007. If the command is
* not supported we detect this and return the appropriate error.
@@ -6248,9 +6393,9 @@ static virDriver qemuDriver = {
qemudDomainDetachDevice, /* domainDetachDevice */
qemudDomainGetAutostart, /* domainGetAutostart */
qemudDomainSetAutostart, /* domainSetAutostart */
- NULL, /* domainGetSchedulerType */
- NULL, /* domainGetSchedulerParameters */
- NULL, /* domainSetSchedulerParameters */
+ qemuGetSchedulerType, /* domainGetSchedulerType */
+ qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
+ qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
NULL, /* domainMigratePrepare (v1) */
qemudDomainMigratePerform, /* domainMigratePerform */
NULL, /* domainMigrateFinish */
diff --git a/src/util.c b/src/util.c
index 5261714..ee64b28 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1479,6 +1479,26 @@ virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned
long long *re
return 0;
}
+int
+virStrToDouble(char const *s,
+ char **end_ptr,
+ double *result)
+{
+ double val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtod(s, &p);
+ err = (errno || (!end_ptr && *p) || p == s);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
/**
* virSkipSpaces:
* @str: pointer to the char pointer used
diff --git a/src/util.h b/src/util.h
index e905c38..e761e83 100644
--- a/src/util.h
+++ b/src/util.h
@@ -154,6 +154,9 @@ int virStrToLong_ull(char const *s,
char **end_ptr,
int base,
unsigned long long *result);
+int virStrToDouble(char const *s,
+ char **end_ptr,
+ double *result);
int virMacAddrCompare (const char *mac1, const char *mac2);
diff --git a/src/virsh.c b/src/virsh.c
index fff73a1..db3d8de 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -1181,111 +1181,118 @@ static const vshCmdOptDef opts_schedinfo[] = {
};
static int
-cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
+cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
+ virSchedParameterPtr param)
{
- char *schedulertype;
- char *set;
- char *param_name = NULL;
- long long int param_value = 0;
- virDomainPtr dom;
- virSchedParameterPtr params = NULL;
- int i, ret;
- int nparams = 0;
- int nr_inputparams = 0;
- int inputparams = 0;
- int weightfound = 0;
- int setfound = 0;
- int weight = 0;
- int capfound = 0;
- int cap = 0;
- char str_weight[] = "weight";
- char str_cap[] = "cap";
- int ret_val = FALSE;
-
- if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
- return FALSE;
-
- if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
- return FALSE;
-
- /* Deprecated Xen-only options */
- if(vshCommandOptBool(cmd, "weight")) {
- weight = vshCommandOptInt(cmd, "weight", &weightfound);
- if (!weightfound) {
+ int found;
+ char *data;
+
+ /* Legacy 'weight' parameter */
+ if (STREQ(param->field, "weight") &&
+ param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
+ vshCommandOptBool(cmd, "weight")) {
+ int val;
+ val = vshCommandOptInt(cmd, "weight", &found);
+ if (!found) {
vshError(ctl, FALSE, "%s", _("Invalid value of
weight"));
- goto cleanup;
+ return -1;
} else {
- nr_inputparams++;
+ param->value.ui = val;
}
+ return 1;
}
- if(vshCommandOptBool(cmd, "cap")) {
- cap = vshCommandOptInt(cmd, "cap", &capfound);
- if (!capfound) {
+ /* Legacy 'cap' parameter */
+ if (STREQ(param->field, "cap") &&
+ param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
+ vshCommandOptBool(cmd, "cap")) {
+ int val;
+ val = vshCommandOptInt(cmd, "cap", &found);
+ if (!found) {
vshError(ctl, FALSE, "%s", _("Invalid value of cap"));
- goto cleanup;
+ return -1;
} else {
- nr_inputparams++;
+ param->value.ui = val;
}
+ return 1;
}
- if(vshCommandOptBool(cmd, "set")) {
- set = vshCommandOptString(cmd, "set", &setfound);
- if (!setfound) {
- vshError(ctl, FALSE, "%s", _("Error getting param"));
- goto cleanup;
+ if ((data = vshCommandOptString(cmd, "set", NULL))) {
+ char *val = strchr(data, '=');
+ int match = 0;
+ if (!val) {
+ vshError(ctl, FALSE, "%s", _("Invalid syntax for --set,
expecting name=value"));
+ return -1;
}
+ *val = '\0';
+ match = STREQ(data, param->field);
+ *val = '=';
+ val++;
- param_name = vshMalloc(ctl, strlen(set) + 1);
- if (param_name == NULL)
- goto cleanup;
+ if (!match)
+ return 0;
- if (sscanf(set, "%[^=]=%lli", param_name, ¶m_value) != 2) {
- vshError(ctl, FALSE, "%s", _("Invalid value of param"));
- goto cleanup;
+ switch (param->type) {
+ case VIR_DOMAIN_SCHED_FIELD_INT:
+ if (virStrToLong_i(val, NULL, 10, ¶m->value.i) < 0) {
+ vshError(ctl, FALSE, "%s",
+ _("Invalid value for parameter, expecting an int"));
+ return -1;
+ }
+ break;
+ case VIR_DOMAIN_SCHED_FIELD_UINT:
+ if (virStrToLong_ui(val, NULL, 10, ¶m->value.ui) < 0) {
+ vshError(ctl, FALSE, "%s",
+ _("Invalid value for parameter, expecting an unsigned
int"));
+ return -1;
+ }
+ break;
+ case VIR_DOMAIN_SCHED_FIELD_LLONG:
+ if (virStrToLong_ll(val, NULL, 10, ¶m->value.l) < 0) {
+ vshError(ctl, FALSE, "%s",
+ _("Invalid value for parameter, expecting an long
long"));
+ return -1;
+ }
+ break;
+ case VIR_DOMAIN_SCHED_FIELD_ULLONG:
+ if (virStrToLong_ull(val, NULL, 10, ¶m->value.ul) < 0) {
+ vshError(ctl, FALSE, "%s",
+ _("Invalid value for parameter, expecting an unsigned long
long"));
+ return -1;
+ }
+ break;
+ case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
+ if (virStrToDouble(val, NULL, ¶m->value.d) < 0) {
+ vshError(ctl, FALSE, "%s", _("Invalid value for parameter,
expecting a double"));
+ return -1;
+ }
+ break;
+ case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
+ param->value.b = STREQ(val, "0") ? 0 : 1;
}
-
- nr_inputparams++;
- }
-
- params = vshMalloc(ctl, sizeof (virSchedParameter) * nr_inputparams);
- if (params == NULL) {
- goto cleanup;
+ return 1;
}
- if (weightfound) {
- strncpy(params[inputparams].field,str_weight,sizeof(str_weight));
- params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[inputparams].value.ui = weight;
- inputparams++;
- }
+ return 0;
+}
- if (capfound) {
- strncpy(params[inputparams].field,str_cap,sizeof(str_cap));
- params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[inputparams].value.ui = cap;
- inputparams++;
- }
- /* End Deprecated Xen-only options */
- if (setfound) {
- strncpy(params[inputparams].field,param_name,sizeof(params[0].field));
- params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_LLONG;
- params[inputparams].value.l = param_value;
- inputparams++;
- }
+static int
+cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
+{
+ char *schedulertype;
+ virDomainPtr dom;
+ virSchedParameterPtr params = NULL;
+ int nparams = 0;
+ int update = 0;
+ int i, ret;
+ int ret_val = FALSE;
- assert (inputparams == nr_inputparams);
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
- /* Set SchedulerParameters */
- if (inputparams > 0) {
- ret = virDomainSetSchedulerParameters(dom, params, inputparams);
- if (ret == -1) {
- goto cleanup;
- }
- }
- free(params);
- params = NULL;
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+ return FALSE;
/* Print SchedulerType */
schedulertype = virDomainGetSchedulerType(dom, &nparams);
@@ -1298,21 +1305,38 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
goto cleanup;
}
- /* Get SchedulerParameters */
- params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
- if (params == NULL) {
- goto cleanup;
- }
- for (i = 0; i < nparams; i++){
- params[i].type = 0;
- memset (params[i].field, 0, sizeof params[i].field);
- }
- ret = virDomainGetSchedulerParameters(dom, params, &nparams);
- if (ret == -1) {
- goto cleanup;
- }
- ret_val = TRUE;
- if(nparams){
+ if (nparams) {
+ params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
+ if (params == NULL)
+ goto cleanup;
+
+ memset(params, 0, sizeof(virSchedParameter)* nparams);
+ ret = virDomainGetSchedulerParameters(dom, params, &nparams);
+ if (ret == -1)
+ goto cleanup;
+
+ /* See if any params are being set */
+ for (i = 0; i < nparams; i++){
+ ret = cmdSchedInfoUpdate(ctl, cmd, &(params[i]));
+ if (ret == -1)
+ goto cleanup;
+
+ if (ret == 1)
+ update = 1;
+ }
+
+ /* Update parameters & refresh data */
+ if (update) {
+ ret = virDomainSetSchedulerParameters(dom, params, nparams);
+ if (ret == -1)
+ goto cleanup;
+
+ ret = virDomainGetSchedulerParameters(dom, params, &nparams);
+ if (ret == -1)
+ goto cleanup;
+ }
+
+ ret_val = TRUE;
for (i = 0; i < nparams; i++){
switch (params[i].type) {
case VIR_DOMAIN_SCHED_FIELD_INT:
@@ -1322,10 +1346,10 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
printf("%-15s: %u\n", params[i].field, params[i].value.ui);
break;
case VIR_DOMAIN_SCHED_FIELD_LLONG:
- printf("%-15s: %Ld\n", params[i].field, params[i].value.l);
+ printf("%-15s: %lld\n", params[i].field, params[i].value.l);
break;
case VIR_DOMAIN_SCHED_FIELD_ULLONG:
- printf("%-15s: %Lu\n", params[i].field, params[i].value.ul);
+ printf("%-15s: %llu\n", params[i].field,
params[i].value.ul);
break;
case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
printf("%-15s: %f\n", params[i].field, params[i].value.d);
@@ -1338,9 +1362,9 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
}
}
}
+
cleanup:
free(params);
- free(param_name);
virDomainFree(dom);
return ret_val;
}
--
1.6.2.5