[libvirt] [PATCH v4 2/2] add interface for blkio.weight_device

Hu Tao hutao at cn.fujitsu.com
Wed Oct 12 09:26:35 UTC 2011


This patch adds a parameter --weight-device to virsh command
blkiotune for setting/getting blkio.weight_device.

---
 daemon/remote.c              |    2 +-
 include/libvirt/libvirt.h.in |    9 ++
 src/conf/domain_conf.c       |  129 ++++++++++++++++++++++++++-
 src/conf/domain_conf.h       |   16 ++++
 src/libvirt_private.syms     |    2 +
 src/qemu/qemu_cgroup.c       |   22 +++++
 src/qemu/qemu_driver.c       |  199 +++++++++++++++++++++++++++++++++++++++--
 src/util/cgroup.c            |   33 +++++++
 src/util/cgroup.h            |    3 +
 tools/virsh.c                |   69 +++++++++++++--
 tools/virsh.pod              |    5 +-
 11 files changed, 467 insertions(+), 22 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 520fef2..7691b08 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1619,7 +1619,7 @@ success:
 cleanup:
     if (rv < 0)
         virNetMessageSaveError(rerr);
-    VIR_FREE(params);
+    virTypedParameterFree(params, nparams);
     if (dom)
         virDomainFree(dom);
     return rv;
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index fa53147..84178c2 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1162,6 +1162,15 @@ char *                  virDomainGetSchedulerType(virDomainPtr domain,
 
 #define VIR_DOMAIN_BLKIO_WEIGHT "weight"
 
+/**
+ * VIR_DOMAIN_BLKIO_WEIGHT_DEVICE:
+ *
+ * Macro for the blkio tunable weight_device: it represents the
+ * per-device weight. This name refers to a VIR_TYPED_PARAM_STRING.
+ */
+
+#define VIR_DOMAIN_BLKIO_WEIGHT_DEVICE "weight_device"
+
 /* Set Blkio tunables for the domain*/
 int     virDomainSetBlkioParameters(virDomainPtr domain,
                                     virTypedParameterPtr params,
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b9ddf26..96723ec 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -580,6 +580,97 @@ VIR_ENUM_IMPL(virDomainNumatuneMemMode, VIR_DOMAIN_NUMATUNE_MEM_LAST,
 #define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
 #define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE
 
+
+void virBlkioWeightDeviceFree(virBlkioWeightDevicePtr deviceWeights,
+                              int ndevices)
+{
+    int i;
+
+    for (i = 0; i < ndevices; i++)
+        VIR_FREE(deviceWeights[i].path);
+    VIR_FREE(deviceWeights);
+}
+
+/**
+ * virBlkioWeightDeviceToStr:
+ *
+ * This function returns a string representing device weights that is
+ * suitable for writing to /cgroup/blkio/blkio.weight_device, given
+ * a list of weight devices.
+ */
+#if defined(major) && defined(minor)
+int virBlkioWeightDeviceToStr(virBlkioWeightDevicePtr weightdevices,
+                              int ndevices,
+                              char **result)
+{
+    int i;
+    struct stat s;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    for (i = 0; i < ndevices; i++) {
+        if (stat(weightdevices[i].path, &s) == -1)
+            return -1;
+        if ((s.st_mode & S_IFMT) != S_IFBLK)
+            return -1;
+        virBufferAsprintf(&buf, "%d:%d %d\n",
+                          major(s.st_rdev),
+                          minor(s.st_rdev),
+                          weightdevices[i].weight);
+    }
+
+    *result = virBufferContentAndReset(&buf);
+    return 0;
+}
+#else
+int virBlkioWeightDeviceToStr(virBlkioWeightDevicePtr weightdevices ATTRIBUTE_UNUSED,
+                              int ndevices ATTRIBUTE_UNUSED,
+                              char **result ATTRIBUTE_UNUSED)
+{
+    return -1;
+}
+#endif
+
+/**
+ * virDomainBlkioWeightDeviceParseXML
+ *
+ * this function parses a XML node:
+ *
+ *   <device>
+ *     <path>/fully/qualified/device/path</path>
+ *     <weight>weight</weight>
+ *   </device>
+ *
+ * and fills a virBlkioWeightDevice struct.
+ */
+static int virDomainBlkioWeightDeviceParseXML(xmlNodePtr root,
+                                              virBlkioWeightDevicePtr dw)
+{
+    char *c;
+    xmlNodePtr node;
+
+    if (!dw)
+        return -1;
+
+    node = root->children;
+    while (node) {
+        if (node->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(node->name, BAD_CAST "path")) {
+                dw->path = (char *)xmlNodeGetContent(node);
+            } else if (xmlStrEqual(node->name, BAD_CAST "weight")) {
+                c = (char *)xmlNodeGetContent(node);
+                if (virStrToLong_i(c, NULL, 10, &dw->weight) < 0)
+                    return -1;
+                VIR_FREE(c);
+            }
+        }
+        node = node->next;
+    }
+
+    return 0;
+}
+
+
+
 static void
 virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
 {
@@ -1244,6 +1335,8 @@ void virDomainDefFree(virDomainDefPtr def)
     VIR_FREE(def->emulator);
     VIR_FREE(def->description);
 
+    virBlkioWeightDeviceFree(def->blkio.weight_devices, def->blkio.ndevices);
+
     virDomainWatchdogDefFree(def->watchdog);
 
     virDomainMemballoonDefFree(def->memballoon);
@@ -6520,6 +6613,20 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                      &def->blkio.weight) < 0)
         def->blkio.weight = 0;
 
+    n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes);
+    if (n > 0) {
+        if (VIR_ALLOC_N(def->blkio.weight_devices, n) < 0) {
+            virReportOOMError();
+            goto error;
+        }
+
+        for (i = 0; i < n; i++) {
+            virDomainBlkioWeightDeviceParseXML(nodes[i], &def->blkio.weight_devices[i]);
+        }
+        def->blkio.ndevices = n;
+        VIR_FREE(nodes);
+    }
+
     /* Extract other memory tunables */
     if (virXPathULong("string(./memtune/hard_limit)", ctxt,
                       &def->mem.hard_limit) < 0)
