[libvirt] [PATCHv4 3/4] blkiotune: add interface for blkiotune.device_weight

Eric Blake eblake at redhat.com
Tue Nov 15 04:30:01 UTC 2011


From: Hu Tao <hutao at cn.fujitsu.com>

This adds per-device weights to <blkiotune>.  Note that the
cgroups implementation only supports weights per block device,
and not per-file within the device; hence this option must be
global to the domain definition rather than tied to individual
<devices>/<disk> entries:

<domain ...>
  <blkiotune>
    <device>
      <path>/path/to/block</path>
      <weight>1000</weight>
    </device>
  </blkiotune>
..

This patch also adds a parameter --device-weights to virsh command
blkiotune for setting/getting blkiotune.weight_device for any
hypervisor that supports it.  All <device> entries under
<blkiotune> are concatenated into a single string attribute under
virDomain{Get,Set}BlkioParameters, named "device_weight".

Signed-off-by: Hu Tao <hutao at cn.fujitsu.com>
Signed-off-by: Eric Blake <eblake at redhat.com>
---
 docs/formatdomain.html.in                          |   29 +++++-
 docs/schemas/domaincommon.rng                      |   26 ++++-
 include/libvirt/libvirt.h.in                       |   10 ++
 src/conf/domain_conf.c                             |   99 +++++++++++++++++++-
 src/conf/domain_conf.h                             |   14 +++
 src/libvirt_private.syms                           |    1 +
 .../qemuxml2argv-blkiotune-device.xml              |   36 +++++++
 tools/virsh.c                                      |   43 +++++++--
 tools/virsh.pod                                    |    8 ++-
 9 files changed, 245 insertions(+), 21 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index cbad196..99c5add 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -505,6 +505,14 @@
   ...
   <blkiotune>
     <weight>800</weight>
+    <device>
+      <path>/dev/sda</path>
+      <weight>1000</weight>
+    </device>
+    <device>
+      <path>/dev/sdb</path>
+      <weight>500</weight>
+    </device>
   </blkiotune>
   ...
 </domain>
@@ -514,10 +522,25 @@
       <dt><code>blkiotune</code></dt>
       <dd> The optional <code>blkiotune</code> element provides the ability
         to tune Blkio cgroup tunable parameters for the domain. If this is
-        omitted, it defaults to the OS provided defaults.</dd>
+        omitted, it defaults to the OS provided
+        defaults. <span class="since">Since 0.8.8</span></dd>
       <dt><code>weight</code></dt>
-      <dd> The optional <code>weight</code> element is the I/O weight of the
-        guest. The value should be in range [100, 1000].</dd>
+      <dd> The optional <code>weight</code> element is the overall I/O
+        weight of the guest. The value should be in the range [100,
+        1000].</dd>
+      <dt><code>device</code></dt>
+      <dd>The domain may have multiple <code>device</code> elements
+        that further tune the weights for each host block device in
+        use by the domain.  Note that
+        multiple <a href="#elementsDisks">guest disks</a> can share a
+        single host block device, if they are backed by files within
+        the same host file system, which is why this tuning parameter
+        is at the global domain level rather than associated with each
+        guest disk device.  Each <code>device</code> element has two
+        mandatory sub-elements, <code>path</code> describing the
+        absolute path of the device, and <code>weight</code> giving
+        the relative weight of that device, in the range [100,
+        1000].  <span class="since">Since 0.9.8</span></dd>
     </dl>


diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6f858e..f776a51 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -322,12 +322,26 @@
       <!-- The Blkio cgroup related tunables would go in the blkiotune -->
       <optional>
         <element name="blkiotune">
