With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bps /dev/sda1,10000,/dev/sda2,20000
--device-write-bps /dev/sda1,10000 --device-read-iops /dev/sda1,10000
--device-write-iops /dev/sda1,10000,/dev/sda2,0
Signed-off-by: Guan Qiang <hzguanqiang(a)corp.netease.com>
Signed-off-by: Gao feng <gaofeng(a)cn.fujitsu.com>
---
include/libvirt/libvirt.h.in | 45 +++++
src/qemu/qemu_driver.c | 418 +++++++++++++++++++++++++++++++++++++++----
tools/virsh-domain.c | 64 +++++++
3 files changed, 488 insertions(+), 39 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 5aad75c..d054900 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1806,6 +1806,51 @@ char * virDomainGetSchedulerType(virDomainPtr
domain,
#define VIR_DOMAIN_BLKIO_DEVICE_WEIGHT "device_weight"
+
+/**
+ * VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS:
+ *
+ * Macro for the blkio tunable throttle.read_iops_device: it represents
+ * the number of reading the block device per second, as a string. The
+ * string is parsed as a series of /path/to/device, read_iops elements,
+ * separated by ','.
+ */
+
+#define VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS "device_read_iops"
+
+
+/**
+ * VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS:
+ *
+ * Macro for the blkio tunable throttle.write_iops_device: it represents
+ * the number of writing the block device per second, as a string. The
+ * string is parsed as a series of /path/to/device, write_iops elements,
+ * separated by ','.
+ */
+#define VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS "device_write_iops"
+
+
+/**
+ * VIR_DOMAIN_BLKIO_DEVICE_READ_BPS:
+ *
+ * Macro for the blkio tunable throttle.read_iops_device: it represents
+ * the bytes of reading the block device per second, as a string. The
+ * string is parsed as a series of /path/to/device, read_bps elements,
+ * separated by ','.
+ */
+#define VIR_DOMAIN_BLKIO_DEVICE_READ_BPS "device_read_bps"
+
+
+/**
+ * VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS:
+ *
+ * Macro for the blkio tunable throttle.read_iops_device: it represents
+ * the number of reading the block device per second, as a string. The
+ * string is parsed as a series of /path/to/device, read_iops elements,
+ * separated by ','.
+ */
+#define VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS "device_write_bps"
+
/* Set Blkio tunables for the domain*/
int virDomainSetBlkioParameters(virDomainPtr domain,
virTypedParameterPtr params,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 61dbe7f..1ad5b94 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -131,7 +131,7 @@
# define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
#endif
-#define QEMU_NB_BLKIO_PARAM 2
+#define QEMU_NB_BLKIO_PARAM 6
#define QEMU_NB_BANDWIDTH_PARAM 6
@@ -7419,12 +7419,12 @@ cleanup:
return ret;
}
-/* deviceWeightStr in the form of /device/path,weight,/device/path,weight
+/* blkioDeviceStr 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
-qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
- virBlkioDevicePtr *dev, size_t *size)
+qemuDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
+ virBlkioDevicePtr *dev, size_t *size)
{
char *temp;
int ndevices = 0;
@@ -7435,10 +7435,10 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
*dev = NULL;
*size = 0;
- if (STREQ(deviceWeightStr, ""))
+ if (STREQ(blkioDeviceStr, ""))
return 0;
- temp = deviceWeightStr;
+ temp = blkioDeviceStr;
while (temp) {
temp = strchr(temp, ',');
if (temp) {
@@ -7458,7 +7458,7 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
return -1;
i = 0;
- temp = deviceWeightStr;
+ temp = blkioDeviceStr;
while (temp) {
char *p = temp;
@@ -7470,11 +7470,25 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
goto cleanup;
- /* weight */
+ /* value */
temp = p + 1;
- if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
- goto error;
+ if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
+ if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
+ goto error;
+ } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
+ if (virStrToLong_ui(temp, &p, 10, &result[i].riops) < 0)
+ goto error;
+ } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
+ if (virStrToLong_ui(temp, &p, 10, &result[i].wiops) < 0)
+ goto error;
+ } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
+ if (virStrToLong_ull(temp, &p, 10, &result[i].rbps) < 0)
+ goto error;
+ } else {
+ if (virStrToLong_ull(temp, &p, 10, &result[i].wbps) < 0)
+ goto error;
+ }
i++;
@@ -7495,20 +7509,21 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
error:
virReportError(VIR_ERR_INVALID_ARG,
- _("unable to parse device weight '%s'"),
deviceWeightStr);
+ _("unable to parse blkio device '%s'"),
blkioDeviceStr);
cleanup:
virBlkioDeviceArrayClear(result, ndevices);
VIR_FREE(result);
return -1;
}
-/* Modify dest_array to reflect all device weight changes described in
+/* Modify dest_array to reflect all blkio device changes described in
* src_array. */
static int
-qemuDomainMergeDeviceWeights(virBlkioDevicePtr *dest_array,
- size_t *dest_size,
- virBlkioDevicePtr src_array,
- size_t src_size)
+qemuDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
+ size_t *dest_size,
+ virBlkioDevicePtr src_array,
+ size_t src_size,
+ const char *type)
{
size_t i, j;
virBlkioDevicePtr dest, src;
@@ -7521,18 +7536,40 @@ qemuDomainMergeDeviceWeights(virBlkioDevicePtr *dest_array,
dest = &(*dest_array)[j];
if (STREQ(src->path, dest->path)) {
found = true;
- dest->weight = src->weight;
+
+ if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT))
+ dest->weight = src->weight;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS))
+ dest->riops = src->riops;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS))
+ dest->wiops = src->wiops;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS))
+ dest->rbps = src->rbps;
+ else
+ dest->wbps = src->wbps;
+
break;
}
}
if (!found) {
- if (!src->weight)
+ if (!src->weight && !src->riops && src->wiops
&& src->rbps && src->wbps)
continue;
if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
return -1;
dest = &(*dest_array)[*dest_size - 1];
dest->path = src->path;
- dest->weight = src->weight;
+
+ if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT))
+ dest->weight = src->weight;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS))
+ dest->riops = src->riops;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS))
+ dest->wiops = src->wiops;
+ else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS))
+ dest->rbps = src->rbps;
+ else
+ dest->wbps = src->wbps;
+
src->path = NULL;
}
}
@@ -7562,6 +7599,14 @@ qemuDomainSetBlkioParameters(virDomainPtr dom,
VIR_TYPED_PARAM_UINT,
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
VIR_TYPED_PARAM_STRING,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
+ VIR_TYPED_PARAM_STRING,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
+ VIR_TYPED_PARAM_STRING,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
+ VIR_TYPED_PARAM_STRING,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
+ VIR_TYPED_PARAM_STRING,
NULL) < 0)
return -1;
@@ -7604,33 +7649,72 @@ qemuDomainSetBlkioParameters(virDomainPtr dom,
if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
ret = -1;
- } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
+ } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
size_t ndevices;
virBlkioDevicePtr devices = NULL;
size_t j;
- if (qemuDomainParseDeviceWeightStr(params[i].value.s,
+ if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
+ param->field,
&devices,
&ndevices) < 0) {
ret = -1;
continue;
}
- for (j = 0; j < ndevices; j++) {
- if (virCgroupSetBlkioDevice(priv->cgroup,
- devices[j].path,
- devices[j].weight,
- devices[j].riops,
- devices[j].wiops,
- devices[j].rbps,
- devices[j].wbps) < 0) {
- ret = -1;
- break;
+ if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
+ for (j = 0; j < ndevices; j++) {
+ if (virCgroupSetBlkioDeviceWeight(priv->cgroup,
+ devices[j].path,
+ devices[j].weight) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
+ for (j = 0; j < ndevices; j++) {
+ if (virCgroupSetBlkioDeviceIops(priv->cgroup,
+ devices[j].path,
+ 1, devices[j].riops) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
+ for (j = 0; j < ndevices; j++) {
+ if (virCgroupSetBlkioDeviceIops(priv->cgroup,
+ devices[j].path,
+ 0, devices[j].wiops) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
+ for (j = 0; j < ndevices; j++) {
+ if (virCgroupSetBlkioDeviceBps(priv->cgroup,
+ devices[j].path,
+ 1, devices[j].rbps) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+ } else {
+ for (j = 0; j < ndevices; j++) {
+ if (virCgroupSetBlkioDeviceBps(priv->cgroup,
+ devices[j].path,
+ 0, devices[j].wbps) < 0) {
+ ret = -1;
+ break;
+ }
}
}
if (j != ndevices ||
- qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
- &vm->def->blkio.ndevices,
- devices, ndevices) < 0)
+ qemuDomainMergeBlkioDevice(&vm->def->blkio.devices,
+ &vm->def->blkio.ndevices,
+ devices, ndevices, param->field) <
0)
ret = -1;
virBlkioDeviceArrayClear(devices, ndevices);
VIR_FREE(devices);
@@ -7655,19 +7739,24 @@ qemuDomainSetBlkioParameters(virDomainPtr dom,
}
persistentDef->blkio.weight = params[i].value.ui;
- } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
+ } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
+ STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
virBlkioDevicePtr devices = NULL;
size_t ndevices;
- if (qemuDomainParseDeviceWeightStr(params[i].value.s,
+ if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
+ params[i].field,
&devices,
&ndevices) < 0) {
ret = -1;
continue;
}
- if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
- &persistentDef->blkio.ndevices,
- devices, ndevices) < 0)
+ if (qemuDomainMergeBlkioDevice(&persistentDef->blkio.devices,
+ &persistentDef->blkio.ndevices,
+ devices, ndevices, param->field) <
0)
ret = -1;
virBlkioDeviceArrayClear(devices, ndevices);
VIR_FREE(devices);
@@ -7753,6 +7842,7 @@ qemuDomainGetBlkioParameters(virDomainPtr dom,
VIR_TYPED_PARAM_UINT, val) < 0)
goto cleanup;
break;
+
case 1: /* blkiotune.device_weight */
if (vm->def->blkio.ndevices > 0) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -7782,6 +7872,122 @@ qemuDomainGetBlkioParameters(virDomainPtr dom,
goto cleanup;
break;
+ case 2: /* blkiotune.device_read_iops */
+ 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].riops)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%u",
+ vm->def->blkio.devices[j].path,
+ vm->def->blkio.devices[j].riops);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
+ VIR_TYPED_PARAM_STRING,
+ param->value.s) < 0)
+ goto cleanup;
+ break;
+
+ case 3: /* blkiotune.device_write_iops */
+ 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].wiops)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%u",
+ vm->def->blkio.devices[j].path,
+ vm->def->blkio.devices[j].wiops);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
+ VIR_TYPED_PARAM_STRING,
+ param->value.s) < 0)
+ goto cleanup;
+ break;
+
+ case 4: /* blkiotune.device_read_bps */
+ 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].rbps)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%llu",
+ vm->def->blkio.devices[j].path,
+ vm->def->blkio.devices[j].rbps);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
+ VIR_TYPED_PARAM_STRING,
+ param->value.s) < 0)
+ goto cleanup;
+ break;
+
+ case 5: /* blkiotune.device_write_bps */
+ 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].wbps)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%llu",
+ vm->def->blkio.devices[j].path,
+ vm->def->blkio.devices[j].wbps);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
+ VIR_TYPED_PARAM_STRING,
+ param->value.s) < 0)
+ goto cleanup;
+ break;
+
default:
break;
/* should not hit here */
@@ -7839,6 +8045,140 @@ qemuDomainGetBlkioParameters(virDomainPtr dom,
}
break;
+ case 2: /* blkiotune.device_read_iops */
+ if (persistentDef->blkio.ndevices > 0) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ bool comma = false;
+
+ for (j = 0; j < persistentDef->blkio.ndevices; j++) {
+ if (!persistentDef->blkio.devices[j].riops)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%u",
+ persistentDef->blkio.devices[j].path,
+ persistentDef->blkio.devices[j].riops);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (!param->value.s && VIR_STRDUP(param->value.s,
"") < 0)
+ goto cleanup;
+ param->type = VIR_TYPED_PARAM_STRING;
+ if (virStrcpyStatic(param->field,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field name '%s' too long"),
+ VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS);
+ goto cleanup;
+ }
+ break;
+ case 3: /* blkiotune.device_write_iops */
+ if (persistentDef->blkio.ndevices > 0) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ bool comma = false;
+
+ for (j = 0; j < persistentDef->blkio.ndevices; j++) {
+ if (!persistentDef->blkio.devices[j].wiops)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%u",
+ persistentDef->blkio.devices[j].path,
+ persistentDef->blkio.devices[j].wiops);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (!param->value.s && VIR_STRDUP(param->value.s,
"") < 0)
+ goto cleanup;
+ param->type = VIR_TYPED_PARAM_STRING;
+ if (virStrcpyStatic(param->field,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field name '%s' too long"),
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS);
+ goto cleanup;
+ }
+ break;
+ case 4: /* blkiotune.device_read_bps */
+ if (persistentDef->blkio.ndevices > 0) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ bool comma = false;
+
+ for (j = 0; j < persistentDef->blkio.ndevices; j++) {
+ if (!persistentDef->blkio.devices[j].rbps)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%llu",
+ persistentDef->blkio.devices[j].path,
+ persistentDef->blkio.devices[j].rbps);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (!param->value.s && VIR_STRDUP(param->value.s,
"") < 0)
+ goto cleanup;
+ param->type = VIR_TYPED_PARAM_STRING;
+ if (virStrcpyStatic(param->field,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field name '%s' too long"),
+ VIR_DOMAIN_BLKIO_DEVICE_READ_BPS);
+ goto cleanup;
+ }
+ break;
+
+ case 5: /* blkiotune.device_write_bps */
+ if (persistentDef->blkio.ndevices > 0) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ bool comma = false;
+
+ for (j = 0; j < persistentDef->blkio.ndevices; j++) {
+ if (!persistentDef->blkio.devices[j].wbps)
+ continue;
+ if (comma)
+ virBufferAddChar(&buf, ',');
+ else
+ comma = true;
+ virBufferAsprintf(&buf, "%s,%llu",
+ persistentDef->blkio.devices[j].path,
+ persistentDef->blkio.devices[j].wbps);
+ }
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ param->value.s = virBufferContentAndReset(&buf);
+ }
+ if (!param->value.s && VIR_STRDUP(param->value.s,
"") < 0)
+ goto cleanup;
+ param->type = VIR_TYPED_PARAM_STRING;
+ if (virStrcpyStatic(param->field,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field name '%s' too long"),
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS);
+ goto cleanup;
+ }
+ break;
+
default:
break;
/* should not hit here */
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 1fe138c..f01691d 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1250,6 +1250,22 @@ static const vshCmdOptDef opts_blkiotune[] = {
.type = VSH_OT_STRING,
.help = N_("per-device IO Weights, in the form of
/path/to/device,weight,...")
},
+ {.name = "device-read-iops",
+ .type = VSH_OT_STRING,
+ .help = N_("per-device read I/O limit per second, in the form of
/path/to/device,read_iops,...")
+ },
+ {.name = "device-write-iops",
+ .type = VSH_OT_STRING,
+ .help = N_("per-device write I/O limit per second, in the form of
/path/to/device,write_iops,...")
+ },
+ {.name = "device-read-bps",
+ .type = VSH_OT_STRING,
+ .help = N_("per-device bytes read per second, in the form of
/path/to/device,read-bps,...")
+ },
+ {.name = "device-write-bps",
+ .type = VSH_OT_STRING,
+ .help = N_("per-device bytes wrote per second, in the form of
/path/to/device,write-bps,...")
+ },
{.name = "config",
.type = VSH_OT_BOOL,
.help = N_("affect next boot")
@@ -1270,6 +1286,10 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
{
virDomainPtr dom;
const char *device_weight = NULL;
+ const char *device_riops = NULL;
+ const char *device_wiops = NULL;
+ const char *device_rbps = NULL;
+ const char *device_wbps = NULL;
int weight = 0;
int nparams = 0;
int maxparams = 0;
@@ -1317,6 +1337,50 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
goto save_error;
}
+ rv = vshCommandOptString(cmd, "device-read-iops", &device_riops);
+ if (rv < 0) {
+ vshError(ctl, "%s", _("Unable to parse string parameter"));
+ goto cleanup;
+ } else if (rv > 0) {
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
+ device_riops) < 0)
+ goto save_error;
+ }
+
+ rv = vshCommandOptString(cmd, "device-write-iops", &device_wiops);
+ if (rv < 0) {
+ vshError(ctl, "%s", _("Unable to parse string parameter"));
+ goto cleanup;
+ } else if (rv > 0) {
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
+ device_wiops) < 0)
+ goto save_error;
+ }
+
+ rv = vshCommandOptString(cmd, "device-read-bps", &device_rbps);
+ if (rv < 0) {
+ vshError(ctl, "%s", _("Unable to parse string parameter"));
+ goto cleanup;
+ } else if (rv > 0) {
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
+ device_rbps) < 0)
+ goto save_error;
+ }
+
+ rv = vshCommandOptString(cmd, "device-write-bps", &device_wbps);
+ if (rv < 0) {
+ vshError(ctl, "%s", _("Unable to parse string parameter"));
+ goto cleanup;
+ } else if (rv > 0) {
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
+ device_wbps) < 0)
+ goto save_error;
+ }
+
if (nparams == 0) {
/* get the number of blkio parameters */
if (virDomainGetBlkioParameters(dom, NULL, &nparams, flags) != 0) {
--
1.8.3.1