mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-08 07:15:46 +00:00
blkiotune: add qemu support for blkiotune.device_weight
Implement setting/getting per-device blkio weights in qemu, using the cgroups blkio.weight_device tunable.
This commit is contained in:
parent
6ac81c8ec8
commit
93ab58595d
@ -89,6 +89,7 @@ virCgroupKillRecursive;
|
|||||||
virCgroupMounted;
|
virCgroupMounted;
|
||||||
virCgroupPathOfController;
|
virCgroupPathOfController;
|
||||||
virCgroupRemove;
|
virCgroupRemove;
|
||||||
|
virCgroupSetBlkioDeviceWeight;
|
||||||
virCgroupSetBlkioWeight;
|
virCgroupSetBlkioWeight;
|
||||||
virCgroupSetCpuShares;
|
virCgroupSetCpuShares;
|
||||||
virCgroupSetCpuCfsPeriod;
|
virCgroupSetCpuCfsPeriod;
|
||||||
|
@ -309,6 +309,28 @@ int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
} else {
|
} else {
|
||||||
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Block I/O tuning is not available on this host"));
|
_("Block I/O tuning is not available on this host"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->def->blkio.ndevices) {
|
||||||
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
|
||||||
|
for (i = 0; i < vm->def->blkio.ndevices; i++) {
|
||||||
|
virBlkioDeviceWeightPtr dw = &vm->def->blkio.devices[i];
|
||||||
|
rc = virCgroupSetBlkioDeviceWeight(cgroup, dw->path,
|
||||||
|
dw->weight);
|
||||||
|
if (rc != 0) {
|
||||||
|
virReportSystemError(-rc,
|
||||||
|
_("Unable to set io device weight "
|
||||||
|
"for domain %s"),
|
||||||
|
vm->def->name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("Block I/O tuning is not available on this host"));
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@
|
|||||||
# define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
|
# define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QEMU_NB_BLKIO_PARAM 1
|
#define QEMU_NB_BLKIO_PARAM 2
|
||||||
|
|
||||||
static void processWatchdogEvent(void *data, void *opaque);
|
static void processWatchdogEvent(void *data, void *opaque);
|
||||||
|
|
||||||
@ -5883,6 +5883,88 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* deviceWeightStr in the form of /device/path,weight,/device/path,weight
|
||||||
|
* for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parseBlkioWeightDeviceStr(char *deviceWeightStr,
|
||||||
|
virBlkioDeviceWeightPtr *dw, int *size)
|
||||||
|
{
|
||||||
|
char *temp;
|
||||||
|
int ndevices = 0;
|
||||||
|
int nsep = 0;
|
||||||
|
int i;
|
||||||
|
virBlkioDeviceWeightPtr result = NULL;
|
||||||
|
|
||||||
|
temp = deviceWeightStr;
|
||||||
|
while (temp) {
|
||||||
|
temp = strchr(temp, ',');
|
||||||
|
if (temp) {
|
||||||
|
temp++;
|
||||||
|
nsep++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A valid string must have even number of fields, hence an odd
|
||||||
|
* number of commas. */
|
||||||
|
if (!(nsep & 1))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ndevices = (nsep + 1) / 2;
|
||||||
|
|
||||||
|
if (VIR_ALLOC_N(result, ndevices) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
temp = deviceWeightStr;
|
||||||
|
while (temp) {
|
||||||
|
char *p = temp;
|
||||||
|
|
||||||
|
/* device path */
|
||||||
|
p = strchr(p, ',');
|
||||||
|
if (!p)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
result[i].path = strndup(temp, p - temp);
|
||||||
|
if (!result[i].path) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* weight */
|
||||||
|
temp = p + 1;
|
||||||
|
|
||||||
|
if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (*p == '\0')
|
||||||
|
break;
|
||||||
|
else if (*p != ',')
|
||||||
|
goto error;
|
||||||
|
temp = p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i)
|
||||||
|
VIR_FREE(result);
|
||||||
|
|
||||||
|
*dw = result;
|
||||||
|
*size = i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("unable to parse %s"), deviceWeightStr);
|
||||||
|
cleanup:
|
||||||
|
virBlkioDeviceWeightArrayClear(result, ndevices);
|
||||||
|
VIR_FREE(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int qemuDomainSetBlkioParameters(virDomainPtr dom,
|
static int qemuDomainSetBlkioParameters(virDomainPtr dom,
|
||||||
virTypedParameterPtr params,
|
virTypedParameterPtr params,
|
||||||
int nparams,
|
int nparams,
|
||||||
@ -5949,10 +6031,10 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
||||||
for (i = 0; i < nparams; i++) {
|
for (i = 0; i < nparams; i++) {
|
||||||
|
int rc;
|
||||||
virTypedParameterPtr param = ¶ms[i];
|
virTypedParameterPtr param = ¶ms[i];
|
||||||
|
|
||||||
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
|
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
|
||||||
int rc;
|
|
||||||
if (param->type != VIR_TYPED_PARAM_UINT) {
|
if (param->type != VIR_TYPED_PARAM_UINT) {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
_("invalid type for blkio weight tunable, expected a 'unsigned int'"));
|
_("invalid type for blkio weight tunable, expected a 'unsigned int'"));
|
||||||
@ -5973,6 +6055,44 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
|
|||||||
_("unable to set blkio weight tunable"));
|
_("unable to set blkio weight tunable"));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
||||||
|
int ndevices;
|
||||||
|
virBlkioDeviceWeightPtr devices = NULL;
|
||||||
|
if (param->type != VIR_TYPED_PARAM_STRING) {
|
||||||
|
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
|
_("invalid type for device_weight tunable, "
|
||||||
|
"expected a 'char *'"));
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseBlkioWeightDeviceStr(params[i].value.s,
|
||||||
|
&devices,
|
||||||
|
&ndevices) < 0) {
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ndevices; i++) {
|
||||||
|
rc = virCgroupSetBlkioDeviceWeight(group,
|
||||||
|
devices[i].path,
|
||||||
|
devices[i].weight);
|
||||||
|
if (rc < 0) {
|
||||||
|
virReportSystemError(-rc,
|
||||||
|
_("Unable to set io device weight "
|
||||||
|
"for path %s"),
|
||||||
|
devices[i].path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i != ndevices) {
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
virBlkioDeviceWeightArrayClear(vm->def->blkio.devices,
|
||||||
|
vm->def->blkio.ndevices);
|
||||||
|
VIR_FREE(vm->def->blkio.devices);
|
||||||
|
vm->def->blkio.devices = devices;
|
||||||
|
vm->def->blkio.ndevices = ndevices;
|
||||||
} else {
|
} else {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("Parameter `%s' not supported"), param->field);
|
_("Parameter `%s' not supported"), param->field);
|
||||||
@ -6005,9 +6125,31 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
persistentDef->blkio.weight = params[i].value.ui;
|
persistentDef->blkio.weight = params[i].value.ui;
|
||||||
|
} else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
|
||||||
|
virBlkioDeviceWeightPtr devices = NULL;
|
||||||
|
int ndevices;
|
||||||
|
if (param->type != VIR_TYPED_PARAM_STRING) {
|
||||||
|
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
|
_("invalid type for device_weight tunable, "
|
||||||
|
"expected a 'char *'"));
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (parseBlkioWeightDeviceStr(params[i].value.s,
|
||||||
|
&devices,
|
||||||
|
&ndevices) < 0) {
|
||||||
|
ret = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
virBlkioDeviceWeightArrayClear(persistentDef->blkio.devices,
|
||||||
|
persistentDef->blkio.ndevices);
|
||||||
|
VIR_FREE(persistentDef->blkio.devices);
|
||||||
|
persistentDef->blkio.devices = devices;
|
||||||
|
persistentDef->blkio.ndevices = ndevices;
|
||||||
} else {
|
} else {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("Parameter `%s' not supported"), param->field);
|
_("Parameter `%s' not supported"),
|
||||||
|
param->field);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6030,7 +6172,7 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
|
|||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
int i;
|
int i, j;
|
||||||
virCgroupPtr group = NULL;
|
virCgroupPtr group = NULL;
|
||||||
virDomainObjPtr vm = NULL;
|
virDomainObjPtr vm = NULL;
|
||||||
virDomainDefPtr persistentDef = NULL;
|
virDomainDefPtr persistentDef = NULL;
|
||||||
@ -6044,7 +6186,9 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
|
|||||||
VIR_TYPED_PARAM_STRING_OKAY, -1);
|
VIR_TYPED_PARAM_STRING_OKAY, -1);
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
|
|
||||||
/* We don't return strings, and thus trivially support this flag. */
|
/* We blindly return a string, and let libvirt.c and
|
||||||
|
* remote_driver.c do the filtering on behalf of older clients
|
||||||
|
* that can't parse it. */
|
||||||
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
||||||
|
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
@ -6123,6 +6267,43 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
param->value.ui = val;
|
param->value.ui = val;
|
||||||
break;
|
break;
|
||||||
|
case 1: /* blkiotune.device_weight */
|
||||||
|
if (vm->def->blkio.ndevices > 0) {
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
bool comma = false;
|
||||||
|
for (j = 0; j < vm->def->blkio.ndevices; j++) {
|
||||||
|
if (!vm->def->blkio.devices[j].weight)
|
||||||
|
continue;
|
||||||
|
if (comma)
|
||||||
|
virBufferAddChar(&buf, ',');
|
||||||
|
else
|
||||||
|
comma = true;
|
||||||
|
virBufferAsprintf(&buf, "%s,%u",
|
||||||
|
vm->def->blkio.devices[j].path,
|
||||||
|
vm->def->blkio.devices[j].weight);
|
||||||
|
}
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value.s = virBufferContentAndReset(&buf);
|
||||||
|
}
|
||||||
|
if (!param->value.s) {
|
||||||
|
param->value.s = strdup("");
|
||||||
|
if (!param->value.s) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
param->type = VIR_TYPED_PARAM_STRING;
|
||||||
|
if (virStrcpyStatic(param->field,
|
||||||
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Field name '%s' too long"),
|
||||||
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -6147,6 +6328,38 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
|
|||||||
param->value.ui = persistentDef->blkio.weight;
|
param->value.ui = persistentDef->blkio.weight;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1: /* blkiotune.device_weight */
|
||||||
|
if (persistentDef->blkio.ndevices > 0) {
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
for (j = 0; j < persistentDef->blkio.ndevices; j++) {
|
||||||
|
if (j)
|
||||||
|
virBufferAddChar(&buf, ',');
|
||||||
|
virBufferAsprintf(&buf, "%s,%u",
|
||||||
|
persistentDef->blkio.devices[j].path,
|
||||||
|
persistentDef->blkio.devices[j].weight);
|
||||||
|
}
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value.s = virBufferContentAndReset(&buf);
|
||||||
|
} else {
|
||||||
|
param->value.s = strdup("");
|
||||||
|
if (!param->value.s) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
param->type = VIR_TYPED_PARAM_STRING;
|
||||||
|
if (virStrcpyStatic(param->field,
|
||||||
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Field name '%s' too long"),
|
||||||
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
/* should not hit here */
|
/* should not hit here */
|
||||||
|
@ -981,6 +981,57 @@ int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCgroupSetBlkioDeviceWeight:
|
||||||
|
*
|
||||||
|
* @group: The cgroup to change io device weight device for
|
||||||
|
* @path: The device with a weight to alter
|
||||||
|
* @weight: The new device weight (100-1000), or 0 to clear
|
||||||
|
*
|
||||||
|
* device_weight is treated as a write-only parameter, so
|
||||||
|
* there isn't a getter counterpart.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -errno on failure
|
||||||
|
*/
|
||||||
|
#if defined(major) && defined(minor)
|
||||||
|
int virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
|
||||||
|
const char *path,
|
||||||
|
unsigned int weight)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
struct stat sb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (weight && (weight > 1000 || weight < 100))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (stat(path, &sb) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (!S_ISBLK(sb.st_mode))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (virAsprintf(&str, "%d:%d %d", major(sb.st_rdev), minor(sb.st_rdev),
|
||||||
|
weight) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
ret = virCgroupSetValueStr(group,
|
||||||
|
VIR_CGROUP_CONTROLLER_BLKIO,
|
||||||
|
"blkio.weight_device",
|
||||||
|
str);
|
||||||
|
VIR_FREE(str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED,
|
||||||
|
const char *path ATTRIBUTE_UNUSED,
|
||||||
|
unsigned int weight ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virCgroupSetMemory:
|
* virCgroupSetMemory:
|
||||||
*
|
*
|
||||||
|
@ -55,6 +55,10 @@ int virCgroupAddTask(virCgroupPtr group, pid_t pid);
|
|||||||
int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight);
|
int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight);
|
||||||
int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight);
|
int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight);
|
||||||
|
|
||||||
|
int virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
|
||||||
|
const char *path,
|
||||||
|
unsigned int weight);
|
||||||
|
|
||||||
int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb);
|
int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb);
|
||||||
int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb);
|
int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb);
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
|
||||||
|
pc -m 214 -smp 1 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor,\
|
||||||
|
server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial \
|
||||||
|
none -parallel none -usb
|
@ -643,6 +643,7 @@ mymain(void)
|
|||||||
|
|
||||||
DO_TEST("memtune", false, QEMU_CAPS_NAME);
|
DO_TEST("memtune", false, QEMU_CAPS_NAME);
|
||||||
DO_TEST("blkiotune", false, QEMU_CAPS_NAME);
|
DO_TEST("blkiotune", false, QEMU_CAPS_NAME);
|
||||||
|
DO_TEST("blkiotune-device", false, QEMU_CAPS_NAME);
|
||||||
DO_TEST("cputune", false, QEMU_CAPS_NAME);
|
DO_TEST("cputune", false, QEMU_CAPS_NAME);
|
||||||
DO_TEST("numatune-memory", false, NONE);
|
DO_TEST("numatune-memory", false, NONE);
|
||||||
|
|
||||||
|
@ -184,6 +184,7 @@ mymain(void)
|
|||||||
DO_TEST("encrypted-disk");
|
DO_TEST("encrypted-disk");
|
||||||
DO_TEST("memtune");
|
DO_TEST("memtune");
|
||||||
DO_TEST("blkiotune");
|
DO_TEST("blkiotune");
|
||||||
|
DO_TEST("blkiotune-device");
|
||||||
DO_TEST("cputune");
|
DO_TEST("cputune");
|
||||||
|
|
||||||
DO_TEST("smp");
|
DO_TEST("smp");
|
||||||
|
Loading…
Reference in New Issue
Block a user