]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Support block I/O throttle in XML
authorLei Li <lilei@linux.vnet.ibm.com>
Tue, 15 Nov 2011 09:02:46 +0000 (17:02 +0800)
committerEric Blake <eblake@redhat.com>
Wed, 30 Nov 2011 18:36:09 +0000 (11:36 -0700)
Enable block I/O throttle for per-disk in XML, as the first
per-disk IO tuning parameter.

Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h

index e4fef9e4b40a03c1380897c6a4ec23cc212675d4..204373e2a2988191420171e1c7f98ae74aab2ba7 100644 (file)
         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
+        guest disk device (contrast this to
+        the <a href="#elementsDisks"><code>&lt;iotune&gt;</code></a>
+        element which can apply to an
+        individual <code>&lt;disk&gt;</code>).
+        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,
       &lt;driver name="tap" type="aio" cache="default"/&gt;
       &lt;source file='/var/lib/xen/images/fv0'/ startupPolicy='optional'&gt;
       &lt;target dev='hda' bus='ide'/&gt;
+      &lt;iotune&gt;
+        &lt;total_bytes_sec&gt;10000000&lt;/total_bytes_sec&gt;
+        &lt;read_iops_sec&gt;400000&lt;/read_iops_sec&gt;
+        &lt;write_iops_sec&gt;100000&lt;/write_iops_sec&gt;
+      &lt;/iotune&gt;
       &lt;boot order='2'/&gt;
       &lt;encryption type='...'&gt;
         ...
         <span class="since">Since 0.0.3; <code>bus</code> attribute since 0.4.3;
         "usb" attribute value since after 0.4.4; "sata" attribute value since
         0.9.7</span></dd>
+      <dt><code>iotune</code></dt>
+      <dd>The optional <code>iotune</code> element provides the
+        ability to provide additional per-device I/O tuning, with
+        values that can vary for each device (contrast this to
+        the <a href="#elementsBlockTuning"><code>&lt;blkiotune&gt;</code></a>
+        element, which applies globally to the domain).  Currently,
+        the only tuning available is Block I/O throttling for qemu.
+        This element has optional sub-elements; any sub-element not
+        specified or given with a value of 0 implies no
+        limit.  <span class="since">Since 0.9.8</span>
+        <dl>
+          <dt><code>total_bytes_sec</code></dt>
+          <dd>The optional <code>total_bytes_sec</code> element is the
+            total throughput limit in bytes per second.  This cannot
+            appear with <code>read_bytes_sec</code>
+            or <code>write_bytes_sec</code>.</dd>
+          <dt><code>read_bytes_sec</code></dt>
+          <dd>The optional <code>read_bytes_sec</code> element is the
+            read throughput limit in bytes per second.</dd>
+          <dt><code>write_bytes_sec</code></dt>
+          <dd>The optional <code>write_bytes_sec</code> element is the
+            write throughput limit in bytes per second.</dd>
+          <dt><code>total_iops_sec</code></dt>
+          <dd>The optional <code>total_iops_sec</code> element is the
+            total I/O operations per second.  This cannot
+            appear with <code>read_iops_sec</code>
+            or <code>write_iops_sec</code>.</dd>
+          <dt><code>read_iops_sec</code></dt>
+          <dd>The optional <code>read_iops_sec</code> element is the
+            read I/O operations per second.</dd>
+          <dt><code>write_iops_sec</code></dt>
+          <dd>The optional <code>write_iops_sec</code> element is the
+            write I/O operations per second.</dd>
+        </dl>
       <dt><code>driver</code></dt>
       <dd>
         The optional driver element allows specifying further details
index 97a23a2a59113cdd04f058317d41927713681fde..22bbd4608e170311370fcf01792c30d986ce17ad 100644 (file)
     </element>
   </define>
   <define name="diskspec">
-    <optional>
-      <ref name="driver"/>
-    </optional>
-    <optional>
-      <ref name="diskAuth"/>
-    </optional>
-    <ref name="target"/>
-    <optional>
-      <ref name="deviceBoot"/>
-    </optional>
-    <optional>
-      <element name="readonly">
-        <empty/>
-      </element>
-    </optional>
-    <optional>
-      <element name="shareable">
-        <empty/>
-      </element>
-    </optional>
-    <optional>
-      <element name="transient">
-        <empty/>
-      </element>
-    </optional>
-    <optional>
-      <element name="serial">
-        <ref name="diskSerial"/>
-      </element>
-    </optional>
-    <optional>
-      <ref name="encryption"/>
-    </optional>
-    <optional>
-      <ref name="address"/>
-    </optional>
+    <interleave>
+      <optional>
+        <ref name="driver"/>
+      </optional>
+      <optional>
+        <ref name="diskAuth"/>
+      </optional>
+      <ref name="target"/>
+      <optional>
+        <ref name="deviceBoot"/>
+      </optional>
+      <optional>
+        <element name="readonly">
+          <empty/>
+        </element>
+      </optional>
+      <optional>
+        <element name="shareable">
+          <empty/>
+        </element>
+      </optional>
+      <optional>
+        <element name="transient">
+          <empty/>
+        </element>
+      </optional>
+      <optional>
+        <element name="serial">
+          <ref name="diskSerial"/>
+        </element>
+      </optional>
+      <optional>
+        <ref name="encryption"/>
+      </optional>
+      <optional>
+        <ref name="diskIoTune"/>
+      </optional>
+      <optional>
+        <ref name="address"/>
+      </optional>
+    </interleave>
   </define>
   <define name="snapshot">
     <attribute name="snapshot">
     </element>
   </define>
 