@@ -10572,10 +10679,26 @@ virDomainDefFormatInternal(virDomainDefPtr def,
                       def->mem.cur_balloon);
 
     /* add blkiotune only if there are any */
-    if (def->blkio.weight) {
+    if (def->blkio.weight || def->blkio.weight_devices) {
         virBufferAsprintf(buf, "  <blkiotune>\n");
-        virBufferAsprintf(buf, "    <weight>%u</weight>\n",
-                          def->blkio.weight);
+
+        if (def->blkio.weight)
+            virBufferAsprintf(buf, "    <weight>%u</weight>\n",
+                              def->blkio.weight);
+
+        if (def->blkio.weight_devices) {
+            int i;
+
+            for (i = 0; i < def->blkio.ndevices; i++) {
+                virBufferAsprintf(buf, "    <device>\n");
+                virBufferAsprintf(buf, "      <path>%s</path>\n",
+                                  def->blkio.weight_devices[i].path);
+                virBufferAsprintf(buf, "      <weight>%d</weight>\n",
+                                  def->blkio.weight_devices[i].weight);
+                virBufferAsprintf(buf, "    </device>\n");
+            }
+        }
+
         virBufferAsprintf(buf, "  </blkiotune>\n");
     }
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 8765f32..140369c 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1297,6 +1297,20 @@ struct _virDomainNumatuneDef {
     /* Future NUMA tuning related stuff should go here. */
 };
 
+typedef struct _virBlkioWeightDevice virBlkioWeightDevice;
+typedef virBlkioWeightDevice *virBlkioWeightDevicePtr;
+struct _virBlkioWeightDevice {
+    char *path;
+    int weight;
+};
+
+void virBlkioWeightDeviceFree(virBlkioWeightDevicePtr deviceWeights,
+                              int ndevices);
+int virBlkioWeightDeviceToStr(virBlkioWeightDevicePtr deviceWeights,
+                              int ndevices,
+                              char **result);
+
+
 /*
  * Guest VM main configuration
  *
@@ -1314,6 +1328,8 @@ struct _virDomainDef {
 
     struct {
         unsigned int weight;
+        int ndevices;
+        virBlkioWeightDevicePtr weight_devices;
     } blkio;
 
     struct {
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d79f65c..00099c0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -227,6 +227,8 @@ virDomainAuditVcpu;
 
 
 # domain_conf.h
+virBlkioWeightDeviceFree;
+virBlkioWeightDeviceToStr;
 virDiskNameToBusDeviceIndex;
 virDiskNameToIndex;
 virDomainActualNetDefFree;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 2a10bd2..ff13965 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -312,6 +312,28 @@ int qemuSetupCgroup(struct qemud_driver *driver,
         }
     }
 
+    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
+        char *tmp;
+        if (virBlkioWeightDeviceToStr(vm->def->blkio.weight_devices,
+                                      vm->def->blkio.ndevices,
+                                      &tmp) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Unable to set io device weight for domain %s"),
+                            vm->def->name);
+            goto cleanup;
+        }
+        if (tmp) {
+            rc = virCgroupSetBlkioWeightDevice(cgroup, tmp);
+            VIR_FREE(tmp);
+            if (rc != 0) {
+                virReportSystemError(-rc,
+                                     _("Unable to set io device weight for domain %s"),
+                                     vm->def->name);
+                goto cleanup;
+            }
+        }
+    }
+
     if (vm->def->mem.hard_limit != 0 ||
         vm->def->mem.soft_limit != 0 ||
         vm->def->mem.swap_hard_limit != 0) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4ea3236..179ecb4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -89,6 +89,7 @@
 #include "locking/lock_manager.h"
 #include "locking/domain_lock.h"
 #include "virkeycode.h"
+#include "c-ctype.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -112,7 +113,7 @@
 # define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
 #endif
 
-#define QEMU_NB_BLKIO_PARAM  1
+#define QEMU_NB_BLKIO_PARAM  2
 
 static void processWatchdogEvent(void *data, void *opaque);
 
@@ -5847,6 +5848,73 @@ cleanup:
     return ret;
 }
 
+/* weightDeviceStr 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(const char *weightDeviceStr, virBlkioWeightDevicePtr *dw, int *size)
+{
+    char *temp;
+    int nDevice = 0;
+    int i;
+    virBlkioWeightDevicePtr result = NULL;
+
+    temp = (char *)weightDeviceStr;
+    while (temp) {
+        temp = strchr(temp, ';');
+        if (temp) {
+            temp++;
+            if (*temp == '\0')
+                break;
+            nDevice++;
+        }
+    }
+    nDevice++;
+
+    if (VIR_ALLOC_N(result, nDevice) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    i = 0;
+    temp = (char *)weightDeviceStr;
+    while (temp && i < nDevice) {
+        char *p = temp;
+
+        /* device path */
+
+        p = strchr(p, ',');
+        if (!p)
+            goto fail;
+
+        result[i].path = strndup(temp, p - temp);
+
+        /* weight */
+
+        temp = p + 1;
+        if (!temp)
+            goto fail;
+
+        if (virStrToLong_i(temp, &p, 10, &result[i].weight) < 0)
+            goto fail;
+
+        i++;
+        if (*p == '\0')
+            break;
+        else if (*p != ';')
+            goto fail;
+        temp = p + 1;
+    }
+
+    *dw = result;
+    *size = i;
+
+    return 0;
+
+fail:
+    VIR_FREE(result);
+    return -1;
+}
+
 static int qemuDomainSetBlkioParameters(virDomainPtr dom,
                                          virTypedParameterPtr params,
                                          int nparams,
@@ -5859,9 +5927,11 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
     virDomainDefPtr persistentDef = NULL;
     int ret = -1;
     bool isActive;
+    bool typed_string;
 
     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  VIR_DOMAIN_TYPED_STRING_OKAY, -1);
     qemuDriverLock(driver);
 
     vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -5874,6 +5944,8 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
 
     isActive = virDomainObjIsActive(vm);
 
