[PATCH 0/2] Enable Bridge network support for ch guests
by Praveen K Paladugu
Enble Bridge network mode for ch guest.
Praveen K Paladugu (2):
ch: Enable bridge network mode
NEWS: Add an entry for network support in ch driver.
NEWS.rst | 4 ++++
src/ch/ch_interface.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
--
2.44.0
7 months, 1 week
[PATCH 0/4] qemu: Fill in panic model automatically on aarch64
by Andrea Bolognani
Back when pvpanic-pci support was introduced 1.5 years ago (!), we
required the user to manually provide the model name. This is
incovenient and doesn't match the behavior seen on other
architectures. Make things more user friendly.
Andrea Bolognani (4):
tests: Add coverage for panic on riscv64
qemu: Refactor default panic model
qemu: Sometimes the default panic model doesn't exist
qemu: Use pvpanic by default on aarch64
src/qemu/qemu_domain.c | 36 ++++++++++++-------
src/qemu/qemu_validate.c | 6 +++-
.../aarch64-panic-no-model.aarch64-latest.err | 1 -
...ault-models.aarch64-latest.abi-update.args | 1 +
...fault-models.aarch64-latest.abi-update.xml | 3 ++
...64-virt-default-models.aarch64-latest.args | 1 +
...h64-virt-default-models.aarch64-latest.xml | 3 ++
.../aarch64-virt-default-models.xml | 2 +-
.../riscv64-panic-no-model.riscv64-latest.err | 1 +
...o-model.xml => riscv64-panic-no-model.xml} | 4 +--
tests/qemuxmlconftest.c | 2 +-
11 files changed, 42 insertions(+), 18 deletions(-)
delete mode 100644 tests/qemuxmlconfdata/aarch64-panic-no-model.aarch64-latest.err
create mode 100644 tests/qemuxmlconfdata/riscv64-panic-no-model.riscv64-latest.err
rename tests/qemuxmlconfdata/{aarch64-panic-no-model.xml => riscv64-panic-no-model.xml} (65%)
--
2.46.0
7 months, 1 week
[libvirt PATCH] ch: interface: correctly update nicindexes
by Pavel Hrdina
Originally nicindexes were updated only for VIR_DOMAIN_NET_TYPE_BRIDGE
and VIR_DOMAIN_NET_TYPE_DIRECT. The mentioned commit adds support for
NAT network mode and changes the code to update nicindexes for
VIR_DOMAIN_NET_TYPE_ETHERNET and VIR_DOMAIN_NET_TYPE_NETWORK as well.
It doesn't work as intended and after the change nicindexes are updated
only for VIR_DOMAIN_NET_TYPE_ETHERNET and VIR_DOMAIN_NET_TYPE_NETWORK.
Fixes: aa642090738eb276f7bd70dea97d3a4fd03d59e3
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
src/ch/ch_interface.c | 42 ++++++++++++++++++++++++++++--------------
1 file changed, 28 insertions(+), 14 deletions(-)
diff --git a/src/ch/ch_interface.c b/src/ch/ch_interface.c
index 47b02bc322..87a95cde53 100644
--- a/src/ch/ch_interface.c
+++ b/src/ch/ch_interface.c
@@ -34,6 +34,26 @@
VIR_LOG_INIT("ch.ch_interface");
+
+static int
+virCHInterfaceUpdateNicindexes(virDomainNetDef *net,
+ int **nicindexes,
+ size_t *nnicindexes)
+{
+ int nicindex = 0;
+
+ if (!nicindexes || !nnicindexes || !net->ifname)
+ return 0;
+
+ if (virNetDevGetIndex(net->ifname, &nicindex) < 0)
+ return -1;
+
+ VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex);
+
+ return 0;
+}
+
+
/**
* virCHConnetNetworkInterfaces:
* @driver: pointer to ch driver object
@@ -78,6 +98,8 @@ virCHConnetNetworkInterfaces(virCHDriver *driver,
net->driver.virtio.queues) < 0)
return -1;
+ if (virCHInterfaceUpdateNicindexes(net, nicindexes, nnicindexes) < 0)
+ return -1;
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
if (virDomainInterfaceBridgeConnect(vm, net,
@@ -88,9 +110,15 @@ virCHConnetNetworkInterfaces(virCHDriver *driver,
false,
NULL) < 0)
return -1;
+
+ if (virCHInterfaceUpdateNicindexes(net, nicindexes, nnicindexes) < 0)
+ return -1;
break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_DIRECT:
+ if (virCHInterfaceUpdateNicindexes(net, nicindexes, nnicindexes) < 0)
+ return -1;
+ break;
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
@@ -109,19 +137,5 @@ virCHConnetNetworkInterfaces(virCHDriver *driver,
return -1;
}
- if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
- actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
- actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (nicindexes && nnicindexes && net->ifname) {
- int nicindex = 0;
-
- if (virNetDevGetIndex(net->ifname, &nicindex) < 0)
- return -1;
-
- VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex);
- }
- }
-
return 0;
}
--
2.46.0
7 months, 1 week
[PATCH RFC v4 16/17] virsh: Add support for throttle group operations
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Implement new throttle cmds
* Add new virsh cmds: domthrottlegroupset, domthrottlegrouplist,
domthrottlegroupinfo, domthrottlegroupdel
* Add doc for new cmds at docs/manpages/virsh.rst
* Add cmd helper "virshDomainThrottleGroupCompleter", which is used by
domthrottlegroupset, domthrottlegroupinfo, domthrottlegroupdel
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
docs/manpages/virsh.rst | 132 +++++++++++++
tools/virsh-completer-domain.c | 55 ++++++
tools/virsh-completer-domain.h | 11 ++
tools/virsh-domain.c | 349 ++++++++++++++++++++++++++++++++-
4 files changed, 546 insertions(+), 1 deletion(-)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index f02a28156d..79840f2ab8 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1122,6 +1122,138 @@ given, but *--current* is exclusive. For querying only one of *--live*,
is different depending on hypervisor.
+domthrottlegroupset
+-------------------
+
+**Syntax:**
+
+::
+
+ domthrottlegroupset domain group-name [[--config] [--live] | [--current]]
+ [[total-bytes-sec] | [read-bytes-sec] [write-bytes-sec]]
+ [[total-iops-sec] | [read-iops-sec] [write-iops-sec]]
+ [[total-bytes-sec-max] | [read-bytes-sec-max] [write-bytes-sec-max]]
+ [[total-iops-sec-max] | [read-iops-sec-max] [write-iops-sec-max]]
+ [[total-bytes-sec-max-length] |
+ [read-bytes-sec-max-length] [write-bytes-sec-max-length]]
+ [[total-iops-sec-max-length] |
+ [read-iops-sec-max-length] [write-iops-sec-max-length]]
+ [size-iops-sec]
+
+Add or update a throttle group against specific *domain*.
+*group-name* specifies a unique throttle group name, which defines limit, and
+will be referenced by drives.
+*domain* (see also ``domblklist`` for listing these names).
+
+If no limit is specified, default them as all zeros, which will fail,
+Otherwise, set limits with these flags:
+*--total-bytes-sec* specifies total throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--read-bytes-sec* specifies read throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--write-bytes-sec* specifies write throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--total-iops-sec* specifies total I/O operations limit per second.
+*--read-iops-sec* specifies read I/O operations limit per second.
+*--write-iops-sec* specifies write I/O operations limit per second.
+*--total-bytes-sec-max* specifies maximum total throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified
+*--read-bytes-sec-max* specifies maximum read throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified.
+*--write-bytes-sec-max* specifies maximum write throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified.
+*--total-iops-sec-max* specifies maximum total I/O operations limit per second.
+*--read-iops-sec-max* specifies maximum read I/O operations limit per second.
+*--write-iops-sec-max* specifies maximum write I/O operations limit per second.
+*--total-bytes-sec-max-length* specifies duration in seconds to allow maximum
+total throughput limit.
+*--read-bytes-sec-max-length* specifies duration in seconds to allow maximum
+read throughput limit.
+*--write-bytes-sec-max-length* specifies duration in seconds to allow maximum
+write throughput limit.
+*--total-iops-sec-max-length* specifies duration in seconds to allow maximum
+total I/O operations limit.
+*--read-iops-sec-max-length* specifies duration in seconds to allow maximum
+read I/O operations limit.
+*--write-iops-sec-max-length* specifies duration in seconds to allow maximum
+write I/O operations limit.
+*--size-iops-sec* specifies size I/O operations limit per second.
+
+Bytes and iops values are independent, but setting only one value (such
+as --read-bytes-sec) resets the other two in that category to unlimited.
+An explicit 0 also clears any limit. A non-zero value for a given total
+cannot be mixed with non-zero values for read or write.
+
+It is up to the hypervisor to determine how to handle the length values.
+For the QEMU hypervisor, if an I/O limit value or maximum value is set,
+then the default value of 1 second will be displayed. Supplying a 0 will
+reset the value back to the default.
+
+If *--live* is specified, affect a running guest.
+If *--config* is specified, affect the next start of a persistent guest.
+If *--current* is specified, it is equivalent to either *--live* or
+*--config*, depending on the current state of the guest.
+When setting the disk io parameters both *--live* and *--config* flags may be
+given, but *--current* is exclusive. If no flag is specified, behavior
+is different depending on hypervisor.
+
+
+domthrottlegroupdel
+-------------------
+
+**Syntax:**
+
+::
+
+ domthrottlegroupdel domain group-name [[--config] [--live] | [--current]]
+
+Delete a Throttlegroup from the domain using the specified *group-name*.
+If an Throttlegroup is currently referenced by a disk resource such as via the
+``attach-disk`` command, then the attempt to remove the Throttlegroup will fail.
+If the *group-name* does not exist an error will occur.
+
+If *--live* is specified, affect a running guest. If the guest is not
+running an error is returned.
+If *--config* is specified, affect the next start of a persistent guest.
+If *--current* is specified, it is equivalent to either *--live* or
+*--config*, depending on the current state of the guest.
+
+
+domthrottlegroupinfo
+--------------------
+
+**Syntax:**
+
+::
+
+ domthrottlegroupinfo domain group-name [[--config] [--live] | [--current]]
+
+Display domain Throttlegroup information including I/O limits setting.
+
+If *--live* is specified, get the Throttlegroup data from the running guest. If
+the guest is not running, an error is returned.
+If *--config* is specified, get the Throttlegroup data from the next start of
+a persistent guest.
+If *--current* is specified or *--live* and *--config* are not specified,
+then get the Throttlegroup data based on the current guest state, which can
+either be live or offline.
+
+
+domthrottlegrouplist
+--------------------
+
+**Syntax:**
+
+::
+
+ domthrottlegrouplist domain [--inactive]
+
+Print a table showing names of all throttle groups
+associated with *domain*. If *--inactive* is specified, query the
+block devices that will be used on the next boot, rather than those
+currently in use by a running domain.
+
+
blkiotune
---------
diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c
index 61362224a3..3b0df15c13 100644
--- a/tools/virsh-completer-domain.c
+++ b/tools/virsh-completer-domain.c
@@ -248,6 +248,61 @@ virshDomainMigrateDisksCompleter(vshControl *ctl,
}
+int
+virshGetThrottleGroupNames(xmlXPathContext *ctxt,
+ xmlNodePtr **groups,
+ char ***groupNames)
+{
+ int ngroups;
+ size_t i;
+
+ ngroups = virXPathNodeSet("./throttlegroups/throttlegroup", ctxt, groups);
+ if (ngroups < 0)
+ return -1;
+
+ *groupNames = g_new0(char *, ngroups + 1);
+
+ for (i = 0; i < ngroups; i++) {
+ ctxt->node = (*groups)[i];
+ if (!((*groupNames)[i] = virXPathString("string(./group_name)", ctxt))) {
+ g_strfreev(*groupNames);
+ *groupNames = NULL;
+ return -1;
+ }
+ }
+
+ return ngroups;
+}
+
+
+char **
+virshDomainThrottleGroupCompleter(vshControl *ctl,
+ const vshCmd *cmd,
+ unsigned int flags)
+{
+ virshControl *priv = ctl->privData;
+ g_autoptr(xmlDoc) xmldoc = NULL;
+ g_autoptr(xmlXPathContext) ctxt = NULL;
+ g_autofree xmlNodePtr *groups = NULL;
+ g_auto(GStrv) groupNames = NULL;
+ int ngroups;
+
+ virCheckFlags(0, NULL);
+
+ if (!priv->conn || virConnectIsAlive(priv->conn) <= 0)
+ return NULL;
+
+ if (virshDomainGetXML(ctl, cmd, 0, &xmldoc, &ctxt) < 0)
+ return NULL;
+
+ ngroups = virshGetThrottleGroupNames(ctxt, &groups, &groupNames);
+ if (ngroups < 0)
+ return NULL;
+
+ return g_steal_pointer(&groupNames);
+}
+
+
char **
virshDomainUndefineStorageDisksCompleter(vshControl *ctl,
const vshCmd *cmd,
diff --git a/tools/virsh-completer-domain.h b/tools/virsh-completer-domain.h
index 27cf963912..680b3fc018 100644
--- a/tools/virsh-completer-domain.h
+++ b/tools/virsh-completer-domain.h
@@ -21,6 +21,7 @@
#pragma once
#include "vsh.h"
+#include <libxml/xpath.h>
char **
virshDomainNameCompleter(vshControl *ctl,
@@ -41,6 +42,16 @@ virshDomainDiskTargetCompleter(vshControl *ctl,
const vshCmd *cmd,
unsigned int flags);
+int
+virshGetThrottleGroupNames(xmlXPathContext *ctxt,
+ xmlNodePtr **groups,
+ char ***groupNames);
+
+char **
+virshDomainThrottleGroupCompleter(vshControl *ctl,
+ const vshCmd *cmd,
+ unsigned int flags);
+
char **
virshDomainInterfaceStateCompleter(vshControl *ctl,
const vshCmd *cmd,
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 7c60920788..aeb783de88 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1375,7 +1375,7 @@ static const vshCmdOptDef opts_blkdeviotune[] = {
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
{.name = NULL}
};
-#undef VSH_OPTS_IOTUNE
+
static bool
cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
@@ -1513,6 +1513,329 @@ cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
goto cleanup;
}
+
+/*
+ * "throttlegrouplist" command
+ */
+static const vshCmdInfo info_throttlegrouplist = {
+ .help = N_("list all domain throttlegroups."),
+ .desc = N_("Get the summary of throttle groups for a domain."),
+};
+
+
+static const vshCmdOptDef opts_throttlegrouplist[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "inactive",
+ .type = VSH_OT_BOOL,
+ .help = N_("get inactive rather than running configuration")
+ },
+ {.name = NULL}
+};
+
+
+static bool
+cmdThrottleGroupList(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ unsigned int flags = 0;
+ size_t i;
+ g_autoptr(xmlDoc) xml = NULL;
+ g_autoptr(xmlXPathContext) ctxt = NULL;
+ g_autofree xmlNodePtr *groups = NULL;
+ g_auto(GStrv) groupNames = NULL;
+ ssize_t ngroups;
+ g_autoptr(vshTable) table = NULL;
+
+ if (vshCommandOptBool(cmd, "inactive"))
+ flags |= VIR_DOMAIN_XML_INACTIVE;
+
+ if (virshDomainGetXML(ctl, cmd, flags, &xml, &ctxt) < 0)
+ return false;
+
+ table = vshTableNew(_("Name"), NULL);
+
+ if (!table)
+ return false;
+
+ ngroups = virshGetThrottleGroupNames(ctxt, &groups, &groupNames);
+ for (i = 0; i < ngroups; i++) {
+ if (vshTableRowAppend(table, groupNames[i], NULL) < 0)
+ return false;
+ }
+
+ vshTablePrintToStdout(table, ctl);
+
+ return true;
+}
+
+
+/*
+ * "throttlegroupset" command
+ */
+static const vshCmdInfo info_throttlegroupset = {
+ .help = N_("Add or update a throttling group."),
+ .desc = N_("Add or updte a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_throttlegroupset[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "group-name",
+ .type = VSH_OT_STRING,
+ .positional = true,
+ .required = true,
+ .completer = virshDomainThrottleGroupCompleter,
+ .help = N_("throttle group name")
+ },
+ VSH_OPTS_IOTUNE(),
+ VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+ VIRSH_COMMON_OPT_DOMAIN_LIVE,
+ VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+ {.name = NULL}
+};
+#undef VSH_OPTS_IOTUNE
+
+
+static bool
+cmdThrottleGroupSet(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ g_autoptr(virshDomain) dom = NULL;
+ const char *group_name = NULL;
+ unsigned long long value;
+ int nparams = 0;
+ int maxparams = 0;
+ virTypedParameterPtr params = NULL;
+ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+ int rv = 0;
+ bool current = vshCommandOptBool(cmd, "current");
+ bool config = vshCommandOptBool(cmd, "config");
+ bool live = vshCommandOptBool(cmd, "live");
+ bool ret = false;
+
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ goto cleanup;
+
+
+#define VSH_SET_THROTTLE_GROUP_SCALED(PARAM, CONST) \
+ if ((rv = vshCommandOptScaledInt(ctl, cmd, #PARAM, &value, \
+ 1, ULLONG_MAX)) < 0) { \
+ goto interror; \
+ } else if (rv > 0) { \
+ if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, \
+ VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
+ value) < 0) \
+ goto save_error; \
+ }
+
+ VSH_SET_THROTTLE_GROUP_SCALED(total-bytes-sec, TOTAL_BYTES_SEC);
+ VSH_SET_THROTTLE_GROUP_SCALED(read-bytes-sec, READ_BYTES_SEC);
+ VSH_SET_THROTTLE_GROUP_SCALED(write-bytes-sec, WRITE_BYTES_SEC);
+ VSH_SET_THROTTLE_GROUP_SCALED(total-bytes-sec-max, TOTAL_BYTES_SEC_MAX);
+ VSH_SET_THROTTLE_GROUP_SCALED(read-bytes-sec-max, READ_BYTES_SEC_MAX);
+ VSH_SET_THROTTLE_GROUP_SCALED(write-bytes-sec-max, WRITE_BYTES_SEC_MAX);
+#undef VSH_SET_THROTTLE_GROUP_SCALED
+
+#define VSH_SET_THROTTLE_GROUP(PARAM, CONST) \
+ if ((rv = vshCommandOptULongLong(ctl, cmd, #PARAM, &value)) < 0) { \
+ goto interror; \
+ } else if (rv > 0) { \
+ if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, \
+ VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
+ value) < 0) \
+ goto save_error; \
+ }
+
+ VSH_SET_THROTTLE_GROUP(total-iops-sec, TOTAL_IOPS_SEC);
+ VSH_SET_THROTTLE_GROUP(read-iops-sec, READ_IOPS_SEC);
+ VSH_SET_THROTTLE_GROUP(write-iops-sec, WRITE_IOPS_SEC);
+ VSH_SET_THROTTLE_GROUP(total-iops-sec-max, TOTAL_IOPS_SEC_MAX);
+ VSH_SET_THROTTLE_GROUP(read-iops-sec-max, READ_IOPS_SEC_MAX);
+ VSH_SET_THROTTLE_GROUP(write-iops-sec-max, WRITE_IOPS_SEC_MAX);
+ VSH_SET_THROTTLE_GROUP(size-iops-sec, SIZE_IOPS_SEC);
+
+ VSH_SET_THROTTLE_GROUP(total-bytes-sec-max-length, TOTAL_BYTES_SEC_MAX_LENGTH);
+ VSH_SET_THROTTLE_GROUP(read-bytes-sec-max-length, READ_BYTES_SEC_MAX_LENGTH);
+ VSH_SET_THROTTLE_GROUP(write-bytes-sec-max-length, WRITE_BYTES_SEC_MAX_LENGTH);
+ VSH_SET_THROTTLE_GROUP(total-iops-sec-max-length, TOTAL_IOPS_SEC_MAX_LENGTH);
+ VSH_SET_THROTTLE_GROUP(read-iops-sec-max-length, READ_IOPS_SEC_MAX_LENGTH);
+ VSH_SET_THROTTLE_GROUP(write-iops-sec-max-length, WRITE_IOPS_SEC_MAX_LENGTH);
+#undef VSH_SET_THROTTLE_GROUP
+
+ if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0) {
+ goto cleanup;
+ }
+
+ if (group_name) {
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+ group_name) < 0)
+ goto save_error;
+ }
+
+ if (virDomainSetThrottleGroup(dom, group_name, params, nparams, flags) < 0)
+ goto error;
+ vshPrintExtra(ctl, "%s", _("Throttle group set successfully\n"));
+
+ ret = true;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ return ret;
+
+ save_error:
+ vshSaveLibvirtError();
+ error:
+ vshError(ctl, "%s", _("Unable to set throttle group"));
+ goto cleanup;
+
+ interror:
+ vshError(ctl, "%s", _("Unable to parse integer parameter"));
+ goto cleanup;
+}
+
+
+/*
+ * "throttlegroupdel" command
+ */
+static const vshCmdInfo info_throttlegroupdel = {
+ .help = N_("Delete a throttling group."),
+ .desc = N_("Delete a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_throttlegroupdel[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "group-name",
+ .type = VSH_OT_STRING,
+ .positional = true,
+ .required = true,
+ .completer = virshDomainThrottleGroupCompleter,
+ .help = N_("throttle group name")
+ },
+ VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+ VIRSH_COMMON_OPT_DOMAIN_LIVE,
+ VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+ {.name = NULL}
+};
+
+
+static bool
+cmdThrottleGroupDel(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ g_autoptr(virshDomain) dom = NULL;
+ const char *group_name = NULL;
+ bool config = vshCommandOptBool(cmd, "config");
+ bool live = vshCommandOptBool(cmd, "live");
+ bool current = vshCommandOptBool(cmd, "current");
+ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+
+ if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0) {
+ return false;
+ }
+
+ if (virDomainDelThrottleGroup(dom, group_name, flags) < 0)
+ return false;
+ vshPrintExtra(ctl, "%s", _("Throttle group deleted successfully\n"));
+
+ return true;
+}
+
+
+/*
+ * "throttlegroupinfo" command
+ */
+static const vshCmdInfo info_throttlegroupinfo = {
+ .help = N_("Get a throttling group."),
+ .desc = N_("Get a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_throttlegroupinfo[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "group-name",
+ .type = VSH_OT_STRING,
+ .positional = true,
+ .required = true,
+ .completer = virshDomainThrottleGroupCompleter,
+ .help = N_("throttle group name")
+ },
+ VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+ VIRSH_COMMON_OPT_DOMAIN_LIVE,
+ VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+ {.name = NULL}
+};
+
+
+static bool
+cmdThrottleGroupInfo(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ g_autoptr(virshDomain) dom = NULL;
+ const char *group_name = NULL;
+ int nparams = 0;
+ virTypedParameterPtr params = NULL;
+ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+ size_t i;
+ bool current = vshCommandOptBool(cmd, "current");
+ bool config = vshCommandOptBool(cmd, "config");
+ bool live = vshCommandOptBool(cmd, "live");
+ bool ret = false;
+
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+ VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ goto cleanup;
+
+ if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0) {
+ goto cleanup;
+ }
+
+ if (virDomainGetThrottleGroup(dom, group_name, ¶ms, &nparams, flags) != 0) {
+ vshError(ctl, "%s",
+ _("Unable to get throttle group parameters"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < nparams; i++) {
+ g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
+ vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
+ }
+
+ ret = true;
+
+ cleanup:
+ virTypedParamsFree(params, nparams);
+ return ret;
+}
+
+
/*
* "blkiotune" command
*/
@@ -13382,6 +13705,30 @@ const vshCmdDef domManagementCmds[] = {
.info = &info_blkdeviotune,
.flags = 0
},
+ {.name = "domthrottlegroupset",
+ .handler = cmdThrottleGroupSet,
+ .opts = opts_throttlegroupset,
+ .info = &info_throttlegroupset,
+ .flags = 0
+ },
+ {.name = "domthrottlegroupdel",
+ .handler = cmdThrottleGroupDel,
+ .opts = opts_throttlegroupdel,
+ .info = &info_throttlegroupdel,
+ .flags = 0
+ },
+ {.name = "domthrottlegroupinfo",
+ .handler = cmdThrottleGroupInfo,
+ .opts = opts_throttlegroupinfo,
+ .info = &info_throttlegroupinfo,
+ .flags = 0
+ },
+ {.name = "domthrottlegrouplist",
+ .handler = cmdThrottleGroupList,
+ .opts = opts_throttlegrouplist,
+ .info = &info_throttlegrouplist,
+ .flags = 0
+ },
{.name = "blkiotune",
.handler = cmdBlkiotune,
.opts = opts_blkiotune,
--
2.43.0
7 months, 2 weeks
[PATCH RFC v4 15/17] virsh: Refactor iotune options for re-use
by danielwuwy@163.com
From: Chun Feng Wu <danielwuwy(a)163.com>
Define macro for iotune options, this macro is used by opts_blkdeviotune and
later throttle group opts
Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com>
---
tools/virsh-domain.c | 308 ++++++++++++++++++++++---------------------
1 file changed, 156 insertions(+), 152 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 50e80689a2..7c60920788 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1197,6 +1197,160 @@ static const vshCmdInfo info_blkdeviotune = {
.desc = N_("Set or query disk I/O parameters such as block throttling."),
};
+#define VSH_OPTS_IOTUNE() \
+ {.name = "total_bytes_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-bytes-sec" \
+ }, \
+ {.name = "total-bytes-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("total throughput limit, as scaled integer (default bytes)") \
+ }, \
+ {.name = "read_bytes_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-bytes-sec" \
+ }, \
+ {.name = "read-bytes-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("read throughput limit, as scaled integer (default bytes)") \
+ }, \
+ {.name = "write_bytes_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-bytes-sec" \
+ }, \
+ {.name = "write-bytes-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("write throughput limit, as scaled integer (default bytes)") \
+ }, \
+ {.name = "total_iops_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-iops-sec" \
+ }, \
+ {.name = "total-iops-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("total I/O operations limit per second") \
+ }, \
+ {.name = "read_iops_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-iops-sec" \
+ }, \
+ {.name = "read-iops-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("read I/O operations limit per second") \
+ }, \
+ {.name = "write_iops_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-iops-sec" \
+ }, \
+ {.name = "write-iops-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("write I/O operations limit per second") \
+ }, \
+ {.name = "total_bytes_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-bytes-sec-max" \
+ }, \
+ {.name = "total-bytes-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("total max, as scaled integer (default bytes)") \
+ }, \
+ {.name = "read_bytes_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-bytes-sec-max" \
+ }, \
+ {.name = "read-bytes-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("read max, as scaled integer (default bytes)") \
+ }, \
+ {.name = "write_bytes_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-bytes-sec-max" \
+ }, \
+ {.name = "write-bytes-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("write max, as scaled integer (default bytes)") \
+ }, \
+ {.name = "total_iops_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-iops-sec-max" \
+ }, \
+ {.name = "total-iops-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("total I/O operations max") \
+ }, \
+ {.name = "read_iops_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-iops-sec-max" \
+ }, \
+ {.name = "read-iops-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("read I/O operations max") \
+ }, \
+ {.name = "write_iops_sec_max", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-iops-sec-max" \
+ }, \
+ {.name = "write-iops-sec-max", \
+ .type = VSH_OT_INT, \
+ .help = N_("write I/O operations max") \
+ }, \
+ {.name = "size_iops_sec", \
+ .type = VSH_OT_ALIAS, \
+ .help = "size-iops-sec" \
+ }, \
+ {.name = "size-iops-sec", \
+ .type = VSH_OT_INT, \
+ .help = N_("I/O size in bytes") \
+ }, \
+ {.name = "total_bytes_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-bytes-sec-max-length" \
+ }, \
+ {.name = "total-bytes-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow total max bytes") \
+ }, \
+ {.name = "read_bytes_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-bytes-sec-max-length" \
+ }, \
+ {.name = "read-bytes-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow read max bytes") \
+ }, \
+ {.name = "write_bytes_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-bytes-sec-max-length" \
+ }, \
+ {.name = "write-bytes-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow write max bytes") \
+ }, \
+ {.name = "total_iops_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "total-iops-sec-max-length" \
+ }, \
+ {.name = "total-iops-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow total I/O operations max") \
+ }, \
+ {.name = "read_iops_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "read-iops-sec-max-length" \
+ }, \
+ {.name = "read-iops-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow read I/O operations max") \
+ }, \
+ {.name = "write_iops_sec_max_length", \
+ .type = VSH_OT_ALIAS, \
+ .help = "write-iops-sec-max-length" \
+ }, \
+ {.name = "write-iops-sec-max-length", \
+ .type = VSH_OT_INT, \
+ .help = N_("duration in seconds to allow write I/O operations max") \
+ } \
+
static const vshCmdOptDef opts_blkdeviotune[] = {
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
{.name = "device",
@@ -1206,110 +1360,6 @@ static const vshCmdOptDef opts_blkdeviotune[] = {
.completer = virshDomainDiskTargetCompleter,
.help = N_("block device")
},
- {.name = "total_bytes_sec",
- .type = VSH_OT_ALIAS,
- .help = "total-bytes-sec"
- },
- {.name = "total-bytes-sec",
- .type = VSH_OT_INT,
- .help = N_("total throughput limit, as scaled integer (default bytes)")
- },
- {.name = "read_bytes_sec",
- .type = VSH_OT_ALIAS,
- .help = "read-bytes-sec"
- },
- {.name = "read-bytes-sec",
- .type = VSH_OT_INT,
- .help = N_("read throughput limit, as scaled integer (default bytes)")
- },
- {.name = "write_bytes_sec",
- .type = VSH_OT_ALIAS,
- .help = "write-bytes-sec"
- },
- {.name = "write-bytes-sec",
- .type = VSH_OT_INT,
- .help = N_("write throughput limit, as scaled integer (default bytes)")
- },
- {.name = "total_iops_sec",
- .type = VSH_OT_ALIAS,
- .help = "total-iops-sec"
- },
- {.name = "total-iops-sec",
- .type = VSH_OT_INT,
- .help = N_("total I/O operations limit per second")
- },
- {.name = "read_iops_sec",
- .type = VSH_OT_ALIAS,
- .help = "read-iops-sec"
- },
- {.name = "read-iops-sec",
- .type = VSH_OT_INT,
- .help = N_("read I/O operations limit per second")
- },
- {.name = "write_iops_sec",
- .type = VSH_OT_ALIAS,
- .help = "write-iops-sec"
- },
- {.name = "write-iops-sec",
- .type = VSH_OT_INT,
- .help = N_("write I/O operations limit per second")
- },
- {.name = "total_bytes_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "total-bytes-sec-max"
- },
- {.name = "total-bytes-sec-max",
- .type = VSH_OT_INT,
- .help = N_("total max, as scaled integer (default bytes)")
- },
- {.name = "read_bytes_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "read-bytes-sec-max"
- },
- {.name = "read-bytes-sec-max",
- .type = VSH_OT_INT,
- .help = N_("read max, as scaled integer (default bytes)")
- },
- {.name = "write_bytes_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "write-bytes-sec-max"
- },
- {.name = "write-bytes-sec-max",
- .type = VSH_OT_INT,
- .help = N_("write max, as scaled integer (default bytes)")
- },
- {.name = "total_iops_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "total-iops-sec-max"
- },
- {.name = "total-iops-sec-max",
- .type = VSH_OT_INT,
- .help = N_("total I/O operations max")
- },
- {.name = "read_iops_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "read-iops-sec-max"
- },
- {.name = "read-iops-sec-max",
- .type = VSH_OT_INT,
- .help = N_("read I/O operations max")
- },
- {.name = "write_iops_sec_max",
- .type = VSH_OT_ALIAS,
- .help = "write-iops-sec-max"
- },
- {.name = "write-iops-sec-max",
- .type = VSH_OT_INT,
- .help = N_("write I/O operations max")
- },
- {.name = "size_iops_sec",
- .type = VSH_OT_ALIAS,
- .help = "size-iops-sec"
- },
- {.name = "size-iops-sec",
- .type = VSH_OT_INT,
- .help = N_("I/O size in bytes")
- },
{.name = "group_name",
.type = VSH_OT_ALIAS,
.help = "group-name"
@@ -1319,59 +1369,13 @@ static const vshCmdOptDef opts_blkdeviotune[] = {
.completer = virshCompleteEmpty,
.help = N_("group name to share I/O quota between multiple drives")
},
- {.name = "total_bytes_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "total-bytes-sec-max-length"
- },
- {.name = "total-bytes-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow total max bytes")
- },
- {.name = "read_bytes_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "read-bytes-sec-max-length"
- },
- {.name = "read-bytes-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow read max bytes")
- },
- {.name = "write_bytes_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "write-bytes-sec-max-length"
- },
- {.name = "write-bytes-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow write max bytes")
- },
- {.name = "total_iops_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "total-iops-sec-max-length"
- },
- {.name = "total-iops-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow total I/O operations max")
- },
- {.name = "read_iops_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "read-iops-sec-max-length"
- },
- {.name = "read-iops-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow read I/O operations max")
- },
- {.name = "write_iops_sec_max_length",
- .type = VSH_OT_ALIAS,
- .help = "write-iops-sec-max-length"
- },
- {.name = "write-iops-sec-max-length",
- .type = VSH_OT_INT,
- .help = N_("duration in seconds to allow write I/O operations max")
- },
+ VSH_OPTS_IOTUNE(),
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
VIRSH_COMMON_OPT_DOMAIN_LIVE,
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
{.name = NULL}
};
+#undef VSH_OPTS_IOTUNE
static bool
cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
--
2.43.0
7 months, 2 weeks
[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
7 months, 2 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
7 months, 2 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
7 months, 2 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
7 months, 2 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
7 months, 2 weeks