+  <define name='diskIoTune'>
+    <element name="iotune">
+      <interleave>
+        <choice>
+          <element name="total_bytes_sec">
+            <data type="unsignedLong"/>
+          </element>
+          <group>
+            <interleave>
+              <optional>
+                <element name="read_bytes_sec">
+                  <data type="unsignedLong"/>
+                </element>
+              </optional>
+              <optional>
+                <element name="write_bytes_sec">
+                  <data type="unsignedLong"/>
+                </element>
+              </optional>
+            </interleave>
+          </group>
+        </choice>
+        <choice>
+          <element name="total_iops_sec">
+            <data type="unsignedLong"/>
+          </element>
+          <group>
+            <interleave>
+              <optional>
+                <element name="read_iops_sec">
+                  <data type="unsignedLong"/>
+                </element>
+              </optional>
+              <optional>
+                <element name="write_iops_sec">
+                  <data type="unsignedLong"/>
+                </element>
+              </optional>
+            </interleave>
+          </group>
+        </choice>
+      </interleave>
+    </element>
+  </define>
+
   <!--
        Optional hypervisor extensions in their own namespace:
          QEmu
index d50a5c708aab7ef388683d1ada19fe66786ae8a9..7ed2c35a1776d7260123acaa64ff41c23dc1e58f 100644 (file)
@@ -2507,11 +2507,13 @@ cleanup:
 static virDomainDiskDefPtr
 virDomainDiskDefParseXML(virCapsPtr caps,
                          xmlNodePtr node,
+                         xmlXPathContextPtr ctxt,
                          virBitmapPtr bootMap,
                          unsigned int flags)
 {
     virDomainDiskDefPtr def;
     xmlNodePtr cur, child;
+    xmlNodePtr save_ctxt = ctxt->node;
     char *type = NULL;
     char *device = NULL;
     char *snapshot = NULL;
@@ -2543,6 +2545,8 @@ virDomainDiskDefParseXML(virCapsPtr caps,
         return NULL;
     }
 
+    ctxt->node = node;
+
     type = virXMLPropString(node, "type");
     if (type) {
         if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
@@ -2707,6 +2711,62 @@ virDomainDiskDefParseXML(virCapsPtr caps,
                     }
                     child = child->next;
                 }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
+                if (virXPathULongLong("string(./iotune/total_bytes_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.total_bytes_sec) < 0) {
+                    def->blkdeviotune.total_bytes_sec = 0;
+                }
+
+                if (virXPathULongLong("string(./iotune/read_bytes_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.read_bytes_sec) < 0) {
+                    def->blkdeviotune.read_bytes_sec = 0;
+                }
+
+                if (virXPathULongLong("string(./iotune/write_bytes_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.write_bytes_sec) < 0) {
+                    def->blkdeviotune.write_bytes_sec = 0;
+                }
+
+                if (virXPathULongLong("string(./iotune/total_iops_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.total_iops_sec) < 0) {
+                    def->blkdeviotune.total_iops_sec = 0;
+                }
+
+                if (virXPathULongLong("string(./iotune/read_iops_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.read_iops_sec) < 0) {
+                    def->blkdeviotune.read_iops_sec = 0;
+                }
+
+                if (virXPathULongLong("string(./iotune/write_iops_sec)",
+                                      ctxt,
+                                      &def->blkdeviotune.write_iops_sec) < 0) {
+                    def->blkdeviotune.write_iops_sec = 0;
+                }
+
+                if ((def->blkdeviotune.total_bytes_sec &&
+                     def->blkdeviotune.read_bytes_sec) ||
+                    (def->blkdeviotune.total_bytes_sec &&
+                     def->blkdeviotune.write_bytes_sec)) {
+                    virDomainReportError(VIR_ERR_XML_ERROR,
+                                         _("total and read/write bytes_sec "
+                                           "cannot be set at the same time"));
+                    goto error;
+                }
+
+                if ((def->blkdeviotune.total_iops_sec &&
+                     def->blkdeviotune.read_iops_sec) ||
+                    (def->blkdeviotune.total_iops_sec &&
+                     def->blkdeviotune.write_iops_sec)) {
+                    virDomainReportError(VIR_ERR_XML_ERROR,
+                                         _("total and read/write iops_sec "
+                                           "cannot be set at the same time"));
+                    goto error;
+                }
             } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                 def->readonly = 1;
             } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -3001,6 +3061,7 @@ cleanup:
     virStorageEncryptionFree(encryption);
     VIR_FREE(startupPolicy);
 
+    ctxt->node = save_ctxt;
     return def;
 
 no_memory:
@@ -6191,7 +6252,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
 
     if (xmlStrEqual(node->name, BAD_CAST "disk")) {
         dev->type = VIR_DOMAIN_DEVICE_DISK;
-        if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
+        if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt,
                                                         NULL, flags)))
             goto error;
     } else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
@@ -7277,6 +7338,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     for (i = 0 ; i < n ; i++) {
         virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
                                                             nodes[i],
+                                                            ctxt,
                                                             bootMap,
                                                             flags);
         if (!disk)
@@ -9733,6 +9795,48 @@ virDomainDiskDefFormat(virBufferPtr buf,
     virBufferAsprintf(buf, "      <target dev='%s' bus='%s'/>\n",
                       def->dst, bus);
 
+    /*disk I/O throttling*/
+    if (def->blkdeviotune.total_bytes_sec ||
+        def->blkdeviotune.read_bytes_sec ||
+        def->blkdeviotune.write_bytes_sec ||
+        def->blkdeviotune.total_iops_sec ||
+        def->blkdeviotune.read_iops_sec ||
+        def->blkdeviotune.write_iops_sec) {
+        virBufferAddLit(buf, "      <iotune>\n");
+        if (def->blkdeviotune.total_bytes_sec) {
+            virBufferAsprintf(buf, "        <total_bytes_sec>%llu</total_bytes_sec>\n",
+                              def->blkdeviotune.total_bytes_sec);
+        }
+
+        if (def->blkdeviotune.read_bytes_sec) {
+            virBufferAsprintf(buf, "        <read_bytes_sec>%llu</read_bytes_sec>\n",
+                              def->blkdeviotune.read_bytes_sec);
+
+        }
+
+        if (def->blkdeviotune.write_bytes_sec) {
+            virBufferAsprintf(buf, "        <write_bytes_sec>%llu</write_bytes_sec>\n",
+                              def->blkdeviotune.write_bytes_sec);
+        }
+
+        if (def->blkdeviotune.total_iops_sec) {
+            virBufferAsprintf(buf, "        <total_iops_sec>%llu</total_iops_sec>\n",
+                              def->blkdeviotune.total_iops_sec);
+        }
+
+        if (def->blkdeviotune.read_iops_sec) {
+            virBufferAsprintf(buf, "        <read_iops_sec>%llu</read_iops_sec>",
+                              def->blkdeviotune.read_iops_sec);
+        }
+
+        if (def->blkdeviotune.write_iops_sec) {
+            virBufferAsprintf(buf, "        <write_iops_sec>%llu</write_iops_sec>",
+                              def->blkdeviotune.write_iops_sec);
+        }
+
+        virBufferAddLit(buf, "      </iotune>\n");
+    }
+
     if (def->bootIndex)
         virBufferAsprintf(buf, "      <boot order='%d'/>\n", def->bootIndex);
     if (def->readonly)
index 8b05b2fe0044e3a2f8ca92f80063226c9cc96185..d6ed8980a3b12e7d6f20f23ce9c45d5086bac479 100644 (file)
@@ -310,6 +310,17 @@ enum virDomainDiskSecretType {
     VIR_DOMAIN_DISK_SECRET_TYPE_LAST
 };
 
+typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
+struct _virDomainBlockIoTuneInfo {
+    unsigned long long total_bytes_sec;
+    unsigned long long read_bytes_sec;
+    unsigned long long write_bytes_sec;
+    unsigned long long total_iops_sec;
+    unsigned long long read_iops_sec;
+    unsigned long long write_iops_sec;
+};
+typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr;
+
 /* Stores the virtual disk configuration */
 typedef struct _virDomainDiskDef virDomainDiskDef;
 typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -332,6 +343,9 @@ struct _virDomainDiskDef {
     } auth;
     char *driverName;
     char *driverType;
+
+    virDomainBlockIoTuneInfo blkdeviotune;
+
     char *serial;
     int cachemode;
     int error_policy;  /* enum virDomainDiskErrorPolicy */