+    typed_string = (flags & VIR_DOMAIN_TYPED_STRING_OKAY) == VIR_DOMAIN_TYPED_STRING_OKAY;
+    flags &= ~VIR_DOMAIN_TYPED_STRING_OKAY;
     if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
         if (isActive)
             flags = VIR_DOMAIN_AFFECT_LIVE;
@@ -5913,10 +5985,10 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
     ret = 0;
     if (flags & VIR_DOMAIN_AFFECT_LIVE) {
         for (i = 0; i < nparams; i++) {
+            int rc;
             virTypedParameterPtr param = &params[i];
 
             if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
-                int rc;
                 if (param->type != VIR_TYPED_PARAM_UINT) {
                     qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                     _("invalid type for blkio weight tunable, expected a 'unsigned int'"));
@@ -5937,6 +6009,46 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
                                          _("unable to set blkio weight tunable"));
                     ret = -1;
                 }
+            } else if(STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT_DEVICE)) {
+                int ndevices;
+                virBlkioWeightDevicePtr weightDevices = NULL;
+                char *tmp;
+                if (param->type != VIR_TYPED_PARAM_STRING) {
+                    qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                    _("invalid type for blkio weight_device tunable, expected a 'char *'"));
+                    ret = -1;
+                    continue;
+                }
+
+                if (parseBlkioWeightDeviceStr(params[i].value.s,
+                                              &weightDevices,
+                                              &ndevices) < 0) {
+                    qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                                    _("invalid format for blkio weight_device"));
+                    ret = -1;
+                    continue;
+                }
+                if (virBlkioWeightDeviceToStr(weightDevices,
+                                              ndevices,
+                                              &tmp) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("Unable to set blkio weight_device tunable"));
+                    virBlkioWeightDeviceFree(weightDevices, ndevices);
+                    ret = -1;
+                    continue;
+                }
+                virBlkioWeightDeviceFree(weightDevices, ndevices);
+                VIR_FREE(weightDevices);
+                if (tmp) {
+                    rc = virCgroupSetBlkioWeightDevice(group, tmp);
+                    VIR_FREE(tmp);
+                    if (rc != 0) {
+                            virReportSystemError(-rc, "%s",
+                                                 _("unable to set blkio weight_device tunable"));
+                            ret = -1;
+                            continue;
+                    }
+                }
             } else {
                 qemuReportError(VIR_ERR_INVALID_ARG,
                                 _("Parameter `%s' not supported"), param->field);
@@ -5966,6 +6078,21 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
                 }
 
                 persistentDef->blkio.weight = params[i].value.ui;
