[PATCH RFC v4 14/17] test_driver: Test throttle group lifecycle APIs
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Test throttle group APIs
* Extract common methods for both "testDomainSetThrottleGroup" and "testDomainSetBlockIoTune":
testDomainValidateBlockIoTune, testDomainSetBlockIoTuneFields,
testDomainCheckBlockIoTuneMutualExclusion, testDomainCheckBlockIoTuneMax
* Test "Set": testDomainSetThrottleGroup
* Test "Get": testDomainGetThrottleGroup
* Test "Del": testDomainDelThrottleGroup
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
src/test/test_driver.c | 452 ++++++++++++++++++++++++++++++-----------
1 file changed, 330 insertions(+), 122 deletions(-)
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 7cb77f044d..d485e552d8 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -3783,25 +3783,8 @@ testDomainGetInterfaceParameters(virDomainPtr dom,
#define TEST_BLOCK_IOTUNE_MAX 1000000000000000LL
static int
-testDomainSetBlockIoTune(virDomainPtr dom,
- const char *path,
- virTypedParameterPtr params,
- int nparams,
- unsigned int flags)
+testDomainValidateBlockIoTune(virTypedParameterPtr params, int nparams)
{
- virDomainObj *vm = NULL;
- virDomainDef *def = NULL;
- virDomainBlockIoTuneInfo info = {0};
- virDomainDiskDef *conf_disk = NULL;
- virTypedParameterPtr eventParams = NULL;
- int eventNparams = 0;
- int eventMaxparams = 0;
- size_t i;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG, -1);
-
if (virTypedParamsValidate(params, nparams,
VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
VIR_TYPED_PARAM_ULLONG,
@@ -3846,34 +3829,29 @@ testDomainSetBlockIoTune(virDomainPtr dom,
NULL) < 0)
return -1;
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- if (!(def = virDomainObjGetOneDef(vm, flags)))
- goto cleanup;
-
- if (!(conf_disk = virDomainDiskByName(def, path, true))) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("missing persistent configuration for disk '%1$s'"),
- path);
- goto cleanup;
- }
+ return 0;
+}
- info = conf_disk->blkdeviotune;
- info.group_name = g_strdup(conf_disk->blkdeviotune.group_name);
- if (virTypedParamsAddString(&eventParams, &eventNparams, &eventMaxparams,
- VIR_DOMAIN_TUNABLE_BLKDEV_DISK, path) < 0)
- goto cleanup;
+static int
+testDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info,
+ virTypedParameterPtr params,
+ int nparams,
+ virTypedParameterPtr *eventParams,
+ int *eventNparams,
+ int *eventMaxparams)
+{
+ size_t i;
+ int ret = -1;
-#define SET_IOTUNE_FIELD(FIELD, STR, TUNABLE_STR) \
- if (STREQ(param->field, STR)) { \
- info.FIELD = param->value.ul; \
- if (virTypedParamsAddULLong(&eventParams, &eventNparams, \
- &eventMaxparams, \
- TUNABLE_STR, \
+#define SET_IOTUNE_FIELD(FIELD, CONST) \
+ if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_##CONST)) { \
+ info->FIELD = param->value.ul; \
+ if (virTypedParamsAddULLong(eventParams, eventNparams, \
+ eventMaxparams, \
+ VIR_DOMAIN_TUNABLE_BLKDEV_##CONST, \
param->value.ul) < 0) \
- goto cleanup; \
+ goto endjob; \
continue; \
}
@@ -3884,119 +3862,99 @@ testDomainSetBlockIoTune(virDomainPtr dom,
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
_("block I/O throttle limit value must be no more than %1$llu"),
TEST_BLOCK_IOTUNE_MAX);
- goto cleanup;
+ goto endjob;
}
- SET_IOTUNE_FIELD(total_bytes_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC);
- SET_IOTUNE_FIELD(read_bytes_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC);
- SET_IOTUNE_FIELD(write_bytes_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC);
- SET_IOTUNE_FIELD(total_iops_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC);
- SET_IOTUNE_FIELD(read_iops_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC);
- SET_IOTUNE_FIELD(write_iops_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC);
-
- SET_IOTUNE_FIELD(total_bytes_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX);
- SET_IOTUNE_FIELD(read_bytes_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC_MAX);
- SET_IOTUNE_FIELD(write_bytes_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC_MAX);
- SET_IOTUNE_FIELD(total_iops_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC_MAX);
- SET_IOTUNE_FIELD(read_iops_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC_MAX);
- SET_IOTUNE_FIELD(write_iops_sec_max,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX);
- SET_IOTUNE_FIELD(size_iops_sec,
- VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC,
- VIR_DOMAIN_TUNABLE_BLKDEV_SIZE_IOPS_SEC);
-
+ SET_IOTUNE_FIELD(total_bytes_sec, TOTAL_BYTES_SEC);
+ SET_IOTUNE_FIELD(read_bytes_sec, READ_BYTES_SEC);
+ SET_IOTUNE_FIELD(write_bytes_sec, WRITE_BYTES_SEC);
+ SET_IOTUNE_FIELD(total_iops_sec, TOTAL_IOPS_SEC);
+ SET_IOTUNE_FIELD(read_iops_sec, READ_IOPS_SEC);
+ SET_IOTUNE_FIELD(write_iops_sec, WRITE_IOPS_SEC);
+
+ SET_IOTUNE_FIELD(total_bytes_sec_max, TOTAL_BYTES_SEC_MAX);
+ SET_IOTUNE_FIELD(read_bytes_sec_max, READ_BYTES_SEC_MAX);
+ SET_IOTUNE_FIELD(write_bytes_sec_max, WRITE_BYTES_SEC_MAX);
+ SET_IOTUNE_FIELD(total_iops_sec_max, TOTAL_IOPS_SEC_MAX);
+ SET_IOTUNE_FIELD(read_iops_sec_max, READ_IOPS_SEC_MAX);
+ SET_IOTUNE_FIELD(write_iops_sec_max, WRITE_IOPS_SEC_MAX);
+ SET_IOTUNE_FIELD(size_iops_sec, SIZE_IOPS_SEC);
+
+ /* NB: Cannot use macro since this is a value.s not a value.ul */
if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME)) {
- VIR_FREE(info.group_name);
- info.group_name = g_strdup(param->value.s);
- if (virTypedParamsAddString(&eventParams,
- &eventNparams,
- &eventMaxparams,
+ VIR_FREE(info->group_name);
+ info->group_name = g_strdup(param->value.s);
+ if (virTypedParamsAddString(eventParams, eventNparams,
+ eventMaxparams,
VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME,
param->value.s) < 0)
- goto cleanup;
+ goto endjob;
continue;
}
- SET_IOTUNE_FIELD(total_bytes_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX_LENGTH);
- SET_IOTUNE_FIELD(read_bytes_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC_MAX_LENGTH);
- SET_IOTUNE_FIELD(write_bytes_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC_MAX_LENGTH);
- SET_IOTUNE_FIELD(total_iops_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC_MAX_LENGTH);
- SET_IOTUNE_FIELD(read_iops_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC_MAX_LENGTH);
- SET_IOTUNE_FIELD(write_iops_sec_max_length,
- VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX_LENGTH,
- VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(total_bytes_sec_max_length, TOTAL_BYTES_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(read_bytes_sec_max_length, READ_BYTES_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(write_bytes_sec_max_length, WRITE_BYTES_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(total_iops_sec_max_length, TOTAL_IOPS_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(read_iops_sec_max_length, READ_IOPS_SEC_MAX_LENGTH);
+ SET_IOTUNE_FIELD(write_iops_sec_max_length, WRITE_IOPS_SEC_MAX_LENGTH);
}
+
#undef SET_IOTUNE_FIELD
- if ((info.total_bytes_sec && info.read_bytes_sec) ||
- (info.total_bytes_sec && info.write_bytes_sec)) {
+ ret = 0;
+ endjob:
+ return ret;
+}
+
+
+static int
+testDomainCheckBlockIoTuneMutualExclusion(virDomainBlockIoTuneInfo *info)
+{
+ if ((info->total_bytes_sec && info->read_bytes_sec) ||
+ (info->total_bytes_sec && info->write_bytes_sec)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of bytes_sec cannot be set at the same time"));
- goto cleanup;
+ return -1;
}
- if ((info.total_iops_sec && info.read_iops_sec) ||
- (info.total_iops_sec && info.write_iops_sec)) {
+ if ((info->total_iops_sec && info->read_iops_sec) ||
+ (info->total_iops_sec && info->write_iops_sec)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of iops_sec cannot be set at the same time"));
- goto cleanup;
+ return -1;
}
- if ((info.total_bytes_sec_max && info.read_bytes_sec_max) ||
- (info.total_bytes_sec_max && info.write_bytes_sec_max)) {
+ if ((info->total_bytes_sec_max && info->read_bytes_sec_max) ||
+ (info->total_bytes_sec_max && info->write_bytes_sec_max)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of bytes_sec_max cannot be set at the same time"));
- goto cleanup;
+ return -1;
}
- if ((info.total_iops_sec_max && info.read_iops_sec_max) ||
- (info.total_iops_sec_max && info.write_iops_sec_max)) {
+ if ((info->total_iops_sec_max && info->read_iops_sec_max) ||
+ (info->total_iops_sec_max && info->write_iops_sec_max)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("total and read/write of iops_sec_max cannot be set at the same time"));
- goto cleanup;
+ return -1;
}
+ return 0;
+}
+
+
+static int
+testDomainCheckBlockIoTuneMax(virDomainBlockIoTuneInfo *info)
+{
+ int ret = -1;
#define TEST_BLOCK_IOTUNE_MAX_CHECK(FIELD, FIELD_MAX) \
do { \
- if (info.FIELD > info.FIELD_MAX) { \
+ if (info->FIELD > info->FIELD_MAX) { \
virReportError(VIR_ERR_INVALID_ARG, \
_("%1$s cannot be set higher than %2$s"), \
#FIELD, #FIELD_MAX); \
- goto cleanup; \
+ goto endjob; \
} \
} while (0);
@@ -4009,6 +3967,69 @@ testDomainSetBlockIoTune(virDomainPtr dom,
#undef TEST_BLOCK_IOTUNE_MAX_CHECK
+ ret = 0;
+ endjob:
+ return ret;
+}
+
+
+static int
+testDomainSetBlockIoTune(virDomainPtr dom,
+ const char *path,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainBlockIoTuneInfo info = {0};
+ virDomainDiskDef *conf_disk = NULL;
+ virTypedParameterPtr eventParams = NULL;
+ int eventNparams = 0;
+ int eventMaxparams = 0;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ if (testDomainValidateBlockIoTune(params, nparams) < 0)
+ return -1;
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+ if (!(conf_disk = virDomainDiskByName(def, path, true))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("missing persistent configuration for disk '%1$s'"),
+ path);
+ goto cleanup;
+ }
+
+ info = conf_disk->blkdeviotune;
+ info.group_name = g_strdup(conf_disk->blkdeviotune.group_name);
+
+ if (virTypedParamsAddString(&eventParams, &eventNparams, &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_DISK, path) < 0)
+ goto cleanup;
+
+ if (testDomainSetBlockIoTuneFields(&info,
+ params,
+ nparams,
+ &eventParams,
+ &eventNparams,
+ &eventMaxparams) < 0)
+ goto cleanup;
+
+ if (testDomainCheckBlockIoTuneMutualExclusion(&info) < 0)
+ goto cleanup;
+
+
+ if (testDomainCheckBlockIoTuneMax(&info) < 0)
+ goto cleanup;
+
virDomainDiskSetBlockIOTune(conf_disk, &info);
ret = 0;
@@ -4119,6 +4140,190 @@ testDomainGetBlockIoTune(virDomainPtr dom,
virDomainObjEndAPI(&vm);
return ret;
}
+
+
+static int
+testDomainSetThrottleGroup(virDomainPtr dom,
+ const char *group,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainThrottleGroupDef info = { 0 };
+ virDomainThrottleGroupDef *cur_info = NULL;
+ virTypedParameterPtr eventParams = NULL;
+ int eventNparams = 0;
+ int eventMaxparams = 0;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+ if (testDomainValidateBlockIoTune(params, nparams) < 0)
+ return -1;
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+ if (virTypedParamsAddString(&eventParams, &eventNparams, &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME, group) < 0)
+ goto cleanup;
+
+ if (testDomainSetBlockIoTuneFields(&info,
+ params,
+ nparams,
+ &eventParams,
+ &eventNparams,
+ &eventMaxparams) < 0)
+ goto cleanup;
+
+ if (testDomainCheckBlockIoTuneMutualExclusion(&info) < 0)
+ goto cleanup;
+
+ if (testDomainCheckBlockIoTuneMax(&info) < 0)
+ goto cleanup;
+
+ cur_info = virDomainThrottleGroupByName(def, group);
+ if (cur_info != NULL) {
+ virDomainThrottleGroupUpdate(def, &info);
+ } else {
+ virDomainThrottleGroupAdd(def, &info);
+ }
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(info.group_name);
+ virDomainObjEndAPI(&vm);
+ if (eventNparams)
+ virTypedParamsFree(eventParams, eventNparams);
+ return ret;
+}
+
+
+static int
+testDomainGetThrottleGroup(virDomainPtr dom,
+ const char *groupname,
+ virTypedParameterPtr *params,
+ int *nparams,
+ unsigned int flags)
+{
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainThrottleGroupDef groupDef = {0};
+ virDomainThrottleGroupDef *reply = &groupDef;
+ int ret = -1;
+ int maxparams = 0;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+
+ if (!(reply = virDomainThrottleGroupByName(def, groupname))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("throttle group '%1$s' was not found in the domain config"),
+ groupname);
+ goto cleanup;
+ }
+ reply->group_name = g_strdup(groupname);
+
+#define TEST_THROTTLE_GROUP_ASSIGN(name, var) \
+ if (virTypedParamsAddULLong(params, \
+ nparams, \
+ &maxparams, \
+ VIR_DOMAIN_BLOCK_IOTUNE_ ## name, \
+ reply->var) < 0) \
+ goto cleanup;
+
+ if (virTypedParamsAddString(params, nparams, &maxparams,
+ "VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME",
+ reply->group_name) < 0)
+ goto cleanup;
+
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC, total_bytes_sec);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC, read_bytes_sec);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC, write_bytes_sec);
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC, total_iops_sec);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC, read_iops_sec);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC, write_iops_sec);
+
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC_MAX, total_bytes_sec_max);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC_MAX, read_bytes_sec_max);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC_MAX, write_bytes_sec_max);
+
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC_MAX, total_iops_sec_max);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC_MAX, read_iops_sec_max);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC_MAX, write_iops_sec_max);
+
+ TEST_THROTTLE_GROUP_ASSIGN(SIZE_IOPS_SEC, size_iops_sec);
+
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC_MAX_LENGTH, total_bytes_sec_max_length);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC_MAX_LENGTH, read_bytes_sec_max_length);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC_MAX_LENGTH, write_bytes_sec_max_length);
+
+ TEST_THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC_MAX_LENGTH, total_iops_sec_max_length);
+ TEST_THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC_MAX_LENGTH, read_iops_sec_max_length);
+ TEST_THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC_MAX_LENGTH, write_iops_sec_max_length);
+#undef TEST_THROTTLE_GROUP_ASSIGN
+
+ ret = 0;
+
+ cleanup:
+ if (reply != NULL && reply->group_name != NULL) {
+ g_free(reply->group_name);
+ }
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+
+static int
+testDomainDelThrottleGroup(virDomainPtr dom,
+ const char *groupname,
+ unsigned int flags)
+{
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainThrottleGroupDef groupDef = {0};
+ virDomainThrottleGroupDef *reply = &groupDef;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+ if (!(reply = virDomainThrottleGroupByName(def, groupname))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("throttle group '%1$s' was not found in the domain config"),
+ groupname);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
#undef TEST_SET_PARAM
@@ -10684,6 +10889,9 @@ static virHypervisorDriver testHypervisorDriver = {
.domainGetInterfaceParameters = testDomainGetInterfaceParameters, /* 5.6.0 */
.domainSetBlockIoTune = testDomainSetBlockIoTune, /* 5.7.0 */
.domainGetBlockIoTune = testDomainGetBlockIoTune, /* 5.7.0 */
+ .domainSetThrottleGroup = testDomainSetThrottleGroup, /* 10.7.0 */
+ .domainGetThrottleGroup = testDomainGetThrottleGroup, /* 10.7.0 */
+ .domainDelThrottleGroup = testDomainDelThrottleGroup, /* 10.7.0 */
.domainSetBlkioParameters = testDomainSetBlkioParameters, /* 7.7.0 */
.domainGetBlkioParameters = testDomainGetBlkioParameters, /* 7.7.0 */
.connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
--
2.43.0
2 months, 3 weeks
[PATCH RFC v4 13/17] qemuxmlconftest: Add 'throttlefilter' tests
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Test domain xml and status xml
* Add tests for "throttlegroup" domain xml processing, including
groups referenced and not referenced by filters
* Add tests for "throttlefilter" domain xml processing, including
throttle group referenced by different disks
* Add negative test case to report error when iotune is configured
together with throttle filters
* Add tests for throttlefilter nodename parse and format for statusxml
(disk/privateData/nodenames/nodename with type='throttle-filter')
* Add iotune limited disk tests to make sure iotune refactory works
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
.../throttlefilter-in.xml | 392 ++++++++++++++++++
.../throttlefilter-out.xml | 392 ++++++++++++++++++
tests/qemuxmlactivetest.c | 1 +
.../throttlefilter-invalid.x86_64-latest.err | 1 +
.../throttlefilter-invalid.xml | 89 ++++
.../throttlefilter.x86_64-latest.args | 55 +++
.../throttlefilter.x86_64-latest.xml | 105 +++++
tests/qemuxmlconfdata/throttlefilter.xml | 95 +++++
tests/qemuxmlconftest.c | 2 +
9 files changed, 1132 insertions(+)
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-in.xml
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-out.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.xml
diff --git a/tests/qemustatusxml2xmldata/throttlefilter-in.xml b/tests/qemustatusxml2xmldata/throttlefilter-in.xml
new file mode 100644
index 0000000000..2a98d6f5e2
--- /dev/null
+++ b/tests/qemustatusxml2xmldata/throttlefilter-in.xml
@@ -0,0 +1,392 @@
+<domstatus state='running' reason='booted' pid='7690'>
+ <taint flag='high-privileges'/>
+ <monitor path='/var/lib/libvirt/qemu/domain-4-copy/monitor.sock' type='unix'/>
+ <namespaces>
+ <mount/>
+ </namespaces>
+ <vcpus>
+ <vcpu id='0' pid='7696'/>
+ </vcpus>
+ <qemuCaps>
+ <flag name='kvm'/>
+ <flag name='no-hpet'/>
+ <flag name='spice'/>
+ <flag name='hda-duplex'/>
+ <flag name='ccid-emulated'/>
+ <flag name='ccid-passthru'/>
+ <flag name='virtio-tx-alg'/>
+ <flag name='virtio-blk-pci.ioeventfd'/>
+ <flag name='sga'/>
+ <flag name='virtio-blk-pci.event_idx'/>
+ <flag name='virtio-net-pci.event_idx'/>
+ <flag name='piix3-usb-uhci'/>
+ <flag name='piix4-usb-uhci'/>
+ <flag name='usb-ehci'/>
+ <flag name='ich9-usb-ehci1'/>
+ <flag name='vt82c686b-usb-uhci'/>
+ <flag name='pci-ohci'/>
+ <flag name='usb-redir'/>
+ <flag name='usb-hub'/>
+ <flag name='ich9-ahci'/>
+ <flag name='no-acpi'/>
+ <flag name='virtio-blk-pci.scsi'/>
+ <flag name='scsi-disk.channel'/>
+ <flag name='scsi-block'/>
+ <flag name='transaction'/>
+ <flag name='block-job-async'/>
+ <flag name='scsi-cd'/>
+ <flag name='ide-cd'/>
+ <flag name='hda-micro'/>
+ <flag name='dump-guest-memory'/>
+ <flag name='nec-usb-xhci'/>
+ <flag name='balloon-event'/>
+ <flag name='lsi'/>
+ <flag name='virtio-scsi-pci'/>
+ <flag name='blockio'/>
+ <flag name='disable-s3'/>
+ <flag name='disable-s4'/>
+ <flag name='usb-redir.filter'/>
+ <flag name='ide-drive.wwn'/>
+ <flag name='scsi-disk.wwn'/>
+ <flag name='seccomp-sandbox'/>
+ <flag name='reboot-timeout'/>
+ <flag name='seamless-migration'/>
+ <flag name='block-commit'/>
+ <flag name='vnc'/>
+ <flag name='drive-mirror'/>
+ <flag name='blockdev-snapshot-sync'/>
+ <flag name='qxl'/>
+ <flag name='VGA'/>
+ <flag name='cirrus-vga'/>
+ <flag name='vmware-svga'/>
+ <flag name='device-video-primary'/>
+ <flag name='usb-serial'/>
+ <flag name='nbd-server'/>
+ <flag name='virtio-rng'/>
+ <flag name='rng-random'/>
+ <flag name='rng-egd'/>
+ <flag name='megasas'/>
+ <flag name='tpm-passthrough'/>
+ <flag name='tpm-tis'/>
+ <flag name='pci-bridge'/>
+ <flag name='vfio-pci'/>
+ <flag name='mem-merge'/>
+ <flag name='drive-discard'/>
+ <flag name='mlock'/>
+ <flag name='device-del-event'/>
+ <flag name='dmi-to-pci-bridge'/>
+ <flag name='i440fx-pci-hole64-size'/>
+ <flag name='q35-pci-hole64-size'/>
+ <flag name='usb-storage'/>
+ <flag name='usb-storage.removable'/>
+ <flag name='ich9-intel-hda'/>
+ <flag name='kvm-pit-lost-tick-policy'/>
+ <flag name='boot-strict'/>
+ <flag name='pvpanic'/>
+ <flag name='spice-file-xfer-disable'/>
+ <flag name='usb-kbd'/>
+ <flag name='msg-timestamp'/>
+ <flag name='active-commit'/>
+ <flag name='change-backing-file'/>
+ <flag name='memory-backend-ram'/>
+ <flag name='numa'/>
+ <flag name='memory-backend-file'/>
+ <flag name='usb-audio'/>
+ <flag name='rtc-reset-reinjection'/>
+ <flag name='splash-timeout'/>
+ <flag name='iothread'/>
+ <flag name='migrate-rdma'/>
+ <flag name='ivshmem'/>
+ <flag name='drive-iotune-max'/>
+ <flag name='VGA.vgamem_mb'/>
+ <flag name='vmware-svga.vgamem_mb'/>
+ <flag name='qxl.vgamem_mb'/>
+ <flag name='pc-dimm'/>
+ <flag name='machine-vmport-opt'/>
+ <flag name='aes-key-wrap'/>
+ <flag name='dea-key-wrap'/>
+ <flag name='pci-serial'/>
+ <flag name='vhost-user-multiqueue'/>
+ <flag name='migration-event'/>
+ <flag name='ioh3420'/>
+ <flag name='x3130-upstream'/>
+ <flag name='xio3130-downstream'/>
+ <flag name='rtl8139'/>
+ <flag name='e1000'/>
+ <flag name='virtio-net'/>
+ <flag name='gic-version'/>
+ <flag name='incoming-defer'/>
+ <flag name='virtio-gpu'/>
+ <flag name='virtio-gpu.virgl'/>
+ <flag name='virtio-keyboard'/>
+ <flag name='virtio-mouse'/>
+ <flag name='virtio-tablet'/>
+ <flag name='virtio-input-host'/>
+ <flag name='chardev-file-append'/>
+ <flag name='ich9-disable-s3'/>
+ <flag name='ich9-disable-s4'/>
+ <flag name='vserport-change-event'/>
+ <flag name='virtio-balloon-pci.deflate-on-oom'/>
+ <flag name='mptsas1068'/>
+ <flag name='spice-gl'/>
+ <flag name='qxl.vram64_size_mb'/>
+ <flag name='chardev-logfile'/>
+ <flag name='debug-threads'/>
+ <flag name='secret'/>
+ <flag name='pxb'/>
+ <flag name='pxb-pcie'/>
+ <flag name='device-tray-moved-event'/>
+ <flag name='nec-usb-xhci-ports'/>
+ <flag name='virtio-scsi-pci.iothread'/>
+ <flag name='name-guest'/>
+ <flag name='qxl.max_outputs'/>
+ <flag name='spice-unix'/>
+ <flag name='drive-detect-zeroes'/>
+ <flag name='tls-creds-x509'/>
+ <flag name='intel-iommu'/>
+ <flag name='smm'/>
+ <flag name='virtio-pci-disable-legacy'/>
+ <flag name='query-hotpluggable-cpus'/>
+ <flag name='virtio-net.rx_queue_size'/>
+ <flag name='virtio-vga'/>
+ <flag name='drive-iotune-max-length'/>
+ <flag name='ivshmem-plain'/>
+ <flag name='ivshmem-doorbell'/>
+ <flag name='query-qmp-schema'/>
+ <flag name='gluster.debug_level'/>
+ <flag name='vhost-scsi'/>
+ <flag name='drive-iotune-group'/>
+ <flag name='query-cpu-model-expansion'/>
+ <flag name='virtio-net.host_mtu'/>
+ <flag name='spice-rendernode'/>
+ <flag name='nvdimm'/>
+ <flag name='pcie-root-port'/>
+ <flag name='query-cpu-definitions'/>
+ <flag name='block-write-threshold'/>
+ <flag name='query-named-block-nodes'/>
+ <flag name='cpu-cache'/>
+ <flag name='qemu-xhci'/>
+ <flag name='kernel-irqchip'/>
+ <flag name='kernel-irqchip.split'/>
+ <flag name='intel-iommu.intremap'/>
+ <flag name='intel-iommu.caching-mode'/>
+ <flag name='intel-iommu.eim'/>
+ <flag name='intel-iommu.device-iotlb'/>
+ <flag name='virtio.iommu_platform'/>
+ <flag name='virtio.ats'/>
+ <flag name='loadparm'/>
+ <flag name='vnc-multi-servers'/>
+ <flag name='virtio-net.tx_queue_size'/>
+ <flag name='chardev-reconnect'/>
+ <flag name='virtio-gpu.max_outputs'/>
+ <flag name='vxhs'/>
+ <flag name='virtio-blk.num-queues'/>
+ <flag name='vmcoreinfo'/>
+ <flag name='numa.dist'/>
+ <flag name='disk-share-rw'/>
+ <flag name='iscsi.password-secret'/>
+ <flag name='isa-serial'/>
+ <flag name='dump-completed'/>
+ <flag name='qcow2-luks'/>
+ <flag name='pcie-pci-bridge'/>
+ <flag name='seccomp-blacklist'/>
+ <flag name='query-cpus-fast'/>
+ <flag name='disk-write-cache'/>
+ <flag name='nbd-tls'/>
+ <flag name='tpm-crb'/>
+ <flag name='pr-manager-helper'/>
+ <flag name='qom-list-properties'/>
+ <flag name='memory-backend-file.discard-data'/>
+ <flag name='sdl-gl'/>
+ <flag name='screendump_device'/>
+ <flag name='hda-output'/>
+ <flag name='blockdev-del'/>
+ <flag name='vmgenid'/>
+ <flag name='vhost-vsock'/>
+ <flag name='chardev-fd-pass'/>
+ <flag name='tpm-emulator'/>
+ <flag name='mch'/>
+ <flag name='mch.extended-tseg-mbytes'/>
+ <flag name='usb-storage.werror'/>
+ <flag name='egl-headless'/>
+ <flag name='vfio-pci.display'/>
+ <flag name='blockdev'/>
+ <flag name='memory-backend-memfd'/>
+ <flag name='memory-backend-memfd.hugetlb'/>
+ <flag name='iothread.poll-max-ns'/>
+ <flag name='egl-headless.rendernode'/>
+ <flag name='incremental-backup'/>
+ </qemuCaps>
+ <devices>
+ <device alias='rng0'/>
+ <device alias='sound0-codec0'/>
+ <device alias='virtio-disk0'/>
+ <device alias='virtio-serial0'/>
+ <device alias='video0'/>
+ <device alias='serial0'/>
+ <device alias='sound0'/>
+ <device alias='channel1'/>
+ <device alias='channel0'/>
+ <device alias='usb'/>
+ </devices>
+ <libDir path='/var/lib/libvirt/qemu/domain-4-copy'/>
+ <channelTargetDir path='/var/lib/libvirt/qemu/channel/target/domain-4-copy'/>
+ <chardevStdioLogd/>
+ <allowReboot value='yes'/>
+ <nodename index='0'/>
+ <fdset index='0'/>
+ <blockjobs active='no'/>
+ <agentTimeout>-2</agentTimeout>
+ <domain type='kvm' id='4'>
+ <name>copy</name>
+ <uuid>0439a4a8-db56-4933-9183-d8681d7b0746</uuid>
+ <memory unit='KiB'>1024000</memory>
+ <currentMemory unit='KiB'>1024000</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <throttlegroups>
+ <throttlegroup>
+ <total_iops_sec>200</total_iops_sec>
+ <total_iops_sec_max>200</total_iops_sec_max>
+ <group_name>limit0</group_name>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>250</total_iops_sec>
+ <total_iops_sec_max>250</total_iops_sec_max>
+ <group_name>limit1</group_name>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>300</total_iops_sec>
+ <total_iops_sec_max>300</total_iops_sec_max>
+ <group_name>limit2</group_name>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>400</total_iops_sec>
+ <total_iops_sec_max>400</total_iops_sec_max>
+ <group_name>limit012</group_name>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ </throttlegroup>
+ </throttlegroups>
+ <resource>
+ <partition>/machine</partition>
+ </resource>
+ <os>
+ <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state='off'/>
+ </features>
+ <clock offset='utc'>
+ <timer name='rtc' tickpolicy='catchup'/>
+ <timer name='pit' tickpolicy='delay'/>
+ <timer name='hpet' present='no'/>
+ </clock>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <pm>
+ <suspend-to-mem enabled='no'/>
+ <suspend-to-disk enabled='no'/>
+ </pm>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/tmp/pull4.qcow2' index='3'>
+ <privateData>
+ <nodenames>
+ <nodename type='storage' name='libvirt-3-storage'/>
+ <nodename type='format' name='libvirt-3-format'/>
+ </nodenames>
+ </privateData>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit0'/>
+ <throttlefilter group='limit012'/>
+ </throttlefilters>
+ <alias name='virtio-disk1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
+ <privateData>
+ <qom name='/machine/peripheral/virtio-disk1/virtio-backend'/>
+ <nodenames>
+ <nodename type='throttle-filter' name='libvirt-4-filter' group='limit0'/>
+ <nodename type='throttle-filter' name='libvirt-5-filter' group='limit012'/>
+ </nodenames>
+ </privateData>
+ </disk>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/tmp/pull5.qcow2' index='4'>
+ <privateData>
+ <nodenames>
+ <nodename type='storage' name='libvirt-4-storage'/>
+ <nodename type='format' name='libvirt-4-format'/>
+ </nodenames>
+ </privateData>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ <iotune>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </iotune>
+ <alias name='virtio-disk2'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
+ <privateData>
+ <qom name='/machine/peripheral/virtio-disk2/virtio-backend'/>
+ </privateData>
+ </disk>
+ <controller type='usb' index='0' model='piix3-uhci'>
+ <alias name='usb'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'>
+ <alias name='pci.0'/>
+ </controller>
+ <serial type='pty'>
+ <source path='/dev/pts/34'/>
+ <target type='isa-serial' port='0'>
+ <model name='isa-serial'/>
+ </target>
+ <alias name='serial0'/>
+ </serial>
+ <console type='pty' tty='/dev/pts/34'>
+ <source path='/dev/pts/34'/>
+ <target type='serial' port='0'/>
+ <alias name='serial0'/>
+ </console>
+ <input type='mouse' bus='ps2'>
+ <alias name='input0'/>
+ </input>
+ <input type='keyboard' bus='ps2'>
+ <alias name='input1'/>
+ </input>
+ <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
+ <listen type='address' address='127.0.0.1' fromConfig='1' autoGenerated='no'/>
+ <image compression='off'/>
+ </graphics>
+ <audio id='1' type='spice'/>
+ <video>
+ <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
+ <alias name='video0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='none'/>
+ </devices>
+ <seclabel type='dynamic' model='selinux' relabel='yes'>
+ <label>unconfined_u:unconfined_r:svirt_t:s0:c550,c786</label>
+ <imagelabel>unconfined_u:object_r:svirt_image_t:s0:c550,c786</imagelabel>
+ </seclabel>
+ <seclabel type='dynamic' model='dac' relabel='yes'>
+ <label>+0:+0</label>
+ <imagelabel>+0:+0</imagelabel>
+ </seclabel>
+ </domain>
+</domstatus>
diff --git a/tests/qemustatusxml2xmldata/throttlefilter-out.xml b/tests/qemustatusxml2xmldata/throttlefilter-out.xml
new file mode 100644
index 0000000000..2217ad929d
--- /dev/null
+++ b/tests/qemustatusxml2xmldata/throttlefilter-out.xml
@@ -0,0 +1,392 @@
+<domstatus state='running' reason='booted' pid='7690'>
+ <taint flag='high-privileges'/>
+ <monitor path='/var/lib/libvirt/qemu/domain-4-copy/monitor.sock' type='unix'/>
+ <namespaces>
+ <mount/>
+ </namespaces>
+ <vcpus>
+ <vcpu id='0' pid='7696'/>
+ </vcpus>
+ <qemuCaps>
+ <flag name='kvm'/>
+ <flag name='no-hpet'/>
+ <flag name='spice'/>
+ <flag name='hda-duplex'/>
+ <flag name='ccid-emulated'/>
+ <flag name='ccid-passthru'/>
+ <flag name='virtio-tx-alg'/>
+ <flag name='virtio-blk-pci.ioeventfd'/>
+ <flag name='sga'/>
+ <flag name='virtio-blk-pci.event_idx'/>
+ <flag name='virtio-net-pci.event_idx'/>
+ <flag name='piix3-usb-uhci'/>
+ <flag name='piix4-usb-uhci'/>
+ <flag name='usb-ehci'/>
+ <flag name='ich9-usb-ehci1'/>
+ <flag name='vt82c686b-usb-uhci'/>
+ <flag name='pci-ohci'/>
+ <flag name='usb-redir'/>
+ <flag name='usb-hub'/>
+ <flag name='ich9-ahci'/>
+ <flag name='no-acpi'/>
+ <flag name='virtio-blk-pci.scsi'/>
+ <flag name='scsi-disk.channel'/>
+ <flag name='scsi-block'/>
+ <flag name='transaction'/>
+ <flag name='block-job-async'/>
+ <flag name='scsi-cd'/>
+ <flag name='ide-cd'/>
+ <flag name='hda-micro'/>
+ <flag name='dump-guest-memory'/>
+ <flag name='nec-usb-xhci'/>
+ <flag name='balloon-event'/>
+ <flag name='lsi'/>
+ <flag name='virtio-scsi-pci'/>
+ <flag name='blockio'/>
+ <flag name='disable-s3'/>
+ <flag name='disable-s4'/>
+ <flag name='usb-redir.filter'/>
+ <flag name='ide-drive.wwn'/>
+ <flag name='scsi-disk.wwn'/>
+ <flag name='seccomp-sandbox'/>
+ <flag name='reboot-timeout'/>
+ <flag name='seamless-migration'/>
+ <flag name='block-commit'/>
+ <flag name='vnc'/>
+ <flag name='drive-mirror'/>
+ <flag name='blockdev-snapshot-sync'/>
+ <flag name='qxl'/>
+ <flag name='VGA'/>
+ <flag name='cirrus-vga'/>
+ <flag name='vmware-svga'/>
+ <flag name='device-video-primary'/>
+ <flag name='usb-serial'/>
+ <flag name='nbd-server'/>
+ <flag name='virtio-rng'/>
+ <flag name='rng-random'/>
+ <flag name='rng-egd'/>
+ <flag name='megasas'/>
+ <flag name='tpm-passthrough'/>
+ <flag name='tpm-tis'/>
+ <flag name='pci-bridge'/>
+ <flag name='vfio-pci'/>
+ <flag name='mem-merge'/>
+ <flag name='drive-discard'/>
+ <flag name='mlock'/>
+ <flag name='device-del-event'/>
+ <flag name='dmi-to-pci-bridge'/>
+ <flag name='i440fx-pci-hole64-size'/>
+ <flag name='q35-pci-hole64-size'/>
+ <flag name='usb-storage'/>
+ <flag name='usb-storage.removable'/>
+ <flag name='ich9-intel-hda'/>
+ <flag name='kvm-pit-lost-tick-policy'/>
+ <flag name='boot-strict'/>
+ <flag name='pvpanic'/>
+ <flag name='spice-file-xfer-disable'/>
+ <flag name='usb-kbd'/>
+ <flag name='msg-timestamp'/>
+ <flag name='active-commit'/>
+ <flag name='change-backing-file'/>
+ <flag name='memory-backend-ram'/>
+ <flag name='numa'/>
+ <flag name='memory-backend-file'/>
+ <flag name='usb-audio'/>
+ <flag name='rtc-reset-reinjection'/>
+ <flag name='splash-timeout'/>
+ <flag name='iothread'/>
+ <flag name='migrate-rdma'/>
+ <flag name='ivshmem'/>
+ <flag name='drive-iotune-max'/>
+ <flag name='VGA.vgamem_mb'/>
+ <flag name='vmware-svga.vgamem_mb'/>
+ <flag name='qxl.vgamem_mb'/>
+ <flag name='pc-dimm'/>
+ <flag name='machine-vmport-opt'/>
+ <flag name='aes-key-wrap'/>
+ <flag name='dea-key-wrap'/>
+ <flag name='pci-serial'/>
+ <flag name='vhost-user-multiqueue'/>
+ <flag name='migration-event'/>
+ <flag name='ioh3420'/>
+ <flag name='x3130-upstream'/>
+ <flag name='xio3130-downstream'/>
+ <flag name='rtl8139'/>
+ <flag name='e1000'/>
+ <flag name='virtio-net'/>
+ <flag name='gic-version'/>
+ <flag name='incoming-defer'/>
+ <flag name='virtio-gpu'/>
+ <flag name='virtio-gpu.virgl'/>
+ <flag name='virtio-keyboard'/>
+ <flag name='virtio-mouse'/>
+ <flag name='virtio-tablet'/>
+ <flag name='virtio-input-host'/>
+ <flag name='chardev-file-append'/>
+ <flag name='ich9-disable-s3'/>
+ <flag name='ich9-disable-s4'/>
+ <flag name='vserport-change-event'/>
+ <flag name='virtio-balloon-pci.deflate-on-oom'/>
+ <flag name='mptsas1068'/>
+ <flag name='spice-gl'/>
+ <flag name='qxl.vram64_size_mb'/>
+ <flag name='chardev-logfile'/>
+ <flag name='debug-threads'/>
+ <flag name='secret'/>
+ <flag name='pxb'/>
+ <flag name='pxb-pcie'/>
+ <flag name='device-tray-moved-event'/>
+ <flag name='nec-usb-xhci-ports'/>
+ <flag name='virtio-scsi-pci.iothread'/>
+ <flag name='name-guest'/>
+ <flag name='qxl.max_outputs'/>
+ <flag name='spice-unix'/>
+ <flag name='drive-detect-zeroes'/>
+ <flag name='tls-creds-x509'/>
+ <flag name='intel-iommu'/>
+ <flag name='smm'/>
+ <flag name='virtio-pci-disable-legacy'/>
+ <flag name='query-hotpluggable-cpus'/>
+ <flag name='virtio-net.rx_queue_size'/>
+ <flag name='virtio-vga'/>
+ <flag name='drive-iotune-max-length'/>
+ <flag name='ivshmem-plain'/>
+ <flag name='ivshmem-doorbell'/>
+ <flag name='query-qmp-schema'/>
+ <flag name='gluster.debug_level'/>
+ <flag name='vhost-scsi'/>
+ <flag name='drive-iotune-group'/>
+ <flag name='query-cpu-model-expansion'/>
+ <flag name='virtio-net.host_mtu'/>
+ <flag name='spice-rendernode'/>
+ <flag name='nvdimm'/>
+ <flag name='pcie-root-port'/>
+ <flag name='query-cpu-definitions'/>
+ <flag name='block-write-threshold'/>
+ <flag name='query-named-block-nodes'/>
+ <flag name='cpu-cache'/>
+ <flag name='qemu-xhci'/>
+ <flag name='kernel-irqchip'/>
+ <flag name='kernel-irqchip.split'/>
+ <flag name='intel-iommu.intremap'/>
+ <flag name='intel-iommu.caching-mode'/>
+ <flag name='intel-iommu.eim'/>
+ <flag name='intel-iommu.device-iotlb'/>
+ <flag name='virtio.iommu_platform'/>
+ <flag name='virtio.ats'/>
+ <flag name='loadparm'/>
+ <flag name='vnc-multi-servers'/>
+ <flag name='virtio-net.tx_queue_size'/>
+ <flag name='chardev-reconnect'/>
+ <flag name='virtio-gpu.max_outputs'/>
+ <flag name='vxhs'/>
+ <flag name='virtio-blk.num-queues'/>
+ <flag name='vmcoreinfo'/>
+ <flag name='numa.dist'/>
+ <flag name='disk-share-rw'/>
+ <flag name='iscsi.password-secret'/>
+ <flag name='isa-serial'/>
+ <flag name='dump-completed'/>
+ <flag name='qcow2-luks'/>
+ <flag name='pcie-pci-bridge'/>
+ <flag name='seccomp-blacklist'/>
+ <flag name='query-cpus-fast'/>
+ <flag name='disk-write-cache'/>
+ <flag name='nbd-tls'/>
+ <flag name='tpm-crb'/>
+ <flag name='pr-manager-helper'/>
+ <flag name='qom-list-properties'/>
+ <flag name='memory-backend-file.discard-data'/>
+ <flag name='sdl-gl'/>
+ <flag name='screendump_device'/>
+ <flag name='hda-output'/>
+ <flag name='blockdev-del'/>
+ <flag name='vmgenid'/>
+ <flag name='vhost-vsock'/>
+ <flag name='chardev-fd-pass'/>
+ <flag name='tpm-emulator'/>
+ <flag name='mch'/>
+ <flag name='mch.extended-tseg-mbytes'/>
+ <flag name='usb-storage.werror'/>
+ <flag name='egl-headless'/>
+ <flag name='vfio-pci.display'/>
+ <flag name='blockdev'/>
+ <flag name='memory-backend-memfd'/>
+ <flag name='memory-backend-memfd.hugetlb'/>
+ <flag name='iothread.poll-max-ns'/>
+ <flag name='egl-headless.rendernode'/>
+ <flag name='incremental-backup'/>
+ </qemuCaps>
+ <devices>
+ <device alias='rng0'/>
+ <device alias='sound0-codec0'/>
+ <device alias='virtio-disk0'/>
+ <device alias='virtio-serial0'/>
+ <device alias='video0'/>
+ <device alias='serial0'/>
+ <device alias='sound0'/>
+ <device alias='channel1'/>
+ <device alias='channel0'/>
+ <device alias='usb'/>
+ </devices>
+ <libDir path='/var/lib/libvirt/qemu/domain-4-copy'/>
+ <channelTargetDir path='/var/lib/libvirt/qemu/channel/target/domain-4-copy'/>
+ <chardevStdioLogd/>
+ <allowReboot value='yes'/>
+ <nodename index='0'/>
+ <fdset index='0'/>
+ <blockjobs active='no'/>
+ <agentTimeout>-2</agentTimeout>
+ <domain type='kvm' id='4'>
+ <name>copy</name>
+ <uuid>0439a4a8-db56-4933-9183-d8681d7b0746</uuid>
+ <memory unit='KiB'>1024000</memory>
+ <currentMemory unit='KiB'>1024000</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <throttlegroups>
+ <throttlegroup>
+ <total_iops_sec>200</total_iops_sec>
+ <total_iops_sec_max>200</total_iops_sec_max>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ <group_name>limit0</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>250</total_iops_sec>
+ <total_iops_sec_max>250</total_iops_sec_max>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ <group_name>limit1</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>300</total_iops_sec>
+ <total_iops_sec_max>300</total_iops_sec_max>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ <group_name>limit2</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <total_iops_sec>400</total_iops_sec>
+ <total_iops_sec_max>400</total_iops_sec_max>
+ <total_iops_sec_max_length>1</total_iops_sec_max_length>
+ <group_name>limit012</group_name>
+ </throttlegroup>
+ </throttlegroups>
+ <resource>
+ <partition>/machine</partition>
+ </resource>
+ <os>
+ <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state='off'/>
+ </features>
+ <clock offset='utc'>
+ <timer name='rtc' tickpolicy='catchup'/>
+ <timer name='pit' tickpolicy='delay'/>
+ <timer name='hpet' present='no'/>
+ </clock>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <pm>
+ <suspend-to-mem enabled='no'/>
+ <suspend-to-disk enabled='no'/>
+ </pm>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/tmp/pull4.qcow2' index='3'>
+ <privateData>
+ <nodenames>
+ <nodename type='storage' name='libvirt-3-storage'/>
+ <nodename type='format' name='libvirt-3-format'/>
+ </nodenames>
+ </privateData>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit0'/>
+ <throttlefilter group='limit012'/>
+ </throttlefilters>
+ <alias name='virtio-disk1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
+ <privateData>
+ <qom name='/machine/peripheral/virtio-disk1/virtio-backend'/>
+ <nodenames>
+ <nodename type='throttle-filter' name='libvirt-4-filter' group='limit0'/>
+ <nodename type='throttle-filter' name='libvirt-5-filter' group='limit012'/>
+ </nodenames>
+ </privateData>
+ </disk>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/tmp/pull5.qcow2' index='4'>
+ <privateData>
+ <nodenames>
+ <nodename type='storage' name='libvirt-4-storage'/>
+ <nodename type='format' name='libvirt-4-format'/>
+ </nodenames>
+ </privateData>
+ </source>
+ <target dev='vda' bus='virtio'/>
+ <iotune>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </iotune>
+ <alias name='virtio-disk2'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
+ <privateData>
+ <qom name='/machine/peripheral/virtio-disk2/virtio-backend'/>
+ </privateData>
+ </disk>
+ <controller type='usb' index='0' model='piix3-uhci'>
+ <alias name='usb'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'>
+ <alias name='pci.0'/>
+ </controller>
+ <serial type='pty'>
+ <source path='/dev/pts/34'/>
+ <target type='isa-serial' port='0'>
+ <model name='isa-serial'/>
+ </target>
+ <alias name='serial0'/>
+ </serial>
+ <console type='pty' tty='/dev/pts/34'>
+ <source path='/dev/pts/34'/>
+ <target type='serial' port='0'/>
+ <alias name='serial0'/>
+ </console>
+ <input type='mouse' bus='ps2'>
+ <alias name='input0'/>
+ </input>
+ <input type='keyboard' bus='ps2'>
+ <alias name='input1'/>
+ </input>
+ <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
+ <listen type='address' address='127.0.0.1' fromConfig='1' autoGenerated='no'/>
+ <image compression='off'/>
+ </graphics>
+ <audio id='1' type='spice'/>
+ <video>
+ <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
+ <alias name='video0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='none'/>
+ </devices>
+ <seclabel type='dynamic' model='selinux' relabel='yes'>
+ <label>unconfined_u:unconfined_r:svirt_t:s0:c550,c786</label>
+ <imagelabel>unconfined_u:object_r:svirt_image_t:s0:c550,c786</imagelabel>
+ </seclabel>
+ <seclabel type='dynamic' model='dac' relabel='yes'>
+ <label>+0:+0</label>
+ <imagelabel>+0:+0</imagelabel>
+ </seclabel>
+ </domain>
+</domstatus>
diff --git a/tests/qemuxmlactivetest.c b/tests/qemuxmlactivetest.c
index 2aefc871ee..44d034a80c 100644
--- a/tests/qemuxmlactivetest.c
+++ b/tests/qemuxmlactivetest.c
@@ -247,6 +247,7 @@ mymain(void)
DO_TEST_STATUS("blockjob-blockdev");
DO_TEST_STATUS("backup-pull");
+ DO_TEST_STATUS("throttlefilter");
cleanup:
qemuTestDriverFree(&driver);
diff --git a/tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err b/tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err
new file mode 100644
index 0000000000..ddb9670617
--- /dev/null
+++ b/tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err
@@ -0,0 +1 @@
+Operation not supported: block 'throttlefilters' can't be used together with 'iotune' for disk 'vda'
diff --git a/tests/qemuxmlconfdata/throttlefilter-invalid.xml b/tests/qemuxmlconfdata/throttlefilter-invalid.xml
new file mode 100644
index 0000000000..ebd250acac
--- /dev/null
+++ b/tests/qemuxmlconfdata/throttlefilter-invalid.xml
@@ -0,0 +1,89 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <throttlegroups>
+ <throttlegroup>
+ <total_bytes_sec>4000</total_bytes_sec>
+ <total_iops_sec>4000</total_iops_sec>
+ <group_name>limit0</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>5000</read_bytes_sec>
+ <write_bytes_sec>5000</write_bytes_sec>
+ <total_iops_sec>5000</total_iops_sec>
+ <group_name>limit1</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>6000</read_bytes_sec>
+ <write_bytes_sec>6000</write_bytes_sec>
+ <total_iops_sec>6000</total_iops_sec>
+ <group_name>limit2</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>7000</read_bytes_sec>
+ <write_bytes_sec>7000</write_bytes_sec>
+ <total_iops_sec>7000</total_iops_sec>
+ <group_name>limit12</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>7000</read_bytes_sec>
+ <write_bytes_sec>7000</write_bytes_sec>
+ <total_iops_sec>7000</total_iops_sec>
+ <group_name>limit3</group_name>
+ </throttlegroup>
+ </throttlegroups>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='vda' bus='virtio'/>
+ <iotune>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </iotune>
+ <throttlefilters>
+ <throttlefilter group='limit0'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='vdb' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit1'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest3'/>
+ <target dev='vdc' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit2'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args b/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args
new file mode 100644
index 0000000000..da757f91f9
--- /dev/null
+++ b/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args
@@ -0,0 +1,55 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \
+-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \
+-accel tcg \
+-cpu qemu64 \
+-m size=219136k \
+-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-object '{"qom-type":"throttle-group","id":"throttle-limit0","limits":{"bps-total":4000,"iops-total":4000}}' \
+-object '{"qom-type":"throttle-group","id":"throttle-limit1","limits":{"bps-read":5000,"bps-write":5000,"iops-total":5000}}' \
+-object '{"qom-type":"throttle-group","id":"throttle-limit2","limits":{"bps-read":6000,"bps-write":6000,"iops-total":6000}}' \
+-object '{"qom-type":"throttle-group","id":"throttle-limit12","limits":{"bps-read":7000,"bps-write":7000,"iops-total":7000}}' \
+-object '{"qom-type":"throttle-group","id":"throttle-limit3","limits":{"bps-read":8000,"bps-write":8000,"iops-total":8000}}' \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-8-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}}' \
+-blockdev '{"node-name":"libvirt-8-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-8-storage"}' \
+-blockdev '{"driver":"throttle","node-name":"libvirt-9-filter","throttle-group":"throttle-limit0","file":"libvirt-8-format"}' \
+-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"libvirt-9-filter","id":"virtio-disk0","bootindex":1,"write-cache":"on"}' \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest2","node-name":"libvirt-5-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}}' \
+-blockdev '{"node-name":"libvirt-5-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-5-storage"}' \
+-blockdev '{"driver":"throttle","node-name":"libvirt-6-filter","throttle-group":"throttle-limit1","file":"libvirt-5-format"}' \
+-blockdev '{"driver":"throttle","node-name":"libvirt-7-filter","throttle-group":"throttle-limit12","file":"libvirt-6-filter"}' \
+-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x5","drive":"libvirt-7-filter","id":"virtio-disk1","write-cache":"on"}' \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest3","node-name":"libvirt-2-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}}' \
+-blockdev '{"node-name":"libvirt-2-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-2-storage"}' \
+-blockdev '{"driver":"throttle","node-name":"libvirt-3-filter","throttle-group":"throttle-limit2","file":"libvirt-2-format"}' \
+-blockdev '{"driver":"throttle","node-name":"libvirt-4-filter","throttle-group":"throttle-limit12","file":"libvirt-3-filter"}' \
+-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x6","drive":"libvirt-4-filter","id":"virtio-disk2","write-cache":"on"}' \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest4","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap","cache":{"direct":true,"no-flush":false}}' \
+-blockdev '{"node-name":"libvirt-1-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-1-storage"}' \
+-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x7","drive":"libvirt-1-format","id":"virtio-disk3","write-cache":"on"}' \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x2"}' \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml b/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml
new file mode 100644
index 0000000000..32d57f1723
--- /dev/null
+++ b/tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml
@@ -0,0 +1,105 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <throttlegroups>
+ <throttlegroup>
+ <total_bytes_sec>4000</total_bytes_sec>
+ <total_iops_sec>4000</total_iops_sec>
+ <group_name>limit0</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>5000</read_bytes_sec>
+ <write_bytes_sec>5000</write_bytes_sec>
+ <total_iops_sec>5000</total_iops_sec>
+ <group_name>limit1</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>6000</read_bytes_sec>
+ <write_bytes_sec>6000</write_bytes_sec>
+ <total_iops_sec>6000</total_iops_sec>
+ <group_name>limit2</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>7000</read_bytes_sec>
+ <write_bytes_sec>7000</write_bytes_sec>
+ <total_iops_sec>7000</total_iops_sec>
+ <group_name>limit12</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>8000</read_bytes_sec>
+ <write_bytes_sec>8000</write_bytes_sec>
+ <total_iops_sec>8000</total_iops_sec>
+ <group_name>limit3</group_name>
+ </throttlegroup>
+ </throttlegroups>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <cpu mode='custom' match='exact' check='none'>
+ <model fallback='forbid'>qemu64</model>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='vda' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit0'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='vdb' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit1'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest3'/>
+ <target dev='vdc' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit2'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest4'/>
+ <target dev='vdd' bus='virtio'/>
+ <iotune>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </iotune>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0' model='piix3-uhci'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <audio id='1' type='none'/>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/throttlefilter.xml b/tests/qemuxmlconfdata/throttlefilter.xml
new file mode 100644
index 0000000000..d7db766755
--- /dev/null
+++ b/tests/qemuxmlconfdata/throttlefilter.xml
@@ -0,0 +1,95 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <throttlegroups>
+ <throttlegroup>
+ <total_bytes_sec>4000</total_bytes_sec>
+ <total_iops_sec>4000</total_iops_sec>
+ <group_name>limit0</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>5000</read_bytes_sec>
+ <write_bytes_sec>5000</write_bytes_sec>
+ <total_iops_sec>5000</total_iops_sec>
+ <group_name>limit1</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>6000</read_bytes_sec>
+ <write_bytes_sec>6000</write_bytes_sec>
+ <total_iops_sec>6000</total_iops_sec>
+ <group_name>limit2</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>7000</read_bytes_sec>
+ <write_bytes_sec>7000</write_bytes_sec>
+ <total_iops_sec>7000</total_iops_sec>
+ <group_name>limit12</group_name>
+ </throttlegroup>
+ <throttlegroup>
+ <read_bytes_sec>8000</read_bytes_sec>
+ <write_bytes_sec>8000</write_bytes_sec>
+ <total_iops_sec>8000</total_iops_sec>
+ <group_name>limit3</group_name>
+ </throttlegroup>
+ </throttlegroups>
+ <os>
+ <type arch='x86_64' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='vda' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit0'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='vdb' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit1'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest3'/>
+ <target dev='vdc' bus='virtio'/>
+ <throttlefilters>
+ <throttlefilter group='limit2'/>
+ <throttlefilter group='limit12'/>
+ </throttlefilters>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest4'/>
+ <target dev='vdd' bus='virtio'/>
+ <iotune>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </iotune>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index f7c0cf4ad0..c256b68331 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -2334,6 +2334,8 @@ mymain(void)
DO_TEST_CAPS_LATEST("blkdeviotune-max");
DO_TEST_CAPS_LATEST("blkdeviotune-group-num");
DO_TEST_CAPS_LATEST("blkdeviotune-max-length");
+ DO_TEST_CAPS_LATEST("throttlefilter");
+ DO_TEST_CAPS_LATEST_PARSE_ERROR("throttlefilter-invalid");
DO_TEST_CAPS_LATEST("multifunction-pci-device");
--
2.43.0
2 months, 3 weeks
[PATCH RFC v4 12/17] config: validate: Verify iotune, throttle group and filter
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Refactor iotune verification, and verify some rules
* Disk iotune validation can be reused for throttle group validation,
refactor it into common method "virDomainDiskIoTuneValidate"
* Add "virDomainDefValidateThrottleGroups" to validate throttle groups,
which in turn calls "virDomainDiskIoTuneValidate"
* Make sure referenced throttle group exists
* Use "iotune" and "throttlefilters" exclusively for specific disk
* Throttle filters cannot be used together with CDROM
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
src/conf/domain_validate.c | 119 ++++++++++++++++++++++++++-----------
src/qemu/qemu_driver.c | 6 ++
src/qemu/qemu_hotplug.c | 8 +++
3 files changed, 99 insertions(+), 34 deletions(-)
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index eddb4a5e74..24613d7155 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -659,11 +659,55 @@ virDomainDiskDefValidateStartupPolicy(const virDomainDiskDef *disk)
}
+static int
+virDomainDiskIoTuneValidate(const virDomainBlockIoTuneInfo blkdeviotune)
+{
+ if ((blkdeviotune.total_bytes_sec &&
+ blkdeviotune.read_bytes_sec) ||
+ (blkdeviotune.total_bytes_sec &&
+ blkdeviotune.write_bytes_sec)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("total and read/write bytes_sec cannot be set at the same time"));
+ return -1;
+ }
+
+ if ((blkdeviotune.total_iops_sec &&
+ blkdeviotune.read_iops_sec) ||
+ (blkdeviotune.total_iops_sec &&
+ blkdeviotune.write_iops_sec)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("total and read/write iops_sec cannot be set at the same time"));
+ return -1;
+ }
+
+ if ((blkdeviotune.total_bytes_sec_max &&
+ blkdeviotune.read_bytes_sec_max) ||
+ (blkdeviotune.total_bytes_sec_max &&
+ blkdeviotune.write_bytes_sec_max)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("total and read/write bytes_sec_max cannot be set at the same time"));
+ return -1;
+ }
+
+ if ((blkdeviotune.total_iops_sec_max &&
+ blkdeviotune.read_iops_sec_max) ||
+ (blkdeviotune.total_iops_sec_max &&
+ blkdeviotune.write_iops_sec_max)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("total and read/write iops_sec_max cannot be set at the same time"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
virDomainDiskDefValidate(const virDomainDef *def,
const virDomainDiskDef *disk)
{
virStorageSource *next;
+ size_t i;
/* disk target is used widely in other code so it must be validated first */
if (!disk->dst) {
@@ -713,41 +757,8 @@ virDomainDiskDefValidate(const virDomainDef *def,
}
/* Validate IotuneParse */
- if ((disk->blkdeviotune.total_bytes_sec &&
- disk->blkdeviotune.read_bytes_sec) ||
- (disk->blkdeviotune.total_bytes_sec &&
- disk->blkdeviotune.write_bytes_sec)) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("total and read/write bytes_sec cannot be set at the same time"));
+ if (virDomainDiskIoTuneValidate(disk->blkdeviotune) < 0)
return -1;
- }
-
- if ((disk->blkdeviotune.total_iops_sec &&
- disk->blkdeviotune.read_iops_sec) ||
- (disk->blkdeviotune.total_iops_sec &&
- disk->blkdeviotune.write_iops_sec)) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("total and read/write iops_sec cannot be set at the same time"));
- return -1;
- }
-
- if ((disk->blkdeviotune.total_bytes_sec_max &&
- disk->blkdeviotune.read_bytes_sec_max) ||
- (disk->blkdeviotune.total_bytes_sec_max &&
- disk->blkdeviotune.write_bytes_sec_max)) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("total and read/write bytes_sec_max cannot be set at the same time"));
- return -1;
- }
-
- if ((disk->blkdeviotune.total_iops_sec_max &&
- disk->blkdeviotune.read_iops_sec_max) ||
- (disk->blkdeviotune.total_iops_sec_max &&
- disk->blkdeviotune.write_iops_sec_max)) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("total and read/write iops_sec_max cannot be set at the same time"));
- return -1;
- }
/* Reject disks with a bus type that is not compatible with the
* given address type. The function considers only buses that are
@@ -943,6 +954,26 @@ virDomainDiskDefValidate(const virDomainDef *def,
return -1;
}
+ /* referenced group should be defined */
+ for (i = 0; i < disk->nthrottlefilters; i++) {
+ virDomainThrottleFilterDef *filter = disk->throttlefilters[i];
+ if (!virDomainThrottleGroupByName(def, filter->group_name)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("throttle group '%1$s' not found"),
+ filter->group_name);
+ return -1;
+ }
+ }
+
+ if (disk->throttlefilters &&
+ (disk->blkdeviotune.group_name ||
+ virDomainBlockIoTuneInfoHasAny(&disk->blkdeviotune))) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+ _("block 'throttlefilters' can't be used together with 'iotune' for disk '%1$s'"),
+ disk->dst);
+ return -1;
+ }
+
return 0;
}
@@ -1843,6 +1874,23 @@ virDomainDefLaunchSecurityValidate(const virDomainDef *def)
#undef CHECK_BASE64_LEN
+static int
+virDomainDefValidateThrottleGroups(const virDomainDef *def)
+{
+ size_t i;
+
+ for (i = 0; i < def->nthrottlegroups; i++) {
+ virDomainThrottleGroupDef *throttleGroup = def->throttlegroups[i];
+
+ /* Validate Throttle Group */
+ if (virDomainDiskIoTuneValidate(*throttleGroup) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
virDomainDefValidateInternal(const virDomainDef *def,
virDomainXMLOption *xmlopt)
@@ -1901,6 +1949,9 @@ virDomainDefValidateInternal(const virDomainDef *def,
if (virDomainDefLaunchSecurityValidate(def) < 0)
return -1;
+ if (virDomainDefValidateThrottleGroups(def) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c8f884c5b8..013393479e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14866,6 +14866,12 @@ qemuDomainDiskBlockIoTuneIsSupported(virDomainDiskDef *disk)
return false;
}
+ if (disk->throttlefilters) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("block 'iotune' can't be used together with 'throttlefilters' for disk '%1$s'"), disk->dst);
+ return false;
+ }
+
return true;
}
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 2eaae3f49d..ac97ea1bf6 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -937,6 +937,14 @@ qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriver *driver,
bool releaseSeclabel = false;
int ret = -1;
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+ if (disk->nthrottlefilters > 0) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("cdrom device with throttle filters isn't supported"));
+ return -1;
+ }
+ }
+
if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("floppy device hotplug isn't supported"));
--
2.43.0
2 months, 3 weeks
[PATCH RFC v4 01/17] schema: Add new domain elements to support multiple throttle groups
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Introduce schema for defining '<throttlegroups>' element which
configures throttling groups which can be configured for multiple
disks.
* Refactor "diskIoTune" to extract common schema "iotune"
* Add new elements '<throttlegroups>'
* <ThrottleGroups> contains <ThrottleGroup> defintion, which references
"iotune"
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
docs/formatdomain.rst | 26 +++
src/conf/schemas/domaincommon.rng | 274 ++++++++++++++++--------------
2 files changed, 174 insertions(+), 126 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 47d3e2125e..0022904a50 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -1957,6 +1957,32 @@ advertisements to the guest OS. (NB: Only qemu driver support)
the guest OS itself can choose to circumvent the unavailability of the sleep
states (e.g. S4 by turning off completely).
+Disk Throttle Group Management
+------------------------------
+
+:since:`Since 10.7.0` it is possible to create multiple named throttle groups
+and then reference them within ``throttlefilters``(sub-element of ``disk`` element)
+to form filter chain in QEMU for specific disk. The limits(throttlegroups) are
+shared within domain, hence the same group can be referenced by different filters.
+
+::
+
+ <domain>
+ ...
+ <throttlegroups>
+ <throttlegroup>
+ <group_name>limit0</group_name>
+ <total_bytes_sec>10000000</total_bytes_sec>
+ <read_iops_sec>400000</read_iops_sec>
+ <write_iops_sec>100000</write_iops_sec>
+ </throttlegroup>
+ </throttlegroups>
+ ...
+ </domain>
+
+``throttlegroup``
+ It has the same sub-elements as ``iotune`` (See `Hard drives, floppy disks, CDROMs`_),
+ The difference is that <group_name> is required.
Hypervisor features
-------------------
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index efb5f00d77..27cd9d9c8c 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -51,6 +51,7 @@
</zeroOrMore>
<ref name="os"/>
<ref name="clock"/>
+ <ref name="throttlegroups"/>
<ref name="resources"/>
<ref name="features"/>
<ref name="events"/>
@@ -6759,6 +6760,23 @@
</interleave>
</element>
</define>
+ <define name="throttlegroup">
+ <element name="throttlegroup">
+ <ref name="iotune"/>
+ </element>
+ </define>
+ <!--
+ A set of optional throttlegroups
+ -->
+ <define name="throttlegroups">
+ <optional>
+ <element name="throttlegroups">
+ <zeroOrMore>
+ <ref name="throttlegroup"/>
+ </zeroOrMore>
+ </element>
+ </optional>
+ </define>
<!--
A set of optional features: PAE, APIC, ACPI, GIC, TCG,
HyperV Enlightenment, KVM features, paravirtual spinlocks and HAP support
@@ -7726,134 +7744,138 @@
</element>
</define>
+ <define name="iotune">
+ <interleave>
+ <choice>
+ <element name="total_bytes_sec">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_bytes_sec">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_bytes_sec">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ <choice>
+ <element name="total_iops_sec">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_iops_sec">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_iops_sec">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ <choice>
+ <element name="total_bytes_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_bytes_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_bytes_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ <choice>
+ <element name="total_iops_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_iops_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_iops_sec_max">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ <optional>
+ <element name="size_iops_sec">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="group_name">
+ <text/>
+ </element>
+ </optional>
+ <choice>
+ <element name="total_bytes_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_bytes_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_bytes_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ <choice>
+ <element name="total_iops_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ <group>
+ <interleave>
+ <optional>
+ <element name="read_iops_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="write_iops_sec_max_length">
+ <data type="unsignedLong"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ </choice>
+ </interleave>
+ </define>
+
<define name="diskIoTune">
<element name="iotune">
- <interleave>
- <choice>
- <element name="total_bytes_sec">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_bytes_sec">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_bytes_sec">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <choice>
- <element name="total_iops_sec">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_iops_sec">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_iops_sec">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <choice>
- <element name="total_bytes_sec_max">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_bytes_sec_max">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_bytes_sec_max">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <choice>
- <element name="total_iops_sec_max">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_iops_sec_max">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_iops_sec_max">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <optional>
- <element name="size_iops_sec">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="group_name">
- <text/>
- </element>
- </optional>
- <choice>
- <element name="total_bytes_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_bytes_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_bytes_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- <choice>
- <element name="total_iops_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- <group>
- <interleave>
- <optional>
- <element name="read_iops_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- </optional>
- <optional>
- <element name="write_iops_sec_max_length">
- <data type="unsignedLong"/>
- </element>
- </optional>
- </interleave>
- </group>
- </choice>
- </interleave>
+ <ref name="iotune"/>
</element>
</define>
--
2.43.0
2 months, 3 weeks
[PATCH RFC v4 00/17] Support throttle block filters
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Hi,
I am thinking to leverage "throttle block filter" in QEMU to support more flexible I/O limits(e.g. tiered I/O groups), one sample provided by QEMU doc is:
https://github.com/qemu/qemu/blob/master/docs/throttle.txt
"For example, let's say that we have three different drives and we want to set I/O limits for
each one of them and an additional set of limits for the combined I/O of all three drives."
The implementation idea is to
- Define throttle groups(limit) in domain
- Define throttle filter to reference throttle group within disk
- Within domain disk, throttle filters references multiple throttle groups to form filter chain to apply multiple limits in QEMU like above sample
- Add new virsh cmds for throttle group management:
domthrottlegroupset Add or update a throttling group.
domthrottlegroupdel Delete a throttling group.
domthrottlegroupinfo Get a throttling group.
domthrottlegrouplist list all domain throttlegroups
- Update "attach-disk" to add one more option "--throttle-groups" to apply throttle filters e.g. "virsh attach-disk $VM_ID ${DISK_PATH}/vm1_disk_2.qcow2 vdd --driver qemu --subdriver qcow2 --targetbus virtio --throttle-groups limit2,limit012"
- I chose above semantics as I felt they're appropriate, if there are better ones please kindly suggest.
Note, this implementation requires flag "QEMU_CAPS_OBJECT_JSON".
From QMP perspective, the sample flow works this way:
- Throttle group creation:
virsh qemu-monitor-command 1 '{"execute":"object-add", "arguments":{"qom-type":"throttle-group","id":"limit0","limits":{"iops-total":200,"iops-read":0,"iops-total-max":200,"iops-total-max-length":1}}}'
virsh qemu-monitor-command 1 '{"execute":"object-add", "arguments":{"qom-type":"throttle-group","id":"limit1","limits":{"iops-total":250,"iops-read":0,"iops-total-max":250,"iops-total-max-length":1}}}'
virsh qemu-monitor-command 1 '{"execute":"object-add", "arguments":{"qom-type":"throttle-group","id":"limit2","limits":{"iops-total":300,"iops-read":0,"iops-total-max":300,"iops-total-max-length":1}}}'
virsh qemu-monitor-command 1 '{"execute":"object-add", "arguments":{"qom-type":"throttle-group","id":"limit012","limits":{"iops-total":400,"iops-read":0,"iops-total-max":400,"iops-total-max-length":1}}}'
- Chain up filters during attaching disk to apply two filters(limit0 and limit012):
virsh qemu-monitor-command 1 '{"execute":"blockdev-add", "arguments": {"driver":"file","filename":"/virt/disks/vm1_disk_1.qcow2","node-name":"test-3-storage","auto-read-only":true,"discard":"unmap"}}'
virsh qemu-monitor-command 1 '{"execute":"blockdev-add", "arguments":{"node-name":"test-4-format","read-only":false,"driver":"qcow2","file":"test-3-storage","backing":null}}'
virsh qemu-monitor-command 1 '{"execute":"blockdev-add", "arguments":{"driver":"throttle","node-name":"libvirt-5-filter","throttle-group": "limit0","file":"test-4-format"}}'
virsh qemu-monitor-command 1 '{"execute":"blockdev-add", "arguments": {"driver":"throttle","node-name":"libvirt-6-filter","throttle-group":"limit012","file":"libvirt-5-filter"}}'
virsh qemu-monitor-command 1 '{"execute": "device_add", "arguments": {"driver":"virtio-blk-pci","scsi":false,"bus":"pci.0","addr":"0x5","drive":"libvirt-6-filter","id":"virtio-disk1"}}'
This patchset includes:
- schema: Add new domain elements to support multiple throttle groups
- schema: Add new domain elements to support multiple throttle filters
- config: Introduce ThrottleGroup and corresponding XML parsing
- config: Introduce ThrottleFilter and corresponding XML parsing
- qemu: monitor: Add support for ThrottleGroup operations
- tests: Test qemuMonitorJSONGetThrottleGroup and qemuMonitorJSONUpdateThrottleGroup
- remote: New APIs for ThrottleGroup lifecycle management
- qemu: Refactor qemuDomainSetBlockIoTune to extract common methods
- qemu: Implement qemu driver for throttle API
- qemu: helper: throttle filter nodename and preparation processing
- qemu: block: Support block disk along with throttle filters
- config: validate: Verify iotune, throttle group and filter
- qemuxmlconftest: Add 'throttlefilter' tests
- test_driver: Test throttle group lifecycle APIs
- virsh: Refactor iotune options for re-use
- virsh: Add support for throttle group operations
- virsh: Add option "throttle-groups" to "attach_disk"
v4 changes:
- Format commit msgs
- Update version to '10.7.0'
- Update formatdomain.rst to remove nodename chain sample which exists in QEMU, and add description that order within <throttlefilters> doesn't mater
- delete "virDomainThrottleGroupFind", which is duplicate to "virDomainThrottleGroupByName"
- Remove "id" within _virDomainThrottleFilterDef, which is not required
- Avoid export for methods not used anywhere else
- Add manpage for new virsh cmds and options
- Update error code&msg
- Consolidate validation logic into one commit
- Format throttle filter nodename into disk/privateData/nodenames/nodename(type='throttle-filter') and parse it reversely
- Add tests for statusxml(disk/privateData/nodenames/nodename) test regarding throttle filter nodename parse and format
- Add more complicated test cases and negative case for throttle filter xml
- Add a 'throttle-' prefix so that we clearly separate the throttle group objects into their own QEMU namespace.
- Update virDomainGetThrottleGroup and virDomainDelThrottleGroup to remove TYPED_PARAM_STRING check
- Update remote_protocol.x "REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP" to set "@acl: domain:write" rather than "read"
- Split commit of "qemu: Implement qemu driver for throttle API" into two commits
- Check QEMU_CAPS_OBJECT_JSON when vm is virDomainObjIsActive(vm), and update error msg
- Address leak in qemuBuildThrottleFiltersAttachPrepareBlockdev
- Prefix new cmd with "dom", e.g. domthrottlegroupset
- Refactor completer and "domthrottlegrouplist" to share the same method "virshGetThrottleGroupNames"
- Update qemuBlockThrottleFilterAttachPrepareBlockdev to remove "data->filterAttached = true;"
- Support CopyOnRead by re-org chain: device -> throttle -> copyOnRead Layer-> image chain
Any comments/suggestions will be appriciated!
Chun Feng Wu (17):
schema: Add new domain elements to support multiple throttle groups
schema: Add new domain elements to support multiple throttle filters
config: Introduce ThrottleGroup and corresponding XML parsing
config: Introduce ThrottleFilter and corresponding XML parsing
qemu: monitor: Add support for ThrottleGroup operations
tests: Test qemuMonitorJSONGetThrottleGroup and
qemuMonitorJSONUpdateThrottleGroup
remote: New APIs for ThrottleGroup lifecycle management
qemu: Refactor qemuDomainSetBlockIoTune to extract common methods
qemu: Implement qemu driver for throttle API
qemu: helper: throttle filter nodename and preparation processing
qemu: block: Support block disk along with throttle filters
config: validate: Verify iotune, throttle group and filter
qemuxmlconftest: Add 'throttlefilter' tests
test_driver: Test throttle group lifecycle APIs
virsh: Refactor iotune options for re-use
virsh: Add support for throttle group operations
virsh: Add option "throttle-groups" to "attach_disk"
docs/formatdomain.rst | 47 ++
docs/manpages/virsh.rst | 135 +++-
include/libvirt/libvirt-domain.h | 21 +
src/conf/domain_conf.c | 398 ++++++++++
src/conf/domain_conf.h | 45 ++
src/conf/domain_validate.c | 119 ++-
src/conf/schemas/domaincommon.rng | 293 ++++----
src/conf/virconftypes.h | 4 +
src/driver-hypervisor.h | 22 +
src/libvirt-domain.c | 174 +++++
src/libvirt_private.syms | 8 +
src/libvirt_public.syms | 7 +
src/qemu/qemu_block.c | 136 ++++
src/qemu/qemu_block.h | 49 ++
src/qemu/qemu_command.c | 180 +++++
src/qemu/qemu_command.h | 6 +
src/qemu/qemu_domain.c | 73 +-
src/qemu/qemu_driver.c | 619 +++++++++++++---
src/qemu/qemu_hotplug.c | 33 +
src/qemu/qemu_monitor.c | 34 +
src/qemu/qemu_monitor.h | 14 +
src/qemu/qemu_monitor_json.c | 134 ++++
src/qemu/qemu_monitor_json.h | 14 +
src/remote/remote_daemon_dispatch.c | 44 ++
src/remote/remote_driver.c | 40 ++
src/remote/remote_protocol.x | 48 +-
src/remote_protocol-structs | 28 +
src/test/test_driver.c | 452 ++++++++----
tests/qemumonitorjsontest.c | 86 +++
.../throttlefilter-in.xml | 392 ++++++++++
.../throttlefilter-out.xml | 392 ++++++++++
tests/qemuxmlactivetest.c | 1 +
.../throttlefilter-invalid.x86_64-latest.err | 1 +
.../throttlefilter-invalid.xml | 89 +++
.../throttlefilter.x86_64-latest.args | 55 ++
.../throttlefilter.x86_64-latest.xml | 105 +++
tests/qemuxmlconfdata/throttlefilter.xml | 95 +++
tests/qemuxmlconftest.c | 2 +
tools/virsh-completer-domain.c | 82 +++
tools/virsh-completer-domain.h | 16 +
tools/virsh-domain.c | 680 ++++++++++++++----
41 files changed, 4648 insertions(+), 525 deletions(-)
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-in.xml
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-out.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.xml
--
2.43.0
2 months, 3 weeks
[PATCH] virschematest: Replace g_lstat() with virFileIsLink()
by Michal Privoznik
Inside of virschematest.c there's testSchemaDir() which iterates
over dentries in given directory but skips some files: those
without ".xml" suffix, hidden files, symlinks, etc.
Now, symlinks are detected as g_lstat() + S_ISLNK() combo which
works, except it fails to compile on mingw where is no concept of
symlinks. Replace the combo with a call to virFileIsLink() which
at least allows us to compile cleanly on mingw.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
The reason this isn't detected by our CI is that we explicitly build
libvirt with -Dtests=disabled which I missed when debugging latest build
error on mingw.
tests/virschematest.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/virschematest.c b/tests/virschematest.c
index 20ac495f4a..83bc945711 100644
--- a/tests/virschematest.c
+++ b/tests/virschematest.c
@@ -125,8 +125,7 @@ testSchemaDir(const char *schema,
continue;
if (ent->d_name[0] == '.')
continue;
- if (g_lstat(ent->d_name, &sb) >= 0 &&
- S_ISLNK(sb.st_mode))
+ if (virFileIsLink(ent->d_name))
continue;
if (filter &&
!g_regex_match(filter, ent->d_name, 0, NULL))
--
2.44.2
2 months, 3 weeks
[RFC PATCH] conf: check for migration job during domain start
by Sergey Dyasli
It's possible to hit the following situation during qemu p2p live
migration:
1. qemu has live migrated and exited (making virDomainObjIsActive()
return false)
2. the live migration job is still in progress, waiting for a
confirmation from the remote libvirt daemon. This may last for
a while with a presence of networking issues (up to keepalive
timeout).
Any attempt to start the domain again would fail with "domain is already
being started" message which is misleading in this situation as it
doesn't reflect what's really happening.
Add a check for the migration job and report a different error message
if the migration job is still running.
Signed-off-by: Sergey Dyasli <sergey.dyasli(a)nutanix.com>
---
src/conf/virdomainobjlist.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
index bb5807d00b42..166bbc5cfd57 100644
--- a/src/conf/virdomainobjlist.c
+++ b/src/conf/virdomainobjlist.c
@@ -301,9 +301,15 @@ virDomainObjListAddLocked(virDomainObjList *doms,
goto error;
}
if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("domain '%1$s' is already being started"),
- vm->def->name);
+ if (vm->job->asyncJob == VIR_ASYNC_JOB_MIGRATION_OUT) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("domain '%1$s' is being migrated out"),
+ vm->def->name);
+ } else {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("domain '%1$s' is already being started"),
+ vm->def->name);
+ }
goto error;
}
}
--
2.22.3
2 months, 3 weeks
[PATCH] hypervisor: interface: Stub out virDomainCreateInBridgePortWithHelper using 'socketpair' on win32
by Peter Krempa
Mingw build failed after commit af87ee7927d3245582d82d36da25b4dc3b34465e
as 'socketpair()' is not available on that platform.
Stub out the function to return failure.
Fixes: af87ee7927d3245582d82d36da25b4dc3b34465e
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
Pipeline:
https://gitlab.com/pipo.sk/libvirt/-/pipelines/1428482965
(Ignore the broken Cirrus jobs. Something broke and it can't find
master branch when building from my user. I blame github :D)
src/hypervisor/domain_interface.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/hypervisor/domain_interface.c b/src/hypervisor/domain_interface.c
index fc82624bb9..5cdba279fa 100644
--- a/src/hypervisor/domain_interface.c
+++ b/src/hypervisor/domain_interface.c
@@ -532,6 +532,7 @@ virDomainClearNetBandwidth(virDomainDef *def)
*
* Returns 0 in case of success or -1 on failure
*/
+#ifndef WIN32
static int
virDomainCreateInBridgePortWithHelper(const char *bridgeHelperName,
const char *brname,
@@ -583,9 +584,9 @@ virDomainCreateInBridgePortWithHelper(const char *bridgeHelperName,
virCommandPassFD(cmd, pair[1],
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
virCommandClearCaps(cmd);
-#ifdef CAP_NET_ADMIN
+# ifdef CAP_NET_ADMIN
virCommandAllowCap(cmd, CAP_NET_ADMIN);
-#endif
+# endif
if (virCommandRunAsync(cmd, NULL) < 0) {
*tapfd = -1;
goto cleanup;
@@ -626,6 +627,20 @@ virDomainCreateInBridgePortWithHelper(const char *bridgeHelperName,
return *tapfd < 0 ? -1 : 0;
}
+#else /* WIN32 */
+
+static int
+virDomainCreateInBridgePortWithHelper(const char *bridgeHelperName G_GNUC_UNUSED,
+ const char *brname G_GNUC_UNUSED,
+ char **ifname G_GNUC_UNUSED,
+ int *tapfd G_GNUC_UNUSED,
+ unsigned int unusedflags G_GNUC_UNUSED)
+{
+ virReportSystemError(ENOSYS, "%s",
+ _("bridge port creation is not supported on this platform"));
+ return -1;
+}
+#endif
/* virDomainInterfaceBridgeConnect:
* @def: the definition of the VM
--
2.46.0
2 months, 3 weeks
Discouraging use of virInterface* APIs
by Jim Fehlig
Laine's attempt long ago [1] to deprecate/obsolete the virInterface* APIs did
not receive a standing ovation. However he raised many good points which are
still valid today. If anything, netcf, the libvirt netcf backend, and the whole
interface driver have become more stale. Personally, I wish we could deprecate
and eventually obsolete the APIs and nuke the entire driver, but understand
that's not desirable/realistic upstream. Given the state of the thing, I'd like
to hear opinions on adding some words to the interface API page and
virtinterfaced man page that describe the state of the APIs/driver and
discourages their use.
The motivation for this request comes from my efforts to take advantage of
libvirt's modularization and not provide virtinterfaced
(libvirt-daemon-driver-interface package) for certain use-cases. Having upstream
documentation warning of the limitations and inactive development of the
APIs/driver would help in convincing unsuspected users to find a better
solution. And I think the use of "unsuspected" is correct :-). Projects closer
to libvirt, like virt-manager, ditched use of the APIs long ago. But projects
with less cross-pollination may not be aware of the general uselessness.
As an example, we recently discovered cockpit-machines uses
virConnectListAllInterfaces and virInterfaceGetXMLDesc. It's not clear to me why
cockpit gathers this info. AFAICT it's not used for anything. The code was added
long ago [2] with no info on purpose or what it's supposed to achieve. We've
opened a github issue [3] to discuss removing use of these APIs. Pointing
cockpit-machines developers to upstream libvirt documentation that describes the
state of virInterface* and sets realistic expectation might help in convincing
them to follow virt-managers footsteps and drop use of the APIs.
I can provide the words of discouragement in the form of a patch if folks are
receptive to the idea :-).
Regards,
Jim
[1] https://listman.redhat.com/archives/libvir-list/2020-December/212791.html
[2] https://github.com/cockpit-project/cockpit/pull/12465
[3] https://github.com/cockpit-project/cockpit-machines/issues/1777
2 months, 3 weeks
[PATCH] remoteDispatchConnectOpen: Fix check for 'BHYVE' connection type
by Peter Krempa
From: aokblast <aokblast(a)FreeBSD.org>
'bhyveConnectGetType' (which is called from 'virConnectGetType') returns
'BHYVE' as the type, but the code in 'remoteDispatchConnectOpen'
responsible for selecting the sub-driver URIs in modular deployment
checks for 'bhyve' and thus would not properly fill the URIs to the
sub-daemons.
Signed-off-by: aokblast <aokblast(a)FreeBSD.org>
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/remote/remote_daemon_dispatch.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index cfffb40095..e812f5c3e9 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -2108,7 +2108,7 @@ remoteDispatchConnectOpen(virNetServer *server G_GNUC_UNUSED,
STREQ(type, "Xen") ||
STREQ(type, "LXC") ||
STREQ(type, "VBOX") ||
- STREQ(type, "bhyve") ||
+ STREQ(type, "BHYVE") ||
STREQ(type, "vz") ||
STREQ(type, "Parallels") ||
STREQ(type, "CH")) {
--
2.46.0
2 months, 3 weeks