Devel
Threads by month
- ----- 2025 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
August 2024
- 45 participants
- 105 discussions

[PATCH v3 0/6] qemu: Introduce the ability to disable the built-in PS/2 controller
by Kamil Szczęk 28 Aug '24
by Kamil Szczęk 28 Aug '24
28 Aug '24
A while back QEMU introduced a new machine property for disabling the
i8042 PS/2 controller (commit 4ccd5fe22feb95137d325f422016a6473541fe9f)
which up until then was a built-in device included by all PC machine
type descendants unconditionally. This new option allowed users to
disable emulation of this controller, thus removing the default PS/2
peripherals. The rationale for why somebody might want to disable
PS/2 peripherals is explained in the aforementioned commit. This series
of patches exposes this machine property via the 'ps2' feature, while
also taking care of side-effects, such as inhibiting the implicit
creation of PS/2 inputs in the domain XML.
Changelog:
v2 -> v3:
- Add missing example usage of the new feature
v1 -> v2:
- Use abstract 'generic-pc' machine type instead of concrete 'pc' for
property detection
- Introduce test cases along with monitor replies and capability
flags
- Add NEWS mention of the new feature
Kamil Szczęk (6):
qemu: Improve PS/2 controller detection
qemu_capabilities: Introduce QEMU_CAPS_MACHINE_I8042_OPT
qemucapabilitiesdata: Add data for QEMU_CAPS_MACHINE_I8042_OPT
qemu: Introduce the 'ps2' feature
qemuxmlconftest: Add test cases for the new 'ps2' feature
NEWS: Mention the new 'ps2' feature
NEWS.rst | 6 +
docs/formatdomain.rst | 6 +
src/conf/domain_conf.c | 6 +-
src/conf/domain_conf.h | 1 +
src/conf/domain_validate.c | 23 ++
src/conf/schemas/domaincommon.rng | 5 +
src/qemu/qemu_capabilities.c | 35 +++
src/qemu/qemu_capabilities.h | 9 +-
src/qemu/qemu_command.c | 5 +
src/qemu/qemu_domain.c | 29 ++-
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_validate.c | 27 +-
.../caps_5.2.0_x86_64.replies | 169 ++++++++++--
.../caps_6.0.0_x86_64.replies | 189 ++++++++++++--
.../caps_6.1.0_x86_64.replies | 203 +++++++++++++--
.../caps_6.2.0_x86_64.replies | 212 ++++++++++++++--
.../caps_7.0.0_x86_64.replies | 225 ++++++++++++++--
.../caps_7.0.0_x86_64.xml | 1 +
.../caps_7.1.0_x86_64.replies | 240 ++++++++++++++++--
.../caps_7.1.0_x86_64.xml | 1 +
.../caps_7.2.0_x86_64+hvf.replies | 240 ++++++++++++++++--
.../caps_7.2.0_x86_64+hvf.xml | 1 +
.../caps_7.2.0_x86_64.replies | 240 ++++++++++++++++--
.../caps_7.2.0_x86_64.xml | 1 +
.../caps_8.0.0_x86_64.replies | 240 ++++++++++++++++--
.../caps_8.0.0_x86_64.xml | 1 +
.../caps_8.1.0_x86_64.replies | 236 +++++++++++++++--
.../caps_8.1.0_x86_64.xml | 1 +
.../caps_8.2.0_x86_64.replies | 236 +++++++++++++++--
.../caps_8.2.0_x86_64.xml | 1 +
.../caps_9.0.0_x86_64.replies | 240 ++++++++++++++++--
.../caps_9.0.0_x86_64.xml | 1 +
.../caps_9.1.0_x86_64.replies | 240 ++++++++++++++++--
.../caps_9.1.0_x86_64.xml | 1 +
...-off-explicit-ps2-inputs.x86_64-latest.err | 1 +
.../machine-i8042-off-explicit-ps2-inputs.xml | 19 ++
...hine-i8042-off-vmport-on.x86_64-latest.err | 1 +
.../machine-i8042-off-vmport-on.xml | 18 ++
.../machine-i8042-off.x86_64-6.2.0.err | 1 +
.../machine-i8042-off.x86_64-latest.args | 33 +++
.../machine-i8042-off.x86_64-latest.xml | 32 +++
tests/qemuxmlconfdata/machine-i8042-off.xml | 17 ++
.../machine-i8042-on.x86_64-6.2.0.err | 1 +
.../machine-i8042-on.x86_64-latest.args | 33 +++
.../machine-i8042-on.x86_64-latest.xml | 34 +++
tests/qemuxmlconfdata/machine-i8042-on.xml | 17 ++
tests/qemuxmlconftest.c | 6 +
47 files changed, 3024 insertions(+), 261 deletions(-)
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off-explicit-ps2-inputs.x86_64-latest.err
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off-explicit-ps2-inputs.xml
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off-vmport-on.x86_64-latest.err
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off-vmport-on.xml
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off.x86_64-6.2.0.err
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off.x86_64-latest.args
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/machine-i8042-off.xml
create mode 100644 tests/qemuxmlconfdata/machine-i8042-on.x86_64-6.2.0.err
create mode 100644 tests/qemuxmlconfdata/machine-i8042-on.x86_64-latest.args
create mode 100644 tests/qemuxmlconfdata/machine-i8042-on.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/machine-i8042-on.xml
--
2.45.0
3
10
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
2
3

28 Aug '24
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
2
5
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
2
1

[PATCH RFC v4 16/17] virsh: Add support for throttle group operations
by danielwuwy@163.com 28 Aug '24
by danielwuwy@163.com 28 Aug '24
28 Aug '24
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
1
1

28 Aug '24
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
1
0

[PATCH RFC v4 14/17] test_driver: Test throttle group lifecycle APIs
by danielwuwy@163.com 28 Aug '24
by danielwuwy@163.com 28 Aug '24
28 Aug '24
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
1
0

28 Aug '24
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
1
0

[PATCH RFC v4 12/17] config: validate: Verify iotune, throttle group and filter
by danielwuwy@163.com 28 Aug '24
by danielwuwy@163.com 28 Aug '24
28 Aug '24
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
1
0

[PATCH RFC v4 01/17] schema: Add new domain elements to support multiple throttle groups
by danielwuwy@163.com 28 Aug '24
by danielwuwy@163.com 28 Aug '24
28 Aug '24
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
1
10