+            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT_DEVICE)) {
+                virBlkioWeightDevicePtr tmp = NULL;
+                int ndevices;
+                if (parseBlkioWeightDeviceStr(params[i].value.s,
+                                              &tmp,
+                                              &ndevices) < 0) {
+                    qemuReportError(VIR_ERR_INVALID_ARG,
+                                    _("invalid device weight format: %s"),
+                                    params[i].value.s);
+                    ret = -1;
+                    continue;
+                }
+                virBlkioWeightDeviceFree(persistentDef->blkio.weight_devices, persistentDef->blkio.ndevices);
+                persistentDef->blkio.weight_devices = tmp;
+                persistentDef->blkio.ndevices = ndevices;
             } else {
                 qemuReportError(VIR_ERR_INVALID_ARG,
                                 _("Parameter `%s' not supported"), param->field);
@@ -5991,7 +6118,7 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
                                          unsigned int flags)
 {
     struct qemud_driver *driver = dom->conn->privateData;
-    int i;
+    int i, j;
     virCgroupPtr group = NULL;
     virDomainObjPtr vm = NULL;
     virDomainDefPtr persistentDef = NULL;
@@ -5999,9 +6126,11 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
     int ret = -1;
     int rc;
     bool isActive;
+    bool typed_string;
 
     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
-                  VIR_DOMAIN_AFFECT_CONFIG, -1);
+                  VIR_DOMAIN_AFFECT_CONFIG |
+                  VIR_DOMAIN_TYPED_STRING_OKAY, -1);
     qemuDriverLock(driver);
 
     vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -6014,19 +6143,32 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
 
     if ((*nparams) == 0) {
         /* Current number of blkio parameters supported by cgroups */
-        *nparams = QEMU_NB_BLKIO_PARAM;
+        if (flags & VIR_DOMAIN_TYPED_STRING_OKAY)
+            *nparams = QEMU_NB_BLKIO_PARAM;
+        else
+            *nparams = QEMU_NB_BLKIO_PARAM - 1;
         ret = 0;
         goto cleanup;
     }
 