-          <!-- I/O weight the VM can use -->
-          <optional>
-            <element name="weight">
-              <ref name="weight"/>
-            </element>
-          </optional>
+          <interleave>
+            <!-- I/O weight the VM can use -->
+            <optional>
+              <element name="weight">
+                <ref name="weight"/>
+              </element>
+            </optional>
+            <zeroOrMore>
+              <element name="device">
+                <interleave>
+                  <element name="path">
+                    <ref name="absFilePath"/>
+                  </element>
+                  <element name="weight">
+                    <ref name="weight"/>
+                  </element>
+                </interleave>
+              </element>
+            </zeroOrMore>
+          </interleave>
         </element>
       </optional>

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2ab89f5..ff4f51b 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1236,6 +1236,16 @@ char *                  virDomainGetSchedulerType(virDomainPtr domain,

 #define VIR_DOMAIN_BLKIO_WEIGHT "weight"

+/**
+ * VIR_DOMAIN_BLKIO_DEVICE_WEIGHT:
+ *
+ * Macro for the blkio tunable weight_device: it represents the
+ * per-device weight, as a string.  The string is parsed as a
+ * series of /path/to/device,weight elements, separated by ','.
+ */
+
+#define VIR_DOMAIN_BLKIO_DEVICE_WEIGHT "device_weight"
+
 /* 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 58f4d0f..b35c83c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -603,6 +603,67 @@ VIR_ENUM_IMPL(virDomainStartupPolicy, VIR_DOMAIN_STARTUP_POLICY_LAST,
 #define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
 #define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE

+
+void
+virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights,
+                               int ndevices)
+{
+    int i;
+
+    for (i = 0; i < ndevices; i++)
+        VIR_FREE(deviceWeights[i].path);
+}
+
+/**
+ * virDomainBlkioDeviceWeightParseXML
+ *
+ * this function parses a XML node:
+ *
+ *   <device>
+ *     <path>/fully/qualified/device/path</path>
+ *     <weight>weight</weight>
+ *   </device>
+ *
+ * and fills a virBlkioDeviceWeight struct.
+ */
+static int
+virDomainBlkioDeviceWeightParseXML(xmlNodePtr root,
+                                   virBlkioDeviceWeightPtr dw)
+{
+    char *c;
+    xmlNodePtr node;
+
+    node = root->children;
+    while (node) {
+        if (node->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(node->name, BAD_CAST "path") && !dw->path) {
+                dw->path = (char *)xmlNodeGetContent(node);
+            } else if (xmlStrEqual(node->name, BAD_CAST "weight")) {
+                c = (char *)xmlNodeGetContent(node);
+                if (virStrToLong_ui(c, NULL, 10, &dw->weight) < 0) {
+                    virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                         _("could not parse weight %s"),
+                                         c);
+                    VIR_FREE(c);
+                    VIR_FREE(dw->path);
+                    return -1;
+                }
+                VIR_FREE(c);
+            }
+        }
+        node = node->next;
+    }
+    if (!dw->path) {
+        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                             _("missing per-device path"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
 static void
 virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
 {
@@ -1272,6 +1333,10 @@ void virDomainDefFree(virDomainDefPtr def)
     VIR_FREE(def->emulator);
     VIR_FREE(def->description);

+    virBlkioDeviceWeightArrayClear(def->blkio.devices,
+                                   def->blkio.ndevices);
+    VIR_FREE(def->blkio.devices);
+
     virDomainWatchdogDefFree(def->watchdog);

     virDomainMemballoonDefFree(def->memballoon);
@@ -6711,6 +6776,22 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                      &def->blkio.weight) < 0)
         def->blkio.weight = 0;

+    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract blkiotune nodes"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
+        goto no_memory;
+
+    for (i = 0; i < n; i++) {
+        if (virDomainBlkioDeviceWeightParseXML(nodes[i],
+                                               &def->blkio.devices[i]) < 0)
+            goto error;
+        def->blkio.ndevices++;
+    }
+    VIR_FREE(nodes);
+
     /* Extract other memory tunables */
     if (virXPathULong("string(./memtune/hard_limit)", ctxt,
                       &def->mem.hard_limit) < 0)
@@ -10849,10 +10930,22 @@ virDomainDefFormatInternal(virDomainDefPtr def,
                       def->mem.cur_balloon);

     /* add blkiotune only if there are any */
-    if (def->blkio.weight) {
+    if (def->blkio.weight || def->blkio.devices) {
         virBufferAddLit(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);
+
+        for (n = 0; n < def->blkio.ndevices; n++) {
+            virBufferAddLit(buf, "    <device>\n");
+            virBufferEscapeString(buf, "      <path>%s</path>\n",
+                                  def->blkio.devices[n].path);
+            virBufferAsprintf(buf, "      <weight>%u</weight>\n",
+                              def->blkio.devices[n].weight);
+            virBufferAddLit(buf, "    </device>\n");
+        }
+
         virBufferAddLit(buf, "  </blkiotune>\n");
     }

diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a3cb834..d3c6381 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1361,6 +1361,17 @@ struct _virDomainNumatuneDef {
     /* Future NUMA tuning related stuff should go here. */
 };

+typedef struct _virBlkioDeviceWeight virBlkioDeviceWeight;
+typedef virBlkioDeviceWeight *virBlkioDeviceWeightPtr;
+struct _virBlkioDeviceWeight {
+    char *path;
+    unsigned int weight;
+};
+
+void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights,
+                                    int ndevices);
+
+
 /*
  * Guest VM main configuration
  *
@@ -1378,6 +1389,9 @@ struct _virDomainDef {

     struct {
         unsigned int weight;
+
+        size_t ndevices;
+        virBlkioDeviceWeightPtr devices;
     } blkio;

     struct {
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b15a8db..d78fd53 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -231,6 +231,7 @@ virDomainAuditVcpu;


 # domain_conf.h
+virBlkioDeviceWeightArrayClear;
 virDiskNameToBusDeviceIndex;
 virDiskNameToIndex;
 virDomainActualNetDefFree;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml b/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml
new file mode 100644
index 0000000..3412753
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219136</memory>
+  <currentMemory>219136</currentMemory>
+  <blkiotune>
+    <weight>800</weight>
+    <device>
+      <path>/dev/sda</path>
+      <weight>400</weight>
+    </device>
+    <device>
+      <path>/dev/sdb</path>
+      <weight>900</weight>
+    </device>
+  </blkiotune>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tools/virsh.c b/tools/virsh.c
index 83dc3c7..a1d2afd 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4648,6 +4648,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]")},
+    {"device-weights", VSH_OT_STRING, VSH_OFLAG_NONE,
+     N_("per-device IO Weights, 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")},
@@ -4658,6 +4660,7 @@ static bool
 cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
 {
     virDomainPtr dom;
+    const char *device_weight = NULL;
     int weight = 0;
     int nparams = 0;
     int rv = 0;
@@ -4702,6 +4705,16 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
         }
     }

+    rv = vshCommandOptString(cmd, "device-weights", &device_weight);
+    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 */
         if (virDomainGetBlkioParameters(dom, NULL, &nparams, flags) != 0) {
@@ -4749,12 +4762,14 @@ 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");
             }
         }
