[PATCH 0/3] qemu: Replace usb-storage with usb-bot
by Akihiko Odaki
usb-storage is a compound device that automatically creates a USB mass
storage device and a SCSI device as its backend. Unfortunately it lacks
some configuration options that are usually present with a SCSI device,
and cannot represent CD-ROM in particular.
Replace usb-storage with usb-bot, which can be combined with a manually
created SCSI device. libvirt will configure the SCSI device in a way
identical with how QEMU does for usb-storage except that now it respects
a configuration option to represent CD-ROM.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/368
Signed-off-by: Akihiko Odaki <akihiko.odaki(a)daynix.com>
---
Akihiko Odaki (3):
qemu_capabilities: Introduce QEMU_CAPS_DEVICE_USB_BOT
qemu: Replace usb-storage with usb-bot
qemu_capabilities: Retire QEMU_CAPS_DEVICE_USB_STORAGE
src/qemu/qemu_alias.c | 3 +-
src/qemu/qemu_capabilities.c | 19 +-
src/qemu/qemu_capabilities.h | 3 +-
src/qemu/qemu_command.c | 55 +++++-
src/qemu/qemu_command.h | 5 +
src/qemu/qemu_hotplug.c | 34 +++-
src/qemu/qemu_validate.c | 4 +-
.../qemucapabilitiesdata/caps_10.0.0_s390x.replies | 186 ++++---------------
tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml | 2 +-
.../caps_10.0.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_10.0.0_x86_64.xml | 2 +-
.../caps_5.2.0_aarch64.replies | 174 ++++-------------
tests/qemucapabilitiesdata/caps_5.2.0_aarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_5.2.0_ppc64.replies | 178 +++++-------------
tests/qemucapabilitiesdata/caps_5.2.0_ppc64.xml | 2 +-
.../caps_5.2.0_riscv64.replies | 170 ++++-------------
tests/qemucapabilitiesdata/caps_5.2.0_riscv64.xml | 2 +-
.../qemucapabilitiesdata/caps_5.2.0_x86_64.replies | 190 +++++--------------
tests/qemucapabilitiesdata/caps_5.2.0_x86_64.xml | 2 +-
.../caps_6.0.0_aarch64.replies | 172 ++++-------------
tests/qemucapabilitiesdata/caps_6.0.0_aarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_6.0.0_x86_64.replies | 188 +++++--------------
tests/qemucapabilitiesdata/caps_6.0.0_x86_64.xml | 2 +-
.../qemucapabilitiesdata/caps_6.1.0_x86_64.replies | 194 +++++--------------
tests/qemucapabilitiesdata/caps_6.1.0_x86_64.xml | 2 +-
.../caps_6.2.0_aarch64.replies | 178 ++++--------------
tests/qemucapabilitiesdata/caps_6.2.0_aarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_6.2.0_ppc64.replies | 182 +++++-------------
tests/qemucapabilitiesdata/caps_6.2.0_ppc64.xml | 2 +-
.../qemucapabilitiesdata/caps_6.2.0_x86_64.replies | 194 +++++--------------
tests/qemucapabilitiesdata/caps_6.2.0_x86_64.xml | 2 +-
.../caps_7.0.0_aarch64+hvf.replies | 182 +++++-------------
.../caps_7.0.0_aarch64+hvf.xml | 2 +-
.../caps_7.0.0_aarch64.replies | 182 +++++-------------
tests/qemucapabilitiesdata/caps_7.0.0_aarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_7.0.0_ppc64.replies | 182 +++++-------------
tests/qemucapabilitiesdata/caps_7.0.0_ppc64.xml | 2 +-
.../qemucapabilitiesdata/caps_7.0.0_x86_64.replies | 194 +++++--------------
tests/qemucapabilitiesdata/caps_7.0.0_x86_64.xml | 2 +-
.../qemucapabilitiesdata/caps_7.1.0_ppc64.replies | 182 +++++-------------
tests/qemucapabilitiesdata/caps_7.1.0_ppc64.xml | 2 +-
.../qemucapabilitiesdata/caps_7.1.0_x86_64.replies | 194 +++++--------------
tests/qemucapabilitiesdata/caps_7.1.0_x86_64.xml | 2 +-
tests/qemucapabilitiesdata/caps_7.2.0_ppc.replies | 186 ++++---------------
tests/qemucapabilitiesdata/caps_7.2.0_ppc.xml | 2 +-
.../caps_7.2.0_x86_64+hvf.replies | 206 +++++----------------
.../qemucapabilitiesdata/caps_7.2.0_x86_64+hvf.xml | 2 +-
.../qemucapabilitiesdata/caps_7.2.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_7.2.0_x86_64.xml | 2 +-
.../caps_8.0.0_riscv64.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_8.0.0_riscv64.xml | 2 +-
.../qemucapabilitiesdata/caps_8.0.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_8.0.0_x86_64.xml | 2 +-
.../qemucapabilitiesdata/caps_8.1.0_s390x.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_8.1.0_s390x.xml | 2 +-
.../qemucapabilitiesdata/caps_8.1.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_8.1.0_x86_64.xml | 2 +-
.../caps_8.2.0_aarch64.replies | 190 ++++---------------
tests/qemucapabilitiesdata/caps_8.2.0_aarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_8.2.0_armv7l.replies | 190 ++++---------------
tests/qemucapabilitiesdata/caps_8.2.0_armv7l.xml | 2 +-
.../caps_8.2.0_loongarch64.replies | 186 ++++---------------
.../caps_8.2.0_loongarch64.xml | 2 +-
.../qemucapabilitiesdata/caps_8.2.0_s390x.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_8.2.0_s390x.xml | 2 +-
.../qemucapabilitiesdata/caps_8.2.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_8.2.0_x86_64.xml | 2 +-
.../qemucapabilitiesdata/caps_9.0.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml | 2 +-
.../caps_9.1.0_riscv64.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_9.1.0_riscv64.xml | 2 +-
.../qemucapabilitiesdata/caps_9.1.0_s390x.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_9.1.0_s390x.xml | 2 +-
.../qemucapabilitiesdata/caps_9.1.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml | 2 +-
.../qemucapabilitiesdata/caps_9.2.0_s390x.replies | 182 ++++--------------
tests/qemucapabilitiesdata/caps_9.2.0_s390x.xml | 2 +-
.../qemucapabilitiesdata/caps_9.2.0_x86_64.replies | 206 +++++----------------
tests/qemucapabilitiesdata/caps_9.2.0_x86_64.xml | 2 +-
tests/qemuhotplugtest.c | 8 +-
.../qemuxmlconfdata/disk-cache.x86_64-latest.args | 3 +-
.../disk-cdrom-bus-other.x86_64-latest.args | 3 +-
.../disk-device-removable.x86_64-latest.args | 3 +-
.../disk-usb-device.x86_64-latest.args | 3 +-
84 files changed, 1689 insertions(+), 5346 deletions(-)
---
base-commit: e5299ddf86121d3c792ca271ffcb54900eb19dc3
change-id: 20250304-bot-5d84aa3a5cfe
Best regards,
--
Akihiko Odaki <akihiko.odaki(a)daynix.com>
3 days, 19 hours
[PATCH] rpm: Enable KVM for riscv64 on RHEL 10+
by Andrea Bolognani
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
---
libvirt.spec.in | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index cb41ea1de1..9217820137 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -8,7 +8,9 @@
%define arches_qemu_kvm %{ix86} x86_64 %{power64} %{arm} aarch64 s390x riscv64
%if 0%{?rhel}
- %if 0%{?rhel} > 8
+ %if 0%{?rhel} >= 10
+ %define arches_qemu_kvm x86_64 aarch64 s390x riscv64
+ %elif 0%{?rhel} >= 9
%define arches_qemu_kvm x86_64 aarch64 s390x
%else
%define arches_qemu_kvm x86_64 %{power64} aarch64 s390x
--
2.48.1
4 days
[PATCH v1] tests: add capabilities for QEMU 10.0.0 on s390x
by Shalini Chellathurai Saroja
Let us introduce the xml and reply files for QEMU 10.0.0 on s390x.
Notable changes:
- new s390-ccw-virtio-10.0 machine type
- old machine types (2.4 - 2.8) dropped
- new CPU models
- New devices:
- virtio-mem-ccw
- chardev now supports qemu-vdagent
Signed-off-by: Shalini Chellathurai Saroja <shalini(a)linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.ibm.com>
Suggested-by: Michal Privoznik <mprivozn(a)redhat.com>
The replies and xml files are removed from this patch and are available in
https://gitlab.com/shalinichellathurai/libvirt/-/commit/3e9df63925e2c86b8...
---
tests/domaincapsdata/qemu_10.0.0.s390x.xml | 359 +
.../caps_10.0.0_s390x.replies | 38002 ++++++++++++++++
.../caps_10.0.0_s390x.xml | 4216 ++
3 files changed, 42577 insertions(+)
create mode 100644 tests/domaincapsdata/qemu_10.0.0.s390x.xml
create mode 100644 tests/qemucapabilitiesdata/caps_10.0.0_s390x.replies
create mode 100644 tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml
diff --git a/tests/domaincapsdata/qemu_10.0.0.s390x.xml b/tests/domaincapsdata/qemu_10.0.0.s390x.xml
new file mode 100644
index 0000000000..4af3c7ec53
--- /dev/null
+++ b/tests/domaincapsdata/qemu_10.0.0.s390x.xml
@@ -0,0 +1,359 @@
+<domainCapabilities>
+ <path>/usr/bin/qemu-system-s390x</path>
+ <domain>kvm</domain>
+ <machine>s390-ccw-virtio-10.0</machine>
+ <arch>s390x</arch>
+ <vcpu max='248'/>
+ <iothreads supported='yes'/>
+ <os supported='yes'>
+ <enum name='firmware'/>
+ <loader supported='yes'>
+ <value>/obviously/fake/firmware1.fd</value>
+ <value>/obviously/fake/firmware2.fd</value>
+ <enum name='type'>
+ <value>rom</value>
+ <value>pflash</value>
+ </enum>
+ <enum name='readonly'>
+ <value>yes</value>
+ <value>no</value>
+ </enum>
+ <enum name='secure'>
+ <value>no</value>
+ </enum>
+ </loader>
+ </os>
+ <cpu>
+ <mode name='host-passthrough' supported='yes'>
+ <enum name='hostPassthroughMigratable'>
+ <value>off</value>
+ </enum>
+ </mode>
+ <mode name='maximum' supported='yes'>
+ <enum name='maximumMigratable'>
+ <value>on</value>
+ <value>off</value>
+ </enum>
+ </mode>
+ <mode name='host-model' supported='yes'>
+ <model fallback='forbid'>gen16a-base</model>
+ <feature policy='require' name='nnpa'/>
+ <feature policy='require' name='aen'/>
+ <feature policy='require' name='cmmnt'/>
+ <feature policy='require' name='vxpdeh'/>
+ <feature policy='require' name='aefsi'/>
+ <feature policy='require' name='diag318'/>
+ <feature policy='require' name='csske'/>
+ <feature policy='require' name='mepoch'/>
+ <feature policy='require' name='msa9'/>
+ <feature policy='require' name='msa8'/>
+ <feature policy='require' name='msa7'/>
+ <feature policy='require' name='msa6'/>
+ <feature policy='require' name='msa5'/>
+ <feature policy='require' name='msa4'/>
+ <feature policy='require' name='msa3'/>
+ <feature policy='require' name='msa2'/>
+ <feature policy='require' name='msa1'/>
+ <feature policy='require' name='sthyi'/>
+ <feature policy='require' name='edat'/>
+ <feature policy='require' name='ri'/>
+ <feature policy='require' name='deflate'/>
+ <feature policy='require' name='edat2'/>
+ <feature policy='require' name='etoken'/>
+ <feature policy='require' name='vx'/>
+ <feature policy='require' name='ipter'/>
+ <feature policy='require' name='pai'/>
+ <feature policy='require' name='paie'/>
+ <feature policy='require' name='mepochptff'/>
+ <feature policy='require' name='ap'/>
+ <feature policy='require' name='vxeh'/>
+ <feature policy='require' name='vxpd'/>
+ <feature policy='require' name='esop'/>
+ <feature policy='require' name='msa9_pckmo'/>
+ <feature policy='require' name='vxeh2'/>
+ <feature policy='require' name='esort'/>
+ <feature policy='require' name='appv'/>
+ <feature policy='require' name='apqi'/>
+ <feature policy='require' name='apft'/>
+ <feature policy='require' name='els'/>
+ <feature policy='require' name='iep'/>
+ <feature policy='require' name='appvi'/>
+ <feature policy='require' name='apqci'/>
+ <feature policy='require' name='cte'/>
+ <feature policy='require' name='ais'/>
+ <feature policy='require' name='bpb'/>
+ <feature policy='require' name='ctop'/>
+ <feature policy='require' name='gs'/>
+ <feature policy='require' name='ppa15'/>
+ <feature policy='require' name='zpci'/>
+ <feature policy='require' name='rdp'/>
+ <feature policy='require' name='sea_esop2'/>
+ <feature policy='require' name='beareh'/>
+ <feature policy='require' name='te'/>
+ <feature policy='require' name='cmm'/>
+ <feature policy='require' name='vxpdeh2'/>
+ </mode>
+ <mode name='custom' supported='yes'>
+ <model usable='yes' vendor='IBM'>gen15a</model>
+ <model usable='yes' vendor='IBM'>gen15a-base</model>
+ <model usable='yes' vendor='IBM'>gen15b</model>
+ <model usable='yes' vendor='IBM'>gen15b-base</model>
+ <model usable='yes' vendor='IBM'>gen16a</model>
+ <model usable='yes' vendor='IBM'>gen16a-base</model>
+ <model usable='yes' vendor='IBM'>gen16b</model>
+ <model usable='yes' vendor='IBM'>gen16b-base</model>
+ <model usable='no' vendor='IBM'>gen17a</model>
+ <blockers model='gen17a'>
+ <feature name='minste4'/>
+ <feature name='msa10'/>
+ <feature name='msa10_pckmo'/>
+ <feature name='msa11'/>
+ <feature name='msa11_pckmo'/>
+ <feature name='msa12'/>
+ <feature name='msa13'/>
+ <feature name='msa13_pckmo'/>
+ <feature name='plo_ext'/>
+ <feature name='sif'/>
+ <feature name='type'/>
+ <feature name='vxeh3'/>
+ <feature name='vxpdeh3'/>
+ </blockers>
+ <model usable='no' vendor='IBM'>gen17a-base</model>
+ <blockers model='gen17a-base'>
+ <feature name='minste4'/>
+ <feature name='msa12'/>
+ <feature name='plo_ext'/>
+ <feature name='sif'/>
+ <feature name='type'/>
+ </blockers>
+ <model usable='no' vendor='IBM'>gen17b</model>
+ <blockers model='gen17b'>
+ <feature name='minste4'/>
+ <feature name='msa10'/>
+ <feature name='msa10_pckmo'/>
+ <feature name='msa11'/>
+ <feature name='msa11_pckmo'/>
+ <feature name='msa12'/>
+ <feature name='msa13'/>
+ <feature name='msa13_pckmo'/>
+ <feature name='plo_ext'/>
+ <feature name='sif'/>
+ <feature name='type'/>
+ <feature name='vxeh3'/>
+ <feature name='vxpdeh3'/>
+ </blockers>
+ <model usable='no' vendor='IBM'>gen17b-base</model>
+ <blockers model='gen17b-base'>
+ <feature name='minste4'/>
+ <feature name='msa12'/>
+ <feature name='plo_ext'/>
+ <feature name='sif'/>
+ <feature name='type'/>
+ </blockers>
+ <model usable='yes' vendor='unknown'>max</model>
+ <model usable='yes' vendor='unknown'>qemu</model>
+ <model usable='yes' vendor='IBM'>z10BC</model>
+ <model usable='yes' vendor='IBM'>z10BC-base</model>
+ <model usable='yes' vendor='IBM'>z10BC.2</model>
+ <model usable='yes' vendor='IBM'>z10BC.2-base</model>
+ <model usable='yes' vendor='IBM'>z10EC</model>
+ <model usable='yes' vendor='IBM'>z10EC-base</model>
+ <model usable='yes' vendor='IBM'>z10EC.2</model>
+ <model usable='yes' vendor='IBM'>z10EC.2-base</model>
+ <model usable='yes' vendor='IBM'>z10EC.3</model>
+ <model usable='yes' vendor='IBM'>z10EC.3-base</model>
+ <model usable='yes' vendor='IBM'>z114</model>
+ <model usable='yes' vendor='IBM'>z114-base</model>
+ <model usable='yes' vendor='IBM'>z13</model>
+ <model usable='yes' vendor='IBM'>z13-base</model>
+ <model usable='yes' vendor='IBM'>z13.2</model>
+ <model usable='yes' vendor='IBM'>z13.2-base</model>
+ <model usable='yes' vendor='IBM'>z13s</model>
+ <model usable='yes' vendor='IBM'>z13s-base</model>
+ <model usable='yes' vendor='IBM'>z14</model>
+ <model usable='yes' vendor='IBM'>z14-base</model>
+ <model usable='yes' vendor='IBM'>z14.2</model>
+ <model usable='yes' vendor='IBM'>z14.2-base</model>
+ <model usable='yes' vendor='IBM'>z14ZR1</model>
+ <model usable='yes' vendor='IBM'>z14ZR1-base</model>
+ <model usable='yes' vendor='IBM'>z196</model>
+ <model usable='yes' vendor='IBM'>z196-base</model>
+ <model usable='yes' vendor='IBM'>z196.2</model>
+ <model usable='yes' vendor='IBM'>z196.2-base</model>
+ <model usable='yes' vendor='IBM'>z800</model>
+ <model usable='yes' vendor='IBM'>z800-base</model>
+ <model usable='yes' vendor='IBM'>z890</model>
+ <model usable='yes' vendor='IBM'>z890-base</model>
+ <model usable='yes' vendor='IBM'>z890.2</model>
+ <model usable='yes' vendor='IBM'>z890.2-base</model>
+ <model usable='yes' vendor='IBM'>z890.3</model>
+ <model usable='yes' vendor='IBM'>z890.3-base</model>
+ <model usable='yes' vendor='IBM'>z900</model>
+ <model usable='yes' vendor='IBM'>z900-base</model>
+ <model usable='yes' vendor='IBM'>z900.2</model>
+ <model usable='yes' vendor='IBM'>z900.2-base</model>
+ <model usable='yes' vendor='IBM'>z900.3</model>
+ <model usable='yes' vendor='IBM'>z900.3-base</model>
+ <model usable='yes' vendor='IBM'>z990</model>
+ <model usable='yes' vendor='IBM'>z990-base</model>
+ <model usable='yes' vendor='IBM'>z990.2</model>
+ <model usable='yes' vendor='IBM'>z990.2-base</model>
+ <model usable='yes' vendor='IBM'>z990.3</model>
+ <model usable='yes' vendor='IBM'>z990.3-base</model>
+ <model usable='yes' vendor='IBM'>z990.4</model>
+ <model usable='yes' vendor='IBM'>z990.4-base</model>
+ <model usable='yes' vendor='IBM'>z990.5</model>
+ <model usable='yes' vendor='IBM'>z990.5-base</model>
+ <model usable='yes' vendor='IBM'>z9BC</model>
+ <model usable='yes' vendor='IBM'>z9BC-base</model>
+ <model usable='yes' vendor='IBM'>z9BC.2</model>
+ <model usable='yes' vendor='IBM'>z9BC.2-base</model>
+ <model usable='yes' vendor='IBM'>z9EC</model>
+ <model usable='yes' vendor='IBM'>z9EC-base</model>
+ <model usable='yes' vendor='IBM'>z9EC.2</model>
+ <model usable='yes' vendor='IBM'>z9EC.2-base</model>
+ <model usable='yes' vendor='IBM'>z9EC.3</model>
+ <model usable='yes' vendor='IBM'>z9EC.3-base</model>
+ <model usable='yes' vendor='IBM'>zBC12</model>
+ <model usable='yes' vendor='IBM'>zBC12-base</model>
+ <model usable='yes' vendor='IBM'>zEC12</model>
+ <model usable='yes' vendor='IBM'>zEC12-base</model>
+ <model usable='yes' vendor='IBM'>zEC12.2</model>
+ <model usable='yes' vendor='IBM'>zEC12.2-base</model>
+ </mode>
+ </cpu>
+ <memoryBacking supported='yes'>
+ <enum name='sourceType'>
+ <value>file</value>
+ <value>anonymous</value>
+ <value>memfd</value>
+ </enum>
+ </memoryBacking>
+ <devices>
+ <disk supported='yes'>
+ <enum name='diskDevice'>
+ <value>disk</value>
+ <value>cdrom</value>
+ <value>floppy</value>
+ <value>lun</value>
+ </enum>
+ <enum name='bus'>
+ <value>fdc</value>
+ <value>scsi</value>
+ <value>virtio</value>
+ <value>usb</value>
+ </enum>
+ <enum name='model'>
+ <value>virtio</value>
+ <value>virtio-transitional</value>
+ <value>virtio-non-transitional</value>
+ </enum>
+ </disk>
+ <graphics supported='yes'>
+ <enum name='type'>
+ <value>sdl</value>
+ <value>vnc</value>
+ <value>egl-headless</value>
+ <value>dbus</value>
+ </enum>
+ </graphics>
+ <video supported='yes'>
+ <enum name='modelType'>
+ <value>virtio</value>
+ <value>none</value>
+ </enum>
+ </video>
+ <hostdev supported='yes'>
+ <enum name='mode'>
+ <value>subsystem</value>
+ </enum>
+ <enum name='startupPolicy'>
+ <value>default</value>
+ <value>mandatory</value>
+ <value>requisite</value>
+ <value>optional</value>
+ </enum>
+ <enum name='subsysType'>
+ <value>usb</value>
+ <value>pci</value>
+ <value>scsi</value>
+ </enum>
+ <enum name='capsType'/>
+ <enum name='pciBackend'>
+ <value>default</value>
+ <value>vfio</value>
+ </enum>
+ </hostdev>
+ <rng supported='yes'>
+ <enum name='model'>
+ <value>virtio</value>
+ <value>virtio-transitional</value>
+ <value>virtio-non-transitional</value>
+ </enum>
+ <enum name='backendModel'>
+ <value>random</value>
+ <value>egd</value>
+ <value>builtin</value>
+ </enum>
+ </rng>
+ <filesystem supported='yes'>
+ <enum name='driverType'>
+ <value>path</value>
+ <value>handle</value>
+ <value>virtiofs</value>
+ </enum>
+ </filesystem>
+ <tpm supported='no'/>
+ <redirdev supported='yes'>
+ <enum name='bus'>
+ <value>usb</value>
+ </enum>
+ </redirdev>
+ <channel supported='yes'>
+ <enum name='type'>
+ <value>pty</value>
+ <value>unix</value>
+ </enum>
+ </channel>
+ <crypto supported='yes'>
+ <enum name='model'>
+ <value>virtio</value>
+ </enum>
+ <enum name='type'>
+ <value>qemu</value>
+ </enum>
+ <enum name='backendModel'>
+ <value>builtin</value>
+ <value>lkcf</value>
+ </enum>
+ </crypto>
+ <interface supported='yes'>
+ <enum name='backendType'>
+ <value>default</value>
+ <value>passt</value>
+ </enum>
+ </interface>
+ <panic supported='yes'>
+ <enum name='model'>
+ <value>s390</value>
+ </enum>
+ </panic>
+ </devices>
+ <features>
+ <gic supported='no'/>
+ <vmcoreinfo supported='no'/>
+ <genid supported='no'/>
+ <backingStoreInput supported='yes'/>
+ <backup supported='yes'/>
+ <async-teardown supported='yes'/>
+ <s390-pv supported='yes'/>
+ <ps2 supported='no'/>
+ <sev supported='no'/>
+ <sgx supported='no'/>
+ <launchSecurity supported='yes'>
+ <enum name='sectype'>
+ <value>s390-pv</value>
+ </enum>
+ </launchSecurity>
+ </features>
+</domainCapabilities>
diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_s390x.replies b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.replies
new file mode 100644
index 0000000000..5195489878
--- /dev/null
+++ b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.replies
@@ -0,0 +1,38002 @@
[...]
diff --git a/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml
new file mode 100644
index 0000000000..242848d6ae
--- /dev/null
+++ b/tests/qemucapabilitiesdata/caps_10.0.0_s390x.xml
@@ -0,0 +1,4216 @@
[...]
5 days, 1 hour
[PATCH] virbitmap: Change return type of virBitmapToData to void
by Alexander Kuznetsov
This function return value is invariant since e59b8f9, so change
its type and remove all dependent checks.
Found by Linux Verification Center (linuxtesting.org) with Svace.
Signed-off-by: Artem Chernyshev <artem.chernyshev(a)red-soft.ru>
Signed-off-by: Alexander Kuznetsov <kuznetsovam(a)altlinux.org>
---
src/ch/ch_monitor.c | 5 +----
src/hypervisor/domain_driver.c | 4 +---
src/qemu/qemu_driver.c | 3 +--
src/util/virbitmap.c | 6 +-----
src/util/virbitmap.h | 2 +-
src/util/virhostcpu.c | 4 ++--
tests/virbitmaptest.c | 3 +--
tools/virsh-completer-domain.c | 6 ++----
tools/virsh-domain.c | 3 +--
9 files changed, 11 insertions(+), 25 deletions(-)
diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c
index 0ba927a194..b772eec8a2 100644
--- a/src/ch/ch_monitor.c
+++ b/src/ch/ch_monitor.c
@@ -1196,10 +1196,7 @@ virCHMonitorGetIOThreads(virCHMonitor *mon,
if (!(map = virProcessGetAffinity(iothreadinfo->iothread_id)))
goto error;
- if (virBitmapToData(map, &(iothreadinfo->cpumap),
- &(iothreadinfo->cpumaplen)) < 0) {
- goto error;
- }
+ virBitmapToData(map, &(iothreadinfo->cpumap), &(iothreadinfo->cpumaplen));
/* Append to iothreadinfolist */
iothreadinfolist[niothreads] = g_steal_pointer(&iothreadinfo);
diff --git a/src/hypervisor/domain_driver.c b/src/hypervisor/domain_driver.c
index e2a08d737e..35966a5a8d 100644
--- a/src/hypervisor/domain_driver.c
+++ b/src/hypervisor/domain_driver.c
@@ -652,9 +652,7 @@ virDomainDriverGetIOThreadsConfig(virDomainDef *targetDef,
cpumask = bitmap;
}
}
- if (virBitmapToData(cpumask, &info_ret[i]->cpumap,
- &info_ret[i]->cpumaplen) < 0)
- goto cleanup;
+ virBitmapToData(cpumask, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen);
}
*info = g_steal_pointer(&info_ret);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6ce949dd07..59ba6cfbf3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4787,8 +4787,7 @@ qemuDomainGetIOThreadsLive(virDomainObj *vm,
if (!(map = virProcessGetAffinity(iothreads[i]->thread_id)))
goto endjob;
- if (virBitmapToData(map, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen) < 0)
- goto endjob;
+ virBitmapToData(map, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen);
}
*info = g_steal_pointer(&info_ret);
diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c
index e42f5b872c..8a3f33c806 100644
--- a/src/util/virbitmap.c
+++ b/src/util/virbitmap.c
@@ -637,10 +637,8 @@ virBitmapNewData(const void *data,
* Convert a bitmap to a chunk of data containing bits information.
* Data consists of sequential bytes, with lower bytes containing
* lower bits. This function allocates @data.
- *
- * Returns 0 on success, -1 otherwise.
*/
-int
+void
virBitmapToData(virBitmap *bitmap,
unsigned char **data,
int *dataLen)
@@ -656,8 +654,6 @@ virBitmapToData(virBitmap *bitmap,
*dataLen = len;
virBitmapToDataBuf(bitmap, *data, *dataLen);
-
- return 0;
}
diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h
index a9f9d97fd0..a9c0a1a307 100644
--- a/src/util/virbitmap.h
+++ b/src/util/virbitmap.h
@@ -91,7 +91,7 @@ virBitmap *virBitmapNewCopy(virBitmap *src) ATTRIBUTE_NONNULL(1);
virBitmap *virBitmapNewData(const void *data, int len) ATTRIBUTE_NONNULL(1);
-int virBitmapToData(virBitmap *bitmap, unsigned char **data, int *dataLen)
+void virBitmapToData(virBitmap *bitmap, unsigned char **data, int *dataLen)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
void virBitmapToDataBuf(virBitmap *bitmap, unsigned char *data, size_t len)
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index 3b4a11effb..80819d83e6 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -1110,8 +1110,8 @@ virHostCPUGetMap(unsigned char **cpumap,
if (!(cpus = virHostCPUGetOnlineBitmap()))
goto cleanup;
- if (cpumap && virBitmapToData(cpus, cpumap, &dummy) < 0)
- goto cleanup;
+ if (cpumap)
+ virBitmapToData(cpus, cpumap, &dummy);
if (online)
*online = virBitmapCountBits(cpus);
diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c
index 27b6c13114..709c62ab54 100644
--- a/tests/virbitmaptest.c
+++ b/tests/virbitmaptest.c
@@ -339,8 +339,7 @@ test5(const void *v G_GNUC_UNUSED)
ignore_value(virBitmapSetBit(bitmap, 2));
ignore_value(virBitmapSetBit(bitmap, 15));
- if (virBitmapToData(bitmap, &data2, &len2) < 0)
- return -1;
+ virBitmapToData(bitmap, &data2, &len2);
if (len2 != sizeof(data) ||
data2[0] != 0x05 ||
diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c
index 0a3a113dca..b020d87f49 100644
--- a/tools/virsh-completer-domain.c
+++ b/tools/virsh-completer-domain.c
@@ -794,8 +794,7 @@ virshDomainVcpulistViaAgentCompleter(vshControl *ctl,
if (!(onlineVcpus = virBitmapParseUnlimited(onlineVcpuStr)))
goto cleanup;
- if (virBitmapToData(onlineVcpus, &onlineVcpumap, &dummy) < 0)
- goto cleanup;
+ virBitmapToData(onlineVcpus, &onlineVcpumap, &dummy);
if (enable) {
offlinableVcpuStr = vshGetTypedParamValue(ctl, ¶ms[2]);
@@ -803,8 +802,7 @@ virshDomainVcpulistViaAgentCompleter(vshControl *ctl,
if (!(offlinableVcpus = virBitmapParseUnlimited(offlinableVcpuStr)))
goto cleanup;
- if (virBitmapToData(offlinableVcpus, &offlinableVcpumap, &dummy) < 0)
- goto cleanup;
+ virBitmapToData(offlinableVcpus, &offlinableVcpumap, &dummy);
lastcpu = virBitmapLastSetBit(offlinableVcpus);
cpulist = g_new0(char *, nvcpus - virBitmapCountBits(onlineVcpus) + 1);
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index ceff6789d8..a2e30a0fa9 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -7420,8 +7420,7 @@ virshParseCPUList(vshControl *ctl, int *cpumaplen,
}
}
- if (virBitmapToData(map, &cpumap, cpumaplen) < 0)
- return NULL;
+ virBitmapToData(map, &cpumap, cpumaplen);
return cpumap;
}
--
2.42.4
1 week, 5 days
[PATCH] USB hostdev: allow addressing by port
by Maximilian Martin
From: Maximilian Martin <maximilian_martin(a)gmx.de>
Currently, only vendor/product and bus/device matching are supported for USB host
devices. Neither of these provide a stable and persistent way of assigning a guest
a specific host device. Vendor/product can be ambiguous. Device numbers change on
every enumeration.
This patch adds a bus/port matching, which allows a specific port on the host to be
specified using the dotted notation found in Linux's "devpath" sysfs attribute.
This patch is based on the previous work of Thomas Hebb: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/7...
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/513
Signed-off-by: Maximilian Martin <maximilian_martin(a)gmx.de>
---
docs/formatdomain.rst | 29 ++--
src/conf/domain_conf.c | 70 +++++++-
src/conf/domain_conf.h | 1 +
src/conf/schemas/domaincommon.rng | 11 +-
src/hypervisor/virhostdev.c | 131 +++++++++------
src/libvirt_private.syms | 2 -
src/util/virusb.c | 159 ++++++------------
src/util/virusb.h | 32 ++--
tests/virusbtest.c | 149 +++++++++++-----
.../sys_bus_usb/devices/1-1.5.3.1/devpath | 1 +
.../sys_bus_usb/devices/1-1.5.3.3/devpath | 1 +
.../sys_bus_usb/devices/1-1.5.3/devpath | 1 +
.../sys_bus_usb/devices/1-1.5.4/devpath | 1 +
.../sys_bus_usb/devices/1-1.5.5/devpath | 1 +
.../sys_bus_usb/devices/1-1.5.6/devpath | 1 +
.../sys_bus_usb/devices/1-1.5/devpath | 1 +
.../sys_bus_usb/devices/1-1.6/devpath | 1 +
.../sys_bus_usb/devices/1-1/devpath | 1 +
.../sys_bus_usb/devices/2-1.2/devpath | 1 +
.../sys_bus_usb/devices/2-1/devpath | 1 +
.../sys_bus_usb/devices/usb1/devpath | 1 +
.../sys_bus_usb/devices/usb2/devpath | 1 +
.../sys_bus_usb/devices/usb3/devpath | 1 +
.../sys_bus_usb/devices/usb4/devpath | 1 +
24 files changed, 355 insertions(+), 244 deletions(-)
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath
create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 543b36cb2e..bc3c11613f 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -4696,19 +4696,22 @@ or:
tweak the loading process further using the ``bar`` or ``file`` attributes
will be rejected. :since:`Since 4.3.0 (QEMU and KVM only)`.
``address``
- The ``address`` element for USB devices has a ``bus`` and ``device``
- attribute to specify the USB bus and device number the device appears at on
- the host. The values of these attributes can be given in decimal, hexadecimal
- (starting with 0x) or octal (starting with 0) form. For PCI devices the
- element carries 4 attributes allowing to designate the device as can be found
- with the ``lspci`` or with ``virsh nodedev-list``. For SCSI devices a 'drive'
- address type must be used. For mediated devices, which are software-only
- devices defining an allocation of resources on the physical parent device,
- the address type used must conform to the ``model`` attribute of element
- ``hostdev``, e.g. any address type other than PCI for ``vfio-pci`` device API
- or any address type other than CCW for ``vfio-ccw`` device API will result in
- an error. See the `Device Addresses`_ section for more details on the address
- element.
+ The ``address`` element for USB devices has a ``bus`` attribute to specify
+ the USB bus. In addition, either a ``device`` attribute or a ``port``
+ attribute is required to identify the device on the host. While the device
+ number is assigned upon connection of the device, the port number is a
+ stable identifier of the physical host port. Bus and device number can be
+ given in decimal, hexadecimal (starting with 0x) or octal (starting with 0)
+ form. The port number is a dotted path (examples: ``2``, ``1.2.5``). For PCI
+ devices the element carries 4 attributes allowing to designate the device as
+ can be found with the ``lspci`` or with ``virsh nodedev-list``. For SCSI
+ devices a 'drive' address type must be used. For mediated devices, which are
+ software-only devices defining an allocation of resources on the physical
+ parent device, the address type used must conform to the ``model`` attribute
+ of element ``hostdev``, e.g. any address type other than PCI for ``vfio-pci``
+ device API or any address type other than CCW for ``vfio-ccw`` device API
+ will result in an error. See the `Device Addresses`_ section for more details
+ on the address element.
``driver``
PCI hostdev devices can have an optional ``driver`` subelement that
specifies which host driver to bind to the device when preparing it
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b94cf99236..bd9c651a07 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2657,6 +2657,15 @@ virDomainHostdevSubsysSCSIClear(virDomainHostdevSubsysSCSI *scsisrc)
}
}
+static void
+virDomainHostdevSubsysUSBClear(virDomainHostdevSubsysUSB *usbsrc)
+{
+ if (!usbsrc)
+ return;
+
+ VIR_FREE(usbsrc->port);
+}
+
static void
virDomainHostdevDefClear(virDomainHostdevDef *def)
@@ -2700,6 +2709,8 @@ virDomainHostdevDefClear(virDomainHostdevDef *def)
g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ virDomainHostdevSubsysUSBClear(&def->source.subsys.u.usb);
+ break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
break;
@@ -5841,6 +5852,9 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
xmlNodePtr productNode;
xmlNodePtr addressNode;
virTristateBool autoAddress;
+ bool found_device, found_port;
+ char *port;
+ int ret = -1;
VIR_XPATH_NODE_AUTORESTORE(ctxt)
ctxt->node = node;
@@ -5891,13 +5905,45 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
}
if ((addressNode = virXPathNode("./address", ctxt))) {
- if (virXMLPropUInt(addressNode, "bus", 0,
- VIR_XML_PROP_REQUIRED, &usbsrc->bus) < 0)
+ found_device = false;
+ found_port = false;
+
+ ret = virXMLPropUInt(addressNode, "bus", 0,
+ VIR_XML_PROP_REQUIRED, &usbsrc->bus);
+ if (ret < 0) {
+ return -1;
+ } else if (ret == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing bus"));
+ return -1;
+ }
+
+ ret = virXMLPropUInt(addressNode, "device", 0,
+ VIR_XML_PROP_NONE, &usbsrc->device);
+ if (ret < 0)
return -1;
+ else if (ret > 0)
+ found_device = true;
- if (virXMLPropUInt(addressNode, "device", 0,
- VIR_XML_PROP_REQUIRED, &usbsrc->device) < 0)
+ port = virXMLPropString(addressNode, "port");
+ if (port) {
+ if (*port) {
+ usbsrc->port = port;
+ found_port = true;
+ } else {
+ VIR_FREE(port);
+ }
+ }
+
+ if (!found_device && !found_port) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("usb address needs either device id or port"));
return -1;
+ } else if (found_device && found_port) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("found both device id and port in usb address (ambiguous setting)"));
+ return -1;
+ }
}
return 0;
@@ -14522,8 +14568,13 @@ virDomainHostdevMatchSubsysUSB(virDomainHostdevDef *first,
virDomainHostdevSubsysUSB *first_usbsrc = &first->source.subsys.u.usb;
virDomainHostdevSubsysUSB *second_usbsrc = &second->source.subsys.u.usb;
- if (first_usbsrc->bus && first_usbsrc->device) {
- /* specified by bus location on host */
+ if (first_usbsrc->bus && first_usbsrc->port) {
+ /* specified by bus and port on host */
+ if (first_usbsrc->bus == second_usbsrc->bus &&
+ STREQ_NULLABLE(first_usbsrc->port, second_usbsrc->port))
+ return 1;
+ } else if (first_usbsrc->bus && first_usbsrc->device) {
+ /* specified by bus and device id on host */
if (first_usbsrc->bus == second_usbsrc->bus &&
first_usbsrc->device == second_usbsrc->device)
return 1;
@@ -23957,10 +24008,15 @@ virDomainHostdevDefFormatSubsysUSB(virBuffer *buf,
virBufferAsprintf(&sourceChildBuf, "<product id='0x%.4x'/>\n", usbsrc->product);
}
- if (usbsrc->bus || usbsrc->device)
+ if (usbsrc->bus && usbsrc->port) {
+ virBufferAsprintf(&sourceChildBuf, "<address %sbus='%d' port='%s'/>\n",
+ includeTypeInAddr ? "type='usb' " : "",
+ usbsrc->bus, usbsrc->port);
+ } else if (usbsrc->bus || usbsrc->device) {
virBufferAsprintf(&sourceChildBuf, "<address %sbus='%d' device='%d'/>\n",
includeTypeInAddr ? "type='usb' " : "",
usbsrc->bus, usbsrc->device);
+ }
virXMLFormatElement(buf, "source", &sourceAttrBuf, &sourceChildBuf);
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3a97fd866c..e5f53c09ac 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -228,6 +228,7 @@ struct _virDomainHostdevSubsysUSB {
on vendor/product */
unsigned bus;
unsigned device;
+ char *port;
unsigned vendor;
unsigned product;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 3276569325..00d97f0cd8 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6687,9 +6687,14 @@
<attribute name="bus">
<ref name="usbAddr"/>
</attribute>
- <attribute name="device">
- <ref name="usbAddr"/>
- </attribute>
+ <choice>
+ <attribute name="device">
+ <ref name="usbAddr"/>
+ </attribute>
+ <attribute name="port">
+ <ref name="usbPort"/>
+ </attribute>
+ </choice>
</element>
</define>
<define name="scsiaddress">
diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c
index 0a1d8500d4..9e77477a9b 100644
--- a/src/hypervisor/virhostdev.c
+++ b/src/hypervisor/virhostdev.c
@@ -1358,6 +1358,42 @@ virHostdevMarkUSBDevices(virHostdevManager *mgr,
return -1;
}
+static int
+virHostdevFindUSBDeviceWithFlags(virDomainHostdevDef *hostdev,
+ bool mandatory,
+ unsigned int flags,
+ virUSBDevice **usb)
+{
+ virDomainHostdevSubsysUSB *usbsrc = &hostdev->source.subsys.u.usb;
+ unsigned vendor = usbsrc->vendor;
+ unsigned product = usbsrc->product;
+ unsigned bus = usbsrc->bus;
+ char *port = usbsrc->port;
+ unsigned device = usbsrc->device;
+ virUSBDeviceList *devs;
+ int rc;
+
+ rc = virUSBDeviceFind(vendor, product, bus, device, port, NULL,
+ mandatory, flags, &devs);
+ if (rc < 0)
+ return -1;
+
+ if (rc == 1) {
+ *usb = virUSBDeviceListGet(devs, 0);
+ virUSBDeviceListSteal(devs, *usb);
+ }
+ virObjectUnref(devs);
+
+ if (rc > 1) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Multiple USB devices for %1$x:%2$x, use <address> to specify one"),
+ vendor, product);
+ return -1;
+ }
+
+ return rc;
+}
+
int
virHostdevFindUSBDevice(virDomainHostdevDef *hostdev,
@@ -1366,77 +1402,64 @@ virHostdevFindUSBDevice(virDomainHostdevDef *hostdev,
{
virDomainHostdevSubsysUSB *usbsrc = &hostdev->source.subsys.u.usb;
unsigned vendor = usbsrc->vendor;
- unsigned product = usbsrc->product;
unsigned bus = usbsrc->bus;
unsigned device = usbsrc->device;
+ char *port = usbsrc->port;
bool autoAddress = usbsrc->autoAddress;
+ unsigned int flags = 0;
int rc;
*usb = NULL;
- if (vendor && bus) {
- rc = virUSBDeviceFind(vendor, product, bus, device,
- NULL,
- autoAddress ? false : mandatory,
- usb);
- if (rc < 0) {
- return -1;
- } else if (!autoAddress) {
- goto out;
- } else {
- VIR_INFO("USB device %x:%x could not be found at previous"
- " address (bus:%u device:%u)",
- vendor, product, bus, device);
- }
+ if (vendor)
+ flags |= USB_DEVICE_FIND_BY_VENDOR;
+ if (device)
+ flags |= USB_DEVICE_FIND_BY_DEVICE;
+ if (port)
+ flags |= USB_DEVICE_FIND_BY_PORT;
+
+ /* Rule out invalid cases. */
+ if (vendor && device && port) {
+ VIR_WARN("Cannot match USB device on vendor/product, bus/device, and bus/port at once. Ignoring bus/device.");
+ flags &= ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE);
+ } else if (device && port) {
+ VIR_WARN("Cannot match USB device on bus/device and bus/port at once. Ignoring bus/device.");
+ flags &= ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE);
+ } else if (!vendor && !device && !port) {
+ VIR_WARN("No matching fields for USB device found. Vendor/product, bus/device, or bus/port required.");
+ return -1;
}
- /* When vendor is specified, its USB address is either unspecified or the
- * device could not be found at the USB device where it had been
- * automatically found before.
- */
- if (vendor) {
- g_autoptr(virUSBDeviceList) devs = NULL;
+ /* First attempt, matching on all valid fields. */
+ rc = virHostdevFindUSBDeviceWithFlags(hostdev,
+ autoAddress ? false : mandatory,
+ flags, usb);
+ if (rc < 0)
+ return -1;
- rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
- if (rc < 0) {
- return -1;
- } else if (rc == 0) {
- goto out;
- } else if (rc > 1) {
- if (autoAddress) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Multiple USB devices for %1$x:%2$x were found, but none of them is at bus:%3$u device:%4$u"),
- vendor, product, bus, device);
- } else {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Multiple USB devices for %1$x:%2$x, use <address> to specify one"),
- vendor, product);
- }
+ if (rc != 1 && autoAddress && device) {
+ VIR_INFO("USB device could not be found at previous address "
+ "(bus:%u device:%u)", bus, device);
+
+ /* Second attempt, for when the device number has changed. */
+ flags &= ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE);
+ usbsrc->device = 0;
+
+ rc = virHostdevFindUSBDeviceWithFlags(hostdev, mandatory,
+ flags, usb);
+ if (rc < 0)
return -1;
- }
- *usb = virUSBDeviceListGet(devs, 0);
- virUSBDeviceListSteal(devs, *usb);
+ usbsrc->autoAddress = true;
+ }
+ if (!*usb) {
+ hostdev->missing = true;
+ } else if (!usbsrc->bus || !usbsrc->device) {
usbsrc->bus = virUSBDeviceGetBus(*usb);
usbsrc->device = virUSBDeviceGetDevno(*usb);
- usbsrc->autoAddress = true;
-
- if (autoAddress) {
- VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
- " from bus:%u device:%u)",
- vendor, product,
- usbsrc->bus, usbsrc->device,
- bus, device);
- }
- } else if (bus) {
- if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
- return -1;
}
- out:
- if (!*usb)
- hostdev->missing = true;
return 0;
}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e63939e2b5..dbc0778fdb 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3668,8 +3668,6 @@ virURIResolveAlias;
# util/virusb.h
virUSBDeviceFileIterate;
virUSBDeviceFind;
-virUSBDeviceFindByBus;
-virUSBDeviceFindByVendor;
virUSBDeviceFree;
virUSBDeviceGetBus;
virUSBDeviceGetDevno;
diff --git a/src/util/virusb.c b/src/util/virusb.c
index cf3461f80a..d193f8f3ba 100644
--- a/src/util/virusb.c
+++ b/src/util/virusb.c
@@ -61,12 +61,6 @@ struct _virUSBDeviceList {
virUSBDevice **devs;
};
-typedef enum {
- USB_DEVICE_ALL = 0,
- USB_DEVICE_FIND_BY_VENDOR = 1 << 0,
- USB_DEVICE_FIND_BY_BUS = 1 << 1,
-} virUSBDeviceFindFlags;
-
static virClass *virUSBDeviceListClass;
static void virUSBDeviceListDispose(void *obj);
@@ -102,11 +96,27 @@ static int virUSBSysReadFile(const char *f_name, const char *d_name,
return 0;
}
+static int virUSBSysReadFileStr(const char *f_name, const char *d_name,
+ char **value)
+{
+ char *buf = NULL;
+ g_autofree char *filename = NULL;
+
+ filename = g_strdup_printf(USB_SYSFS "/devices/%s/%s", d_name, f_name);
+
+ if (virFileReadAll(filename, 1024, &buf) < 0)
+ return -1;
+
+ *value = buf;
+ return 0;
+}
+
static virUSBDeviceList *
virUSBDeviceSearch(unsigned int vendor,
unsigned int product,
unsigned int bus,
unsigned int devno,
+ const char *port,
const char *vroot,
unsigned int flags)
{
@@ -127,6 +137,8 @@ virUSBDeviceSearch(unsigned int vendor,
while ((direrr = virDirRead(dir, &de, USB_SYSFS "/devices")) > 0) {
unsigned int found_prod, found_vend, found_bus, found_devno;
+ char *found_port;
+ bool port_matches;
char *tmpstr = de->d_name;
if (strchr(de->d_name, ':'))
@@ -154,16 +166,32 @@ virUSBDeviceSearch(unsigned int vendor,
10, &found_devno) < 0)
goto cleanup;
- if ((flags & USB_DEVICE_FIND_BY_VENDOR) &&
- (found_prod != product || found_vend != vendor))
- continue;
+ if (virUSBSysReadFileStr("devpath", de->d_name,
+ &found_port) < 0) {
+ goto cleanup;
+ } else {
+ found_port[strlen(found_port) - 1] = '\0'; /* remove newline */
+ port_matches = STREQ_NULLABLE(found_port, port);
+ VIR_FREE(found_port);
+ }
- if (flags & USB_DEVICE_FIND_BY_BUS) {
+ if (flags & USB_DEVICE_FIND_BY_VENDOR) {
+ if (found_prod != product || found_vend != vendor)
+ continue;
+ }
+
+ if (flags & USB_DEVICE_FIND_BY_DEVICE) {
if (found_bus != bus || found_devno != devno)
continue;
found = true;
}
+ if (flags & USB_DEVICE_FIND_BY_PORT) {
+ if (found_bus != bus || !port_matches)
+ continue;
+ found = true;
+ }
+
usb = virUSBDeviceNew(found_bus, found_devno, vroot);
if (!usb)
@@ -186,36 +214,41 @@ virUSBDeviceSearch(unsigned int vendor,
}
int
-virUSBDeviceFindByVendor(unsigned int vendor,
- unsigned int product,
- const char *vroot,
- bool mandatory,
- virUSBDeviceList **devices)
+virUSBDeviceFind(unsigned int vendor,
+ unsigned int product,
+ unsigned int bus,
+ unsigned int devno,
+ const char *port,
+ const char *vroot,
+ bool mandatory,
+ unsigned int flags,
+ virUSBDeviceList **devices)
{
virUSBDeviceList *list;
int count;
- if (!(list = virUSBDeviceSearch(vendor, product, 0, 0,
- vroot,
- USB_DEVICE_FIND_BY_VENDOR)))
+ if (!(list = virUSBDeviceSearch(vendor, product, bus, devno, port,
+ vroot, flags)))
return -1;
- if (list->count == 0) {
+ count = list->count;
+ if (count == 0) {
virObjectUnref(list);
if (!mandatory) {
- VIR_DEBUG("Did not find USB device %04x:%04x",
- vendor, product);
if (devices)
*devices = NULL;
return 0;
}
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Did not find USB device %1$04x:%2$04x"), vendor, product);
+ _("Did not find matching USB device (matching on%1$s%2$s%3$s others are ignored): vid:%4$04x, pid:%5$04x, bus:%6$u, device:%7$u, port:%8$s"),
+ flags & USB_DEVICE_FIND_BY_VENDOR ? " vid/pid," : "",
+ flags & USB_DEVICE_FIND_BY_DEVICE ? " bus/device," : "",
+ flags & USB_DEVICE_FIND_BY_PORT ? " bus/port," : "",
+ vendor, product, bus, devno, port ? port : "(null)");
return -1;
}
- count = list->count;
if (devices)
*devices = list;
else
@@ -224,86 +257,6 @@ virUSBDeviceFindByVendor(unsigned int vendor,
return count;
}
-int
-virUSBDeviceFindByBus(unsigned int bus,
- unsigned int devno,
- const char *vroot,
- bool mandatory,
- virUSBDevice **usb)
-{
- virUSBDeviceList *list;
-
- if (!(list = virUSBDeviceSearch(0, 0, bus, devno,
- vroot,
- USB_DEVICE_FIND_BY_BUS)))
- return -1;
-
- if (list->count == 0) {
- virObjectUnref(list);
- if (!mandatory) {
- VIR_DEBUG("Did not find USB device bus:%u device:%u",
- bus, devno);
- if (usb)
- *usb = NULL;
- return 0;
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Did not find USB device bus:%1$u device:%2$u"),
- bus, devno);
- return -1;
- }
-
- if (usb) {
- *usb = virUSBDeviceListGet(list, 0);
- virUSBDeviceListSteal(list, *usb);
- }
- virObjectUnref(list);
-
- return 0;
-}
-
-int
-virUSBDeviceFind(unsigned int vendor,
- unsigned int product,
- unsigned int bus,
- unsigned int devno,
- const char *vroot,
- bool mandatory,
- virUSBDevice **usb)
-{
- virUSBDeviceList *list;
-
- unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS;
- if (!(list = virUSBDeviceSearch(vendor, product, bus, devno,
- vroot, flags)))
- return -1;
-
- if (list->count == 0) {
- virObjectUnref(list);
- if (!mandatory) {
- VIR_DEBUG("Did not find USB device %04x:%04x bus:%u device:%u",
- vendor, product, bus, devno);
- if (usb)
- *usb = NULL;
- return 0;
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Did not find USB device %1$04x:%2$04x bus:%3$u device:%4$u"),
- vendor, product, bus, devno);
- return -1;
- }
-
- if (usb) {
- *usb = virUSBDeviceListGet(list, 0);
- virUSBDeviceListSteal(list, *usb);
- }
- virObjectUnref(list);
-
- return 0;
-}
-
virUSBDevice *
virUSBDeviceNew(unsigned int bus,
unsigned int devno,
diff --git a/src/util/virusb.h b/src/util/virusb.h
index d2b3f69942..cfd1ad51cc 100644
--- a/src/util/virusb.h
+++ b/src/util/virusb.h
@@ -30,30 +30,26 @@ typedef struct _virUSBDeviceList virUSBDeviceList;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virUSBDeviceList, virObjectUnref);
+typedef enum {
+ USB_DEVICE_ALL = 0,
+ USB_DEVICE_FIND_BY_VENDOR = 1 << 0,
+ USB_DEVICE_FIND_BY_DEVICE = 1 << 1,
+ USB_DEVICE_FIND_BY_PORT = 1 << 2,
+} virUSBDeviceFindFlags;
virUSBDevice *virUSBDeviceNew(unsigned int bus,
unsigned int devno,
const char *vroot);
-int virUSBDeviceFindByBus(unsigned int bus,
- unsigned int devno,
- const char *vroot,
- bool mandatory,
- virUSBDevice **usb);
-
-int virUSBDeviceFindByVendor(unsigned int vendor,
- unsigned int product,
- const char *vroot,
- bool mandatory,
- virUSBDeviceList **devices);
-
int virUSBDeviceFind(unsigned int vendor,
- unsigned int product,
- unsigned int bus,
- unsigned int devno,
- const char *vroot,
- bool mandatory,
- virUSBDevice **usb);
+ unsigned int product,
+ unsigned int bus,
+ unsigned int devno,
+ const char *port,
+ const char *vroot,
+ bool mandatory,
+ unsigned int flags,
+ virUSBDeviceList **devices);
void virUSBDeviceFree(virUSBDevice *dev);
int virUSBDeviceSetUsedBy(virUSBDevice *dev,
diff --git a/tests/virusbtest.c b/tests/virusbtest.c
index 870e136321..62b7b8bc29 100644
--- a/tests/virusbtest.c
+++ b/tests/virusbtest.c
@@ -26,9 +26,11 @@
#define VIR_FROM_THIS VIR_FROM_NONE
typedef enum {
- FIND_BY_ALL,
FIND_BY_VENDOR,
- FIND_BY_BUS
+ FIND_BY_DEVICE,
+ FIND_BY_PORT,
+ FIND_BY_VENDOR_AND_DEVICE,
+ FIND_BY_VENDOR_AND_PORT
} testUSBFindFlags;
struct findTestInfo {
@@ -37,6 +39,7 @@ struct findTestInfo {
unsigned int product;
unsigned int bus;
unsigned int devno;
+ const char *port;
const char *vroot;
bool mandatory;
int how;
@@ -70,25 +73,34 @@ static int testDeviceFind(const void *opaque)
g_autoptr(virUSBDeviceList) devs = NULL;
int rv = 0;
size_t i, ndevs = 0;
+ unsigned int flags = 0;
switch (info->how) {
- case FIND_BY_ALL:
- rv = virUSBDeviceFind(info->vendor, info->product,
- info->bus, info->devno,
- info->vroot, info->mandatory, &dev);
- break;
case FIND_BY_VENDOR:
- rv = virUSBDeviceFindByVendor(info->vendor, info->product,
- info->vroot, info->mandatory, &devs);
+ flags = USB_DEVICE_FIND_BY_VENDOR;
+ break;
+ case FIND_BY_DEVICE:
+ flags = USB_DEVICE_FIND_BY_DEVICE;
+ break;
+ case FIND_BY_PORT:
+ flags = USB_DEVICE_FIND_BY_PORT;
break;
- case FIND_BY_BUS:
- rv = virUSBDeviceFindByBus(info->bus, info->devno,
- info->vroot, info->mandatory, &dev);
+ case FIND_BY_VENDOR_AND_DEVICE:
+ flags = USB_DEVICE_FIND_BY_VENDOR |
+ USB_DEVICE_FIND_BY_DEVICE;
+ break;
+ case FIND_BY_VENDOR_AND_PORT:
+ flags = USB_DEVICE_FIND_BY_VENDOR |
+ USB_DEVICE_FIND_BY_PORT;
break;
}
+ rv = virUSBDeviceFind(info->vendor, info->product,
+ info->bus, info->devno, info->port,
+ info->vroot, info->mandatory, flags, &devs);
+
if (info->expectFailure) {
- if (rv == 0) {
+ if (rv >= 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected success");
} else {
@@ -99,9 +111,20 @@ static int testDeviceFind(const void *opaque)
goto cleanup;
}
+ if (info->how != FIND_BY_VENDOR) {
+ if (rv == 1) {
+ dev = virUSBDeviceListGet(devs, 0);
+ virUSBDeviceListSteal(devs, dev);
+ } else {
+ goto cleanup;
+ }
+ }
+
switch (info->how) {
- case FIND_BY_ALL:
- case FIND_BY_BUS:
+ case FIND_BY_DEVICE:
+ case FIND_BY_PORT:
+ case FIND_BY_VENDOR_AND_DEVICE:
+ case FIND_BY_VENDOR_AND_PORT:
if (virUSBDeviceFileIterate(dev, testDeviceFileActor, NULL) < 0)
goto cleanup;
break;
@@ -146,14 +169,17 @@ testUSBList(const void *opaque G_GNUC_UNUSED)
virUSBDeviceList *list = NULL;
virUSBDeviceList *devlist = NULL;
virUSBDevice *dev = NULL;
+ virUSBDeviceList *devs = NULL;
int ret = -1;
+ int rv;
size_t i, ndevs;
if (!(list = virUSBDeviceListNew()))
goto cleanup;
#define EXPECTED_NDEVS_ONE 3
- if (virUSBDeviceFindByVendor(0x1d6b, 0x0002, NULL, true, &devlist) < 0)
+ if (virUSBDeviceFind(0x1d6b, 0x0002, 0, 0, NULL, NULL, true,
+ USB_DEVICE_FIND_BY_VENDOR, &devlist) < 0)
goto cleanup;
ndevs = virUSBDeviceListCount(devlist);
@@ -176,7 +202,8 @@ testUSBList(const void *opaque G_GNUC_UNUSED)
goto cleanup;
#define EXPECTED_NDEVS_TWO 3
- if (virUSBDeviceFindByVendor(0x18d1, 0x4e22, NULL, true, &devlist) < 0)
+ if (virUSBDeviceFind(0x18d1, 0x4e22, 0, 0, NULL, NULL, true,
+ USB_DEVICE_FIND_BY_VENDOR, &devlist) < 0)
goto cleanup;
ndevs = virUSBDeviceListCount(devlist);
@@ -196,8 +223,16 @@ testUSBList(const void *opaque G_GNUC_UNUSED)
EXPECTED_NDEVS_ONE + EXPECTED_NDEVS_TWO) < 0)
goto cleanup;
- if (virUSBDeviceFind(0x18d1, 0x4e22, 1, 20, NULL, true, &dev) < 0)
+ rv = virUSBDeviceFind(0x18d1, 0x4e22, 1, 20, NULL, NULL, true,
+ USB_DEVICE_FIND_BY_VENDOR |
+ USB_DEVICE_FIND_BY_DEVICE, &devs);
+ if (rv != 1) {
goto cleanup;
+ } else {
+ dev = virUSBDeviceListGet(devs, 0);
+ virUSBDeviceListSteal(devs, dev);
+ }
+ virObjectUnref(devs);
if (!virUSBDeviceListFind(list, dev)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -229,49 +264,75 @@ mymain(void)
{
int rv = 0;
-#define DO_TEST_FIND_FULL(name, vend, prod, bus, devno, vroot, mand, how, fail) \
+#define DO_TEST_FIND_FULL(name, vend, prod, bus, devno, \
+ port, vroot, mand, how, fail) \
do { \
struct findTestInfo data = { name, vend, prod, bus, \
- devno, vroot, mand, how, fail \
+ devno, port, vroot, mand, how, fail \
}; \
if (virTestRun("USBDeviceFind " name, testDeviceFind, &data) < 0) \
rv = -1; \
} while (0)
-#define DO_TEST_FIND(name, vend, prod, bus, devno) \
- DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \
- FIND_BY_ALL, false)
-#define DO_TEST_FIND_FAIL(name, vend, prod, bus, devno) \
- DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \
- FIND_BY_ALL, true)
-
-#define DO_TEST_FIND_BY_BUS(name, bus, devno) \
- DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \
- FIND_BY_BUS, false)
-#define DO_TEST_FIND_BY_BUS_FAIL(name, bus, devno) \
- DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \
- FIND_BY_BUS, true)
-
#define DO_TEST_FIND_BY_VENDOR(name, vend, prod) \
- DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \
+ DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, NULL, true, \
FIND_BY_VENDOR, false)
#define DO_TEST_FIND_BY_VENDOR_FAIL(name, vend, prod) \
- DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \
+ DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, NULL, true, \
FIND_BY_VENDOR, true)
- DO_TEST_FIND("Nexus", 0x18d1, 0x4e22, 1, 20);
- DO_TEST_FIND_FAIL("Nexus wrong devnum", 0x18d1, 0x4e22, 1, 25);
- DO_TEST_FIND_FAIL("Bogus", 0xf00d, 0xbeef, 1024, 768);
-
- DO_TEST_FIND_BY_BUS("integrated camera", 1, 5);
- DO_TEST_FIND_BY_BUS_FAIL("wrong bus/devno combination", 2, 20);
- DO_TEST_FIND_BY_BUS_FAIL("missing bus", 5, 20);
- DO_TEST_FIND_BY_BUS_FAIL("missing devnum", 1, 158);
+#define DO_TEST_FIND_BY_DEVICE(name, bus, devno) \
+ DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, devno, NULL, NULL, true, \
+ FIND_BY_DEVICE, false)
+#define DO_TEST_FIND_BY_DEVICE_FAIL(name, bus, devno) \
+ DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, devno, NULL, NULL, true, \
+ FIND_BY_DEVICE, true)
+
+#define DO_TEST_FIND_BY_PORT(name, bus, port) \
+ DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, 456, port, NULL, true, \
+ FIND_BY_PORT, false)
+#define DO_TEST_FIND_BY_PORT_FAIL(name, bus, port) \
+ DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, 456, port, NULL, true, \
+ FIND_BY_PORT, true)
+
+#define DO_TEST_FIND_BY_VENDOR_AND_DEVICE(name, vend, prod, bus, devno) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, NULL, true, \
+ FIND_BY_VENDOR_AND_DEVICE, false)
+#define DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL(name, vend, prod, bus, devno) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, NULL, true, \
+ FIND_BY_VENDOR_AND_DEVICE, true)
+
+#define DO_TEST_FIND_BY_VENDOR_AND_PORT(name, vend, prod, bus, port) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, 456, port, NULL, true, \
+ FIND_BY_VENDOR_AND_PORT, false)
+#define DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL(name, vend, prod, bus, port) \
+ DO_TEST_FIND_FULL(name, vend, prod, bus, 456, port, NULL, true, \
+ FIND_BY_VENDOR_AND_PORT, true)
+
+ DO_TEST_FIND_BY_DEVICE("integrated camera", 1, 5);
+ DO_TEST_FIND_BY_DEVICE_FAIL("wrong bus/devno combination", 2, 20);
+ DO_TEST_FIND_BY_DEVICE_FAIL("missing bus", 5, 20);
+ DO_TEST_FIND_BY_DEVICE_FAIL("missing devnum", 1, 158);
DO_TEST_FIND_BY_VENDOR("Nexus (multiple results)", 0x18d1, 0x4e22);
DO_TEST_FIND_BY_VENDOR_FAIL("Bogus vendor and product", 0xf00d, 0xbeef);
DO_TEST_FIND_BY_VENDOR_FAIL("Valid vendor", 0x1d6b, 0xbeef);
+ DO_TEST_FIND_BY_PORT("Logitech mouse", 1, "1.5.3.3");
+ DO_TEST_FIND_BY_PORT_FAIL("wrong bus/port combination", 2, "1.5.3.3");
+ DO_TEST_FIND_BY_PORT_FAIL("missing bus", 5, "1.5.3.3");
+ DO_TEST_FIND_BY_PORT_FAIL("missing port", 1, "8.2.5");
+
+ DO_TEST_FIND_BY_VENDOR_AND_DEVICE("Nexus", 0x18d1, 0x4e22, 1, 20);
+ DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Bogus vendor and product", 0xf00d, 0xbeef, 1, 25);
+ DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Nexus wrong devnum", 0x18d1, 0x4e22, 1, 25);
+ DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Bogus", 0xf00d, 0xbeef, 1024, 768);
+
+ DO_TEST_FIND_BY_VENDOR_AND_PORT("Nexus", 0x046d, 0xc069, 1, "1.5.3.3");
+ DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Bogus vendor and product", 0xf00d, 0xbeef, 1, "1.5.3.3");
+ DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Nexus wrong port", 0x18d1, 0x4e22, 1, "8.2.5");
+ DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Bogus", 0xf00d, 0xbeef, 1024, "1.1.1.1");
+
if (virTestRun("USB List test", testUSBList, NULL) < 0)
rv = -1;
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath
new file mode 100644
index 0000000000..02a7fbef02
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath
@@ -0,0 +1 @@
+1.5.3.1
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath
new file mode 100644
index 0000000000..23ca863cd4
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath
@@ -0,0 +1 @@
+1.5.3.3
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath
new file mode 100644
index 0000000000..8af85beb51
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath
@@ -0,0 +1 @@
+1.5.3
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath
new file mode 100644
index 0000000000..94fe62c274
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath
@@ -0,0 +1 @@
+1.5.4
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath
new file mode 100644
index 0000000000..9075be4951
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath
@@ -0,0 +1 @@
+1.5.5
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath
new file mode 100644
index 0000000000..eac1e0ada6
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath
@@ -0,0 +1 @@
+1.5.6
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath
new file mode 100644
index 0000000000..c239c60cba
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath
@@ -0,0 +1 @@
+1.5
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath
new file mode 100644
index 0000000000..810ee4e91e
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath
@@ -0,0 +1 @@
+1.6
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath b/tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath
@@ -0,0 +1 @@
+1
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath b/tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath
new file mode 100644
index 0000000000..5625e59da8
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath
@@ -0,0 +1 @@
+1.2
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath b/tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath
@@ -0,0 +1 @@
+1
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath b/tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath
@@ -0,0 +1 @@
+0
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath b/tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath
@@ -0,0 +1 @@
+0
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath b/tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath
@@ -0,0 +1 @@
+0
diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath b/tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath
@@ -0,0 +1 @@
+0
--
2.39.5
2 weeks, 2 days
[PATCH v2 0/4] Adding POWER11 CPU Support
by Narayana Murty N
This patch series introduces the necessary changes to
support the POWER11 CPU and POWER11 host in libvirt.
Additionally, it updates the QEMU capabilities with
the latest QEMU version 9.2.1 to include POWER11 in
the capabilities tests.
Patch Summary:
Patch 0001: Remove test cases for the QEMU-dropped pseries-2.7 machine.
Patch 0002: Add capabilities test support for QEMU 9.2.0 on PPC64.
Patch 0003: Add POWER11 CPU model support.
Patch 0004: Add POWER11 host model support.
The corresponding patches for the Linux kernel and QEMU
are already upstream. Relevant links are provided below:
Linux kernel patches:
1. Linux P11 support: commit c2ed087ed35c ("powerpc: Add Power11 architected and raw mode")
2. Linux P11 KVM support: commit 96e266e3bcd6 ("KVM: PPC: Book3S HV: Add Power11 capability support for Nested PAPR guests")
Qemu patches:
3. Qemu P11 support: commit 273db89bcaf4 ("ppc/pseries: Add Power11 cpu type")
4. Qemu P11 DD02.0 support: commit c0d964076c3e ("target/ppc: Add Power11 DD2.0 processor")
Signed-off-by: Narayana Murty N <nnmlinux(a)linux.ibm.com>
----
Changelog:
-V1:https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/4A3IND2QP5CE654XE755ICRZKLUNYXAE/
*Addressed v2 patch readability issues.
*Fixed the Unit test failures at individual patch levels.
Narayana Murty N (4):
tests: Remove pseries-2.7 machine type
tests: add capabilities for QEMU 9.2.0 on ppc64
cpu_map: Add POWER11 cpu model support
cpu_ppc64: Add POWER11 host-model support
src/cpu/cpu_ppc64.c | 8 +-
src/cpu_map/index.xml | 1 +
src/cpu_map/meson.build | 1 +
src/cpu_map/ppc64_POWER11.xml | 6 +
tests/domaincapsdata/qemu_9.2.0.ppc64.xml | 190 +
.../caps_9.2.0_ppc64.replies | 39302 ++++++++++++++++
.../qemucapabilitiesdata/caps_9.2.0_ppc64.xml | 1095 +
.../ppc64-modern-bulk-result-conf.xml | 2 +-
.../ppc64-modern-bulk-result-live.xml | 2 +-
.../ppc64-modern-individual-result-conf.xml | 2 +-
.../ppc64-modern-individual-result-live.xml | 2 +-
.../disk-floppy-pseries.ppc64-latest.xml | 2 +-
...-nvdimm-ppc64.ppc64-latest.abi-update.args | 2 +-
...g-nvdimm-ppc64.ppc64-latest.abi-update.xml | 2 +-
...ory-hotplug-nvdimm-ppc64.ppc64-latest.args | 2 +-
...mory-hotplug-nvdimm-ppc64.ppc64-latest.xml | 2 +-
...-ppc64-nonuma.ppc64-latest.abi-update.args | 2 +-
...g-ppc64-nonuma.ppc64-latest.abi-update.xml | 2 +-
...ory-hotplug-ppc64-nonuma.ppc64-latest.args | 2 +-
...mory-hotplug-ppc64-nonuma.ppc64-latest.xml | 2 +-
.../panic-pseries.ppc64-latest.args | 2 +-
.../panic-pseries.ppc64-latest.xml | 2 +-
...ault-cpu-kvm-pseries-2.7.ppc64-latest.args | 38 -
...fault-cpu-kvm-pseries-2.7.ppc64-latest.xml | 49 -
.../ppc64-default-cpu-kvm-pseries-2.7.xml | 22 -
...ault-cpu-kvm-pseries-3.1.ppc64-latest.args | 2 +-
...fault-cpu-kvm-pseries-3.1.ppc64-latest.xml | 2 +-
...ault-cpu-kvm-pseries-4.2.ppc64-latest.args | 2 +-
...fault-cpu-kvm-pseries-4.2.ppc64-latest.xml | 2 +-
...ault-cpu-tcg-pseries-2.7.ppc64-latest.args | 38 -
...fault-cpu-tcg-pseries-2.7.ppc64-latest.xml | 49 -
.../ppc64-default-cpu-tcg-pseries-2.7.xml | 22 -
...ault-cpu-tcg-pseries-4.2.ppc64-latest.args | 2 +-
...fault-cpu-tcg-pseries-4.2.ppc64-latest.xml | 2 +-
...efault-models.ppc64-latest.abi-update.args | 4 +-
...default-models.ppc64-latest.abi-update.xml | 2 +-
...4-pseries-default-models.ppc64-latest.args | 4 +-
...64-pseries-default-models.ppc64-latest.xml | 2 +-
.../ppc64-pseries-graphics.ppc64-latest.args | 4 +-
.../ppc64-pseries-graphics.ppc64-latest.xml | 2 +-
.../ppc64-pseries-headless.ppc64-latest.args | 4 +-
.../ppc64-pseries-headless.ppc64-latest.xml | 2 +-
...eries-minimal.ppc64-latest.abi-update.args | 2 +-
...series-minimal.ppc64-latest.abi-update.xml | 2 +-
.../ppc64-pseries-minimal.ppc64-latest.args | 2 +-
.../ppc64-pseries-minimal.ppc64-latest.xml | 2 +-
.../ppc64-tpmproxy-single.ppc64-latest.args | 2 +-
.../ppc64-tpmproxy-single.ppc64-latest.xml | 2 +-
.../ppc64-tpmproxy-with-tpm.ppc64-latest.args | 2 +-
.../ppc64-tpmproxy-with-tpm.ppc64-latest.xml | 2 +-
.../pseries-basic.ppc64-latest.args | 2 +-
.../pseries-basic.ppc64-latest.xml | 2 +-
.../pseries-console-virtio.ppc64-latest.args | 2 +-
.../pseries-console-virtio.ppc64-latest.xml | 2 +-
...eries-cpu-compat-power11.ppc64-latest.args | 31 +
...series-cpu-compat-power11.ppc64-latest.err | 1 +
...series-cpu-compat-power11.ppc64-latest.xml | 29 +
.../pseries-cpu-compat-power11.xml | 19 +
.../pseries-cpu-le.ppc64-latest.args | 2 +-
.../pseries-cpu-le.ppc64-latest.xml | 2 +-
.../pseries-features.ppc64-latest.args | 2 +-
.../pseries-features.ppc64-latest.xml | 2 +-
.../pseries-hostdevs-1.ppc64-latest.args | 2 +-
.../pseries-hostdevs-1.ppc64-latest.xml | 2 +-
.../pseries-hostdevs-2.ppc64-latest.args | 2 +-
.../pseries-hostdevs-2.ppc64-latest.xml | 2 +-
.../pseries-hostdevs-3.ppc64-latest.args | 2 +-
.../pseries-hostdevs-3.ppc64-latest.xml | 2 +-
.../pseries-many-buses-1.ppc64-latest.args | 2 +-
.../pseries-many-buses-1.ppc64-latest.xml | 2 +-
.../pseries-many-buses-2.ppc64-latest.args | 2 +-
.../pseries-many-buses-2.ppc64-latest.xml | 2 +-
.../pseries-many-devices.ppc64-latest.args | 2 +-
.../pseries-many-devices.ppc64-latest.xml | 2 +-
.../pseries-nvram.ppc64-latest.args | 2 +-
.../pseries-nvram.ppc64-latest.xml | 2 +-
.../pseries-panic-missing.ppc64-latest.args | 2 +-
.../pseries-panic-missing.ppc64-latest.xml | 2 +-
...pseries-panic-no-address.ppc64-latest.args | 2 +-
.../pseries-panic-no-address.ppc64-latest.xml | 2 +-
...ries-phb-default-missing.ppc64-latest.args | 2 +-
...eries-phb-default-missing.ppc64-latest.xml | 2 +-
.../pseries-phb-numa-node.ppc64-latest.args | 2 +-
.../pseries-phb-numa-node.ppc64-latest.xml | 2 +-
.../pseries-phb-simple.ppc64-latest.args | 6 +-
.../pseries-phb-simple.ppc64-latest.xml | 2 +-
.../pseries-phb-user-alias.ppc64-latest.args | 6 +-
.../pseries-phb-user-alias.ppc64-latest.xml | 2 +-
.../pseries-serial-native.ppc64-latest.args | 2 +-
.../pseries-serial-native.ppc64-latest.xml | 2 +-
.../pseries-serial-pci.ppc64-latest.args | 2 +-
.../pseries-serial-pci.ppc64-latest.xml | 2 +-
.../pseries-serial-usb.ppc64-latest.args | 2 +-
.../pseries-serial-usb.ppc64-latest.xml | 2 +-
.../pseries-usb-default.ppc64-latest.args | 2 +-
.../pseries-usb-default.ppc64-latest.xml | 2 +-
.../pseries-usb-kbd.ppc64-latest.args | 2 +-
.../pseries-usb-kbd.ppc64-latest.xml | 2 +-
.../pseries-usb-multi.ppc64-latest.args | 2 +-
.../pseries-usb-multi.ppc64-latest.xml | 2 +-
...series-vio-user-assigned.ppc64-latest.args | 7 +-
...pseries-vio-user-assigned.ppc64-latest.xml | 2 +-
.../pseries-vio.ppc64-latest.args | 7 +-
.../pseries-vio.ppc64-latest.xml | 2 +-
...fault-pseries.ppc64-latest.abi-update.args | 2 +-
...efault-pseries.ppc64-latest.abi-update.xml | 2 +-
...ntroller-default-pseries.ppc64-latest.args | 2 +-
...ontroller-default-pseries.ppc64-latest.xml | 2 +-
...fault-unavailable-pseries.ppc64-latest.xml | 2 +-
tests/qemuxmlconftest.c | 6 +-
tests/testutilshostcpus.h | 11 +
tests/testutilsqemu.c | 4 +
tests/testutilsqemu.h | 1 +
113 files changed, 40803 insertions(+), 330 deletions(-)
create mode 100644 src/cpu_map/ppc64_POWER11.xml
create mode 100644 tests/domaincapsdata/qemu_9.2.0.ppc64.xml
create mode 100644 tests/qemucapabilitiesdata/caps_9.2.0_ppc64.replies
create mode 100644 tests/qemucapabilitiesdata/caps_9.2.0_ppc64.xml
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-kvm-pseries-2.7.ppc64-latest.args
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-kvm-pseries-2.7.ppc64-latest.xml
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-kvm-pseries-2.7.xml
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-tcg-pseries-2.7.ppc64-latest.args
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-tcg-pseries-2.7.ppc64-latest.xml
delete mode 100644 tests/qemuxmlconfdata/ppc64-default-cpu-tcg-pseries-2.7.xml
create mode 100644 tests/qemuxmlconfdata/pseries-cpu-compat-power11.ppc64-latest.args
create mode 100644 tests/qemuxmlconfdata/pseries-cpu-compat-power11.ppc64-latest.err
create mode 100644 tests/qemuxmlconfdata/pseries-cpu-compat-power11.ppc64-latest.xml
create mode 100644 tests/qemuxmlconfdata/pseries-cpu-compat-power11.xml
--
2.48.1
2 weeks, 3 days
[PATCH v3 00/20] Add qemu RDP server support
by marcandre.lureau@redhat.com
From: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Hi,
This patch series offers an out-of-process Remote Desktop Protocol (RDP)
server solution utilizing QEMU's -display dbus interface, offering improved
modularity and potential security benefits compared to built-in server.
This initiative was spearheaded by Mihnea Buzatu during the QEMU Summer of Code
2023. The project's goal was to develop an out-of-process RDP server using the
-display dbus interface, implemented in Rust. Given that the IronRDP crate
lacked some server support at the time, investments in IronRDP were required.
I finally released an initial v0.1 version of qemu-rdp on crates.io
(https://crates.io/crates/qemu-rdp). That should allow more people to review and
evaluate the state of this work.
On unix systems, with cargo/rust toolchain installed, it should be as easy as
running "cargo install qemu-rdp", apply this patch series for libvirt, set the
"rdp_tls_x509_cert_dir" location for your TLS certificates, and configure a VM
with both dbus & rdp graphics (run "virsh domdisplay DOMAIN" to get the display
connection details).
Thanks for the reviews & feedback!
v3: thanks to Martin Kletzander review
- drop "[PATCH v2 05/21] qemu: fall-through for unsupported graphics" patch
- drop extra \n when reporting dbus-daemon log
- check password != NULL or VIR_ERR_INTERNAL_ERROR
- remove some needless #include/leftover
- remove some needless g_auto pointer
- rebased
- add r-b tags
v2: thanks to Daniel review
- drop extra error report from "qemu: report an error for unsupported graphics"
- replace g_return pre-conditions with ATTRIBUTE_NONNULL
- improve "qemu/dbus: keep a connection to the VM D-Bus" to also reconnect
- use domainLogContext for logging (for virtiofs as well)
- check for qemu-rdp availabilty for setting 'rdp' capability
- make dbus-addr qemu-rdp capability mandatory
- rebased
- add r-b tags
Marc-André Lureau (20):
build-sys: drop -Winline when optimization=g
build: fix -Werror=maybe-uninitialized
qemu-slirp: drop unneeded check for OOM
util: annotate non-null arguments for virGDBusCallMethod()
qemu: add rdp state directory
qemu: add qemu RDP configuration
conf: parse optional RDP username & password
conf: generalize virDomainDefHasSpiceGraphics
qemu: use virDomainDefHasGraphics
qemu: add RDP ports range allocator
qemu: limit to one <graphics type='rdp'>
qemu/virtiofs: use domainLogContext
qemu/dbus: keep a connection to the VM D-Bus
qemu/dbus: log daemon stdout/err, use domainLogContext
qemu: validate RDP configuration
qemu: add qemu-rdp helper unit
qemu: pass virQEMUDriverConfig to capabilities
qemu: add 'rdp' capability if qemu-rdp is available
qemu: add RDP support
tests: add qemu <graphics type='rdp'/> test
docs/formatdomain.rst | 25 +-
meson.build | 7 +-
po/POTFILES | 1 +
src/conf/domain_conf.c | 28 +-
src/conf/domain_conf.h | 5 +-
src/conf/schemas/domaincommon.rng | 10 +
src/libvirt_private.syms | 2 +-
src/qemu/libvirtd_qemu.aug | 7 +
src/qemu/meson.build | 1 +
src/qemu/qemu.conf.in | 31 ++
src/qemu/qemu_capabilities.c | 24 +-
src/qemu/qemu_capabilities.h | 12 +-
src/qemu/qemu_command.c | 8 +-
src/qemu/qemu_conf.c | 56 ++-
src/qemu/qemu_conf.h | 13 +
src/qemu/qemu_dbus.c | 69 ++-
src/qemu/qemu_dbus.h | 3 +
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 4 +
src/qemu/qemu_driver.c | 20 +
src/qemu/qemu_extdevice.c | 46 +-
src/qemu/qemu_hotplug.c | 51 ++-
src/qemu/qemu_hotplug.h | 1 +
src/qemu/qemu_process.c | 169 ++++++-
src/qemu/qemu_rdp.c | 424 ++++++++++++++++++
src/qemu/qemu_rdp.h | 73 +++
src/qemu/qemu_slirp.c | 6 -
src/qemu/qemu_validate.c | 48 +-
src/qemu/qemu_virtiofs.c | 53 +--
src/qemu/test_libvirtd_qemu.aug.in | 5 +
src/util/virgdbus.h | 13 +-
.../qemu_10.0.0-q35.x86_64+amdsev.xml | 1 +
.../domaincapsdata/qemu_10.0.0-q35.x86_64.xml | 1 +
.../qemu_10.0.0-tcg.x86_64+amdsev.xml | 1 +
.../domaincapsdata/qemu_10.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_10.0.0.s390x.xml | 1 +
.../qemu_10.0.0.x86_64+amdsev.xml | 1 +
tests/domaincapsdata/qemu_10.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 1 +
.../qemu_7.2.0-hvf.x86_64+hvf.xml | 1 +
.../domaincapsdata/qemu_7.2.0-q35.x86_64.xml | 1 +
.../qemu_7.2.0-tcg.x86_64+hvf.xml | 1 +
.../domaincapsdata/qemu_7.2.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.2.0.ppc.xml | 1 +
tests/domaincapsdata/qemu_7.2.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_8.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.1.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.1.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_8.1.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_8.1.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.2.0-q35.x86_64.xml | 1 +
.../qemu_8.2.0-tcg-virt.loongarch64.xml | 1 +
.../domaincapsdata/qemu_8.2.0-tcg.x86_64.xml | 1 +
.../qemu_8.2.0-virt.aarch64.xml | 1 +
.../qemu_8.2.0-virt.loongarch64.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.aarch64.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.armv7l.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_9.0.0.sparc.xml | 1 +
tests/domaincapsdata/qemu_9.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.1.0-q35.x86_64.xml | 1 +
.../qemu_9.1.0-tcg-virt.riscv64.xml | 1 +
.../domaincapsdata/qemu_9.1.0-tcg.x86_64.xml | 1 +
.../qemu_9.1.0-virt.riscv64.xml | 1 +
tests/domaincapsdata/qemu_9.1.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_9.1.0.x86_64.xml | 1 +
.../qemu_9.2.0-hvf.aarch64+hvf.xml | 1 +
.../qemu_9.2.0-q35.x86_64+amdsev.xml | 1 +
.../domaincapsdata/qemu_9.2.0-q35.x86_64.xml | 1 +
.../qemu_9.2.0-tcg.x86_64+amdsev.xml | 1 +
.../domaincapsdata/qemu_9.2.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_9.2.0.s390x.xml | 1 +
.../qemu_9.2.0.x86_64+amdsev.xml | 1 +
tests/domaincapsdata/qemu_9.2.0.x86_64.xml | 1 +
tests/domaincapstest.c | 7 +-
.../graphics-rdp.x86_64-latest.args | 35 ++
.../graphics-rdp.x86_64-latest.xml | 1 +
tests/qemuxmlconfdata/graphics-rdp.xml | 43 ++
tests/qemuxmlconftest.c | 2 +
tests/testutilsqemu.c | 10 +
tools/nss/libvirt_nss_leases.c | 2 +-
tools/nss/libvirt_nss_macs.c | 2 +-
92 files changed, 1234 insertions(+), 137 deletions(-)
create mode 100644 src/qemu/qemu_rdp.c
create mode 100644 src/qemu/qemu_rdp.h
create mode 100644 tests/qemuxmlconfdata/graphics-rdp.x86_64-latest.args
create mode 120000 tests/qemuxmlconfdata/graphics-rdp.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/graphics-rdp.xml
--
2.47.0
2 weeks, 6 days
[PATCH] libxl_conf: Implement hyperv domain flags for Xen
by Will
Adds support for configuring <hyperv/> flags for domains
running under Xen.
The following flags, making use of QEMU's existing flags, are now
configurable for Xen: vapic, synic, stimer, frequencies, tlbflush and
ipi
Tests have been added validating translation to libxl's viridian flags
Updated docs section on <hyperv/> flags to note support and to specify
which flags work with Xen
Signed-off-by: Will <tcosprojects(a)gmail.com>
---
NEWS.rst | 5 +
docs/formatdomain.rst | 20 +--
src/libxl/libxl_conf.c | 90 ++++++++++
.../viridian-hvm-full.json | 101 ++++++++++++
.../viridian-hvm-full.xml | 45 +++++
.../viridian-hvm-none.json | 89 ++++++++++
.../viridian-hvm-none.xml | 36 ++++
.../libxlxml2domconfigdata/viridian-hvm.json | 99 +++++++++++
tests/libxlxml2domconfigdata/viridian-hvm.xml | 42 +++++
.../viridian-passthrough.json | 155 ++++++++++++++++++
.../viridian-passthrough.xml | 37 +++++
tests/libxlxml2domconfigtest.c | 9 +
12 files changed, 718 insertions(+), 10 deletions(-)
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm-full.json
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm-full.xml
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm-none.json
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm-none.xml
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm.json
create mode 100644 tests/libxlxml2domconfigdata/viridian-hvm.xml
create mode 100644 tests/libxlxml2domconfigdata/viridian-passthrough.json
create mode 100644 tests/libxlxml2domconfigdata/viridian-passthrough.xml
diff --git a/NEWS.rst b/NEWS.rst
index 9c940b1a81..d6ad961f56 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -17,6 +17,11 @@ v11.2.0 (unreleased)
* **New features**
+ * Support for configuration of ``<hyperv/>`` flags for Xen domains.
+
+ The following flags are now configurable for Xen: ``vapic``, ``synic``,
+ ``stimer``, ``frequencies``, ``tlbflush`` and ``ipi``.
+
* **Improvements**
* **Bug fixes**
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index cbe378e61d..4162ae7930 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -2084,31 +2084,31 @@ are:
based virtualization drivers, such as LXC.
``hyperv``
Enable various features improving behavior of guests running Microsoft
- Windows.
+ Windows. :since:`Since 11.2.0` some of these flags are also available for Xen domains running Microsoft Windows.
=============== ====================================================================== ============================================ ========================================================================
Feature Description Value Since
=============== ====================================================================== ============================================ ========================================================================
- relaxed Relax constraints on timers on, off :since:`1.0.0 (QEMU 2.0)`
- vapic Enable virtual APIC on, off :since:`1.1.0 (QEMU 2.0)`
+ relaxed Relax constraints on timers on, off :since:`1.0.0 (QEMU 2.0), 11.2.0 (Xen, always on)`
+ vapic Enable virtual APIC on, off :since:`1.1.0 (QEMU 2.0), 11.2.0 (Xen)`
spinlocks Enable spinlock support on, off; retries - at least 4095 :since:`1.1.0 (QEMU 2.0)`
- vpindex Virtual processor index on, off :since:`1.3.3 (QEMU 2.5)`
+ vpindex Virtual processor index on, off :since:`1.3.3 (QEMU 2.5), 11.2.0 (Xen, always on)`
runtime Processor time spent on running guest code and on behalf of guest code on, off :since:`1.3.3 (QEMU 2.5)`
- synic Enable Synthetic Interrupt Controller (SynIC) on, off :since:`1.3.3 (QEMU 2.6)`
- stimer Enable SynIC timers, optionally with Direct Mode support on, off; direct - on,off :since:`1.3.3 (QEMU 2.6), direct mode 5.7.0 (QEMU 4.1)`
+ synic Enable Synthetic Interrupt Controller (SynIC) on, off :since:`1.3.3 (QEMU 2.6), 11.2.0 (Xen)`
+ stimer Enable SynIC timers, optionally with Direct Mode support on, off; direct - on,off :since:`1.3.3 (QEMU 2.6), direct mode 5.7.0 (QEMU 4.1), 11.2.0 (Xen, on/off only)`
reset Enable hypervisor reset on, off :since:`1.3.3 (QEMU 2.5)`
vendor_id Set hypervisor vendor id on, off; value - string, up to 12 characters :since:`1.3.3 (QEMU 2.5)`
- frequencies Expose frequency MSRs on, off :since:`4.7.0 (QEMU 2.12)`
+ frequencies Expose frequency MSRs on, off :since:`4.7.0 (QEMU 2.12), 11.2.0 (Xen)`
reenlightenment Enable re-enlightenment notification on migration on, off :since:`4.7.0 (QEMU 3.0)`
- tlbflush Enable PV TLB flush support on, off; direct - on,off; extended - on,off :since:`4.7.0 (QEMU 3.0), direct and extended modes 11.0.0 (QEMU 7.1.0)`
- ipi Enable PV IPI support on, off :since:`4.10.0 (QEMU 3.1)`
+ tlbflush Enable PV TLB flush support on, off; direct - on,off; extended - on,off :since:`4.7.0 (QEMU 3.0), direct and extended modes 11.0.0 (QEMU 7.1.0), 11.2.0 (Xen, on/off only)`
+ ipi Enable PV IPI support on, off :since:`4.10.0 (QEMU 3.1), 11.2.0 (Xen)`
evmcs Enable Enlightened VMCS on, off :since:`4.10.0 (QEMU 3.1)`
avic Enable use Hyper-V SynIC with hardware APICv/AVIC on, off :since:`8.10.0 (QEMU 6.2)`
emsr_bitmap Avoid unnecessary updates to L2 MSR Bitmap upon vmexits. on, off :since:`10.7.0 (QEMU 7.1)`
xmm_input Enable XMM Fast Hypercall Input on, off :since:`10.7.0 (QEMU 7.1)`
=============== ====================================================================== ============================================ ========================================================================
- :since:`Since 8.0.0`, the hypervisor can be configured further by setting
+ :since:`Since 8.0.0 (QEMU) Since 11.2.0 (Xen)`, the hypervisor can be configured further by setting
the ``mode`` attribute to one of the following values:
``custom``
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index c404226e43..d79cf93573 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -582,6 +582,96 @@ libxlMakeDomBuildInfo(virDomainDef *def,
VIR_TRISTATE_SWITCH_ON);
#endif
+#ifdef LIBXL_HAVE_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE
+ if (def->features[VIR_DOMAIN_FEATURE_HYPERV] != VIR_DOMAIN_HYPERV_MODE_NONE) {
+ libxl_bitmap_alloc(ctx, &b_info->u.hvm.viridian_enable,
+ LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH);
+
+ switch ((virDomainHyperVMode) def->features[VIR_DOMAIN_FEATURE_HYPERV]) {
+ case VIR_DOMAIN_HYPERV_MODE_CUSTOM:
+ // Base is required by Xen to enable any other flag
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_BASE);
+ // Enable crash ctl register by default to allow guest logs to reach Xen
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_CRASH_CTL);
+ break;
+ case VIR_DOMAIN_HYPERV_MODE_PASSTHROUGH:
+ libxl_bitmap_set_any(&b_info->u.hvm.viridian_enable);
+ break;
+ case VIR_DOMAIN_HYPERV_MODE_NONE:
+ case VIR_DOMAIN_HYPERV_MODE_LAST:
+ default:
+ virReportEnumRangeError(virDomainHyperVMode,
+ def->features[VIR_DOMAIN_FEATURE_HYPERV]);
+ return -1;
+ }
+
+ for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
+ switch ((virDomainHyperv) i) {
+ case VIR_DOMAIN_HYPERV_VPINDEX:
+ case VIR_DOMAIN_HYPERV_RELAXED:
+ // Already set by base flag
+ break;
+ case VIR_DOMAIN_HYPERV_SYNIC:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_SYNIC);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_STIMER:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ // STIMER implies synic and clock features
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_STIMER);
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_SYNIC);
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_TIME_REF_COUNT);
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_REFERENCE_TSC);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_VAPIC:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_APIC_ASSIST);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_FREQUENCIES:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_FREQ);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_TLBFLUSH:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_HCALL_REMOTE_TLB_FLUSH);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_IPI:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ libxl_bitmap_set(&b_info->u.hvm.viridian_enable, LIBXL_VIRIDIAN_ENLIGHTENMENT_HCALL_IPI);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_SPINLOCKS:
+ case VIR_DOMAIN_HYPERV_VENDOR_ID:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ const char *name = virDomainHypervTypeToString(i);
+ VIR_WARN("Hyper-v flag '%s' is specified per-domain but is a global Xen setting and will be ignored.", name);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_RUNTIME:
+ case VIR_DOMAIN_HYPERV_RESET:
+ case VIR_DOMAIN_HYPERV_REENLIGHTENMENT:
+ case VIR_DOMAIN_HYPERV_EVMCS:
+ case VIR_DOMAIN_HYPERV_AVIC:
+ case VIR_DOMAIN_HYPERV_EMSR_BITMAP:
+ case VIR_DOMAIN_HYPERV_XMM_INPUT:
+ if (def->hyperv_features[i] == VIR_TRISTATE_SWITCH_ON) {
+ const char *name = virDomainHypervTypeToString(i);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Hyper-v enlightenment feature '%1$s' is not supported for Xen domains."), name);
+ }
+ break;
+ case VIR_DOMAIN_HYPERV_LAST:
+ break;
+ }
+ }
+ }
+#endif
+
/* copy SLIC table path to acpi_firmware */
b_info->u.hvm.acpi_firmware = g_strdup(def->os.slic_table);
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm-full.json b/tests/libxlxml2domconfigdata/viridian-hvm-full.json
new file mode 100644
index 0000000000..5cb69f7b5d
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm-full.json
@@ -0,0 +1,101 @@
+{
+ "c_info": {
+ "type": "hvm",
+ "name": "test-hvm",
+ "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+ },
+ "b_info": {
+ "max_vcpus": 4,
+ "avail_vcpus": [
+ 0,
+ 1,
+ 2,
+ 3
+ ],
+ "max_memkb": 1048576,
+ "target_memkb": 1048576,
+ "video_memkb": 8192,
+ "shadow_memkb": 1234,
+ "device_model_version": "qemu_xen",
+ "device_model": "/bin/true",
+ "sched_params": {
+
+ },
+ "apic": "True",
+ "acpi": "True",
+ "type.hvm": {
+ "pae": "True",
+ "viridian_enable": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "vga": {
+ "kind": "cirrus"
+ },
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ },
+ "spice": {
+
+ },
+ "boot": "c",
+ "rdm": {
+
+ }
+ },
+ "arch_arm": {
+
+ }
+ },
+ "disks": [
+ {
+ "pdev_path": "/var/lib/xen/images/test-hvm.img",
+ "vdev": "hda",
+ "backend": "qdisk",
+ "format": "raw",
+ "removable": 1,
+ "readwrite": 1
+ }
+ ],
+ "nics": [
+ {
+ "devid": 0,
+ "mac": "00:16:3e:66:12:b4",
+ "bridge": "br0",
+ "script": "/etc/xen/scripts/vif-bridge",
+ "nictype": "vif_ioemu"
+ }
+ ],
+ "vfbs": [
+ {
+ "devid": -1,
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ }
+ }
+ ],
+ "vkbs": [
+ {
+ "devid": -1
+ }
+ ],
+ "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm-full.xml b/tests/libxlxml2domconfigdata/viridian-hvm-full.xml
new file mode 100644
index 0000000000..17f5ed5209
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm-full.xml
@@ -0,0 +1,45 @@
+<domain type='xen'>
+ <name>test-hvm</name>
+ <description>None</description>
+ <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+ <memory>1048576</memory>
+ <currentMemory>1048576</currentMemory>
+ <vcpu>4</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <clock offset='utc'/>
+ <os>
+ <type>hvm</type>
+ <loader>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <apic/>
+ <acpi/>
+ <pae/>
+ <hyperv>
+ <vapic state='on'/>
+ <vpindex state='on'/>
+ <synic state='on'/>
+ <stimer state='on'/>
+ <frequencies state='on'/>
+ <tlbflush state='on'/>
+ <ipi state='on'/>
+ </hyperv>
+ </features>
+ <devices>
+ <emulator>/bin/true</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu'/>
+ <source file='/var/lib/xen/images/test-hvm.img'/>
+ <target dev='hda'/>
+ </disk>
+ <interface type='bridge'>
+ <source bridge='br0'/>
+ <mac address='00:16:3e:66:12:b4'/>
+ <script path='/etc/xen/scripts/vif-bridge'/>
+ </interface>
+ <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+ </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm-none.json b/tests/libxlxml2domconfigdata/viridian-hvm-none.json
new file mode 100644
index 0000000000..d30875420d
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm-none.json
@@ -0,0 +1,89 @@
+{
+ "c_info": {
+ "type": "hvm",
+ "name": "test-hvm",
+ "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+ },
+ "b_info": {
+ "max_vcpus": 4,
+ "avail_vcpus": [
+ 0,
+ 1,
+ 2,
+ 3
+ ],
+ "max_memkb": 1048576,
+ "target_memkb": 1048576,
+ "video_memkb": 8192,
+ "shadow_memkb": 1234,
+ "device_model_version": "qemu_xen",
+ "device_model": "/bin/true",
+ "sched_params": {
+
+ },
+ "apic": "True",
+ "acpi": "True",
+ "type.hvm": {
+ "pae": "True",
+ "vga": {
+ "kind": "cirrus"
+ },
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ },
+ "spice": {
+
+ },
+ "boot": "c",
+ "rdm": {
+
+ }
+ },
+ "arch_arm": {
+
+ }
+ },
+ "disks": [
+ {
+ "pdev_path": "/var/lib/xen/images/test-hvm.img",
+ "vdev": "hda",
+ "backend": "qdisk",
+ "format": "raw",
+ "removable": 1,
+ "readwrite": 1
+ }
+ ],
+ "nics": [
+ {
+ "devid": 0,
+ "mac": "00:16:3e:66:12:b4",
+ "bridge": "br0",
+ "script": "/etc/xen/scripts/vif-bridge",
+ "nictype": "vif_ioemu"
+ }
+ ],
+ "vfbs": [
+ {
+ "devid": -1,
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ }
+ }
+ ],
+ "vkbs": [
+ {
+ "devid": -1
+ }
+ ],
+ "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm-none.xml b/tests/libxlxml2domconfigdata/viridian-hvm-none.xml
new file mode 100644
index 0000000000..68c2ef08af
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm-none.xml
@@ -0,0 +1,36 @@
+<domain type='xen'>
+ <name>test-hvm</name>
+ <description>None</description>
+ <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+ <memory>1048576</memory>
+ <currentMemory>1048576</currentMemory>
+ <vcpu>4</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <clock offset='utc'/>
+ <os>
+ <type>hvm</type>
+ <loader>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <apic/>
+ <acpi/>
+ <pae/>
+ </features>
+ <devices>
+ <emulator>/bin/true</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu'/>
+ <source file='/var/lib/xen/images/test-hvm.img'/>
+ <target dev='hda'/>
+ </disk>
+ <interface type='bridge'>
+ <source bridge='br0'/>
+ <mac address='00:16:3e:66:12:b4'/>
+ <script path='/etc/xen/scripts/vif-bridge'/>
+ </interface>
+ <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+ </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm.json b/tests/libxlxml2domconfigdata/viridian-hvm.json
new file mode 100644
index 0000000000..4f9a52ed89
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm.json
@@ -0,0 +1,99 @@
+{
+ "c_info": {
+ "type": "hvm",
+ "name": "test-hvm",
+ "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+ },
+ "b_info": {
+ "max_vcpus": 4,
+ "avail_vcpus": [
+ 0,
+ 1,
+ 2,
+ 3
+ ],
+ "max_memkb": 1048576,
+ "target_memkb": 1048576,
+ "video_memkb": 8192,
+ "shadow_memkb": 1234,
+ "device_model_version": "qemu_xen",
+ "device_model": "/bin/true",
+ "sched_params": {
+
+ },
+ "apic": "True",
+ "acpi": "True",
+ "type.hvm": {
+ "pae": "True",
+ "viridian_enable": [
+ 0,
+ 2,
+ 3,
+ 4,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "vga": {
+ "kind": "cirrus"
+ },
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ },
+ "spice": {
+
+ },
+ "boot": "c",
+ "rdm": {
+
+ }
+ },
+ "arch_arm": {
+
+ }
+ },
+ "disks": [
+ {
+ "pdev_path": "/var/lib/xen/images/test-hvm.img",
+ "vdev": "hda",
+ "backend": "qdisk",
+ "format": "raw",
+ "removable": 1,
+ "readwrite": 1
+ }
+ ],
+ "nics": [
+ {
+ "devid": 0,
+ "mac": "00:16:3e:66:12:b4",
+ "bridge": "br0",
+ "script": "/etc/xen/scripts/vif-bridge",
+ "nictype": "vif_ioemu"
+ }
+ ],
+ "vfbs": [
+ {
+ "devid": -1,
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ }
+ }
+ ],
+ "vkbs": [
+ {
+ "devid": -1
+ }
+ ],
+ "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/viridian-hvm.xml b/tests/libxlxml2domconfigdata/viridian-hvm.xml
new file mode 100644
index 0000000000..c6139885aa
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-hvm.xml
@@ -0,0 +1,42 @@
+<domain type='xen'>
+ <name>test-hvm</name>
+ <description>None</description>
+ <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+ <memory>1048576</memory>
+ <currentMemory>1048576</currentMemory>
+ <vcpu>4</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <clock offset='utc'/>
+ <os>
+ <type>hvm</type>
+ <loader>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <apic/>
+ <acpi/>
+ <pae/>
+ <hyperv mode="custom">
+ <synic state='on'/>
+ <stimer state='on'/>
+ <tlbflush state='on'/>
+ <ipi state='on'/>
+ </hyperv>
+ </features>
+ <devices>
+ <emulator>/bin/true</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu'/>
+ <source file='/var/lib/xen/images/test-hvm.img'/>
+ <target dev='hda'/>
+ </disk>
+ <interface type='bridge'>
+ <source bridge='br0'/>
+ <mac address='00:16:3e:66:12:b4'/>
+ <script path='/etc/xen/scripts/vif-bridge'/>
+ </interface>
+ <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+ </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigdata/viridian-passthrough.json b/tests/libxlxml2domconfigdata/viridian-passthrough.json
new file mode 100644
index 0000000000..66069931f6
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-passthrough.json
@@ -0,0 +1,155 @@
+{
+ "c_info": {
+ "type": "hvm",
+ "name": "test-hvm",
+ "uuid": "2147d599-9cc6-c0dc-92ab-4064b5446e9b"
+ },
+ "b_info": {
+ "max_vcpus": 4,
+ "avail_vcpus": [
+ 0,
+ 1,
+ 2,
+ 3
+ ],
+ "max_memkb": 1048576,
+ "target_memkb": 1048576,
+ "video_memkb": 8192,
+ "shadow_memkb": 1234,
+ "device_model_version": "qemu_xen",
+ "device_model": "/bin/true",
+ "sched_params": {
+
+ },
+ "apic": "True",
+ "acpi": "True",
+ "type.hvm": {
+ "pae": "True",
+ "viridian_enable": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63
+ ],
+ "vga": {
+ "kind": "cirrus"
+ },
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ },
+ "spice": {
+
+ },
+ "boot": "c",
+ "rdm": {
+
+ }
+ },
+ "arch_arm": {
+
+ }
+ },
+ "disks": [
+ {
+ "pdev_path": "/var/lib/xen/images/test-hvm.img",
+ "vdev": "hda",
+ "backend": "qdisk",
+ "format": "raw",
+ "removable": 1,
+ "readwrite": 1
+ }
+ ],
+ "nics": [
+ {
+ "devid": 0,
+ "mac": "00:16:3e:66:12:b4",
+ "bridge": "br0",
+ "script": "/etc/xen/scripts/vif-bridge",
+ "nictype": "vif_ioemu"
+ }
+ ],
+ "vfbs": [
+ {
+ "devid": -1,
+ "vnc": {
+ "enable": "True",
+ "listen": "0.0.0.0",
+ "findunused": "False"
+ },
+ "sdl": {
+ "enable": "False"
+ }
+ }
+ ],
+ "vkbs": [
+ {
+ "devid": -1
+ }
+ ],
+ "on_reboot": "restart"
+}
diff --git a/tests/libxlxml2domconfigdata/viridian-passthrough.xml b/tests/libxlxml2domconfigdata/viridian-passthrough.xml
new file mode 100644
index 0000000000..6d6b7d22cd
--- /dev/null
+++ b/tests/libxlxml2domconfigdata/viridian-passthrough.xml
@@ -0,0 +1,37 @@
+<domain type='xen'>
+ <name>test-hvm</name>
+ <description>None</description>
+ <uuid>2147d599-9cc6-c0dc-92ab-4064b5446e9b</uuid>
+ <memory>1048576</memory>
+ <currentMemory>1048576</currentMemory>
+ <vcpu>4</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <clock offset='utc'/>
+ <os>
+ <type>hvm</type>
+ <loader>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <apic/>
+ <acpi/>
+ <pae/>
+ <hyperv mode="passthrough"/>
+ </features>
+ <devices>
+ <emulator>/bin/true</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu'/>
+ <source file='/var/lib/xen/images/test-hvm.img'/>
+ <target dev='hda'/>
+ </disk>
+ <interface type='bridge'>
+ <source bridge='br0'/>
+ <mac address='00:16:3e:66:12:b4'/>
+ <script path='/etc/xen/scripts/vif-bridge'/>
+ </interface>
+ <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+ </devices>
+</domain>
diff --git a/tests/libxlxml2domconfigtest.c b/tests/libxlxml2domconfigtest.c
index 255855b156..4654821c3f 100644
--- a/tests/libxlxml2domconfigtest.c
+++ b/tests/libxlxml2domconfigtest.c
@@ -211,6 +211,15 @@ mymain(void)
DO_TEST("single-serial");
DO_TEST("multiple-serial");
+#ifdef LIBXL_HAVE_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE
+ DO_TEST("viridian-hvm");
+ DO_TEST("viridian-hvm-full");
+ DO_TEST("viridian-hvm-none");
+#if LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH == 64
+ DO_TEST("viridian-passthrough");
+#endif
+#endif
+
unlink("libxl-driver.log");
testXLFreeDriver(driver);
--
2.48.1
3 weeks, 3 days
[PATCH 0/3] ch: monitor daemonization, sync after reboot, and shutdown fixes
by Kirill Shchetiniuk
1. Run CH monitor as a daemon
Made the monitor process daemonized to prevent VM termination if
the CH driver crashes. Added pidfile for daemon's pid aquiring and tracking
as well as its init.
2. Update domain info after reboot
Fixed an issue where domain properties (e.g., serial console path)
were not updated after VM reboot. Added VIR_CH_EVENT_VM_REBOOTED
handling to keep the transient domain definition consistent.
3. Update VM shutdown event handler
VM monitor was still up even if VM was shut off, which led to an
inability to start the domain again.
virsh # shutdown ch-test
Domain 'ch-test' is being shutdown
virsh # list
Id Name State
------------------------------
722117 ch-test shut off
Ensured the CH monitor process terminates along with the
VM shutdown (e.g., executed using virsh). Updated
virCHEventStopProcess to have proper job type.
Kirill Shchetiniuk (3):
ch: virCHMonitorNew() run new CH monitor daemonized
ch: virCHProcessEvent() update domain info after reboot
ch: virCHProcessEvent() vm shutdown event handler fix
src/ch/ch_domain.c | 1 +
src/ch/ch_domain.h | 1 +
src/ch/ch_events.c | 8 ++++----
src/ch/ch_monitor.c | 24 ++++++++++++++++++++++--
src/ch/ch_process.c | 18 +++++++++++++++++-
src/ch/ch_process.h | 2 ++
6 files changed, 47 insertions(+), 7 deletions(-)
--
2.48.1
3 weeks, 3 days
[PATCH 1/5] virpci: Switch to an implementation using libpciaccess
by Alexander Shursha
The current virpci code uses the Linux-specific sysfs subsystem, which makes
it impossible to use on other Unix-like systems. The libpciaccess library
provides a cross-platform API for accessing the PCI bus. Employ it to make
the code portable.
This makes libpciaccess a non-optional dependency of libvirt.
Signed-off-by: Alexander Shursha <kekek2(a)ya.ru>
---
meson.build | 11 +-
meson_options.txt | 4 +-
src/meson.build | 1 +
src/util/virpci.c | 465 +++++++++++----------------------------------
tests/virpcimock.c | 22 ++-
5 files changed, 139 insertions(+), 364 deletions(-)
diff --git a/meson.build b/meson.build
index 2d76a0846c..85bd882406 100644
--- a/meson.build
+++ b/meson.build
@@ -1207,7 +1207,10 @@ parallels_sdk_version = '7.0.22'
parallels_sdk_dep = dependency('parallels-sdk', version: '>=' + parallels_sdk_version, required: false)
pciaccess_version = '0.10.0'
-pciaccess_dep = dependency('pciaccess', version: '>=' + pciaccess_version, required: get_option('pciaccess'))
+pciaccess_dep = dependency('pciaccess', version: '>=' + pciaccess_version)
+if not pciaccess_dep.found()
+ error('pciaccess is required to build libvirt')
+endif
rbd_dep = cc.find_library('rbd', required: get_option('storage_rbd'))
rados_dep = cc.find_library('rados', required: get_option('storage_rbd'))
@@ -1461,11 +1464,6 @@ if not get_option('polkit').disabled()
endif
endif
-if udev_dep.found() and not pciaccess_dep.found()
- error('You must install the pciaccess module to build with udev')
-endif
-
-
# build driver options
remote_default_mode = get_option('remote_default_mode')
@@ -2341,7 +2339,6 @@ libs_summary = {
'numactl': numactl_dep.found(),
'openwsman': openwsman_dep.found(),
'parallels-sdk': parallels_sdk_dep.found(),
- 'pciaccess': pciaccess_dep.found(),
'polkit': conf.has('WITH_POLKIT'),
'rbd': rbd_dep.found(),
'readline': readline_dep.found(),
diff --git a/meson_options.txt b/meson_options.txt
index 3dc3e8667b..69605238ba 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -38,7 +38,6 @@ option('netcf', type: 'feature', value: 'auto', description: 'netcf support')
option('nls', type: 'feature', value: 'auto', description: 'nls support')
option('numactl', type: 'feature', value: 'auto', description: 'numactl support')
option('openwsman', type: 'feature', value: 'auto', description: 'openwsman support')
-option('pciaccess', type: 'feature', value: 'auto', description: 'pciaccess support')
option('polkit', type: 'feature', value: 'auto', description: 'use PolicyKit for UNIX socket access checks')
option('readline', type: 'feature', value: 'auto', description: 'readline support')
option('sanlock', type: 'feature', value: 'auto', description: 'sanlock support')
@@ -46,7 +45,6 @@ option('sasl', type: 'feature', value: 'auto', description: 'sasl support')
option('selinux', type: 'feature', value: 'auto', description: 'selinux support')
option('selinux_mount', type: 'string', value: '', description: 'set SELinux mount point')
option('sshconfdir', type: 'string', value: '', description: 'directory for SSH client configuration')
-# dep:pciaccess
option('udev', type: 'feature', value: 'auto', description: 'udev support')
# dep:driver_remote
option('wireshark_dissector', type: 'feature', value: 'auto', description: 'wireshark support')
@@ -59,7 +57,7 @@ option('driver_bhyve', type: 'feature', value: 'auto', description: 'bhyve drive
option('driver_esx', type: 'feature', value: 'auto', description: 'esx driver')
# dep:openwsman
option('driver_hyperv', type: 'feature', value: 'auto', description: 'Hyper-V driver')
-# dep:pciaccess dep:udev dep:driver_remote dep:driver_libvirtd
+# dep:udev dep:driver_remote dep:driver_libvirtd
option('driver_interface', type: 'feature', value: 'auto', description: 'host interface driver')
# dep:driver_remote
option('driver_libvirtd', type: 'feature', value: 'auto', description: 'libvirtd driver')
diff --git a/src/meson.build b/src/meson.build
index 9413192a55..39788ac4d7 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -411,6 +411,7 @@ libvirt_lib = shared_library(
dtrace_gen_objects,
dependencies: [
src_dep,
+ pciaccess_dep
],
link_args: libvirt_link_args,
link_whole: [
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 90617e69c6..b5bbe73ece 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2,6 +2,7 @@
* virpci.c: helper APIs for managing host PCI devices
*
* Copyright (C) 2009-2015 Red Hat, Inc.
+ * Copyright (C) 2024-2025 Future Crew, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,6 +30,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <pciaccess.h>
#ifdef __linux__
# include <sys/utsname.h>
@@ -72,7 +74,7 @@ struct _virPCIDevice {
char *name; /* domain:bus:slot.function */
char id[PCI_ID_LEN]; /* product vendor */
- char *path;
+ struct pci_device *device;
/* The driver:domain which uses the device */
char *used_by_drvname;
@@ -359,121 +361,6 @@ virPCIDeviceGetCurrentDriverNameAndType(virPCIDevice *dev,
}
-static int
-virPCIDeviceConfigOpenInternal(virPCIDevice *dev, bool readonly, bool fatal)
-{
- int fd;
-
- fd = open(dev->path, readonly ? O_RDONLY : O_RDWR);
-
- if (fd < 0) {
- if (fatal) {
- virReportSystemError(errno,
- _("Failed to open config space file '%1$s'"),
- dev->path);
- } else {
- VIR_WARN("Failed to open config space file '%s': %s",
- dev->path, g_strerror(errno));
- }
- return -1;
- }
-
- VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path);
- return fd;
-}
-
-static int
-virPCIDeviceConfigOpen(virPCIDevice *dev)
-{
- return virPCIDeviceConfigOpenInternal(dev, true, true);
-}
-
-static int
-virPCIDeviceConfigOpenTry(virPCIDevice *dev)
-{
- return virPCIDeviceConfigOpenInternal(dev, true, false);
-}
-
-static int
-virPCIDeviceConfigOpenWrite(virPCIDevice *dev)
-{
- return virPCIDeviceConfigOpenInternal(dev, false, true);
-}
-
-static void
-virPCIDeviceConfigClose(virPCIDevice *dev, int cfgfd)
-{
- if (VIR_CLOSE(cfgfd) < 0) {
- VIR_WARN("Failed to close config space file '%s': %s",
- dev->path, g_strerror(errno));
- }
-}
-
-
-static int
-virPCIDeviceRead(virPCIDevice *dev,
- int cfgfd,
- unsigned int pos,
- uint8_t *buf,
- unsigned int buflen)
-{
- memset(buf, 0, buflen);
- errno = 0;
-
- if (lseek(cfgfd, pos, SEEK_SET) != pos ||
- saferead(cfgfd, buf, buflen) != buflen) {
- VIR_DEBUG("Failed to read %u bytes at %u from '%s' : %s",
- buflen, pos, dev->path, g_strerror(errno));
- return -1;
- }
- return 0;
-}
-
-
-/**
- * virPCIDeviceReadN:
- * @dev: virPCIDevice object (used only to log name of config file)
- * @cfgfd: open file descriptor for device config file in sysfs
- * @pos: byte offset in the file to read from
- *
- * read "N" (where "N" is "8", "16", or "32", and appears at the end
- * of the function name) bytes from a PCI device's already-opened
- * sysfs config file and return them as the return value from the
- * function.
- *
- * Returns the value at @pos in the file, or 0 if there was an
- * error. NB: since 0 could be a valid value, occurrence of an error
- * must be determined by examining errno. errno is always reset to 0
- * before the seek/read is attempted (see virPCIDeviceRead()), so if
- * errno != 0 on return from one of these functions, then either the
- * seek or the read operation failed for some reason. If errno == 0
- * and the return value is 0, then the config file really does contain
- * the value 0 at @pos.
- */
-static uint8_t
-virPCIDeviceRead8(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
- uint8_t buf;
- virPCIDeviceRead(dev, cfgfd, pos, &buf, sizeof(buf));
- return buf;
-}
-
-static uint16_t
-virPCIDeviceRead16(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
- uint8_t buf[2];
- virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
- return (buf[0] << 0) | (buf[1] << 8);
-}
-
-static uint32_t
-virPCIDeviceRead32(virPCIDevice *dev, int cfgfd, unsigned int pos)
-{
- uint8_t buf[4];
- virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
- return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
static int
virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
{
@@ -499,36 +386,6 @@ virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
return 0;
}
-static int
-virPCIDeviceWrite(virPCIDevice *dev,
- int cfgfd,
- unsigned int pos,
- uint8_t *buf,
- unsigned int buflen)
-{
- if (lseek(cfgfd, pos, SEEK_SET) != pos ||
- safewrite(cfgfd, buf, buflen) != buflen) {
- VIR_WARN("Failed to write to '%s' : %s", dev->path,
- g_strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static void
-virPCIDeviceWrite16(virPCIDevice *dev, int cfgfd, unsigned int pos, uint16_t val)
-{
- uint8_t buf[2] = { (val >> 0), (val >> 8) };
- virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
-}
-
-static void
-virPCIDeviceWrite32(virPCIDevice *dev, int cfgfd, unsigned int pos, uint32_t val)
-{
- uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) };
- virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
-}
-
typedef int (*virPCIDeviceIterPredicate)(virPCIDevice *, virPCIDevice *,
void *);
@@ -610,7 +467,6 @@ virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate,
*/
static int
virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
- int cfgfd,
unsigned int capability,
unsigned int *offset)
{
@@ -619,11 +475,13 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
*offset = 0; /* assume failure (*nothing* can be at offset 0) */
- status = virPCIDeviceRead16(dev, cfgfd, PCI_STATUS);
+ pci_device_cfg_read_u16(dev->device, &status, PCI_STATUS);
+
if (errno != 0 || !(status & PCI_STATUS_CAP_LIST))
goto error;
- pos = virPCIDeviceRead8(dev, cfgfd, PCI_CAPABILITY_LIST);
+ pci_device_cfg_read_u8(dev->device, &pos, PCI_CAPABILITY_LIST);
+
if (errno != 0)
goto error;
@@ -635,7 +493,9 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
* capabilities here.
*/
while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
- uint8_t capid = virPCIDeviceRead8(dev, cfgfd, pos);
+ uint8_t capid;
+ pci_device_cfg_read_u8(dev->device, &capid, pos);
+
if (errno != 0)
goto error;
@@ -646,7 +506,8 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
return 0;
}
- pos = virPCIDeviceRead8(dev, cfgfd, pos + 1);
+ pci_device_cfg_read_u8(dev->device, &pos, pos + 1);
+
if (errno != 0)
goto error;
}
@@ -665,7 +526,6 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
static unsigned int
virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
- int cfgfd,
unsigned int capability)
{
int ttl;
@@ -677,7 +537,7 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
pos = PCI_EXT_CAP_BASE;
while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) {
- header = virPCIDeviceRead32(dev, cfgfd, pos);
+ header = pci_device_cfg_read_u32(dev->device, &header, pos);
if ((header & PCI_EXT_CAP_ID_MASK) == capability)
return pos;
@@ -693,7 +553,7 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
* not have FLR, 1 if it does, and -1 on error
*/
static bool
-virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev)
{
uint32_t caps;
unsigned int pos;
@@ -707,7 +567,7 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* on SR-IOV NICs at the moment.
*/
if (dev->pcie_cap_pos) {
- caps = virPCIDeviceRead32(dev, cfgfd, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
+ pci_device_cfg_read_u32(dev->device, &caps, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
if (caps & PCI_EXP_DEVCAP_FLR) {
VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
return true;
@@ -718,11 +578,13 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* the same thing, except for conventional PCI
* devices. This is not common yet.
*/
- if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_AF, &pos) < 0)
+ if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_AF, &pos) < 0)
goto error;
if (pos) {
- caps = virPCIDeviceRead16(dev, cfgfd, pos + PCI_AF_CAP);
+ uint16_t caps16;
+ pci_device_cfg_read_u16(dev->device, &caps16, pos + PCI_AF_CAP);
+ caps = caps16;
if (caps & PCI_AF_CAP_FLR) {
VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
return true;
@@ -754,13 +616,13 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* internal reset, not just a soft reset.
*/
static bool
-virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev)
{
if (dev->pci_pm_cap_pos) {
uint32_t ctl;
/* require the NO_SOFT_RESET bit is clear */
- ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+ pci_device_cfg_read_u32(dev->device, &ctl, dev->pci_pm_cap_pos + PCI_PM_CTRL);
if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
return true;
@@ -811,26 +673,22 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
uint8_t header_type, secondary, subordinate;
virPCIDevice **best = data;
int ret = 0;
- int fd;
if (dev->address.domain != check->address.domain)
return 0;
- if ((fd = virPCIDeviceConfigOpenTry(check)) < 0)
- return 0;
-
/* Is it a bridge? */
ret = virPCIDeviceReadClass(check, &device_class);
if (ret < 0 || device_class != PCI_CLASS_BRIDGE_PCI)
- goto cleanup;
+ return ret;
/* Is it a plane? */
- header_type = virPCIDeviceRead8(check, fd, PCI_HEADER_TYPE);
+ pci_device_cfg_read_u8(check->device, &header_type, PCI_HEADER_TYPE);
if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
- goto cleanup;
+ return ret;
- secondary = virPCIDeviceRead8(check, fd, PCI_SECONDARY_BUS);
- subordinate = virPCIDeviceRead8(check, fd, PCI_SUBORDINATE_BUS);
+ pci_device_cfg_read_u8(check->device, &secondary, PCI_SECONDARY_BUS);
+ pci_device_cfg_read_u8(check->device, &subordinate, PCI_SUBORDINATE_BUS);
VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
@@ -838,8 +696,7 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
* the direct parent. No further work is necessary
*/
if (dev->address.bus == secondary) {
- ret = 1;
- goto cleanup;
+ return 1;
}
/* otherwise, SRIOV allows VFs to be on different buses than their PFs.
@@ -850,35 +707,26 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
if (*best == NULL) {
*best = virPCIDeviceNew(&check->address);
if (*best == NULL) {
- ret = -1;
- goto cleanup;
+ return -1;
}
} else {
/* OK, we had already recorded a previous "best" match for the
* parent. See if the current device is more restrictive than the
* best, and if so, make it the new best
*/
- int bestfd;
uint8_t best_secondary;
- if ((bestfd = virPCIDeviceConfigOpenTry(*best)) < 0)
- goto cleanup;
- best_secondary = virPCIDeviceRead8(*best, bestfd, PCI_SECONDARY_BUS);
- virPCIDeviceConfigClose(*best, bestfd);
+ pci_device_cfg_read_u8((*best)->device, &best_secondary, PCI_SECONDARY_BUS);
if (secondary > best_secondary) {
virPCIDeviceFree(*best);
*best = virPCIDeviceNew(&check->address);
if (*best == NULL) {
- ret = -1;
- goto cleanup;
+ return -1;
}
}
}
}
-
- cleanup:
- virPCIDeviceConfigClose(check, fd);
return ret;
}
@@ -902,15 +750,14 @@ virPCIDeviceGetParent(virPCIDevice *dev, virPCIDevice **parent)
*/
static int
virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
- int cfgfd,
virPCIDeviceList *inactiveDevs)
{
g_autoptr(virPCIDevice) parent = NULL;
g_autoptr(virPCIDevice) conflict = NULL;
uint8_t config_space[PCI_CONF_LEN];
uint16_t ctl;
- int ret = -1;
- int parentfd;
+ pciaddr_t bytes_read;
+ pciaddr_t bytes_written;
/* Refuse to do a secondary bus reset if there are other
* devices/functions behind the bus are used by the host
@@ -932,8 +779,6 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
dev->name);
return -1;
}
- if ((parentfd = virPCIDeviceConfigOpenWrite(parent)) < 0)
- goto out;
VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);
@@ -941,38 +786,37 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
* for the supplied device since we refuse to do a reset if there
* are multiple devices/functions
*/
- if (virPCIDeviceRead(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+ pci_device_cfg_read(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_read);
+ if (bytes_read < PCI_CONF_LEN) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to read PCI config space for %1$s"),
dev->name);
- goto out;
+ return -1;
}
/* Read the control register, set the reset flag, wait 200ms,
* unset the reset flag and wait 200ms.
*/
- ctl = virPCIDeviceRead16(dev, parentfd, PCI_BRIDGE_CONTROL);
- virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL,
- ctl | PCI_BRIDGE_CTL_RESET);
+ pci_device_cfg_read_u16(parent->device, &ctl, PCI_BRIDGE_CONTROL);
+
+ pci_device_cfg_write_u16(parent->device, ctl | PCI_BRIDGE_CTL_RESET, PCI_BRIDGE_CONTROL);
g_usleep(200 * 1000); /* sleep 200ms */
- virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, ctl);
+ pci_device_cfg_write_u16(parent->device, ctl, PCI_BRIDGE_CONTROL);
g_usleep(200 * 1000); /* sleep 200ms */
- if (virPCIDeviceWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+ pci_device_cfg_write(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_written);
+ if (bytes_written < PCI_CONF_LEN) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to restore PCI config space for %1$s"),
dev->name);
- goto out;
+ return -1;
}
- ret = 0;
- out:
- virPCIDeviceConfigClose(parent, parentfd);
- return ret;
+ return 0;
}
/* Power management reset attempts to reset a device using a
@@ -980,16 +824,19 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
* above we require the device supports a full internal reset.
*/
static int
-virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
+virPCIDeviceTryPowerManagementReset(virPCIDevice *dev)
{
uint8_t config_space[PCI_CONF_LEN];
uint32_t ctl;
+ pciaddr_t bytes_read;
+ pciaddr_t bytes_written;
if (!dev->pci_pm_cap_pos)
return -1;
/* Save and restore the device's config space. */
- if (virPCIDeviceRead(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+ pci_device_cfg_read(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_read);
+ if (bytes_read < PCI_CONF_LEN) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to read PCI config space for %1$s"),
dev->name);
@@ -998,20 +845,19 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);
- ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+ pci_device_cfg_read_u32(dev->device, &ctl, dev->pci_pm_cap_pos + PCI_PM_CTRL);
ctl &= ~PCI_PM_CTRL_STATE_MASK;
- virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
- ctl | PCI_PM_CTRL_STATE_D3hot);
+ pci_device_cfg_write_u32(dev->device, ctl | PCI_PM_CTRL_STATE_D3hot, dev->pci_pm_cap_pos + PCI_PM_CTRL);
g_usleep(10 * 1000); /* sleep 10ms */
- virPCIDeviceWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL,
- ctl | PCI_PM_CTRL_STATE_D0);
+ pci_device_cfg_write_u32(dev->device, ctl | PCI_PM_CTRL_STATE_D0, dev->pci_pm_cap_pos + PCI_PM_CTRL);
g_usleep(10 * 1000); /* sleep 10ms */
- if (virPCIDeviceWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+ pci_device_cfg_write(dev->device, config_space, 0, PCI_CONF_LEN, &bytes_written);
+ if (bytes_written < PCI_CONF_LEN) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to restore PCI config space for %1$s"),
dev->name);
@@ -1046,10 +892,10 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
* Always returns success (0) (for now)
*/
static int
-virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
+virPCIDeviceInit(virPCIDevice *dev)
{
dev->is_pcie = false;
- if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
+ if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
/* an unprivileged process is unable to read *all* of a
* device's PCI config (it can only read the first 64
* bytes, which isn't enough for see the Express
@@ -1065,18 +911,13 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
* -1), then we blindly assume the most likely outcome -
* PCIe.
*/
- off_t configLen = virFileLength(virPCIDeviceGetConfigPath(dev), -1);
-
- if (configLen != 256)
- dev->is_pcie = true;
-
} else {
dev->is_pcie = (dev->pcie_cap_pos != 0);
}
- virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
- dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev, cfgfd);
- dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev, cfgfd);
+ virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
+ dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev);
+ dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev);
return 0;
}
@@ -1089,7 +930,6 @@ virPCIDeviceReset(virPCIDevice *dev,
g_autofree char *drvName = NULL;
virPCIStubDriver drvType;
int ret = -1;
- int fd = -1;
int hdrType = -1;
if (virPCIGetHeaderType(dev, &hdrType) < 0)
@@ -1114,29 +954,26 @@ virPCIDeviceReset(virPCIDevice *dev,
* be redundant.
*/
if (virPCIDeviceGetCurrentDriverNameAndType(dev, &drvName, &drvType) < 0)
- goto cleanup;
+ return -1;
if (drvType == VIR_PCI_STUB_DRIVER_VFIO) {
VIR_DEBUG("Device %s is bound to %s - skip reset", dev->name, drvName);
ret = 0;
- goto cleanup;
+ return 0;
}
VIR_DEBUG("Resetting device %s", dev->name);
- if ((fd = virPCIDeviceConfigOpenWrite(dev)) < 0)
- goto cleanup;
-
- if (virPCIDeviceInit(dev, fd) < 0)
- goto cleanup;
+ if (virPCIDeviceInit(dev) < 0)
+ return -1;
/* KVM will perform FLR when starting and stopping
* a guest, so there is no need for us to do it here.
*/
if (dev->has_flr) {
ret = 0;
- goto cleanup;
+ return 0;
}
/* If the device supports PCI power management reset,
@@ -1144,11 +981,11 @@ virPCIDeviceReset(virPCIDevice *dev,
* the function, not the whole device.
*/
if (dev->has_pm_reset)
- ret = virPCIDeviceTryPowerManagementReset(dev, fd);
+ ret = virPCIDeviceTryPowerManagementReset(dev);
/* Bus reset is not an option with the root bus */
if (ret < 0 && dev->address.bus != 0)
- ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
+ ret = virPCIDeviceTrySecondaryBusReset(dev, inactiveDevs);
if (ret < 0) {
virErrorPtr err = virGetLastError();
@@ -1159,8 +996,6 @@ virPCIDeviceReset(virPCIDevice *dev,
_("no FLR, PM reset or bus reset available"));
}
- cleanup:
- virPCIDeviceConfigClose(dev, fd);
return ret;
}
@@ -1756,28 +1591,6 @@ virPCIDeviceReattach(virPCIDevice *dev,
return 0;
}
-static char *
-virPCIDeviceReadID(virPCIDevice *dev, const char *id_name)
-{
- g_autofree char *path = NULL;
- g_autofree char *id_str = NULL;
-
- path = virPCIFile(dev->name, id_name);
-
- /* ID string is '0xNNNN\n' ... i.e. 7 bytes */
- if (virFileReadAll(path, 7, &id_str) < 0)
- return NULL;
-
- /* Check for 0x suffix */
- if (id_str[0] != '0' || id_str[1] != 'x')
- return NULL;
-
- /* Chop off the newline; we know the string is 7 bytes */
- id_str[6] = '\0';
-
- return g_steal_pointer(&id_str);
-}
-
bool
virPCIDeviceAddressIsValid(virPCIDeviceAddress *addr,
bool report)
@@ -1865,9 +1678,9 @@ virPCIDeviceExists(const virPCIDeviceAddress *addr)
virPCIDevice *
virPCIDeviceNew(const virPCIDeviceAddress *address)
{
+ struct pci_device * device;
+
g_autoptr(virPCIDevice) dev = NULL;
- g_autofree char *vendor = NULL;
- g_autofree char *product = NULL;
dev = g_new0(virPCIDevice, 1);
@@ -1875,31 +1688,21 @@ virPCIDeviceNew(const virPCIDeviceAddress *address)
dev->name = virPCIDeviceAddressAsString(&dev->address);
- dev->path = g_strdup_printf(PCI_SYSFS "devices/%s/config", dev->name);
-
- if (!virFileExists(dev->path)) {
- virReportSystemError(errno,
- _("Device %1$s not found: could not access %2$s"),
- dev->name, dev->path);
+ pci_system_init();
+ device = pci_device_find_by_slot(address->domain, address->bus, address->slot, address->function);
+ if (!device)
return NULL;
- }
-
- vendor = virPCIDeviceReadID(dev, "vendor");
- product = virPCIDeviceReadID(dev, "device");
-
- if (!vendor || !product) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to read product/vendor ID for %1$s"),
- dev->name);
+ dev->device = g_memdup(device, sizeof(*dev->device));
+ if (!dev->device) {
+ virReportSystemError(errno,
+ _("Not found device domain: %1$d, bus: %2$d, slot: %3$d, function: %4$d"),
+ address->domain, address->bus, address->slot, address->function);
return NULL;
}
-
- /* strings contain '0x' prefix */
- if (g_snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2],
- &product[2]) >= sizeof(dev->id)) {
+ if (g_snprintf(dev->id, sizeof(dev->id), "%x %x", dev->device->vendor_id, dev->device->device_id) >= sizeof(dev->id)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("dev->id buffer overflow: %1$s %2$s"),
- &vendor[2], &product[2]);
+ _("dev->id buffer overflow: %1$d %2$d"),
+ dev->device->vendor_id, dev->device->device_id);
return NULL;
}
@@ -1918,10 +1721,10 @@ virPCIDeviceCopy(virPCIDevice *dev)
/* shallow copy to take care of most attributes */
*copy = *dev;
- copy->path = NULL;
- copy->used_by_drvname = copy->used_by_domname = NULL;
+ copy->device = NULL;
+ copy->device = g_memdup(dev->device, sizeof(*dev->device));
+ copy->name = copy->used_by_drvname = copy->used_by_domname = copy->stubDriverName = NULL;
copy->name = g_strdup(dev->name);
- copy->path = g_strdup(dev->path);
copy->used_by_drvname = g_strdup(dev->used_by_drvname);
copy->used_by_domname = g_strdup(dev->used_by_domname);
copy->stubDriverName = g_strdup(dev->stubDriverName);
@@ -1936,10 +1739,11 @@ virPCIDeviceFree(virPCIDevice *dev)
return;
VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
g_free(dev->name);
- g_free(dev->path);
g_free(dev->used_by_drvname);
g_free(dev->used_by_domname);
g_free(dev->stubDriverName);
+ if (dev->device)
+ g_free(dev->device);
g_free(dev);
}
@@ -1971,9 +1775,9 @@ virPCIDeviceGetName(virPCIDevice *dev)
* config file.
*/
const char *
-virPCIDeviceGetConfigPath(virPCIDevice *dev)
+virPCIDeviceGetConfigPath(virPCIDevice *dev G_GNUC_UNUSED)
{
- return dev->path;
+ return NULL;
}
void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed)
@@ -2484,47 +2288,37 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev)
uint16_t flags;
uint16_t ctrl;
unsigned int pos;
- int fd;
- int ret = 0;
uint16_t device_class;
- if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
+ if (virPCIDeviceInit(dev) < 0) {
return -1;
-
- if (virPCIDeviceInit(dev, fd) < 0) {
- ret = -1;
- goto cleanup;
}
if (virPCIDeviceReadClass(dev, &device_class) < 0)
- goto cleanup;
+ return 0;
pos = dev->pcie_cap_pos;
if (!pos || device_class != PCI_CLASS_BRIDGE_PCI)
- goto cleanup;
+ return 0;
- flags = virPCIDeviceRead16(dev, fd, pos + PCI_EXP_FLAGS);
+ pci_device_cfg_read_u16(dev->device, &flags, pos + PCI_EXP_FLAGS);
if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM)
- goto cleanup;
+ return 0;
- pos = virPCIDeviceFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS);
+ pos = virPCIDeviceFindExtendedCapabilityOffset(dev, PCI_EXT_CAP_ID_ACS);
if (!pos) {
VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name);
- ret = 1;
- goto cleanup;
+ return 1;
}
- ctrl = virPCIDeviceRead16(dev, fd, pos + PCI_EXT_ACS_CTRL);
+ pci_device_cfg_read_u16(dev->device, &ctrl, pos + PCI_EXT_ACS_CTRL);
if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) {
VIR_DEBUG("%s %s: downstream port has ACS disabled",
dev->id, dev->name);
- ret = 1;
- goto cleanup;
+ return 1;
}
- cleanup:
- virPCIDeviceConfigClose(dev, fd);
- return ret;
+ return 0;
}
static int
@@ -3189,48 +2983,27 @@ virPCIDeviceGetVPD(virPCIDevice *dev G_GNUC_UNUSED)
int
virPCIDeviceIsPCIExpress(virPCIDevice *dev)
{
- int fd;
- int ret = -1;
-
- if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
- return ret;
-
- if (virPCIDeviceInit(dev, fd) < 0)
- goto cleanup;
-
- ret = dev->is_pcie;
+ if (virPCIDeviceInit(dev) < 0)
+ return -1;
- cleanup:
- virPCIDeviceConfigClose(dev, fd);
- return ret;
+ return dev->is_pcie;
}
int
virPCIDeviceHasPCIExpressLink(virPCIDevice *dev)
{
- int fd;
- int ret = -1;
uint16_t cap, type;
-
- if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
- return ret;
-
- if (virPCIDeviceInit(dev, fd) < 0)
- goto cleanup;
+ if (virPCIDeviceInit(dev) < 0)
+ return -1;
if (dev->pcie_cap_pos == 0) {
- ret = 0;
- goto cleanup;
+ return 0;
}
- cap = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_CAP_FLAGS);
+ pci_device_cfg_read_u16(dev->device, &cap, dev->pcie_cap_pos + PCI_CAP_FLAGS);
type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;
- ret = type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;
-
- cleanup:
- virPCIDeviceConfigClose(dev, fd);
- return ret;
+ return type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;
}
int
@@ -3242,53 +3015,39 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev,
unsigned int *sta_width)
{
uint32_t t;
- int fd;
- int ret = -1;
-
- if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
- return ret;
-
- if (virPCIDeviceInit(dev, fd) < 0)
- goto cleanup;
+ uint16_t t16;
+ if (virPCIDeviceInit(dev) < 0)
+ return -1;
if (!dev->pcie_cap_pos) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("pci device %1$s is not a PCI-Express device"),
dev->name);
- goto cleanup;
+ return -1;
}
- t = virPCIDeviceRead32(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
+ pci_device_cfg_read_u32(dev->device, &t, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
*cap_port = t >> 24;
*cap_speed = t & PCI_EXP_LNKCAP_SPEED;
*cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;
- t = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+ pci_device_cfg_read_u16(dev->device, &t16, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+ t = t16;
*sta_speed = t & PCI_EXP_LNKSTA_SPEED;
*sta_width = (t & PCI_EXP_LNKSTA_WIDTH) >> 4;
- ret = 0;
-
- cleanup:
- virPCIDeviceConfigClose(dev, fd);
- return ret;
+ return 0;
}
int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType)
{
- int fd;
uint8_t type;
*hdrType = -1;
- if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
- return -1;
-
- type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);
-
- virPCIDeviceConfigClose(dev, fd);
+ pci_device_cfg_read_u8(dev->device, &type, PCI_HEADER_TYPE);
type &= PCI_HEADER_TYPE_MASK;
if (type >= VIR_PCI_HEADER_LAST) {
diff --git a/tests/virpcimock.c b/tests/virpcimock.c
index 5b923c63ce..36bb57edb0 100644
--- a/tests/virpcimock.c
+++ b/tests/virpcimock.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (C) 2024-2025 Future Crew, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,7 +23,7 @@
#include "virpcivpdpriv.h"
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+#if defined(__linux__) || defined(__APPLE__)
# define VIR_MOCK_LOOKUP_MAIN
# include "virmock.h"
# include "virpci.h"
@@ -42,6 +43,10 @@ static int (*real___open_2)(const char *path, int flags);
static int (*real_close)(int fd);
static DIR * (*real_opendir)(const char *name);
static char *(*real_virFileCanonicalizePath)(const char *path);
+static int (*real_scandir)(const char *restrict dirp,
+ struct dirent ***restrict namelist,
+ typeof(int(const struct dirent *)) *filter,
+ typeof(int(const struct dirent **, const struct dirent **)) *compar);
static char *fakerootdir;
@@ -955,6 +960,7 @@ init_syms(void)
VIR_MOCK_REAL_INIT(opendir);
# endif
VIR_MOCK_REAL_INIT(virFileCanonicalizePath);
+ VIR_MOCK_REAL_INIT(scandir);
}
static void
@@ -1172,6 +1178,20 @@ virFileCanonicalizePath(const char *path)
return real_virFileCanonicalizePath(newpath);
}
+int scandir(const char *restrict dirp, struct dirent ***restrict namelist,
+ typeof(int(const struct dirent *)) *filter,
+ typeof(int(const struct dirent **, const struct dirent **)) *compar)
+{
+ g_autofree char *newpath = NULL;
+
+ init_syms();
+
+ if (getrealpath(&newpath, dirp) < 0)
+ return -1;
+
+ return real_scandir(newpath, namelist, filter, compar);
+}
+
# include "virmockstathelpers.c"
#else
--
2.46.1
3 weeks, 4 days