-    if ((*nparams) != QEMU_NB_BLKIO_PARAM) {
-        qemuReportError(VIR_ERR_INVALID_ARG,
-                        "%s", _("Invalid parameter count"));
-        goto cleanup;
+    if (flags & VIR_DOMAIN_TYPED_STRING_OKAY) {
+        if ((*nparams) != QEMU_NB_BLKIO_PARAM) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            "%s", _("Invalid parameter count"));
+            goto cleanup;
+        }
+    } else {
+        if ((*nparams) != QEMU_NB_BLKIO_PARAM - 1) {
+            qemuReportError(VIR_ERR_INVALID_ARG,
+                            "%s", _("Invalid parameter count"));
+            goto cleanup;
+        }
     }
 
     isActive = virDomainObjIsActive(vm);
 
+    typed_string = (flags & VIR_DOMAIN_TYPED_STRING_OKAY) == VIR_DOMAIN_TYPED_STRING_OKAY;
+    flags &= ~VIR_DOMAIN_TYPED_STRING_OKAY;
     if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
         if (isActive)
             flags = VIR_DOMAIN_AFFECT_LIVE;
@@ -6065,6 +6207,7 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
 
     if (flags & VIR_DOMAIN_AFFECT_LIVE) {
         for (i = 0; i < *nparams; i++) {
+            char *weight_device;
             virTypedParameterPtr param = &params[i];
             val = 0;
             param->value.ui = 0;
@@ -6085,6 +6228,23 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
                 }
                 param->value.ui = val;
                 break;
+            case 1: /* blkio.weight_device */
+                if (typed_string) {
+                    param->type = VIR_TYPED_PARAM_STRING;
+                    rc = virCgroupGetBlkioWeightDevice(group, &weight_device);
+                    if (rc != 0) {
+                        virReportSystemError(-rc, "%s",
+                                             _("unable to get blkio weight_device"));
+                        goto cleanup;
+                    }
+                    if (virStrcpyStatic(param->field, VIR_DOMAIN_BLKIO_WEIGHT_DEVICE) == NULL) {
+                        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                        "%s", _("Field blkio weight_device too long for destination"));
+                        goto cleanup;
+                    }
+                    param->value.s = weight_device;
+                }
+                break;
 
             default:
                 break;
@@ -6108,6 +6268,25 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
                 param->value.ui = persistentDef->blkio.weight;
                 break;
 