-
-        ret = true;
     } else {
         /* set the blkio parameters */
         params = vshCalloc(ctl, nparams, sizeof(*params));
@@ -4765,18 +4780,30 @@ cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)

             if (weight) {
                 temp->value.ui = weight;
-                strncpy(temp->field, VIR_DOMAIN_BLKIO_WEIGHT,
-                        sizeof(temp->field));
-                weight = 0;
+                if (!virStrcpy(temp->field, VIR_DOMAIN_BLKIO_WEIGHT,
+                               sizeof(temp->field)))
+                    goto cleanup;
+            }
+
+            if (device_weight) {
+                temp->value.s = vshStrdup(ctl, device_weight);
+                temp->type = VIR_TYPED_PARAM_STRING;
+                if (!virStrcpy(temp->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
+                               sizeof(temp->field)))
+                    goto cleanup;
             }
         }
-        if (virDomainSetBlkioParameters(dom, params, nparams, flags) != 0)
+
+        if (virDomainSetBlkioParameters(dom, params, nparams, flags) < 0) {
             vshError(ctl, "%s", _("Unable to change blkio parameters"));
-        else
-            ret = true;
+            goto cleanup;
+        }
     }

+    ret = true;
+
   cleanup:
+    virTypedParameterArrayClear(params, nparams);
     VIR_FREE(params);
     virDomainFree(dom);
     return ret;
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 775d302..ef024c5 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1032,12 +1032,18 @@ 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<--device-weights> B<device-weights>] [[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<device-weights> is a single string listing one or more device/weight
+pairs, in the format of /path/to/device,weight,/path/to/device,weight.
+Each weight is in the range [100, 1000], or the value 0 to remove that
+device from per-device listings.
+
 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.7.1




More information about the libvir-list mailing list