Add support to read/parse the iotune group setting for qemu.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
include/libvirt/libvirt-domain.h | 8 +++++
src/conf/domain_conf.c | 1 +
src/conf/domain_conf.h | 1 +
src/qemu/qemu_driver.c | 50 ++++++++++++++++++++++++---
src/qemu/qemu_monitor.c | 2 ++
src/qemu/qemu_monitor.h | 1 +
src/qemu/qemu_monitor_json.c | 21 ++++++++++--
src/qemu/qemu_monitor_json.h | 1 +
tests/qemumonitorjsontest.c | 74 +++++++++++++++++++++++++++++++---------
9 files changed, 134 insertions(+), 25 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 8c9876c..1212e5a 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3854,6 +3854,14 @@ typedef void
(*virConnectDomainEventJobCompletedCallback)(virConnectPtr conn,
# define VIR_DOMAIN_TUNABLE_BLKDEV_SIZE_IOPS_SEC "blkdeviotune.size_iops_sec"
/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME:
+ *
+ * Macro represents the group name to be used,
+ * as VIR_TYPED_PARAM_STRING.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME "blkdeviotune.group_name"
+
+/**
* VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX_LENGTH:
*
* Macro represents the length in seconds allowed for a burst period
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 03506cb..f41a783 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1644,6 +1644,7 @@ virDomainDiskDefFree(virDomainDiskDefPtr def)
VIR_FREE(def->vendor);
VIR_FREE(def->product);
VIR_FREE(def->domain_name);
+ VIR_FREE(def->blkdeviotune.group_name);
virDomainDeviceInfoClear(&def->info);
virObjectUnref(def->privateData);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 24aa79c..cb32685 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -548,6 +548,7 @@ struct _virDomainBlockIoTuneInfo {
unsigned long long read_iops_sec_max;
unsigned long long write_iops_sec_max;
unsigned long long size_iops_sec;
+ char *group_name;
unsigned long long total_bytes_sec_max_length;
unsigned long long read_bytes_sec_max_length;
unsigned long long write_bytes_sec_max_length;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b8cec49..4af1cb0 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -114,7 +114,8 @@ VIR_LOG_INIT("qemu.qemu_driver");
#define QEMU_NB_BLOCK_IO_TUNE_PARAM 6
#define QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX 13
-#define QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX_LENGTH 19
+#define QEMU_NB_BLOCK_IO_TUNE_PARAM_GROUP 14
+#define QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX_LENGTH 20
#define QEMU_NB_NUMA_PARAM 2
@@ -17316,7 +17317,8 @@ qemuDomainSetBlockIoTuneDefaults(virDomainBlockIoTuneInfoPtr
newinfo,
bool set_iops_max,
bool set_size_iops,
bool set_bytes_max_length,
- bool set_iops_max_length)
+ bool set_iops_max_length,
+ bool set_group_name)
{
#define SET_IOTUNE_DEFAULTS(BOOL, FIELD) \
if (!BOOL) { \
@@ -17333,6 +17335,8 @@ qemuDomainSetBlockIoTuneDefaults(virDomainBlockIoTuneInfoPtr
newinfo,
if (!set_size_iops)
newinfo->size_iops_sec = oldinfo->size_iops_sec;
+ if (!set_group_name)
+ VIR_STEAL_PTR(newinfo->group_name, oldinfo->group_name);
/* The length field is handled a bit differently. If not defined/set,
* QEMU will default these to 0 or 1 depending on whether something in
@@ -17389,9 +17393,11 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
bool set_bytes_max = false;
bool set_iops_max = false;
bool set_size_iops = false;
+ bool set_group_name = false;
bool set_bytes_max_length = false;
bool set_iops_max_length = false;
bool supportMaxOptions = true;
+ bool supportGroupNameOption = true;
bool supportMaxLengthOptions = true;
virQEMUDriverConfigPtr cfg = NULL;
virObjectEventPtr event = NULL;
@@ -17428,6 +17434,8 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
VIR_TYPED_PARAM_ULLONG,
VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC,
VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+ VIR_TYPED_PARAM_STRING,
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX_LENGTH,
VIR_TYPED_PARAM_ULLONG,
VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX_LENGTH,
@@ -17507,6 +17515,16 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
SET_IOTUNE_FIELD(write_iops_sec_max, set_iops_max,
WRITE_IOPS_SEC_MAX);
SET_IOTUNE_FIELD(size_iops_sec, set_size_iops, SIZE_IOPS_SEC);
+ if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME)) {
+ if (VIR_STRDUP(info.group_name, params->value.s) < 0)
+ goto endjob;
+ set_group_name = true;
+ if (virTypedParamsAddString(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME,
+ param->value.s) < 0)
+ goto endjob;
+ }
SET_IOTUNE_FIELD(total_bytes_sec_max_length, set_bytes_max_length,
TOTAL_BYTES_SEC_MAX_LENGTH);
@@ -17559,6 +17577,8 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
if (def) {
supportMaxOptions = virQEMUCapsGet(priv->qemuCaps,
QEMU_CAPS_DRIVE_IOTUNE_MAX);
+ supportGroupNameOption = virQEMUCapsGet(priv->qemuCaps,
+ QEMU_CAPS_DRIVE_IOTUNE_GROUP);
supportMaxLengthOptions =
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX_LENGTH);
@@ -17577,6 +17597,13 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
goto endjob;
}
+ if (!supportGroupNameOption && set_group_name) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("the block I/O throttling group parameter is not
"
+ "supported with this QEMU binary"));
+ goto endjob;
+ }
+
if (!supportMaxLengthOptions &&
(set_iops_max_length || set_bytes_max_length)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -17595,7 +17622,8 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
set_bytes, set_iops, set_bytes_max,
set_iops_max, set_size_iops,
set_bytes_max_length,
- set_iops_max_length);
+ set_iops_max_length,
+ set_group_name);
#define CHECK_MAX(val) \
do { \
@@ -17623,6 +17651,7 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorSetBlockIoThrottle(priv->mon, device,
&info, supportMaxOptions,
+ supportGroupNameOption,
supportMaxLengthOptions);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
ret = -1;
@@ -17652,7 +17681,8 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
set_bytes, set_iops, set_bytes_max,
set_iops_max, set_size_iops,
set_bytes_max_length,
- set_iops_max_length);
+ set_iops_max_length,
+ set_group_name);
conf_disk->blkdeviotune = info;
ret = virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef);
if (ret < 0)
@@ -17725,8 +17755,11 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX))
maxparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
else if (!virQEMUCapsGet(priv->qemuCaps,
- QEMU_CAPS_DRIVE_IOTUNE_MAX_LENGTH))
+ QEMU_CAPS_DRIVE_IOTUNE_GROUP))
maxparams = QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX;
+ else if (!virQEMUCapsGet(priv->qemuCaps,
+ QEMU_CAPS_DRIVE_IOTUNE_MAX_LENGTH))
+ maxparams = QEMU_NB_BLOCK_IO_TUNE_PARAM_GROUP;
}
if (*nparams == 0) {
@@ -17790,6 +17823,13 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
BLOCK_IOTUNE_ASSIGN(SIZE_IOPS_SEC, size_iops_sec);
+ if (*nparams < maxparams &&
+ virTypedParameterAssign(¶ms[(*nparams)++],
+ VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+ VIR_TYPED_PARAM_STRING,
+ reply.group_name) < 0)
+ goto endjob;
+
BLOCK_IOTUNE_ASSIGN(TOTAL_BYTES_SEC_MAX_LENGTH, total_bytes_sec_max_length);
BLOCK_IOTUNE_ASSIGN(READ_BYTES_SEC_MAX_LENGTH, read_bytes_sec_max_length);
BLOCK_IOTUNE_ASSIGN(WRITE_BYTES_SEC_MAX_LENGTH, write_bytes_sec_max_length);
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index a5e14b2..950d476 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3428,6 +3428,7 @@ qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info,
bool supportMaxOptions,
+ bool supportGroupNameOption,
bool supportMaxLengthOptions)
{
VIR_DEBUG("device=%p, info=%p", device, info);
@@ -3437,6 +3438,7 @@ qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
if (mon->json)
return qemuMonitorJSONSetBlockIoThrottle(mon, device, info,
supportMaxOptions,
+ supportGroupNameOption,
supportMaxLengthOptions);
else
return qemuMonitorTextSetBlockIoThrottle(mon, device, info);
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c3133c4..7476c11 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -877,6 +877,7 @@ int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info,
bool supportMaxOptions,
+ bool supportGroupNameOption,
bool supportMaxLengthOptions);
int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 6c13832..7a08253 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4524,6 +4524,7 @@ qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
virJSONValuePtr temp_dev = virJSONValueArrayGet(io_throttle, i);
virJSONValuePtr inserted;
const char *current_dev;
+ const char *group_name;
if (!temp_dev || temp_dev->type != VIR_JSON_TYPE_OBJECT) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -4549,7 +4550,6 @@ qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
"was not in expected format"));
goto cleanup;
}
-
GET_THROTTLE_STATS("bps", total_bytes_sec);
GET_THROTTLE_STATS("bps_rd", read_bytes_sec);
GET_THROTTLE_STATS("bps_wr", write_bytes_sec);
@@ -4563,6 +4563,12 @@ qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
GET_THROTTLE_STATS_OPTIONAL("iops_rd_max", read_iops_sec_max);
GET_THROTTLE_STATS_OPTIONAL("iops_wr_max", write_iops_sec_max);
GET_THROTTLE_STATS_OPTIONAL("iops_size", size_iops_sec);
+
+ if ((group_name = virJSONValueObjectGetString(inserted, "group"))) {
+ if (VIR_STRDUP(reply->group_name, group_name) < 0)
+ goto cleanup;
+ }
+
GET_THROTTLE_STATS_OPTIONAL("bps_max_length",
total_bytes_sec_max_length);
GET_THROTTLE_STATS_OPTIONAL("bps_rd_max_length",
read_bytes_sec_max_length);
GET_THROTTLE_STATS_OPTIONAL("bps_wr_max_length",
write_bytes_sec_max_length);
@@ -4591,17 +4597,23 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info,
bool supportMaxOptions,
+ bool supportGroupNameOption,
bool supportMaxLengthOptions)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
virJSONValuePtr result = NULL;
+ char *group_name = NULL;
+
+ if (supportGroupNameOption && VIR_STRDUP(group_name, info->group_name)
< 0)
+ return -1;
/* The qemu capability check has already been made in
* qemuDomainSetBlockIoTune. NB, once a NULL is found in
* the sequence, qemuMonitorJSONMakeCommand will stop. So
* let's make use of that when !supportMaxOptions and
- * similarly when !supportMaxLengthOptions */
+ * similarly when !supportGroupNameOption as well as when
+ * when !supportMaxLengthOptions */
cmd = qemuMonitorJSONMakeCommand("block_set_io_throttle",
"s:device", device,
"U:bps", info->total_bytes_sec,
@@ -4618,6 +4630,8 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
"U:iops_rd_max",
info->read_iops_sec_max,
"U:iops_wr_max",
info->write_iops_sec_max,
"U:iops_size", info->size_iops_sec,
+ !supportGroupNameOption ? NULL :
+ "s:group", group_name,
!supportMaxLengthOptions ? NULL :
"P:bps_max_length",
info->total_bytes_sec_max_length,
@@ -4633,7 +4647,7 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
info->write_iops_sec_max_length,
NULL);
if (!cmd)
- return -1;
+ goto cleanup;
if (qemuMonitorJSONCommand(mon, cmd, &result) < 0)
goto cleanup;
@@ -4657,6 +4671,7 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
ret = 0;
cleanup:
+ VIR_FREE(group_name);
virJSONValueFree(cmd);
virJSONValueFree(result);
return ret;
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 77b2e02..55bdfe8 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -328,6 +328,7 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info,
bool supportMaxOptions,
+ bool supportGroupNameOption,
bool supportMaxLengthOptions);
int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index d8fd958..19bfc2a 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -67,12 +67,13 @@ const char *queryBlockReply =
" \"iops_rd_max\": 11,"
" \"iops_wr_max\": 12,"
" \"iops_size\": 13,"
-" \"bps_max_length\": 14,"
-" \"bps_rd_max_length\": 15,"
-" \"bps_wr_max_length\": 16,"
-" \"iops_max_length\": 17,"
-" \"iops_rd_max_length\": 18,"
-" \"iops_wr_max_length\": 19,"
+" \"group\": \"group14\","
+" \"bps_max_length\": 15,"
+" \"bps_rd_max_length\": 16,"
+" \"bps_wr_max_length\": 17,"
+" \"iops_max_length\": 18,"
+" \"iops_rd_max_length\": 19,"
+" \"iops_wr_max_length\": 20,"
" \"file\":
\"/home/zippy/work/tmp/gentoo.qcow2\","
" \"encryption_key_missing\": false"
" },"
@@ -2002,7 +2003,9 @@ testQemuMonitorJSONqemuMonitorJSONSetBlockIoThrottle(const void
*data)
if (!test)
return -1;
- expectedInfo = (virDomainBlockIoTuneInfo) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19};
+ expectedInfo = (virDomainBlockIoTuneInfo) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
NULL, 15, 16, 17, 18, 19, 20};
+ if (VIR_STRDUP(expectedInfo.group_name, "group14") < 0)
+ return -1;
if (qemuMonitorTestAddItem(test, "query-block", queryBlockReply) < 0 ||
qemuMonitorTestAddItemParams(test, "block_set_io_throttle",
@@ -2014,12 +2017,13 @@ testQemuMonitorJSONqemuMonitorJSONSetBlockIoThrottle(const void
*data)
"bps_wr_max", "9",
"iops_max", "10",
"iops_rd_max", "11",
"iops_wr_max", "12",
"iops_size", "13",
- "bps_max_length", "14",
- "bps_rd_max_length", "15",
- "bps_wr_max_length", "16",
- "iops_max_length", "17",
- "iops_rd_max_length", "18",
- "iops_wr_max_length", "19",
+ "group",
"\"group14\"",
+ "bps_max_length", "15",
+ "bps_rd_max_length", "16",
+ "bps_wr_max_length", "17",
+ "iops_max_length", "18",
+ "iops_rd_max_length", "19",
+ "iops_wr_max_length", "20",
NULL, NULL) < 0)
goto cleanup;
@@ -2027,19 +2031,55 @@ testQemuMonitorJSONqemuMonitorJSONSetBlockIoThrottle(const void
*data)
"drive-virtio-disk0", &info) <
0)
goto cleanup;
- if (memcmp(&info, &expectedInfo, sizeof(info)) != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- "Invalid @info");
+#define VALIDATE_IOTUNE(field) \
+ if (info.field != expectedInfo.field) { \
+ virReportError(VIR_ERR_INTERNAL_ERROR, \
+ "info.%s=%llu != expected=%llu", \
+ #field, info.field, expectedInfo.field); \
+ goto cleanup; \
+ } \
+ if (info.field##_max != expectedInfo.field##_max) { \
+ virReportError(VIR_ERR_INTERNAL_ERROR, \
+ "info.%s_max=%llu != expected=%llu", \
+ #field, info.field##_max, expectedInfo.field##_max); \
+ goto cleanup; \
+ } \
+ if (info.field##_max_length != expectedInfo.field##_max_length) { \
+ virReportError(VIR_ERR_INTERNAL_ERROR, \
+ "info.%s_max_length=%llu != expected=%llu", \
+ #field, info.field##_max_length, \
+ expectedInfo.field##_max_length); \
+ goto cleanup; \
+ }
+ VALIDATE_IOTUNE(total_bytes_sec);
+ VALIDATE_IOTUNE(read_bytes_sec);
+ VALIDATE_IOTUNE(write_bytes_sec);
+ VALIDATE_IOTUNE(total_iops_sec);
+ VALIDATE_IOTUNE(read_iops_sec);
+ VALIDATE_IOTUNE(write_iops_sec);
+ if (info.size_iops_sec != expectedInfo.size_iops_sec) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "info.size_iops_sec=%llu != expected=%llu",
+ info.size_iops_sec, expectedInfo.size_iops_sec);
+ goto cleanup;
+ }
+ if (STRNEQ(info.group_name, expectedInfo.group_name)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "info.group_name=%s != expected=%s",
+ info.group_name, expectedInfo.group_name);
goto cleanup;
}
+#undef VALIDATE_IOTUNE
if (qemuMonitorJSONSetBlockIoThrottle(qemuMonitorTestGetMonitor(test),
"drive-virtio-disk1", &info,
true,
- true) < 0)
+ true, true) < 0)
goto cleanup;
ret = 0;
cleanup:
+ VIR_FREE(info.group_name);
+ VIR_FREE(expectedInfo.group_name);
qemuMonitorTestFree(test);
return ret;
}
--
2.7.4