+            case 1: /* blkio.weight_device */
+                if (typed_string && persistentDef->blkio.ndevices > 0) {
+                    virBuffer buf = VIR_BUFFER_INITIALIZER;
+                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
+                        virBufferAsprintf(&buf, "%s %d\n",
+                                          persistentDef->blkio.weight_devices[j].path,
+                                          persistentDef->blkio.weight_devices[j].weight);
+                    }
+
+                    param->value.s = virBufferContentAndReset(&buf);
+                    param->type = VIR_TYPED_PARAM_STRING;
+                }
+                if (virStrcpyStatic(param->field, VIR_DOMAIN_BLKIO_WEIGHT_DEVICE) == NULL) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    "%s", _("Field blkio weight_device too long for destination"));
+                    goto cleanup;
+                }
+                break;
+
             default:
                 break;
                 /* should not hit here */
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index c8d1f33..f6e5a08 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -982,6 +982,39 @@ int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight)
 }
 
 /**
+ * virCgroupSetBlkioWeightDevice:
+ *
+ * @group: The cgroup to change io weight device for
+ * @weight_device: The Weight device for this cgroup
+ *
+ * Returns: 0 on success
+ */
+int virCgroupSetBlkioWeightDevice(virCgroupPtr group,
+                                  const char *weight_device)
+{
+    return virCgroupSetValueStr(group,
+                                VIR_CGROUP_CONTROLLER_BLKIO,
+                                "blkio.weight_device",
+                                weight_device);
+}
+
+/**
+ * virCgroupGetBlkioWeightDevice:
+ *
+ * @group: The cgroup to get weight_device for
+ * @weight_device: returned weight_device string
+ *
+ * Returns: 0 on success
+ */
+int virCgroupGetBlkioWeightDevice(virCgroupPtr group,
+                                  char **weight_device)
+{
+    return virCgroupGetValueStr(group,
+                                VIR_CGROUP_CONTROLLER_BLKIO,
+                                "blkio.weight_device", weight_device);
+}
+
+/**
  * virCgroupSetMemory:
  *
  * @group: The cgroup to change memory for
diff --git a/src/util/cgroup.h b/src/util/cgroup.h
index d190bb3..87e196b 100644
--- a/src/util/cgroup.h
+++ b/src/util/cgroup.h
@@ -55,6 +55,9 @@ int virCgroupAddTask(virCgroupPtr group, pid_t pid);
 int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight);
 int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight);
 
+int virCgroupSetBlkioWeightDevice(virCgroupPtr group, const char *weight_device);
+int virCgroupGetBlkioWeightDevice(virCgroupPtr group, char **weight_device);
+
 int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb);
 int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb);
 
diff --git a/tools/virsh.c b/tools/virsh.c
index 067d3e5..c85f5b6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4644,6 +4644,8 @@ static const vshCmdOptDef opts_blkiotune[] = {
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
     {"weight", VSH_OT_INT, VSH_OFLAG_NONE,
      N_("IO Weight in range [100, 1000]")},
+    {"weight-device", VSH_OT_STRING, VSH_OFLAG_NONE,
+     N_("per-device IO Weight, in the form of /path/to/device,weight")},
     {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
     {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
     {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
@@ -4654,6 +4656,7 @@ static bool
 cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
 {
     virDomainPtr dom;
+    const char *weight_device = NULL;
     int weight = 0;
     int nparams = 0;
     int rv = 0;
@@ -4698,12 +4701,36 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
         }
     }
 
+    rv = vshCommandOptString(cmd, "weight-device", &weight_device);
+    if (rv < 0) {
+        vshError(ctl, "%s",
+                 _("Unable to parse string parameter"));
+        goto cleanup;
+    }
+    if (rv > 0) {
+        nparams++;
+    }
+
     if (nparams == 0) {
         /* get the number of blkio parameters */
