To ease LXC configuration conversion, allow blkiotune device XML fragments to define the device using its major:minor numbers. --- docs/formatdomain.html.in | 10 +- src/conf/domain_conf.c | 45 ++++++++- src/conf/domain_conf.h | 2 + src/lxc/lxc_cgroup.c | 5 + src/lxc/lxc_driver.c | 10 ++ src/lxc/lxc_native.c | 24 ++++- src/qemu/qemu_cgroup.c | 5 + src/qemu/qemu_driver.c | 10 ++ src/util/vircgroup.c | 126 ++++++++++-------------- src/util/vircgroup.h | 10 ++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 4 +- 11 files changed, 165 insertions(+), 86 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fd02864..2ab7d39 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -761,6 +761,10 @@ <path>/dev/sdb</path> <weight>500</weight> </device> + <device> + <node major='8' minor='0'/> + <weight>500</weight> + </device> </blkiotune> ... </domain> @@ -794,7 +798,11 @@ absolute path of the device, and <code>weight</code> giving the relative weight of that device, in the range [100, 1000]. After kernel 2.6.39, the value could be in the - range [10, 1000].<span class="since">Since 0.9.8</span></dd> + range [10, 1000].<span class="since">Since 0.9.8</span>. + <span class="since">Since 1.2.2</span> each <code>device</code> + element can replace the mandatory <code>path</code> sub-element + by a <code>node</code> one. <code>node</code> has two mandatory + attributes <code>major</code> and <code>minor</code>.</dd> </dl> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 28e24f9..65192df 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -905,6 +905,7 @@ virBlkioDeviceArrayClear(virBlkioDevicePtr devices, * * <device> * <path>/fully/qualified/device/path</path> + * <node major='8' minor='0/> * <weight>weight</weight> * <read_bytes_sec>bps</read_bytes_sec> * <write_bytes_sec>bps</write_bytes_sec> @@ -920,12 +921,38 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, { char *c = NULL; xmlNodePtr node; + char *major = NULL; + char *minor = NULL; + bool hasNumbers = false; node = root->children; while (node) { if (node->type == XML_ELEMENT_NODE) { if (xmlStrEqual(node->name, BAD_CAST "path") && !dev->path) { dev->path = (char *)xmlNodeGetContent(node); + } else if (xmlStrEqual(node->name, BAD_CAST "node") && + !hasNumbers){ + if (!(major = virXMLPropString(node, "major")) || + (!(minor = virXMLPropString(node, "minor")))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("node missing major or minor attribute")); + goto error; + } + if (virStrToLong_ui(major, NULL, 10, &dev->major) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not parse major %s"), + major); + goto error; + } + if (virStrToLong_ui(major, NULL, 10, &dev->minor) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("could not parse minor %s"), + minor); + goto error; + } + hasNumbers = true; + VIR_FREE(major); + VIR_FREE(minor); } else if (xmlStrEqual(node->name, BAD_CAST "weight")) { c = (char *)xmlNodeGetContent(node); if (virStrToLong_ui(c, NULL, 10, &dev->weight) < 0) { @@ -975,9 +1002,13 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, } node = node->next; } - if (!dev->path) { + if (!dev->path && !hasNumbers) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("missing per-device path")); + _("missing per-device path or major/minor")); + return -1; + } else if (dev->path && hasNumbers) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cannot have both per-device path and major/minor")); return -1; } @@ -985,6 +1016,8 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root, error: VIR_FREE(c); + VIR_FREE(major); + VIR_FREE(minor); VIR_FREE(dev->path); return -1; } @@ -16855,8 +16888,12 @@ virDomainDefFormatInternal(virDomainDefPtr def, !dev->rbps && !dev->wbps) continue; virBufferAddLit(buf, " <device>\n"); - virBufferEscapeString(buf, " <path>%s</path>\n", - dev->path); + if (dev->path) + virBufferEscapeString(buf, " <path>%s</path>\n", + dev->path); + else + virBufferAsprintf(buf, " <node major='%u' minor='%u'/>\n", + dev->major, dev->minor); if (dev->weight) virBufferAsprintf(buf, " <weight>%u</weight>\n", dev->weight); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d8f2e49..24cc00c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1890,6 +1890,8 @@ struct _virBlkioDevice { unsigned int wiops; unsigned long long rbps; unsigned long long wbps; + unsigned int major; + unsigned int minor; }; enum virDomainRNGModel { diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index cc0d5e8..aabd4f8 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -116,26 +116,31 @@ static int virLXCCgroupSetupBlkioTune(virDomainDefPtr def, if (dev->weight && (virCgroupSetBlkioDeviceWeight(cgroup, dev->path, + dev->major, dev->minor, dev->weight) < 0)) return -1; if (dev->riops && (virCgroupSetBlkioDeviceReadIops(cgroup, dev->path, + dev->major, dev->minor, dev->riops) < 0)) return -1; if (dev->wiops && (virCgroupSetBlkioDeviceWriteIops(cgroup, dev->path, + dev->major, dev->minor, dev->wiops) < 0)) return -1; if (dev->rbps && (virCgroupSetBlkioDeviceReadBps(cgroup, dev->path, + dev->major, dev->minor, dev->rbps) < 0)) return -1; if (dev->wbps && (virCgroupSetBlkioDeviceWriteBps(cgroup, dev->path, + dev->major, dev->minor, dev->wbps) < 0)) return -1; } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index dc0e8e0..057214a 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2323,6 +2323,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWeight(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].weight) < 0) { ret = -1; break; @@ -2332,6 +2334,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].riops) < 0) { ret = -1; break; @@ -2341,6 +2345,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wiops) < 0) { ret = -1; break; @@ -2350,6 +2356,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].rbps) < 0) { ret = -1; break; @@ -2359,6 +2367,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wbps) < 0) { ret = -1; break; diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 675883c..c7ebfb2 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -725,36 +725,52 @@ static int lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) { char **parts = NULL; + char **numbers = NULL; virBlkioDevicePtr device = NULL; virDomainDefPtr def = data; size_t i = 0; char *path = NULL; + unsigned int major, minor = 0; if (!STRPREFIX(name, "lxc.cgroup.blkio.") || STREQ(name, "lxc.cgroup.blkio.weight")|| !value->str) return 0; - if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + if ((!(parts = lxcStringSplit(value->str))) || virStringListLength(parts) != 2 || + (!(numbers = virStringSplit(parts[0], ":", 2))) || + virStringListLength(numbers) != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid %s value: '%s'"), name, value->str); goto error; } - if (virAsprintf(&path, "/dev/block/%s", parts[0]) < 0) + /* *Get the major:minor numbers */ + if (virStrToLong_ui(numbers[0], NULL, 10, &major) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse major: '%s'"), numbers[0]); goto error; + } + if (virStrToLong_ui(numbers[1], NULL, 10, &minor) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse minor: '%s'"), numbers[1]); + goto error; + } /* Do we already have a device definition for this path? * Get that device or create a new one */ for (i = 0; !device && i < def->blkio.ndevices; i++) { - if (STREQ(def->blkio.devices[i].path, path)) + if (def->blkio.devices[i].major == major && + def->blkio.devices[i].minor == minor) device = &def->blkio.devices[i]; } if (!device) { if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) goto error; device = &def->blkio.devices[def->blkio.ndevices - 1]; - device->path = path; + device->major = major; + device->minor = minor; + device->path = NULL; } /* Set the value */ diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index a97f184..2808749 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -404,26 +404,31 @@ qemuSetupBlkioCgroup(virDomainObjPtr vm) virBlkioDevicePtr dev = &vm->def->blkio.devices[i]; if (dev->weight && (virCgroupSetBlkioDeviceWeight(priv->cgroup, dev->path, + dev->major, dev->minor, dev->weight) < 0)) return -1; if (dev->riops && (virCgroupSetBlkioDeviceReadIops(priv->cgroup, dev->path, + dev->major, dev->minor, dev->riops) < 0)) return -1; if (dev->wiops && (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, dev->path, + dev->major, dev->minor, dev->wiops) < 0)) return -1; if (dev->rbps && (virCgroupSetBlkioDeviceReadBps(priv->cgroup, dev->path, + dev->major, dev->minor, dev->rbps) < 0)) return -1; if (dev->wbps && (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, dev->path, + dev->major, dev->minor, dev->wbps) < 0)) return -1; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0128356..f73d942 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7691,6 +7691,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWeight(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].weight) < 0) { ret = -1; break; @@ -7700,6 +7702,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].riops) < 0) { ret = -1; break; @@ -7709,6 +7713,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wiops) < 0) { ret = -1; break; @@ -7718,6 +7724,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceReadBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].rbps) < 0) { ret = -1; break; @@ -7727,6 +7735,8 @@ qemuDomainSetBlkioParameters(virDomainPtr dom, for (j = 0; j < ndevices; j++) { if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, devices[j].path, + devices[j].major, + devices[j].minor, devices[j].wbps) < 0) { ret = -1; break; diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index a6d60c5..e29d7c3 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -1824,6 +1824,37 @@ virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) return ret; } +static int +virCgroupGetBlkioDeviceNumbers(const char *path, + unsigned int *major, + unsigned int *minor) +{ + struct stat sb; + + if (!major || !minor) + return -1; + + if (path) { + if (stat(path, &sb) < 0) { + virReportSystemError(errno, + _("Path '%s' is not accessible"), + path); + return -1; + } + + if (!S_ISBLK(sb.st_mode)) { + virReportSystemError(EINVAL, + _("Path '%s' must be a block device"), + path); + return -1; + } + + *major = major(sb.st_rdev); + *minor = minor(sb.st_rdev); + } + return 0; +} + /** * virCgroupSetBlkioDeviceReadIops: * @group: The cgroup to change block io setting for @@ -1835,28 +1866,17 @@ virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) int virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int riops) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev), - minor(sb.st_rdev), riops) < 0) + if (virAsprintf(&str, "%u:%u %u", major, minor, riops) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1880,28 +1900,17 @@ virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, int virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int wiops) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev), - minor(sb.st_rdev), wiops) < 0) + if (virAsprintf(&str, "%u:%u %u", major, minor, wiops) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1925,28 +1934,17 @@ virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, int virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long rbps) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); - return -1; - } - - if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev), - minor(sb.st_rdev), rbps) < 0) + if (virAsprintf(&str, "%u:%u %llu", major, minor, rbps) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -1969,28 +1967,17 @@ virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, int virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long wbps) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); - return -1; - } - - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev), - minor(sb.st_rdev), wbps) < 0) + if (virAsprintf(&str, "%u:%u %llu", major, minor, wbps) < 0) return -1; ret = virCgroupSetValueStr(group, @@ -2018,28 +2005,17 @@ virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int weight) { char *str; - struct stat sb; int ret; - if (stat(path, &sb) < 0) { - virReportSystemError(errno, - _("Path '%s' is not accessible"), - path); - return -1; - } - - if (!S_ISBLK(sb.st_mode)) { - virReportSystemError(EINVAL, - _("Path '%s' must be a block device"), - path); + if (virCgroupGetBlkioDeviceNumbers(path, &major, &minor) < 0) return -1; - } - if (virAsprintf(&str, "%d:%d %d", major(sb.st_rdev), minor(sb.st_rdev), - weight) < 0) + if (virAsprintf(&str, "%u:%u %d", major, minor, weight) < 0) return -1; ret = virCgroupSetValueStr(group, diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h index a70eb18..2258b36 100644 --- a/src/util/vircgroup.h +++ b/src/util/vircgroup.h @@ -124,22 +124,32 @@ int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight); int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int weight); int virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int riops); int virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned int wiops); int virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long rbps); int virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, const char *path, + unsigned int major, + unsigned int minor, unsigned long long wbps); int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb); diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml index 628798d..73f90ef 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -6,7 +6,7 @@ <blkiotune> <weight>500</weight> <device> - <path>/dev/block/8:16</path> + <node major='8' minor='16'/> <weight>1000</weight> <read_iops_sec>4321</read_iops_sec> <write_iops_sec>8765</write_iops_sec> @@ -14,7 +14,7 @@ <write_bytes_sec>5678</write_bytes_sec> </device> <device> - <path>/dev/block/8:0</path> + <node major='8' minor='0'/> <weight>300</weight> </device> </blkiotune> -- 1.8.5.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list