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