+        /* old libvirtd doesn't understand VIR_DOMAIN_TYPED_STRING_OKAY, we
+         * give it a second try with this flag disabled in the case of an
+         * old libvirtd. */
+        flags |= VIR_DOMAIN_TYPED_STRING_OKAY;
         if (virDomainGetBlkioParameters(dom, NULL, &nparams, flags) != 0) {
-            vshError(ctl, "%s",
-                     _("Unable to get number of blkio parameters"));
-            goto cleanup;
+            if (last_error->code == VIR_ERR_INVALID_ARG) {
+                flags &= ~VIR_DOMAIN_TYPED_STRING_OKAY;
+                nparams = 0;
+                if (virDomainGetBlkioParameters(dom, NULL, &nparams, flags) != 0) {
+                    vshError(ctl, "%s",
+                             _("Unable to get number of blkio parameters"));
+                    goto cleanup;
+                }
+            } else {
+                vshError(ctl, "%s",
+                         _("Unable to get number of blkio parameters"));
+                goto cleanup;
+            }
         }
 
         if (nparams == 0) {
@@ -4745,6 +4772,10 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
                     vshPrint(ctl, "%-15s: %d\n", params[i].field,
                              params[i].value.b);
                     break;
+                case VIR_TYPED_PARAM_STRING:
+                    vshPrint(ctl, "%-15s: %s\n", params[i].field,
+                             params[i].value.s);
+                    break;
                 default:
                     vshPrint(ctl, "unimplemented blkio parameter type\n");
             }
@@ -4765,11 +4796,35 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
                         sizeof(temp->field));
                 weight = 0;
             }
+
+            if (weight_device) {
+                temp->value.s = (char *)weight_device;
+                temp->type = VIR_TYPED_PARAM_STRING;
+                strncpy(temp->field, VIR_DOMAIN_BLKIO_WEIGHT_DEVICE,
+                        sizeof(temp->field));
+            }
+        }
+        ret = true;
+        if (weight_device) {
+            flags |= VIR_DOMAIN_TYPED_STRING_OKAY;
+            if (virDomainSetBlkioParameters(dom, params, nparams, flags) != 0) {
+                if (last_error->code == VIR_ERR_INVALID_ARG) {
+                    flags &= ~VIR_DOMAIN_TYPED_STRING_OKAY;
+                    if (virDomainSetBlkioParameters(dom, params, nparams, flags) != 0) {
+                        vshError(ctl, "%s", _("Unable to change blkio parameters"));
+                        ret = false;
+                    }
+                } else {
+                    vshError(ctl, "%s", _("Unable to change blkio parameters"));
+                    ret = false;
+                }
+            }
+        } else {
+            if (virDomainSetBlkioParameters(dom, params, nparams, flags) != 0) {
+                vshError(ctl, "%s", _("Unable to change blkio parameters"));
+                ret = false;
+            }
         }
-        if (virDomainSetBlkioParameters(dom, params, nparams, flags) != 0)
-            vshError(ctl, "%s", _("Unable to change blkio parameters"));
-        else
-            ret = true;
     }
 
   cleanup:
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 7712db4..8c29759 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1030,12 +1030,15 @@ value are kilobytes (i.e. blocks of 1024 bytes).
 
 Specifying -1 as a value for these limits is interpreted as unlimited.
 
-=item B<blkiotune> I<domain-id> [I<--weight> B<weight>] [[I<--config>]
+=item B<blkiotune> I<domain-id> [I<--weight> B<weight>]
+[I<--weight-device> B<weight-device>] [[I<--config>]
 [I<--live>] | [I<--current>]]
 
 Display or set the blkio parameters. QEMU/KVM supports I<--weight>.
 I<--weight> is in range [100, 1000].
 
+B<weight-device> is in the format of /device/path,weight;/device/path,weight.
+
 If I<--live> is specified, affect a running guest.
 If I<--config> is specified, affect the next boot of a persistent guest.
 If I<--current> is specified, affect the current guest state.
-- 
1.7.3.1




More information about the libvir-list mailing list