From 6ac81c8ec861399a8195abbdfbf4588521fc84ba Mon Sep 17 00:00:00 2001 From: Hu Tao Date: Tue, 8 Nov 2011 19:00:33 +0800 Subject: [PATCH] blkiotune: add interface for blkiotune.device_weight This adds per-device weights to . 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 / entries: /path/to/block 1000 .. 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 entries under are concatenated into a single string attribute under virDomain{Get,Set}BlkioParameters, named "device_weight". Signed-off-by: Hu Tao Signed-off-by: Eric Blake --- docs/formatdomain.html.in | 29 ++++- docs/schemas/domaincommon.rng | 26 +++- include/libvirt/libvirt.h.in | 10 ++ src/conf/domain_conf.c | 111 +++++++++++++++++- 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, 258 insertions(+), 20 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 61123ac1ca..e4fef9e4b4 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 @@
blkiotune
The optional blkiotune element provides the ability to tune Blkio cgroup tunable parameters for the domain. If this is - omitted, it defaults to the OS provided defaults.
+ omitted, it defaults to the OS provided + defaults. Since 0.8.8
weight
-
The optional weight element is the I/O weight of the - guest. The value should be in range [100, 1000].
+
The optional weight element is the overall I/O + weight of the guest. The value should be in the range [100, + 1000].
+
device
+
The domain may have multiple device elements + that further tune the weights for each host block device in + use by the domain. Note that + multiple guest disks 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 device element has two + mandatory sub-elements, path describing the + absolute path of the device, and weight giving + the relative weight of that device, in the range [100, + 1000]. Since 0.9.8
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 14b55b229f..97a23a2a59 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -327,12 +327,26 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index f8ca5cfbc7..3d5d574e27 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1252,6 +1252,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 3ea99f73d8..d50a5c708a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -601,6 +601,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: + * + * + * /fully/qualified/device/path + * weight + * + * + * 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) { @@ -1397,6 +1458,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); @@ -6834,6 +6899,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) @@ -10956,6 +11037,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, 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 | @@ -10994,9 +11076,34 @@ virDomainDefFormatInternal(virDomainDefPtr def, /* 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, " \n"); - virBufferAsprintf(buf, " %u\n", - def->blkio.weight); + + if (def->blkio.weight) + virBufferAsprintf(buf, " %u\n", + def->blkio.weight); + + for (n = 0; n < def->blkio.ndevices; n++) { + if (def->blkio.devices[n].weight == 0) + continue; + virBufferAddLit(buf, " \n"); + virBufferEscapeString(buf, " %s\n", + def->blkio.devices[n].path); + virBufferAsprintf(buf, " %u\n", + def->blkio.devices[n].weight); + virBufferAddLit(buf, " \n"); + } + virBufferAddLit(buf, " \n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4439f55c12..8b05b2fe00 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1360,6 +1360,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 * @@ -1377,6 +1388,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 9f2a224a21..fdf61bb849 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 0000000000..3412753b40 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml @@ -0,0 +1,36 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + + 800 + + /dev/sda + 400 + + + /dev/sdb + 900 + + + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + +
+ + + + + diff --git a/tools/virsh.c b/tools/virsh.c index 3370fc4603..01da8e51a4 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -4653,6 +4653,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")}, @@ -4663,6 +4665,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; @@ -4707,6 +4710,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) { @@ -4754,12 +4767,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)); @@ -4770,18 +4785,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 b5aadef92c..d606f995b6 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1045,12 +1045,18 @@ value are kilobytes (i.e. blocks of 1024 bytes). Specifying -1 as a value for these limits is interpreted as unlimited. -=item B I [I<--weight> B] [[I<--config>] +=item B I [I<--weight> B] +[I<--device-weights> B] [[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 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. -- GitLab