diff --git a/src/cgroup.c b/src/cgroup.c index d3d45d2e7ec4cc91c306502b4d2b5356f40531a6..1a80a204198403e5be094a193e87a3fab4526f68 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 dbb444bef0af592a1cafb8741c31d78750e60d96..f452e2d84477dd398746af5c810009d721522092 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 0e9c9f72a38d59d05a1b9da16b1ed57dec6abf4c..22fb08356b623c21231d6d78c1930bb4a6213e05 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 e670fb60e900444e2fc7d2556b2cd18c49a9c27b..f37fc5d96421c165061de4345b2814e1b72d9ea1 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -1612,9 +1612,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, @@ -1638,7 +1643,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 6b730f3704173936345452a70438e973410ad387..6e3b75bc436c8f96800793a4a3879b296b2405c1 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 5261714498f67a403b81e7c5d42ce7268c2071ce..ee64b28f7f0cdad90b5d9835ef78c634c370b5eb 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 3102014e75626394adf6b24ade93e5bb3fc1ea6b..b3e628ae7713626f5538ea6075366693b7b10798 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 ced525e46f42e1b8b2df62b9be79cf8755267755..94c3c4ef0ab2e733d218588a49fd1321f8685827 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -1185,111 +1185,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); @@ -1302,21 +1309,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: @@ -1326,10 +1350,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); @@ -1342,9 +1366,9 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) } } } + cleanup: free(params); - free(param_name); virDomainFree(dom); return ret_val; }