[libvirt] [PATCH 6/9] qemu: allow to setup throttle blkio cgroup through virsh

Gao feng gaofeng at cn.fujitsu.com
Mon Dec 2 06:48:01 UTC 2013


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 at corp.netease.com>
Signed-off-by: Gao feng <gaofeng at 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(&params, &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(&params, &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(&params, &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(&params, &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




More information about the libvir-list mailing list