diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 91d130495e205505dbdc03c7507b7d46bbfcdbdd..3ede3d5ebca142a97914a7fb596cbfcd2d649ff6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1035,7 +1035,11 @@ virCgroupNewVcpu;
virCgroupPathOfController;
virCgroupRemove;
virCgroupRemoveRecursively;
+virCgroupSetBlkioDeviceReadBps;
+virCgroupSetBlkioDeviceReadIops;
virCgroupSetBlkioDeviceWeight;
+virCgroupSetBlkioDeviceWriteBps;
+virCgroupSetBlkioDeviceWriteIops;
virCgroupSetBlkioWeight;
virCgroupSetCpuCfsPeriod;
virCgroupSetCpuCfsQuota;
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 310a4760e6a471089df9a78dde363b927df1e594..cc0d5e8d08bde72aea62e9aa2562010c2c224c7a 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -113,9 +113,30 @@ static int virLXCCgroupSetupBlkioTune(virDomainDefPtr def,
if (def->blkio.ndevices) {
for (i = 0; i < def->blkio.ndevices; i++) {
virBlkioDevicePtr dev = &def->blkio.devices[i];
- if (!dev->weight)
- continue;
- if (virCgroupSetBlkioDeviceWeight(cgroup, dev->path, dev->weight) < 0)
+
+ if (dev->weight &&
+ (virCgroupSetBlkioDeviceWeight(cgroup, dev->path,
+ dev->weight) < 0))
+ return -1;
+
+ if (dev->riops &&
+ (virCgroupSetBlkioDeviceReadIops(cgroup, dev->path,
+ dev->riops) < 0))
+ return -1;
+
+ if (dev->wiops &&
+ (virCgroupSetBlkioDeviceWriteIops(cgroup, dev->path,
+ dev->wiops) < 0))
+ return -1;
+
+ if (dev->rbps &&
+ (virCgroupSetBlkioDeviceReadBps(cgroup, dev->path,
+ dev->rbps) < 0))
+ return -1;
+
+ if (dev->wbps &&
+ (virCgroupSetBlkioDeviceWriteBps(cgroup, dev->path,
+ dev->wbps) < 0))
return -1;
}
}
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index a18955e779060fb0a3783d7bd72665a928bb5a0a..1cc929c5ecae2392318d45953d679da59d2caf85 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -400,10 +400,29 @@ qemuSetupBlkioCgroup(virDomainObjPtr vm)
if (vm->def->blkio.ndevices) {
for (i = 0; i < vm->def->blkio.ndevices; i++) {
virBlkioDevicePtr dev = &vm->def->blkio.devices[i];
- if (!dev->weight)
- continue;
- if (virCgroupSetBlkioDeviceWeight(priv->cgroup, dev->path,
- dev->weight) < 0)
+ if (dev->weight &&
+ (virCgroupSetBlkioDeviceWeight(priv->cgroup, dev->path,
+ dev->weight) < 0))
+ return -1;
+
+ if (dev->riops &&
+ (virCgroupSetBlkioDeviceReadIops(priv->cgroup, dev->path,
+ dev->riops) < 0))
+ return -1;
+
+ if (dev->wiops &&
+ (virCgroupSetBlkioDeviceWriteIops(priv->cgroup, dev->path,
+ dev->wiops) < 0))
+ return -1;
+
+ if (dev->rbps &&
+ (virCgroupSetBlkioDeviceReadBps(priv->cgroup, dev->path,
+ dev->rbps) < 0))
+ return -1;
+
+ if (dev->wbps &&
+ (virCgroupSetBlkioDeviceWriteBps(priv->cgroup, dev->path,
+ dev->wbps) < 0))
return -1;
}
}
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 43eb64920ec61046ed5eb30db453a441818214d0..a6d60c54b59c4b6f1b0825ed205234ba4afb8c9f 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -1824,12 +1824,189 @@ virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight)
return ret;
}
+/**
+ * virCgroupSetBlkioDeviceReadIops:
+ * @group: The cgroup to change block io setting for
+ * @path: The path of device
+ * @riops: The new device read iops throttle, or 0 to clear
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupSetBlkioDeviceReadIops(virCgroupPtr group,
+ const char *path,
+ unsigned int riops)
+{
+ 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);
+ return -1;
+ }
+
+ if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev),
+ minor(sb.st_rdev), riops) < 0)
+ return -1;
+
+ ret = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.read_iops_device",
+ str);
+
+ VIR_FREE(str);
+ return ret;
+}
+
/**
- * virCgroupSetBlkioDeviceWeight:
+ * virCgroupSetBlkioDeviceWriteIops:
+ * @group: The cgroup to change block io setting for
+ * @path: The path of device
+ * @wiops: The new device write iops throttle, or 0 to clear
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group,
+ const char *path,
+ unsigned int wiops)
+{
+ 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);
+ return -1;
+ }
+
+ if (virAsprintf(&str, "%d:%d %u", major(sb.st_rdev),
+ minor(sb.st_rdev), wiops) < 0)
+ return -1;
+
+ ret = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.write_iops_device",
+ str);
+
+ VIR_FREE(str);
+ return ret;
+}
+
+
+/**
+ * virCgroupSetBlkioDeviceReadBps:
+ * @group: The cgroup to change block io setting for
+ * @path: The path of device
+ * @rbps: The new device read bps throttle, or 0 to clear
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupSetBlkioDeviceReadBps(virCgroupPtr group,
+ const char *path,
+ unsigned long long rbps)
+{
+ 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);
+ return -1;
+ }
+
+ if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev),
+ minor(sb.st_rdev), rbps) < 0)
+ return -1;
+
+ ret = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.read_bps_device",
+ str);
+
+ VIR_FREE(str);
+ return ret;
+}
+
+/**
+ * virCgroupSetBlkioDeviceWriteBps:
+ * @group: The cgroup to change block io setting for
+ * @path: The path of device
+ * @wbps: The new device write bps throttle, or 0 to clear
*
- * @group: The cgroup to change io device weight device for
- * @path: The device with a weight to alter
+ * Returns: 0 on success, -1 on error
+ */
+int
+virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group,
+ const char *path,
+ 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);
+ return -1;
+ }
+
+ if (virAsprintf(&str, "%d:%d %llu", major(sb.st_rdev),
+ minor(sb.st_rdev), wbps) < 0)
+ return -1;
+
+ ret = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_BLKIO,
+ "blkio.throttle.write_bps_device",
+ str);
+
+ VIR_FREE(str);
+ return ret;
+}
+
+
+/**
+ * virCgroupSetBlkioDeviceWeight:
+ * @group: The cgroup to change block io setting for
+ * @path: The path of device
* @weight: The new device weight (100-1000),
* (10-1000) after kernel 2.6.39, or 0 to clear
*
@@ -1874,7 +2051,6 @@ virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
}
-
/**
* virCgroupSetMemory:
*
@@ -3312,6 +3488,46 @@ virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED,
return -1;
}
+int
+virCgroupSetBlkioDeviceReadIops(virCgroupPtr group ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED,
+ unsigned int riops ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Control groups not supported on this platform"));
+ return -1;
+}
+
+int
+virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED,
+ unsigned int wiops ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Control groups not supported on this platform"));
+ return -1;
+}
+
+int
+virCgroupSetBlkioDeviceReadBps(virCgroupPtr group ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED,
+ unsigned long long rbps ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Control groups not supported on this platform"));
+ return -1;
+}
+
+int
+virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED,
+ unsigned long long wbps ATTRIBUTE_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("Control groups not supported on this platform"));
+ return -1;
+}
+
int
virCgroupSetMemory(virCgroupPtr group ATTRIBUTE_UNUSED,
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index 835eb306896eacac5208a111fbc85ec99c112c5f..a70eb18aad41b65e699645d922b6cab9d1115f2b 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -126,6 +126,22 @@ int virCgroupSetBlkioDeviceWeight(virCgroupPtr group,
const char *path,
unsigned int weight);
+int virCgroupSetBlkioDeviceReadIops(virCgroupPtr group,
+ const char *path,
+ unsigned int riops);
+
+int virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group,
+ const char *path,
+ unsigned int wiops);
+
+int virCgroupSetBlkioDeviceReadBps(virCgroupPtr group,
+ const char *path,
+ unsigned long long rbps);
+
+int virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group,
+ const char *path,
+ unsigned long long wbps);
+
int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb);
int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml b/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml
index 743cf2958ff7f9499ff552c05f55884c110f2e46..bfb5b0378269347180c397f4041d44fc99f0ce57 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkiotune-device.xml
@@ -8,10 +8,18 @@
/dev/sda
400
+ 10000
+ 10000
+ 10000
+ 10000
/dev/sdb
900
+ 20000
+ 20000
+ 20000
+ 20000
1