mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
Support block I/O throttle in XML
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>
This commit is contained in:
parent
115a2a3fbb
commit
6df7ccb10e
@ -536,7 +536,11 @@
|
||||
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><iotune></code></a>
|
||||
element which can apply to an
|
||||
individual <code><disk></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,
|
||||
@ -945,6 +949,11 @@
|
||||
<driver name="tap" type="aio" cache="default"/>
|
||||
<source file='/var/lib/xen/images/fv0'/ startupPolicy='optional'>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<iotune>
|
||||
<total_bytes_sec>10000000</total_bytes_sec>
|
||||
<read_iops_sec>400000</read_iops_sec>
|
||||
<write_iops_sec>100000</write_iops_sec>
|
||||
</iotune>
|
||||
<boot order='2'/>
|
||||
<encryption type='...'>
|
||||
...
|
||||
@ -1062,6 +1071,40 @@
|
||||
<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><blkiotune></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
|
||||
|
@ -618,42 +618,47 @@
|
||||
</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">
|
||||
@ -2615,6 +2620,51 @@
|
||||
</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
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user