[libvirt] RFC: revival of hotplug/unplug for PCI Multifunction devices in QEMU guests
by Daniel Henrique Barboza
Hi,
This is labeled as RFC but it's more like a FYI to let people know and
comment beforehand. Shiva sent a 28 patch series last year that implements
hotplug/unplug support for PCI multifunction devices [1]. The design
motivation of his work was based in a RFC sent to this mailing list back
in 2016 [2].
I'll briefly summarize the goals and motivations here. What we have today
in Libvirt:
- no hotplug/unplug support for multifunction PCI devices
This is explained in details in [2]. When hotplugging a multifunction
device, QEMU will queue the hotplug operation of all non-zero functions and,
when function 0 is hotplugged, all functions are hotplugged together. This
is true for all archs that supports PCI multifunction devices in QEMU. For
unplug it varies: x86 will unplug all functions if any function is
unplugged,
ppc64 needs to unplug each one.
Due to the nature of how Libvirt hotplug works now, hotplug of these devices
is not possible. All hotplugs are considered in an isolated manner. Even if
we hotplug each function in the proper order (i.e. leaving function 0 last),
Libvirt can assign different slots in the guest for each. Similar problems
happens with hot-unplug.
This feature aims to address these by creating a new <devices> element,
exclusive for multifunction devices, that aggregates all functions of a
device
in a single operation. To handle this new element, the existing
attach/detach
functions in the QEMU driver now handles multiple devices.
Attaching/detaching
a single device is routed away from the specialized multifunction code to be
handled to the existing attach/detach code base.
- no support for partial assignment of functions
We can't make the assumption that the guest will always assign all devices
of a multifunction device. Some functions might be a security risk to expose
to a guest, or the device can behave differently depending on the amount
of functions assigned.
Even if the 'leftover' functions can't be used to anything else in the host,
the decision of full/partial assignment of functions should come from the
user, not us. We can't predict how any other hardware vendor will setup
its devices.
This patch series also handles this case.
------
The latest version of this feature, rebase to cdd362e0e7a (the current
master as I'm writing this), can be found at:
https://github.com/danielhb/libvirt/tree/multifunction-rc2
This is a work still ongoing that it's not ready for contribution yet
(first patches that changes the unit test code are breaking existing
tests). The feature itself is being stress tested using a Broadcom BCM5719
with 4 functions and it looks solid. I'll see if I can grab a x86 env
with a multifunction card to test it there too when I have the chance.
Thoughts/comments are welcome. Instead of dropping a 28+ patch set for
review, I'm planning into sending smaller chunks that makes senses
individually.
Thanks,
DHB
[1] https://www.redhat.com/archives/libvir-list/2018-March/msg00729.html
[2] https://www.redhat.com/archives/libvir-list/2016-April/msg01057.html
5 years, 4 months
[libvirt] [PATCHv2 00/11] util/resctrl cleanups and refactors
by Wang Huaqiang
Patches submitted for purpose of refactoring existing 'resctrl' related
source code, including some code cleanups as well as some fixes. This is
also a preparation for memory bandwidth monitor codes.
Plan to support Resctrl Control Monitors, which is a feature introduced
by kernel 'resctrl' sub-model. Submit some cleanup and refactoring patches
for upcoming memory bandwidth resource monitoring (MBM) monitors.
Related MBM RFC is
https://www.redhat.com/archives/libvir-list/2019-April/msg01409.html.
This RFC is not actively discussed since libvirt already implemented similar
resctrl cache monitoring (CMT), and lots details have been discussed
and implemented during the work of CMT.
The cleanups and refactoring includes:
v2 changes:
1. Addressed comments of v1.
2. Introduce a new algorithm for verifying new monitor vcpus and existing
monitors and allocations.
3. Fixes for creating default-allocation-monitor in 'resctrl' file
system.(patch 0001).
v1 changes:
1. Removing some reluctant lines and white spaces that is existing
in current code and not meet the libvirt coding style.
2. Replace 'virResctrlAllocIsEmpty' with @n==0 for indicating no
resctrl allocation in configuration file.
3. Private API changes, removed 'virResctrlMonitorGetCacheOccupancy'
and exported a new API named 'virResctrlMonitorGetStats' with similar
functionality, but with capability to be used for retrieving MBM
statistical information.
4. Refactoring 'virResctrlMonitorFreeStats' for more reusing in code.
5. Extend data structure 'virResctrlMonitorStats' with the capability
to carry multiple statistical information from monitor.
Wang Huaqiang (11):
util,conf: Handle default monitor group of an allocation properly
conf: code cleanup, remove empty line and one space
conf: code cleanup for return error code directly
conf: some code cleanup
conf: refactor 'virDomainResctrlVcpuMatch' and some code cleanup
conf: Append 'resctrl' object according to number of monitor group
directly
util: Refactor and rename 'virResctrlMonitorFreeStats'
util: Refactor 'virResctrlMonitorStats'
util: Extend virresctl API to retrieve multiple monitor statistics
util: Remove unused virResctrlMonitorGetCacheOccupancy
conf: Refactor and rename the function to validate a new resctrl
monitor
src/conf/domain_conf.c | 145 ++++++++++++++++++++++++-----------------------
src/libvirt_private.syms | 5 +-
src/qemu/qemu_driver.c | 41 ++++++++++----
src/qemu/qemu_process.c | 3 +-
src/util/virresctrl.c | 75 ++++++++++--------------
src/util/virresctrl.h | 23 +++++---
6 files changed, 156 insertions(+), 136 deletions(-)
--
2.7.4
5 years, 4 months
[libvirt] [PATCH v2]daemon: Fix a crash during virNetlinkEventServiceStopAll
by Liu Haitao
When reboot the host, a core dump file would be generated.
The call traces are:
Note.In this case, the main thread is thread 5.
(gdb) thread 5
[Switching to thread 5 (LWP 4142)]
(gdb) bt
0 0x00007f00a6838273 in futex_wait_cancelable (private=<optimized out>,
expected=0, futex_word=0x7f004c0125c0)
at /usr/src/debug/glibc/2.24-r0/git/sysdeps/unix/sysv/linux/futex-internal.h:88
1 __pthread_cond_wait_common (abstime=0x0, mutex=0x7f004c012540,
cond=0x7f004c012598)
at /usr/src/debug/glibc/2.24-r0/git/nptl/pthread_cond_wait.c:502
2 __pthread_cond_wait (cond=0x7f004c012598, mutex=0x7f004c012540)
at /usr/src/debug/glibc/2.24-r0/git/nptl/pthread_cond_wait.c:655
3 0x00007f00aa467246 in virCondWait (c=<optimized out>, m=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virthread.c:154
4 0x00007f00aa467eb0 in virThreadPoolFree (pool=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virthreadpool.c:286
5 0x00007f0074349f9d in qemuStateCleanup ()
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/qemu/qemu_driver.c:1036
6 0x00007f00aa5e9486 in virStateCleanup ()
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/libvirt.c:682
7 0x000055a687ab86a4 in main (argc=<optimized out>, argv=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/remote/remote_daemon.c:1473
(gdb) thread 1
[Switching to thread 1 (LWP 4403)]
(gdb) bt
0 __GI___pthread_mutex_lock (mutex=mutex@entry=0x0)
at /usr/src/debug/glibc/2.24-r0/git/nptl/pthread_mutex_lock.c:67
1 0x00007f00aa467165 in virMutexLock (m=m@entry=0x0)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virthread.c:89
2 0x00007f00aa43c0f9 in virNetlinkEventServerLock (driver=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virnetlink.c:799
3 virNetlinkEventRemoveClient (watch=watch@entry=0,
macaddr=macaddr@entry=0x7f0088014944, protocol=protocol@entry=0)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virnetlink.c:1197
4 0x00007f00aa4341df in virNetDevMacVLanDeleteWithVPortProfile (
ifname=<optimized out>, macaddr=macaddr@entry=0x7f0088014944,
linkdev=0x7f0088014920 "eth1", mode=mode@entry=1,
virtPortProfile=virtPortProfile@entry=0x0,
stateDir=stateDir@entry=0x7f004c12fa90 "/var/run/libvirt/qemu")
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virnetdevmacvlan.c:1112
5 0x00007f0074312251 in qemuProcessStop (driver=driver@entry=0x7f004c0ecef0,
vm=vm@entry=0x7f0088000b00,
reason=reason@entry=VIR_DOMAIN_SHUTOFF_SHUTDOWN,
asyncJob=asyncJob@entry=QEMU_ASYNC_JOB_NONE, flags=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/qemu/qemu_process.c:7291
6 0x00007f007437a5ea in processMonitorEOFEvent (vm=0x7f0088000b00, driver=0x7f004c0ecef0)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/qemu/qemu_driver.c:4756
7 qemuProcessEventHandler (data=0x55a687d6df10, opaque=0x7f004c0ecef0)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/qemu/qemu_driver.c:4859
8 0x00007f00aa467c5b in virThreadPoolWorker (
opaque=opaque@entry=0x55a687d6c110)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virthreadpool.c:163
9 0x00007f00aa466fe8 in virThreadHelper (data=<optimized out>)
at /usr/src/debug/libvirt/5.3.0-r0/libvirt-5.3.0/src/util/virthread.c:206
10 0x00007f00a68323f4 in start_thread (arg=0x7f00699df700)
at /usr/src/debug/glibc/2.24-r0/git/nptl/pthread_create.c:456
11 0x00007f00a616e10f in clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:105
1. The execution flow of main thread (Thread 5 LWP 4142):
main()
-->virNetDaemonRun()
-->virNetDaemonClose(dmn) //cleanup
-->virNetlinkEventServiceStopAll()
-->virStateCleanup()
-->qemuStateCleanup()
-->virThreadPoolFree()
-->__pthread_cond_wait()
virNetDaemonRun()
-->virEventRunDefaultImpl
-->virEventPollRunOnce
-->virEventPollDispatchHandles
-->qemuMonitorIO
-->qemuProcessHandleMonitorEOF
-->processEvent->eventType = QEMU_PROCESS_EVENT_MONITOR_EOF
-->virThreadPoolSendJob()
After typing reboot command on the host, the main thread would send an event message to another thread.
Here it would let thread 1 to handle the shutdown of qemu process. But it could
not be executed immediately.
virNetlinkEventServiceStopAll()
--> virNetlinkEventServiceStop()
--> server[protocol] = NULL; // set server to null
IN virNetlinkEventServiceStopAll(), some variables related to network are freed,
like (static virNetlinkEventSrvPrivatePtr server).
virStateCleanup()
-->qemuStateCleanup()
-->virThreadPoolFree()
-->__pthread_cond_wait()
In virThreadPoolFree() it will wait other thread to end up.
2. The execution flow of thread 5 (LWP 4403):
qemuProcessStop()
-->virNetDevMacVLanDeleteWithVPortProfile()
-->virNetlinkEventRemoveClient()
--> srv = server[protocol]
Although the main thread had sent the message to thread 1(4403), it could not be
run instantly. It means that the virNetlinkEventServiceStopAll() might be
executed earlier than virNetlinkEventRemoveClient(). We could get it from the log file.
""
2019-06-12 00:10:09.230+0000: 4142: info : virNetlinkEventServiceStopAll:941 : stopping all netlink event services
2019-06-12 00:10:09.230+0000: 4142: info : virNetlinkEventServiceStop:904 : stopping netlink event service
2019-06-12 00:10:21.165+0000: 4403: debug : virNetlinkEventRemoveClient:1190 : removing client watch=0, mac=0x7f0088014944.
"
In virNetlinkEventRemoveClient() the variable server is used again, but now it
is null that is freed by virNetlinkEventServiceStopAll().So it would case a crash .
The virNetlinkEventServiceStopAll() should be executed behind virStateCleanup(),
Signed-off-by: Liu Haitao <haitao.liu(a)windriver.com>
---
src/remote/remote_daemon.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c
index c3782971f1..7da20a6644 100644
--- a/src/remote/remote_daemon.c
+++ b/src/remote/remote_daemon.c
@@ -1464,8 +1464,6 @@ int main(int argc, char **argv) {
/* Keep cleanup order in inverse order of startup */
virNetDaemonClose(dmn);
- virNetlinkEventServiceStopAll();
-
if (driversInitialized) {
/* NB: Possible issue with timing window between driversInitialized
* setting if virNetlinkEventServerStart fails */
@@ -1473,6 +1471,8 @@ int main(int argc, char **argv) {
virStateCleanup();
}
+ virNetlinkEventServiceStopAll();
+
virObjectUnref(adminProgram);
virObjectUnref(srvAdm);
virObjectUnref(qemuProgram);
--
2.21.0
5 years, 4 months
[libvirt] [PATCH 0/7] qemu: use domCaps for validation
by Cole Robinson
I'm trying to remove some hurdles and pitfalls WRT extending
domaincapabilities data. One issue is that it's too easy to add
invalid data to it, or let the data become out of date.
For example the first two patches of this series add <rng model=X>
domcaps reporting. The logic to fill in the domcaps data from qemuCaps
is nearly identical to the logic we use to validate rng->model in
qemuDomainRNGDefValidate. If just those patches are added, and later
a new qemu rng model was introduced, a future patch could easily
miss updated domaincapabilities output.
This series aims to set up a pattern to prevent these types of issues
from sneaking in. A function virDomainCapsDeviceDefValidate is added
which will use domcaps data to perform validation against a devicedef.
The existing qemu <rng> model validation is moved there. This ensures
that any future <rng> model additions, if they want to work in the
qemu driver, effectively need to extend domaincapabilities as well.
It's also theoretically useful for other drivers too.
One issue is that at DomainDefValidate time we don't have domCaps
handy, or any cache layer for domCaps assembling. Patch #4 adds
a domCapsCache hashtable to the virQEMUCaps class for caching domCaps
builds based on the full tuple of emulator+machine+arch+virttype.
If qemuCaps need to be regenerated, the domCaps cache is wiped out
for us so we don't need to worry about the data being stale, it's
tied to the lifetime of a qemuCaps instance.
Cole Robinson (7):
conf: domcaps: Report device <rng>
qemu: capabilities: fill in domcaps <rng>
qemu: conf: add virQEMUDriverGetDomainCapabilities
qemu: conf: Cache domCaps in qemuCaps
conf: domcaps: Add virDomainCapsDeviceDefValidate
qemu: domain: Call virDomainCapsDeviceDefValidate
qemu: Move rng model validation to domcaps
docs/formatdomaincaps.html.in | 35 ++++++++
docs/schemas/domaincaps.rng | 10 +++
src/conf/domain_capabilities.c | 83 ++++++++++++++++++
src/conf/domain_capabilities.h | 14 ++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_capabilities.c | 41 +++++++++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_conf.c | 84 +++++++++++++++++++
src/qemu/qemu_conf.h | 7 ++
src/qemu/qemu_domain.c | 38 +++------
src/qemu/qemu_driver.c | 18 +---
.../qemu_1.7.0.x86_64.xml | 9 ++
.../qemu_2.12.0-virt.aarch64.xml | 11 +++
.../qemu_2.12.0.ppc64.xml | 11 +++
.../qemu_2.12.0.s390x.xml | 11 +++
.../qemu_2.12.0.x86_64.xml | 11 +++
.../qemu_2.6.0-virt.aarch64.xml | 11 +++
.../qemu_2.6.0.aarch64.xml | 11 +++
.../domaincapsschemadata/qemu_2.6.0.ppc64.xml | 11 +++
.../qemu_2.6.0.x86_64.xml | 11 +++
.../domaincapsschemadata/qemu_2.7.0.s390x.xml | 11 +++
.../qemu_2.8.0-tcg.x86_64.xml | 11 +++
.../domaincapsschemadata/qemu_2.8.0.s390x.xml | 11 +++
.../qemu_2.8.0.x86_64.xml | 11 +++
.../qemu_2.9.0-q35.x86_64.xml | 11 +++
.../qemu_2.9.0-tcg.x86_64.xml | 11 +++
.../qemu_2.9.0.x86_64.xml | 11 +++
.../domaincapsschemadata/qemu_3.0.0.s390x.xml | 11 +++
.../qemu_4.0.0.x86_64.xml | 11 +++
29 files changed, 488 insertions(+), 40 deletions(-)
--
2.21.0
5 years, 4 months
[libvirt] [python PATCH v7] Add virDomainCheckpoint APIs
by Eric Blake
Copies heavily from existing virDomainSnapshot handling, regarding
what special cases the generator has to be taught and what overrides
need to be written.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Python counterparts to my incremental backup patches. An earlier
version was already reviewed by Dan; the main diff here is the
addition of virDomainSnapshotCreateXML2 handling.
HACKING | 2 +
MANIFEST.in | 1 +
generator.py | 37 ++++++++--
libvirt-override-api.xml | 12 ++++
libvirt-override-virDomain.py | 13 ++++
libvirt-override-virDomainCheckpoint.py | 19 +++++
libvirt-override.c | 96 +++++++++++++++++++++++++
sanitytest.py | 11 +--
typewrappers.c | 13 ++++
typewrappers.h | 10 +++
10 files changed, 206 insertions(+), 8 deletions(-)
create mode 100644 libvirt-override-virDomainCheckpoint.py
diff --git a/HACKING b/HACKING
index 6eeb9e6..39e7cd3 100644
--- a/HACKING
+++ b/HACKING
@@ -28,6 +28,8 @@ hand written source files
the virConnect class
- libvirt-override-virDomain.py - high level overrides in
the virDomain class
+ - libvirt-override-virDomainCheckpoint.py - high level overrides in
+ the virDomainCheckpoint class
- libvirt-override-virDomainSnapshot.py - high level overrides in
the virDomainSnapshot class
- libvirt-override-virStoragePool.py - high level overrides in
diff --git a/MANIFEST.in b/MANIFEST.in
index b6788f4..5d2f559 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -23,6 +23,7 @@ include libvirt-override.c
include libvirt-override.py
include libvirt-override-virConnect.py
include libvirt-override-virDomain.py
+include libvirt-override-virDomainCheckpoint.py
include libvirt-override-virDomainSnapshot.py
include libvirt-override-virStoragePool.py
include libvirt-override-virStream.py
diff --git a/generator.py b/generator.py
index ffa3ce5..a16f9b1 100755
--- a/generator.py
+++ b/generator.py
@@ -35,6 +35,7 @@ libvirt_headers = [
"libvirt",
"libvirt-common",
"libvirt-domain",
+ "libvirt-domain-checkpoint",
"libvirt-domain-snapshot",
"libvirt-event",
"libvirt-host",
@@ -364,6 +365,10 @@ py_types = {
'virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
'const virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
+ 'virDomainCheckpointPtr': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+ 'virDomainCheckpoint *': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+ 'const virDomainCheckpoint *': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
+
'virDomainSnapshotPtr': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
'virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
'const virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
@@ -536,6 +541,8 @@ skip_function = (
'virSaveLastError', # We have our own python error wrapper
'virFreeError', # Only needed if we use virSaveLastError
'virConnectListAllDomains', # overridden in virConnect.py
+ 'virDomainListAllCheckpoints', # overridden in virDomain.py
+ 'virDomainCheckpointListAllChildren', # overridden in virDomainCheckpoint.py
'virDomainListAllSnapshots', # overridden in virDomain.py
'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py
'virConnectListAllStoragePools', # overridden in virConnect.py
@@ -582,6 +589,7 @@ skip_function = (
"virStoragePoolRef",
"virStorageVolRef",
"virStreamRef",
+ "virDomainCheckpointRef",
"virDomainSnapshotRef",
# This functions shouldn't be called via the bindings (and even the docs
@@ -594,6 +602,8 @@ skip_function = (
"virNWFilterGetConnect",
"virStoragePoolGetConnect",
"virStorageVolGetConnect",
+ "virDomainCheckpointGetConnect",
+ "virDomainCheckpointGetDomain",
"virDomainSnapshotGetConnect",
"virDomainSnapshotGetDomain",
@@ -1023,6 +1033,8 @@ classes_type = {
"virStream *": ("._o", "virStream(self, _obj=%s)", "virStream"),
"virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
"virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
+ "virDomainCheckpointPtr": ("._o", "virDomainCheckpoint(self,_obj=%s)", "virDomainCheckpoint"),
+ "virDomainCheckpoint *": ("._o", "virDomainCheckpoint(self, _obj=%s)", "virDomainCheckpoint"),
"virDomainSnapshotPtr": ("._o", "virDomainSnapshot(self,_obj=%s)", "virDomainSnapshot"),
"virDomainSnapshot *": ("._o", "virDomainSnapshot(self, _obj=%s)", "virDomainSnapshot"),
}
@@ -1031,7 +1043,7 @@ primary_classes = ["virDomain", "virNetwork", "virInterface",
"virStoragePool", "virStorageVol",
"virConnect", "virNodeDevice", "virSecret",
"virNWFilter", "virNWFilterBinding",
- "virStream", "virDomainSnapshot"]
+ "virStream", "virDomainCheckpoint", "virDomainSnapshot"]
classes_destructors = {
"virDomain": "virDomainFree",
@@ -1043,6 +1055,7 @@ classes_destructors = {
"virSecret": "virSecretFree",
"virNWFilter": "virNWFilterFree",
"virNWFilterBinding": "virNWFilterBindingFree",
+ "virDomainCheckpoint": "virDomainCheckpointFree",
"virDomainSnapshot": "virDomainSnapshotFree",
# We hand-craft __del__ for this one
#"virStream": "virStreamFree",
@@ -1053,6 +1066,7 @@ class_skip_connect_impl = {
}
class_domain_impl = {
+ "virDomainCheckpoint": True,
"virDomainSnapshot": True,
}
@@ -1171,6 +1185,18 @@ def nameFixup(name, classe, type, file):
elif name[0:12] == "virDomainGet":
func = name[12:]
func = func[0:1].lower() + func[1:]
+ elif name[0:31] == "virDomainCheckpointLookupByName":
+ func = name[9:]
+ func = func[0:1].lower() + func[1:]
+ elif name[0:28] == "virDomainCheckpointCreateXML":
+ func = name[9:]
+ func = func[0:1].lower() + func[1:]
+ elif name[0:26] == "virDomainCheckpointCurrent":
+ func = name[9:]
+ func = func[0:1].lower() + func[1:]
+ elif name[0:19] == "virDomainCheckpoint":
+ func = name[19:]
+ func = func[0:1].lower() + func[1:]
elif name[0:29] == "virDomainSnapshotLookupByName":
func = name[9:]
func = func[0:1].lower() + func[1:]
@@ -1183,6 +1209,9 @@ def nameFixup(name, classe, type, file):
elif name[0:20] == "virDomainSnapshotNum":
func = name[9:]
func = func[0:1].lower() + func[1:]
+ elif name[0:27] == "virDomainSnapshotCreateXML2":
+ func = name[9:]
+ func = func[0:1].lower() + func[1:]
elif name[0:26] == "virDomainSnapshotCreateXML":
func = name[9:]
func = func[0:1].lower() + func[1:]
@@ -1501,7 +1530,7 @@ def buildWrappers(module):
"virStorageVol", "virNodeDevice", "virSecret","virStream",
"virNWFilter", "virNWFilterBinding" ]:
classes.write(" def __init__(self, conn, _obj=None):\n")
- elif classname in [ 'virDomainSnapshot' ]:
+ elif classname in [ "virDomainCheckpoint", "virDomainSnapshot" ]:
classes.write(" def __init__(self, dom, _obj=None):\n")
else:
classes.write(" def __init__(self, _obj=None):\n")
@@ -1513,7 +1542,7 @@ def buildWrappers(module):
classes.write(" self._conn = conn\n" + \
" if not isinstance(conn, virConnect):\n" + \
" self._conn = conn._conn\n")
- elif classname in [ "virDomainSnapshot" ]:
+ elif classname in [ "virDomainCheckpoint", "virDomainSnapshot" ]:
classes.write(" self._dom = dom\n")
classes.write(" self._conn = dom.connect()\n")
classes.write(" if type(_obj).__name__ not in [\"PyCapsule\", \"PyCObject\"]:\n")
@@ -1641,7 +1670,7 @@ def buildWrappers(module):
classes.write(
" if ret is None:raise libvirtError('%s() failed', vol=self)\n" %
(name))
- elif classname == "virDomainSnapshot":
+ elif classname in [ "virDomainCheckpoint", "virDomainSnapshot"]:
classes.write(
" if ret is None:raise libvirtError('%s() failed', dom=self._dom)\n" %
(name))
diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml
index 7f578e0..1edf0c5 100644
--- a/libvirt-override-api.xml
+++ b/libvirt-override-api.xml
@@ -576,6 +576,18 @@
<arg name='flags' type='unsigned int' info='flags'/>
<return type='int' info="0 on success, -1 on error"/>
</function>
+ <function name='virDomainListAllCheckpoints' file='python'>
+ <info>returns the list of checkpoints for the given domain</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='flags' type='unsigned int' info='flags'/>
+ <return type='char *' info='the list of checkpoints or None in case of error'/>
+ </function>
+ <function name='virDomainCheckpointListAllChildren' file='python'>
+ <info>collect the list of child checkpoint names for the given checkpoint</info>
+ <arg name='checkpoint' type='virDomainCheckpointPtr' info='pointer to the checkpoint'/>
+ <arg name='flags' type='unsigned int' info='flags'/>
+ <return type='char *' info='the list of checkpoints or None in case of error'/>
+ </function>
<function name='virDomainGetBlockJobInfo' file='python'>
<info>Get progress information for a block job</info>
<arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
diff --git a/libvirt-override-virDomain.py b/libvirt-override-virDomain.py
index 7c417b8..7ce34f1 100644
--- a/libvirt-override-virDomain.py
+++ b/libvirt-override-virDomain.py
@@ -11,6 +11,19 @@
return retlist
+ def listAllCheckpoints(self, flags=0):
+ """List all checkpoints and returns a list of checkpoint objects"""
+ ret = libvirtmod.virDomainListAllCheckpoints(self._o, flags)
+ if ret is None:
+ raise libvirtError("virDomainListAllCheckpoints() failed", conn=self)
+
+ retlist = list()
+ for chkptr in ret:
+ retlist.append(virDomainCheckpoint(self, _obj=chkptr))
+
+ return retlist
+
+
def createWithFiles(self, files, flags=0):
"""Launch a defined domain. If the call succeeds the domain moves from the
defined to the running domains pools.
diff --git a/libvirt-override-virDomainCheckpoint.py b/libvirt-override-virDomainCheckpoint.py
new file mode 100644
index 0000000..371b0fd
--- /dev/null
+++ b/libvirt-override-virDomainCheckpoint.py
@@ -0,0 +1,19 @@
+ def getConnect(self):
+ """Get the connection that owns the domain that a checkpoint was created for"""
+ return self.connect()
+
+ def getDomain(self):
+ """Get the domain that a checkpoint was created for"""
+ return self.domain()
+
+ def listAllChildren(self, flags=0):
+ """List all child checkpoints and returns a list of checkpoint objects"""
+ ret = libvirtmod.virDomainCheckpointListAllChildren(self._o, flags)
+ if ret is None:
+ raise libvirtError("virDomainCheckpointListAllChildren() failed", conn=self)
+
+ retlist = list()
+ for chkptr in ret:
+ retlist.append(virDomainCheckpoint(self, _obj=chkptr))
+
+ return retlist
diff --git a/libvirt-override.c b/libvirt-override.c
index c5e2908..777f533 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -2325,6 +2325,98 @@ libvirt_virConnectListDefinedDomains(PyObject *self ATTRIBUTE_UNUSED,
goto cleanup;
}
+#if LIBVIR_CHECK_VERSION(5, 1, 0)
+static PyObject *
+libvirt_virDomainListAllCheckpoints(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ PyObject *py_retval = NULL;
+ virDomainCheckpointPtr *chks = NULL;
+ int c_retval;
+ ssize_t i;
+ virDomainPtr dom;
+ PyObject *pyobj_dom;
+ unsigned int flags;
+
+ if (!PyArg_ParseTuple(args, (char *)"OI:virDomainListAllCheckpoints",
+ &pyobj_dom, &flags))
+ return NULL;
+ dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_retval = virDomainListAllCheckpoints(dom, &chks, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_retval < 0)
+ return VIR_PY_NONE;
+
+ if (!(py_retval = PyList_New(c_retval)))
+ goto cleanup;
+
+ for (i = 0; i < c_retval; i++) {
+ VIR_PY_LIST_SET_GOTO(py_retval, i,
+ libvirt_virDomainCheckpointPtrWrap(chks[i]), error);
+ chks[i] = NULL;
+ }
+
+ cleanup:
+ for (i = 0; i < c_retval; i++)
+ if (chks[i])
+ virDomainCheckpointFree(chks[i]);
+ VIR_FREE(chks);
+ return py_retval;
+
+ error:
+ Py_CLEAR(py_retval);
+ goto cleanup;
+}
+
+static PyObject *
+libvirt_virDomainCheckpointListAllChildren(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ PyObject *py_retval = NULL;
+ virDomainCheckpointPtr *chks = NULL;
+ int c_retval;
+ ssize_t i;
+ virDomainCheckpointPtr parent;
+ PyObject *pyobj_parent;
+ unsigned int flags;
+
+ if (!PyArg_ParseTuple(args, (char *)"OI:virDomainCheckpointListAllChildren",
+ &pyobj_parent, &flags))
+ return NULL;
+ parent = (virDomainCheckpointPtr) PyvirDomainCheckpoint_Get(pyobj_parent);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_retval = virDomainCheckpointListAllChildren(parent, &chks, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_retval < 0)
+ return VIR_PY_NONE;
+
+ if (!(py_retval = PyList_New(c_retval)))
+ goto cleanup;
+
+ for (i = 0; i < c_retval; i++) {
+ VIR_PY_LIST_SET_GOTO(py_retval, i,
+ libvirt_virDomainCheckpointPtrWrap(chks[i]), error);
+ chks[i] = NULL;
+ }
+
+ cleanup:
+ for (i = 0; i < c_retval; i++)
+ if (chks[i])
+ virDomainCheckpointFree(chks[i]);
+ VIR_FREE(chks);
+ return py_retval;
+
+ error:
+ Py_CLEAR(py_retval);
+ goto cleanup;
+}
+#endif /* LIBVIR_CHECK_VERSION(5, 1, 0) */
+
static PyObject *
libvirt_virDomainSnapshotListNames(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args)
@@ -10100,6 +10192,10 @@ static PyMethodDef libvirtMethods[] = {
#if LIBVIR_CHECK_VERSION(1, 0, 3)
{(char *) "virDomainGetJobStats", libvirt_virDomainGetJobStats, METH_VARARGS, NULL},
#endif /* LIBVIR_CHECK_VERSION(1, 0, 3) */
+#if LIBVIR_CHECK_VERSION(5, 1, 0)
+ {(char *) "virDomainListAllCheckpoints", libvirt_virDomainListAllCheckpoints, METH_VARARGS, NULL},
+ {(char *) "virDomainCheckpointListAllChildren", libvirt_virDomainCheckpointListAllChildren, METH_VARARGS, NULL},
+#endif /* LIBVIR_CHECK_VERSION(5, 1, 0) */
{(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
#if LIBVIR_CHECK_VERSION(0, 9, 13)
{(char *) "virDomainListAllSnapshots", libvirt_virDomainListAllSnapshots, METH_VARARGS, NULL},
diff --git a/sanitytest.py b/sanitytest.py
index 68dde6b..b044231 100644
--- a/sanitytest.py
+++ b/sanitytest.py
@@ -249,13 +249,13 @@ for name in sorted(basicklassmap):
# Remove 'Get' prefix from most APIs, except those in virConnect
# and virDomainSnapshot namespaces which stupidly used a different
# convention which we now can't fix without breaking API
- if func[0:3] == "Get" and klass not in ["virConnect", "virDomainSnapshot", "libvirt"]:
+ if func[0:3] == "Get" and klass not in ["virConnect", "virDomainCheckpoint", "virDomainSnapshot", "libvirt"]:
if func not in ["GetCPUStats", "GetTime"]:
func = func[3:]
# The object creation and lookup APIs all have to get re-mapped
# into the parent class
- if func in ["CreateXML", "CreateLinux", "CreateXMLWithFiles",
+ if func in ["CreateXML", "CreateXML2", "CreateLinux", "CreateXMLWithFiles",
"DefineXML", "CreateXMLFrom", "LookupByUUID",
"LookupByUUIDString", "LookupByVolume" "LookupByName",
"LookupByID", "LookupByName", "LookupByKey", "LookupByPath",
@@ -266,7 +266,7 @@ for name in sorted(basicklassmap):
if klass != "virDomain":
func = klass[3:] + func
- if klass == "virDomainSnapshot":
+ if klass in [ "virDomainCheckpoint", "virDomainSnapshot"]:
klass = "virDomain"
func = func[6:]
elif klass == "virStorageVol" and func in ["StorageVolCreateXMLFrom", "StorageVolCreateXML"]:
@@ -297,10 +297,13 @@ for name in sorted(basicklassmap):
if func[0:6] == "Change":
klass = "virConnect"
- # Need to special case the snapshot APIs
+ # Need to special case the checkpoint and snapshot APIs
if klass == "virDomainSnapshot" and func in ["Current", "ListNames", "Num"]:
klass = "virDomain"
func = "snapshot" + func
+ elif klass == "virDomainCheckpoint" and func == "Current":
+ klass = "virDomain"
+ func = "checkpoint" + func
# Names should start with lowercase letter...
func = func[0:1].lower() + func[1:]
diff --git a/typewrappers.c b/typewrappers.c
index 9ba14b4..cd7a70b 100644
--- a/typewrappers.c
+++ b/typewrappers.c
@@ -568,6 +568,19 @@ libvirt_virStreamPtrWrap(virStreamPtr node)
return ret;
}
+PyObject *
+libvirt_virDomainCheckpointPtrWrap(virDomainCheckpointPtr node)
+{
+ PyObject *ret;
+
+ if (node == NULL) {
+ return VIR_PY_NONE;
+ }
+
+ ret = libvirt_buildPyObject(node, "virDomainCheckpointPtr", NULL);
+ return ret;
+}
+
PyObject *
libvirt_virDomainSnapshotPtrWrap(virDomainSnapshotPtr node)
{
diff --git a/typewrappers.h b/typewrappers.h
index 4423774..198397b 100644
--- a/typewrappers.h
+++ b/typewrappers.h
@@ -128,6 +128,15 @@ typedef struct {
} PyvirStream_Object;
+#define PyvirDomainCheckpoint_Get(v) (((v) == Py_None) ? NULL : \
+ (((PyvirDomainCheckpoint_Object *)(v))->obj))
+
+typedef struct {
+ PyObject_HEAD
+ virDomainCheckpointPtr obj;
+} PyvirDomainCheckpoint_Object;
+
+
#define PyvirDomainSnapshot_Get(v) (((v) == Py_None) ? NULL : \
(((PyvirDomainSnapshot_Object *)(v))->obj))
@@ -204,6 +213,7 @@ PyObject * libvirt_virSecretPtrWrap(virSecretPtr node);
PyObject * libvirt_virNWFilterPtrWrap(virNWFilterPtr node);
PyObject * libvirt_virNWFilterBindingPtrWrap(virNWFilterBindingPtr node);
PyObject * libvirt_virStreamPtrWrap(virStreamPtr node);
+PyObject * libvirt_virDomainCheckpointPtrWrap(virDomainCheckpointPtr node);
PyObject * libvirt_virDomainSnapshotPtrWrap(virDomainSnapshotPtr node);
--
2.20.1
5 years, 4 months
[libvirt] [PATCH] virfile: adds quobyte as a shared fs
by Silvan Kaiser
Adds detection of a Quobyte shared file system for
live migration.
Signed-off-by: Silvan Kaiser <silvan(a)quobyte.com>
---
src/util/virfile.c | 13 ++++++++++++-
src/util/virfile.h | 1 +
tests/virfiledata/mounts3.txt | 1 +
tests/virfilemock.c | 3 +++
tests/virfiletest.c | 1 +
5 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/util/virfile.c b/src/util/virfile.c
index f7415cf633..a46b8792f6 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -3434,6 +3434,9 @@ int virFilePrintf(FILE *fp, const char *msg, ...)
# ifndef GPFS_SUPER_MAGIC
# define GPFS_SUPER_MAGIC 0x47504653
# endif
+# ifndef QB_MAGIC
+# define QB_MAGIC 0x51626d6e
+# endif
# define PROC_MOUNTS "/proc/mounts"
@@ -3490,6 +3493,10 @@ virFileIsSharedFixFUSE(const char *path,
VIR_DEBUG("Found gluster FUSE mountpoint=%s for path=%s. "
"Fixing shared FS type", mntDir, canonPath);
*f_type = GFS2_MAGIC;
+ } else if (STREQ_NULLABLE(mntType, "fuse.quobyte")) {
+ VIR_DEBUG("Found Quobyte FUSE mountpoint=%s for path=%s. "
+ "Fixing shared FS type", mntDir, canonPath);
+ *f_type = QB_MAGIC;
}
ret = 0;
@@ -3582,6 +3589,9 @@ virFileIsSharedFSType(const char *path,
if ((fstypes & VIR_FILE_SHFS_GPFS) &&
(f_type == GPFS_SUPER_MAGIC))
return 1;
+ if ((fstypes & VIR_FILE_SHFS_QB) &&
+ (f_type == QB_MAGIC))
+ return 1;
return 0;
}
@@ -3771,7 +3781,8 @@ int virFileIsSharedFS(const char *path)
VIR_FILE_SHFS_SMB |
VIR_FILE_SHFS_CIFS |
VIR_FILE_SHFS_CEPH |
- VIR_FILE_SHFS_GPFS);
+ VIR_FILE_SHFS_GPFS|
+ VIR_FILE_SHFS_QB);
}
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 641960e2ca..e06855ea86 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -212,6 +212,7 @@ enum {
VIR_FILE_SHFS_CIFS = (1 << 5),
VIR_FILE_SHFS_CEPH = (1 << 6),
VIR_FILE_SHFS_GPFS = (1 << 7),
+ VIR_FILE_SHFS_QB = (1 << 8),
};
int virFileIsSharedFSType(const char *path, int fstypes) ATTRIBUTE_NONNULL(1);
diff --git a/tests/virfiledata/mounts3.txt b/tests/virfiledata/mounts3.txt
index 4377e5d471..b91804a4e4 100644
--- a/tests/virfiledata/mounts3.txt
+++ b/tests/virfiledata/mounts3.txt
@@ -36,3 +36,4 @@ root@host:/tmp/mkdir /gluster/sshfs fuse.sshfs rw 0 0
192.168.0.1:/ceph/data /ceph ceph rw,noatime,name=cephfs,secret=<hidden>,acl,wsize=16777216 0 0
192.168.0.1,192.168.0.2,192.168.0.3:/ceph/data2 /ceph/multi ceph rw,noatime,name=cephfs,secret=<hidden>,acl,wsize=16777216 0 0
gpfs_data /gpfs/data gpfs rw,relatime 0 0
+quobyte(a)192.168.0.1/data /quobyte fuse.quobyte rw,nosuid,nodev,noatime,user_id=0,group_id=0,allow_other 0 0
diff --git a/tests/virfilemock.c b/tests/virfilemock.c
index 106032f857..54c57d417b 100644
--- a/tests/virfilemock.c
+++ b/tests/virfilemock.c
@@ -92,6 +92,9 @@ setmntent(const char *filename, const char *type)
#ifndef GPFS_SUPER_MAGIC
# define GPFS_SUPER_MAGIC 0x47504653
#endif
+# ifndef QB_MAGIC
+# define QB_MAGIC 0x51626d6e
+# endif
static int
diff --git a/tests/virfiletest.c b/tests/virfiletest.c
index e2bd4953ed..aa4c3435e5 100644
--- a/tests/virfiletest.c
+++ b/tests/virfiletest.c
@@ -458,6 +458,7 @@ mymain(void)
DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/ceph/file", true);
DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/ceph/multi/file", true);
DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gpfs/data", true);
+ DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/quobyte", true);
return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
--
2.16.5
5 years, 5 months
[libvirt] [PATCH 0/2] tools: Introduce virshNodedevCapabilityNameCompleter
by Michal Privoznik
Yet again, couple of patches I have on my local branch for the feature
I'm working on and which can go separately.
Michal Prívozník (2):
virsh-completer: Separate comma list construction into a function
tools: Introduce virshNodedevCapabilityNameCompleter
tools/virsh-completer.c | 147 ++++++++++++++++++++++++++++------------
tools/virsh-completer.h | 4 ++
tools/virsh-nodedev.c | 1 +
3 files changed, 109 insertions(+), 43 deletions(-)
--
2.21.0
5 years, 5 months
[libvirt] [dockerfiles PATCH] Add git-publish configuration file
by Andrea Bolognani
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
---
.gitpublish | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 .gitpublish
diff --git a/.gitpublish b/.gitpublish
new file mode 100644
index 0000000..a56a6d0
--- /dev/null
+++ b/.gitpublish
@@ -0,0 +1,4 @@
+[gitpublishprofile "default"]
+base = master
+to = libvir-list(a)redhat.com
+prefix = dockerfiles PATCH
--
2.20.1
5 years, 5 months
[libvirt] [PATCH 0/9] qemu: monitor: Pepare APIs for blockdev (blockdev-add saga)
by Peter Krempa
This contains set of monitor adjustments needed for supporting the block
job APIs with -blockdev.
Note that the last patch does not contain tests as there is a extensive
testsuite added with the actual formatter of the JSON properties which
are used with that API which will be posted later.
I can and probably will hold-off pushing this series together with the
rest once I iron out a few wrinkles.
Peter Krempa (9):
qemu: monitor: Add new fields for 'block-stream' command
qemu: monitor: Add new fields for 'block-commit' command
qemu: monitor: Add new fields for 'blockdev-mirror' command
qemu: monitor: Add support for 'job-dismiss' command
qemu: monitor: Add support for 'job-cancel' command
qemu: monitor: Add support for 'job-complete' command
qemu: monitor: Add infrastructure for 'query-jobs'
qemu: monitor: Implement support for 'JOB_STATUS_CHANGE' event
qemu: monitor: Add APIs for 'blockdev-create'
src/qemu/qemu_driver.c | 8 +-
src/qemu/qemu_migration.c | 2 +-
src/qemu/qemu_monitor.c | 150 ++++++++++-
src/qemu/qemu_monitor.h | 86 ++++++-
src/qemu/qemu_monitor_json.c | 243 +++++++++++++++++-
src/qemu/qemu_monitor_json.h | 33 ++-
.../query-jobs-create.json | 20 ++
.../query-jobs-create.result | 11 +
.../qemumonitorjsondata/query-jobs-empty.json | 1 +
.../query-jobs-empty.result | 0
tests/qemumonitorjsontest.c | 97 ++++++-
11 files changed, 625 insertions(+), 26 deletions(-)
create mode 100644 tests/qemumonitorjsondata/query-jobs-create.json
create mode 100644 tests/qemumonitorjsondata/query-jobs-create.result
create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.json
create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.result
--
2.21.0
5 years, 5 months
[libvirt] [PATCH 00/10] qemu: remove json fields from domain and monitor objects
by Ján Tomko
Applies on top of Peter's removal of commandline parsing
https://www.redhat.com/archives/libvir-list/2019-June/msg00405.html
After removal of qemuProcessAttach there is no codepath that could
possibly set monJSON to false (not that libvirt would be able to much
with such domain), so we can finish cleaning it up.
Ján Tomko (10):
qemu: also delete qemuProcessAttach
qemu: assume monJSON is always true
qemu: domain: remove monJSON field
qemu: stop formatting json='1' in status XML
qemu: remove json argument from qemuMonitorOpen
qemu: monitor: assume JSON in QEMU_CHECK_MONITOR macro
qemu: monitor: remove mon->json checks
qemu: monitor: remove the json field
qemu: monitor: use VIR_AUTOFREE in qemuMonitor*VideoSize
qemu: monitor: s/ret/rc/ in UpdateVideoSize functions
src/qemu/qemu_command.c | 8 +-
src/qemu/qemu_domain.c | 12 +-
src/qemu/qemu_domain.h | 1 -
src/qemu/qemu_driver.c | 3 +-
src/qemu/qemu_migration.c | 21 +-
src/qemu/qemu_monitor.c | 109 ++------
src/qemu/qemu_monitor.h | 2 -
src/qemu/qemu_process.c | 247 +-----------------
src/qemu/qemu_process.h | 8 -
tests/qemuhotplugtest.c | 2 -
tests/qemumonitortestutils.c | 1 -
.../blockjob-mirror-in.xml | 2 +-
.../disk-secinfo-upgrade-out.xml | 2 +-
.../migration-in-params-in.xml | 2 +-
.../migration-out-nbd-out.xml | 2 +-
.../migration-out-nbd-tls-out.xml | 2 +-
.../migration-out-params-in.xml | 2 +-
tests/qemustatusxml2xmldata/modern-in.xml | 2 +-
.../qemustatusxml2xmldata/vcpus-multi-in.xml | 2 +-
19 files changed, 52 insertions(+), 378 deletions(-)
--
2.20.1
5 years, 5 months