...
<blkiotune>
<weight>800</weight>
+ <device>
+ <path>/dev/sda</path>
+ <weight>1000</weight>
+ </device>
+ <device>
+ <path>/dev/sdb</path>
+ <weight>500</weight>
+ </device>
</blkiotune>
...
</domain>
<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>
<!-- 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>
#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,
#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)
{
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);
&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)
char uuidstr[VIR_UUID_STRING_BUFLEN];
const char *type = NULL;
int n, allones = 1;
+ bool blkio = false;
virCheckFlags(DUMPXML_FLAGS |
VIR_DOMAIN_XML_INTERNAL_STATUS |
/* add blkiotune only if there are any */
if (def->blkio.weight) {
+ blkio = true;
+ } else {
+ for (n = 0; n < def->blkio.ndevices; n++) {
+ if (def->blkio.devices[n].weight) {
+ blkio = true;
+ break;
+ }
+ }
+ }
+
+ if (blkio) {
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++) {
+ if (def->blkio.devices[n].weight == 0)
+ continue;
+ 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");
}
/* 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
*
struct {
unsigned int weight;
+
+ size_t ndevices;
+ virBlkioDeviceWeightPtr devices;
} blkio;
struct {
# domain_conf.h
+virBlkioDeviceWeightArrayClear;
virDiskNameToBusDeviceIndex;
virDiskNameToIndex;
virDomainActualNetDefFree;
--- /dev/null
+<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>
{"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")},
cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
{
virDomainPtr dom;
+ const char *device_weight = NULL;
int weight = 0;
int nparams = 0;
int rv = 0;
}
}
+ 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) {
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));
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;
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.