提交 55bc5090 编写于 作者: D Daniel P. Berrange

Implement schedular tunables API using cgroups

* 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
上级 38f6f47b
...@@ -790,23 +790,23 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group, ...@@ -790,23 +790,23 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group,
return rc; return rc;
} }
int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares) int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
{ {
return virCgroupSetValueU64(group, return virCgroupSetValueU64(group,
VIR_CGROUP_CONTROLLER_CPU, 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, return virCgroupGetValueU64(group,
VIR_CGROUP_CONTROLLER_CPU, VIR_CGROUP_CONTROLLER_CPU,
"cpu.shares", (uint64_t *)shares); "cpu.shares", shares);
} }
int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage) int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
{ {
return virCgroupGetValueU64(group, return virCgroupGetValueU64(group,
VIR_CGROUP_CONTROLLER_CPUACCT, VIR_CGROUP_CONTROLLER_CPUACCT,
"cpuacct.usage", (uint64_t *)usage); "cpuacct.usage", usage);
} }
...@@ -39,8 +39,8 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group, ...@@ -39,8 +39,8 @@ int virCgroupAllowDeviceMajor(virCgroupPtr group,
char type, char type,
int major); int major);
int virCgroupSetCpuShares(virCgroupPtr group, unsigned long shares); int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares);
int virCgroupGetCpuShares(virCgroupPtr group, unsigned long *shares); int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares);
int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage); int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage);
......
...@@ -348,6 +348,7 @@ virStrToLong_i; ...@@ -348,6 +348,7 @@ virStrToLong_i;
virStrToLong_ll; virStrToLong_ll;
virStrToLong_ull; virStrToLong_ull;
virStrToLong_ui; virStrToLong_ui;
virStrToDouble;
virFileLinkPointsTo; virFileLinkPointsTo;
virFileResolveLink; virFileResolveLink;
saferead; saferead;
......
...@@ -1612,9 +1612,14 @@ static int lxcSetSchedulerParameters(virDomainPtr domain, ...@@ -1612,9 +1612,14 @@ static int lxcSetSchedulerParameters(virDomainPtr domain,
for (i = 0; i < nparams; i++) { for (i = 0; i < nparams; i++) {
virSchedParameterPtr param = &params[i]; virSchedParameterPtr param = &params[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 (STREQ(param->field, "cpu_shares")) {
if (virCgroupSetCpuShares(group, params[i].value.ui) != 0) if (virCgroupSetCpuShares(group, params[i].value.ul) != 0)
goto cleanup; goto cleanup;
} else { } else {
lxcError(NULL, domain, VIR_ERR_INVALID_ARG, lxcError(NULL, domain, VIR_ERR_INVALID_ARG,
...@@ -1638,7 +1643,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain, ...@@ -1638,7 +1643,7 @@ static int lxcGetSchedulerParameters(virDomainPtr domain,
lxc_driver_t *driver = domain->conn->privateData; lxc_driver_t *driver = domain->conn->privateData;
virCgroupPtr group = NULL; virCgroupPtr group = NULL;
virDomainObjPtr vm = NULL; virDomainObjPtr vm = NULL;
unsigned long val; unsigned long long val;
int ret = -1; int ret = -1;
if (driver->cgroup == NULL) if (driver->cgroup == NULL)
......
...@@ -5275,6 +5275,151 @@ cleanup: ...@@ -5275,6 +5275,151 @@ cleanup:
return ret; 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 = &params[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 /* This uses the 'info blockstats' monitor command which was
* integrated into both qemu & kvm in late 2007. If the command is * integrated into both qemu & kvm in late 2007. If the command is
* not supported we detect this and return the appropriate error. * not supported we detect this and return the appropriate error.
...@@ -6248,9 +6393,9 @@ static virDriver qemuDriver = { ...@@ -6248,9 +6393,9 @@ static virDriver qemuDriver = {
qemudDomainDetachDevice, /* domainDetachDevice */ qemudDomainDetachDevice, /* domainDetachDevice */
qemudDomainGetAutostart, /* domainGetAutostart */ qemudDomainGetAutostart, /* domainGetAutostart */
qemudDomainSetAutostart, /* domainSetAutostart */ qemudDomainSetAutostart, /* domainSetAutostart */
NULL, /* domainGetSchedulerType */ qemuGetSchedulerType, /* domainGetSchedulerType */
NULL, /* domainGetSchedulerParameters */ qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
NULL, /* domainSetSchedulerParameters */ qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
NULL, /* domainMigratePrepare (v1) */ NULL, /* domainMigratePrepare (v1) */
qemudDomainMigratePerform, /* domainMigratePerform */ qemudDomainMigratePerform, /* domainMigratePerform */
NULL, /* domainMigrateFinish */ NULL, /* domainMigrateFinish */
......
...@@ -1479,6 +1479,26 @@ virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *re ...@@ -1479,6 +1479,26 @@ virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *re
return 0; 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: * virSkipSpaces:
* @str: pointer to the char pointer used * @str: pointer to the char pointer used
......
...@@ -154,6 +154,9 @@ int virStrToLong_ull(char const *s, ...@@ -154,6 +154,9 @@ int virStrToLong_ull(char const *s,
char **end_ptr, char **end_ptr,
int base, int base,
unsigned long long *result); unsigned long long *result);
int virStrToDouble(char const *s,
char **end_ptr,
double *result);
int virMacAddrCompare (const char *mac1, const char *mac2); int virMacAddrCompare (const char *mac1, const char *mac2);
......
...@@ -1185,111 +1185,118 @@ static const vshCmdOptDef opts_schedinfo[] = { ...@@ -1185,111 +1185,118 @@ static const vshCmdOptDef opts_schedinfo[] = {
}; };
static int static int
cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
virSchedParameterPtr param)
{ {
char *schedulertype; int found;
char *set; char *data;
char *param_name = NULL;
long long int param_value = 0; /* Legacy 'weight' parameter */
virDomainPtr dom; if (STREQ(param->field, "weight") &&
virSchedParameterPtr params = NULL; param->type == VIR_DOMAIN_SCHED_FIELD_UINT &&
int i, ret; vshCommandOptBool(cmd, "weight")) {
int nparams = 0; int val;
int nr_inputparams = 0; val = vshCommandOptInt(cmd, "weight", &found);
int inputparams = 0; if (!found) {
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) {
vshError(ctl, FALSE, "%s", _("Invalid value of weight")); vshError(ctl, FALSE, "%s", _("Invalid value of weight"));
goto cleanup; return -1;
} else { } else {
nr_inputparams++; param->value.ui = val;
} }
return 1;
} }
if(vshCommandOptBool(cmd, "cap")) { /* Legacy 'cap' parameter */
cap = vshCommandOptInt(cmd, "cap", &capfound); if (STREQ(param->field, "cap") &&
if (!capfound) { 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")); vshError(ctl, FALSE, "%s", _("Invalid value of cap"));
goto cleanup; return -1;
} else { } else {
nr_inputparams++; param->value.ui = val;
} }
return 1;
} }
if(vshCommandOptBool(cmd, "set")) { if ((data = vshCommandOptString(cmd, "set", NULL))) {
set = vshCommandOptString(cmd, "set", &setfound); char *val = strchr(data, '=');
if (!setfound) { int match = 0;
vshError(ctl, FALSE, "%s", _("Error getting param")); if (!val) {
goto cleanup; 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 (!match)
if (param_name == NULL) return 0;
goto cleanup;
if (sscanf(set, "%[^=]=%lli", param_name, &param_value) != 2) { switch (param->type) {
vshError(ctl, FALSE, "%s", _("Invalid value of param")); case VIR_DOMAIN_SCHED_FIELD_INT:
goto cleanup; if (virStrToLong_i(val, NULL, 10, &param->value.i) < 0) {
vshError(ctl, FALSE, "%s",
_("Invalid value for parameter, expecting an int"));
return -1;
} }
break;
nr_inputparams++; case VIR_DOMAIN_SCHED_FIELD_UINT:
if (virStrToLong_ui(val, NULL, 10, &param->value.ui) < 0) {
vshError(ctl, FALSE, "%s",
_("Invalid value for parameter, expecting an unsigned int"));
return -1;
} }
break;
params = vshMalloc(ctl, sizeof (virSchedParameter) * nr_inputparams); case VIR_DOMAIN_SCHED_FIELD_LLONG:
if (params == NULL) { if (virStrToLong_ll(val, NULL, 10, &param->value.l) < 0) {
goto cleanup; vshError(ctl, FALSE, "%s",
_("Invalid value for parameter, expecting an long long"));
return -1;
} }
break;
if (weightfound) { case VIR_DOMAIN_SCHED_FIELD_ULLONG:
strncpy(params[inputparams].field,str_weight,sizeof(str_weight)); if (virStrToLong_ull(val, NULL, 10, &param->value.ul) < 0) {
params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_UINT; vshError(ctl, FALSE, "%s",
params[inputparams].value.ui = weight; _("Invalid value for parameter, expecting an unsigned long long"));
inputparams++; return -1;
} }
break;
if (capfound) { case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
strncpy(params[inputparams].field,str_cap,sizeof(str_cap)); if (virStrToDouble(val, NULL, &param->value.d) < 0) {
params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_UINT; vshError(ctl, FALSE, "%s", _("Invalid value for parameter, expecting a double"));
params[inputparams].value.ui = cap; return -1;
inputparams++;
} }
/* End Deprecated Xen-only options */ break;
case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
if (setfound) { param->value.b = STREQ(val, "0") ? 0 : 1;
strncpy(params[inputparams].field,param_name,sizeof(params[0].field)); }
params[inputparams].type = VIR_DOMAIN_SCHED_FIELD_LLONG; return 1;
params[inputparams].value.l = param_value;
inputparams++;
} }
assert (inputparams == nr_inputparams); return 0;
}
/* Set SchedulerParameters */
if (inputparams > 0) { static int
ret = virDomainSetSchedulerParameters(dom, params, inputparams); cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
if (ret == -1) { {
goto cleanup; char *schedulertype;
} virDomainPtr dom;
} virSchedParameterPtr params = NULL;
free(params); int nparams = 0;
params = NULL; int update = 0;
int i, ret;
int ret_val = FALSE;
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return FALSE;
/* Print SchedulerType */ /* Print SchedulerType */
schedulertype = virDomainGetSchedulerType(dom, &nparams); schedulertype = virDomainGetSchedulerType(dom, &nparams);
...@@ -1302,21 +1309,38 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) ...@@ -1302,21 +1309,38 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
goto cleanup; goto cleanup;
} }
/* Get SchedulerParameters */ if (nparams) {
params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams); params = vshMalloc(ctl, sizeof(virSchedParameter)* nparams);
if (params == NULL) { if (params == NULL)
goto cleanup; 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++){ for (i = 0; i < nparams; i++){
params[i].type = 0; ret = cmdSchedInfoUpdate(ctl, cmd, &(params[i]));
memset (params[i].field, 0, sizeof params[i].field); 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); ret = virDomainGetSchedulerParameters(dom, params, &nparams);
if (ret == -1) { if (ret == -1)
goto cleanup; goto cleanup;
} }
ret_val = TRUE; ret_val = TRUE;
if(nparams){
for (i = 0; i < nparams; i++){ for (i = 0; i < nparams; i++){
switch (params[i].type) { switch (params[i].type) {
case VIR_DOMAIN_SCHED_FIELD_INT: case VIR_DOMAIN_SCHED_FIELD_INT:
...@@ -1326,10 +1350,10 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) ...@@ -1326,10 +1350,10 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
printf("%-15s: %u\n", params[i].field, params[i].value.ui); printf("%-15s: %u\n", params[i].field, params[i].value.ui);
break; break;
case VIR_DOMAIN_SCHED_FIELD_LLONG: 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; break;
case VIR_DOMAIN_SCHED_FIELD_ULLONG: 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; break;
case VIR_DOMAIN_SCHED_FIELD_DOUBLE: case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
printf("%-15s: %f\n", params[i].field, params[i].value.d); printf("%-15s: %f\n", params[i].field, params[i].value.d);
...@@ -1342,9 +1366,9 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd) ...@@ -1342,9 +1366,9 @@ cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
} }
} }
} }
cleanup: cleanup:
free(params); free(params);
free(param_name);
virDomainFree(dom); virDomainFree(dom);
return ret_val; return ret_val;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册