Skip to contentSkip to conversation

pci, vhost, virtio, iommu, apci: features, fixes

GIT PULL Michael S. Tsirkin 3 participants 95 messages Sep 10 – Sep 11

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

The following changes since commit 1df256f5968e9f7c3c4533a1383b071c044a36d6:

Merge tag 'qom-qapi-pr-pr-v1' of https://gitlab.com/marcandre.lureau/qemu into staging (2026-09-08 18:35:31 +0100)

are available in the Git repository at:

https://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream

for you to fetch changes up to 99c75c61d61251d98e0b93dd199edbb10a990205:

MAINTAINERS: add Junjie Cao as CXL reviewer (2026-09-10 10:55:03 -0400)

----------------------------------------------------------------
pci, vhost, virtio, iommu, apci: features, fixes

migration/cpr now supports vhost-vsock devices
new vhost-user-media device
virtio-net now supports live-TAP local migration vhost-user-gpu now supports blob resources and shared memory cxl now supports CFMW restrictions and per-window options intel_iommu now supports concurrent page fault handling with PRI pci now batches memory transactions around mapping updates vhost-user-blk now allows toggling inflight-migration at runtime virtio-rtc now supports smeared UTC clock type intel_iommu now exposes SMPWC when SVM is enabled
new reviewer for CXL patches

Fixes, cleanups all over the place

----------------------------------------------------------------
Albert Esteve (4):
linux-headers: add VIRTIO_ID_MEDIA
hw/display: add vhost-user-media device hw/display/vhost-user-media: add shared memory region BAR
linux-headers: Update to Linux v7.3-rc1

Alexandr Moshkov (6):
vhost-user: add skip_drain param to do_vhost_virtqueue_stop
vhost-user: add GET_VRING_BASE_SKIP_DRAIN message
vhost-user: use skip_drain with GET_VRING_BASE_SKIP_DRAIN message
vhost-user-blk: make inflight-migration prop mutable on running vm
vhost-user-blk: move inflight_needed higher
vhost-user-blk: use GET_VRING_BASE_SKIP_DRAIN when inflight-migration is on

Alyssa Ross (1):
vhost-user.rst: fix typo

Andrey Drobyshev (10):
vhost-vsock: block CPR migration modes
vhost: add vhost_reset_owner op
vhost-vsock: don't reset connections during CPR
vhost-vsock: fix FD leak in realize()
vhost-vsock: preserve vhost FD during CPR
vhost: factor out vhost_dev_init_backend()
vhost: make vhost_dev_cleanup() safe on a partially initialized device
vhost: add vhost_dev_set_owner() / vhost_dev_reset_owner() helpers
vhost: add vhost_dev_is_initialized() helper
vhost-vsock: hand off device ownership across CPR

Bin Guo (2):
libvhost-user: accept the postcopy client base ack in vu_add_mem_reg()
libvhost-user: return the backend mapping address for added regions

Clément MATHIEU--DRIF (4):
intel_iommu: Support concurrent page fault handling with PRI
intel_iommu: Only set dirty bit when PTE exposes write permission
intel_iommu: Always write all the flags passed to vtd_set_flag_in_pte
intel_iommu: Expose SMPWC when SVM is enabled

Davidlohr Bueso (5):
tests/bios-tables-test: Exclude CEDT.cxl for the CFMW restriction change hw/cxl: Drop Back-Invalidate from default CFMW window restrictions tests/acpi/cxl: Update CEDT.cxl for the default CFMW restrictions hw/cxl: Add configurable CXL Fixed Memory Window restriction flags tests/qtest/cxl: Add CXL Fixed Memory Window restriction flag tests

Denis V. Lunev (2):
pci: batch BAR remapping into one memory transaction
pci: load a device's config inside one memory transaction

Dorinda Bassey (1):
vhost: Fix SHMEM_MAP transaction ordering and resulting deadlock

Feifan Qian (1):
vhost-user: Reject SHMEM_MAP when no KVM memory slot is left

GuoHan Zhao (1):
virtio-crypto: clean up every data queue

Hanna Czenczek (6):
hw/virtio-blk: Account discard operations hw/virtio-blk: Complete zone-append cookies hw/nvme: Fix block accounting in nvme_copy() hw/nvme: Fix block accounting for compare hw/ide: Have ide_dma_cb() complete accounting hw/scsi-disk: Fix accounting for IGNORE, ret > 0

Jia Jia (2):
virtio: reduce code duplication for split ring hw/virtio: reject inverted virtio-iommu IOVA ranges

Junjie Cao (3):
hw/cxl: Fix guest-triggerable QEMU exit on reserved interleave ways hw/cxl: fix the CDAT DOE overlapping the Flex Bus DVSEC when sn= is set
MAINTAINERS: add Junjie Cao as CXL reviewer

Kuan-Wei Chiu (1):
virtio-rtc: Report smeared UTC clock type

Laurent Vivier (2):
hw/net/virtio-net: check packet size before VLAN tag access in receive_filter() hw/net/virtio-net: strip trailing padding when caching RSC segment

Marc-André Lureau (1):
vhost-user-gpu: validate command buffer size in submit_3d

Matej Hrica (2):
vhost-user-gpu: Add shared memory region support
vhost-user-gpu: Forward RESOURCE_BLOB and CONTEXT_INIT flags

Michael S. Tsirkin (7):
virtio: fix exit(1) on DMA mapping failure during migration restore
virtio: fix config_len DoS in migration restore path
virtio-pci: reject Q_ENABLE write on already-enabled queue
meson: disable "maybe uninitilized" errors with -Og
virtio-balloon: fix free-page BH teardown on unrealize net/tap-solaris: Fix resource leaks on error paths
virtio-net: validate IHL in virtio_net_rsc_extract_unit4 before use

Philippe Mathieu-Daudé (4):
hw/acpi: Make AcpiGedState const in build_ged_aml() hw/hotplug: Mark various HotplugHandlerClass variables as const hw/hotplug: Reduce some HotplugHandler variables scope hw/hotplug: Constify HotplugHandler

Sairaj Kodilkar (7):
amd_iommu: Return empty efr for stub call
tests/acpi: x86: Allow IVRS acpi table changes
amd_iommu: acpi-build: update PA, GVA and VA size macros
acpi_build: Use IOMMU pci device to build IOMMU DeviceID
acpi_build: Build IVRS feature report using extended feature register
amd_iommu: acpi-build: Remove unsupported PPR and HE feature tests/acpi: x86: update golden masters for IVRS

Stefan Hajnoczi (1):
virtio-scsi: set dataplane_started to false upon failure

Vladimir Sementsov-Ogievskiy (16):
net/tap: rework tap_parse_script
net/tap: improve script/downscript options documentation net/tap: deprecate "no" as special value for script/downscript net/tap: move vhost-net open() calls to tap_parse_vhost_fds() net/tap: move vhost initialization to tap_setup_vhost() net/tap: use container_of instead of DO_UPCAST net/tap: QOMify tap backend
net/tap: add TYPE_VMSTATE_IF interface
qapi: add local migration parameter
migration/fd: fix fd leak when fd is not valid for migration migration/fd: add errp parameter to migration_fd_valid()
migration: check that transfer is UNIX socket when "local" set
virtio-net: support local migration of backend net/tap: disable read polling for stopped VM net/tap: support local migration with virtio-net tests/functional: add test_tap_migration

Xiong Weimin (1):
hw/virtio: Propagate vhost_virtqueue_mask errors

 MAINTAINERS                                   |   7 +
 docs/about/deprecated.rst                     |  18 +
 docs/interop/vhost-user.rst                   |  44 ++-
 docs/system/devices/cxl.rst                   |  25 +-
 docs/system/i386/microvm.rst                  |   4 +-
 docs/system/i386/xenpvh.rst                   |   2 +-
 docs/system/ppc/ppce500.rst                   |   4 +-
 docs/system/riscv/microchip-icicle-kit.rst    |   2 +-
 docs/system/riscv/sifive_u.rst                |   2 +-
 meson.build                                   |   4 +
 qapi/machine.json                             |  28 ++
 qapi/migration.json                           |  21 +-
 qapi/net.json                                 |  45 ++-
 hw/i386/amd_iommu.h                           |  27 +-
 hw/i386/intel_iommu_internal.h                |   1 +
 hw/s390x/ccw-device.h                         |   2 +-
 include/hw/acpi/cpu.h                         |   4 +-
 include/hw/acpi/cpu_hotplug.h                 |   2 +-
 include/hw/acpi/generic_event_device.h        |   3 +-
 include/hw/acpi/ich9.h                        |  10 +-
 include/hw/acpi/memory_hotplug.h              |   4 +-
 include/hw/acpi/pcihp.h                       |   8 +-
 include/hw/core/boards.h                      |   4 +-
 include/hw/core/hotplug.h                     |  13 +-
 include/hw/core/qdev.h                        |  14 +-
 include/hw/cxl/cxl.h                          |  12 +
 include/hw/i386/microvm.h                     |   4 +-
 include/hw/i386/x86.h                         |  10 +-
 include/hw/mem/nvdimm.h                       |   2 +-
 include/hw/pci/pci_bridge.h                   |   6 +-
 include/hw/pci/pcie.h                         |   8 +-
 include/hw/pci/shpc.h                         |   6 +-
 include/hw/ppc/spapr_nvdimm.h                 |   2 +-
 include/hw/virtio/vhost-backend.h             |   2 +
 include/hw/virtio/vhost-user-media.h          |  46 +++
 include/hw/virtio/vhost-user.h                |   2 +-
 include/hw/virtio/vhost-vsock.h               |   4 +
 include/hw/virtio/vhost.h                     |  65 +++-
 include/hw/virtio/virtio-balloon.h            |   1 +
 include/hw/virtio/virtio-net.h                |   1 +
 include/hw/virtio/virtio.h                    |   2 +-
 include/migration/misc.h                      |   2 +
 include/migration/vmstate.h                   |   2 +
 include/net/net.h                             |   9 +
 include/net/tap.h                             |   2 +
 include/standard-headers/linux/ethtool.h      |   6 +
 include/standard-headers/linux/virtio_ids.h   |   1 +
 linux-headers/linux/iommufd.h                 |  45 ++-
 linux-headers/linux/userfaultfd.h             |  54 ++-
 linux-headers/linux/vduse.h                   |  28 ++
 linux-headers/linux/vfio.h                    |  21 ++
 linux-headers/linux/vfio_zdev.h               |   2 +
 backends/cryptodev-vhost.c                    |   2 +-
 backends/vhost-user.c                         |   2 +-
 contrib/vhost-user-gpu/virgl.c                |  12 +-
 hw/acpi/acpi-cpu-hotplug-stub.c               |   4 +-
 hw/acpi/acpi-mem-hotplug-stub.c               |   4 +-
 hw/acpi/acpi-nvdimm-stub.c                    |   2 +-
 hw/acpi/acpi-pci-hotplug-stub.c               |   8 +-
 hw/acpi/cpu.c                                 |   6 +-
 hw/acpi/cxl.c                                 |   2 +-
 hw/acpi/generic_event_device.c                |  13 +-
 hw/acpi/ich9.c                                |  10 +-
 hw/acpi/memory_hotplug.c                      |   7 +-
 hw/acpi/nvdimm.c                              |   2 +-
 hw/acpi/pcihp.c                               |  11 +-
 hw/acpi/piix4.c                               |  12 +-
 hw/arm/virt.c                                 |  23 +-
 hw/block/vhost-user-blk.c                     |  60 +++-
 hw/block/virtio-blk.c                         |  38 ++-
 hw/char/virtio-serial-bus.c                   |   6 +-
 hw/core/hotplug.c                             |  16 +-
 hw/core/qdev-hotplug.c                        |  10 +-
 hw/core/qdev.c                                |   2 +-
 hw/cxl/cxl-host.c                             |  48 ++-
 hw/display/vhost-user-gpu.c                   |  17 +
 hw/display/vhost-user-media-pci.c             | 115 +++++++
 hw/display/vhost-user-media.c                 | 388 ++++++++++++++++++++++
 hw/i386/acpi-build.c                          |  65 ++--
 hw/i386/amd_iommu-stub.c                      |   2 +-
 hw/i386/amd_iommu.c                           |   2 +-
 hw/i386/intel_iommu.c                         | 118 ++++---
 hw/i386/intel_iommu_accel.c                   |   6 +
 hw/i386/microvm.c                             |  12 +-
 hw/i386/pc.c                                  |  28 +-
 hw/i386/x86-common.c                          |   8 +-
 hw/ide/core.c                                 |   3 +-
 hw/intc/loongarch_dintc.c                     |   8 +-
 hw/intc/loongarch_extioi_common.c             |   4 +-
 hw/intc/loongarch_ipi.c                       |   4 +-
 hw/loongarch/virt.c                           |  44 +--
 hw/mem/cxl_type3.c                            |   6 +-
 hw/net/vhost_net.c                            |   9 +-
 hw/net/virtio-net.c                           | 131 +++++++-
 hw/nvme/ctrl.c                                |  78 +++--
 hw/pci-bridge/pci_bridge_dev.c                |   6 +-
 hw/pci/pci.c                                  |   8 +
 hw/pci/pcie.c                                 |  10 +-
 hw/pci/pcie_port.c                            |   2 +-
 hw/pci/shpc.c                                 |  11 +-
 hw/ppc/e500plat.c                             |   4 +-
 hw/ppc/spapr.c                                |  48 +--
 hw/ppc/spapr_nvdimm.c                         |   2 +-
 hw/ppc/spapr_pci.c                            |  12 +-
 hw/remote/machine.c                           |   2 +-
 hw/riscv/virt.c                               |   6 +-
 hw/s390x/css-bridge.c                         |   2 +-
 hw/s390x/s390-pci-bus.c                       |  12 +-
 hw/s390x/s390-virtio-ccw.c                    |  16 +-
 hw/s390x/virtio-ccw-md.c                      |  10 +-
 hw/s390x/virtio-ccw.c                         |   2 +-
 hw/scsi/scsi-disk.c                           |   7 +
 hw/scsi/vhost-scsi-common.c                   |   2 +-
 hw/scsi/virtio-scsi-dataplane.c               |   2 +-
 hw/scsi/virtio-scsi.c                         |  10 +-
 hw/scsi/vmw_pvscsi.c                          |   4 +-
 hw/virtio/vdpa-dev.c                          |   2 +-
 hw/virtio/vhost-kernel.c                      |   6 +
 hw/virtio/vhost-user-base.c                   |   2 +-
 hw/virtio/vhost-user-fs.c                     |   2 +-
 hw/virtio/vhost-user-scmi.c                   |   2 +-
 hw/virtio/vhost-user.c                        |  83 +++--
 hw/virtio/vhost-vsock-common.c                |   2 +-
 hw/virtio/vhost-vsock.c                       | 220 +++++++++++-
 hw/virtio/vhost.c                             | 111 +++++--
 hw/virtio/virtio-balloon.c                    |  19 +-
 hw/virtio/virtio-crypto.c                     |   5 +-
 hw/virtio/virtio-iommu.c                      |  17 +-
 hw/virtio/virtio-md-pci.c                     |  10 +-
 hw/virtio/virtio-pci.c                        |   7 +
 hw/virtio/virtio-rtc.c                        |   3 +-
 hw/virtio/virtio.c                            |  85 ++---
 hw/xen/xen-bus.c                              |   2 +-
 migration/fd.c                                |  28 +-
 migration/migration.c                         |  13 +
 migration/options.c                           |  18 +-
 net/net.c                                     |  14 +-
 net/tap-solaris.c                             |  69 ++--
 net/tap.c                                     | 448 ++++++++++++++++++++-----
 stubs/hotplug-stubs.c                         |   6 +-
 subprojects/libvhost-user/libvhost-user.c     |  34 +-
 system/qdev-monitor.c                         |   4 +-
 tests/qtest/cxl-test.c                        |  95 ++++++
 hw/display/Kconfig                            |   5 +
 hw/display/meson.build                        |   3 +
 qemu-options.hx                               |  13 +-
 tests/data/acpi/x86/q35/CEDT.cxl              | Bin 184 -> 184 bytes
 tests/data/acpi/x86/q35/IVRS.ivrs             | Bin 176 -> 176 bytes
 tests/functional/x86_64/meson.build           |   1 +
 tests/functional/x86_64/test_tap_migration.py | 461 ++++++++++++++++++++++++++
 150 files changed, 3245 insertions(+), 714 deletions(-)
 create mode 100644 include/hw/virtio/vhost-user-media.h
 create mode 100644 hw/display/vhost-user-media-pci.c
 create mode 100644 hw/display/vhost-user-media.c
 create mode 100755 tests/functional/x86_64/test_tap_migration.py
#1 lore raw

[PULL 04/90] hw/cxl: Fix guest-triggerable QEMU exit on reserved interleave ways

From: Junjie Cao <[email protected]>

A buggy or malicious guest can program a committed HDM decoder with a reserved Interleave Ways encoding (e.g. 0x5-0x7, 0xb-0xf). Two call sites pass &error_fatal to cxl_interleave_ways_dec(), which calls exit(1) on the reserved encoding before the subsequent decoded_iw == 0 guards can run:

- cxl-host.c update_non_interleaved(): called at commit time from hdm_decoder_commit() via cfmws_update_non_interleaved(), so a guest writing COMMIT with a reserved IW terminates QEMU immediately. This is the primary trigger on the current tree.

- cxl_type3.c cxl_type3_dpa(): called on memory access while iterating past committed decoders to accumulate dpa_base. Once the commit-time exit is removed, the decoder stays committed with the reserved encoding, so a later guest access outside that decoder's range would otherwise hit this second &error_fatal; both are fixed here.

Pass NULL instead of &error_fatal at both sites so that the reserved encoding returns zero and the existing guards handle it gracefully.

This can be reproduced by writing the HDM Decoder 0 Control register with a reserved IW encoding and the COMMIT bit set (e.g. IW=0x5, COMMIT=1).

Fixes 680935c9a6ff ("hw/cxl: Add a performant (and correct) path for the non interleaved cases")
Fixes 48461825af1b ("hw/mem/cxl_type3: Fix potential divide by zero reported by coverity")

Message-ID: <[email protected]>

---
 hw/cxl/cxl-host.c  | 2 +-
 hw/mem/cxl_type3.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
hw/cxl/cxl-host.c +1 -1
index eba13c9e7c..369a985f9b 100644
@@ -442,7 +442,7 @@ static int update_non_interleaved(Object *obj, void *opaque)
             }
         }
 
-        interleave_ways_dec = cxl_interleave_ways_dec(iw, &error_fatal);
+        interleave_ways_dec = cxl_interleave_ways_dec(iw, NULL);
         if (interleave_ways_dec == 0) {
             return 0;
         }
hw/mem/cxl_type3.c +1 -1
index 28f41fa623..6f44770db6 100644
@@ -1200,7 +1200,7 @@ static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
         }
         if (((uint64_t)host_addr < decoder_base) ||
             (hpa_offset >= decoder_size)) {
-            int decoded_iw = cxl_interleave_ways_dec(iw, &error_fatal);
+            int decoded_iw = cxl_interleave_ways_dec(iw, NULL);
 
             if (decoded_iw == 0) {
                 return false;
Signature · 1 line
MST
#2 lore raw

[PULL 21/90] net/tap: deprecate "no" as special value for script/downscript

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

The interface is ambiguous, as "no" is valid file name. So, using "no" as a special value to disable script is deprecated. Use an empty string ("script=" / "downscript=") instead.

In a future version, "no" will be treated as a plain file name, just like any other non-empty value.

Document the deprecation in docs/about/deprecated.rst, qapi/net.json, and qemu-options.hx. Update other docs to use empty string instead of "no". Add a warning.

Message-ID: <[email protected]>

---
 docs/about/deprecated.rst                  | 18 ++++++++++++++++++
 docs/system/i386/microvm.rst               |  4 ++--
 docs/system/i386/xenpvh.rst                |  2 +-
 docs/system/ppc/ppce500.rst                |  4 ++--
 docs/system/riscv/microchip-icicle-kit.rst |  2 +-
 docs/system/riscv/sifive_u.rst             |  2 +-
 qapi/net.json                              | 14 ++++++++++----
 net/tap.c                                  | 17 +++++++++++------
 qemu-options.hx                            |  8 ++++++--
 9 files changed, 52 insertions(+), 19 deletions(-)
docs/about/deprecated.rst +18 -0
index 98c32991c9..61e775373d 100644
@@ -71,6 +71,15 @@ flexible enough. The monitor objects have been converted to QOM, so
 ``-mon mode=control`` is replaced by ``-object monitor-qmp``. The
 short convenience options are not deprecated, only ``-mon``.
 
+``script=no`` and ``downscript=no`` for ``-netdev tap`` (since 11.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The special value ``"no"`` for the ``script`` and ``downscript``
+parameters of ``-netdev tap`` disables script execution.  This special
+treatment of ``"no"`` is deprecated.  Use an empty string (``script=``
+or ``downscript=``) to disable script execution instead.  In a future
+version, ``"no"`` will be treated as a plain file name.
+
 QEMU Machine Protocol (QMP) commands
 ------------------------------------
 
@@ -164,6 +173,15 @@ Use ``job-finalize`` instead.
 
 Use ``query-accelerators`` instead.
 
+``"no"`` as value of ``script``/``downscript`` for tap in ``netdev_add`` (since 11.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The special value ``"no"`` for the ``script`` and ``downscript``
+parameters of ``netdev_add`` with ``type=tap`` disables script
+execution.  This special treatment of ``"no"`` is deprecated.  Use an
+empty string instead.  In a future version, ``"no"`` will be treated as
+a plain file name.
+
 Human Machine Protocol (HMP) commands
 -------------------------------------
 
docs/system/i386/microvm.rst +2 -2
index 1675e37d3e..077ea15751 100644
@@ -79,7 +79,7 @@ legacy ``ISA serial`` device as console::
      -serial stdio \
      -drive id=test,file=test.img,format=raw,if=none \
      -device virtio-blk-device,drive=test \
-     -netdev tap,id=tap0,script=no,downscript=no \
+     -netdev tap,id=tap0,script=,downscript= \
      -device virtio-net-device,netdev=tap0
 
 While the example above works, you might be interested in reducing the
@@ -103,7 +103,7 @@ disabled::
      -device virtconsole,chardev=virtiocon0 \
      -drive id=test,file=test.img,format=raw,if=none \
      -device virtio-blk-device,drive=test \
-     -netdev tap,id=tap0,script=no,downscript=no \
+     -netdev tap,id=tap0,script=,downscript= \
      -device virtio-net-device,netdev=tap0
 
 
docs/system/i386/xenpvh.rst +1 -1
index 904778e3f5..862f38830b 100644
@@ -42,7 +42,7 @@ case you need to construct one manually:
       -vnc none                                       \
       -display none                                   \
       -device virtio-net-pci,id=nic0,netdev=net0,mac=00:16:3e:5c:81:78 \
-      -netdev type=tap,id=net0,ifname=vif3.0-emu,br=xenbr0,script=no,downscript=no \
+      -netdev type=tap,id=net0,ifname=vif3.0-emu,br=xenbr0,script=,downscript= \
       -smp 4,maxcpus=4                                \
       -nographic                                      \
       -machine xenpvh,ram-low-base=0,ram-low-size=2147483648,ram-high-base=4294967296,ram-high-size=2147483648,pci-ecam-base=824633720832,pci-ecam-size=268435456,pci-mmio-base=4026531840,pci-mmio-size=33554432,pci-mmio-high-base=824902156288,pci-mmio-high-size=68719476736 \
docs/system/ppc/ppce500.rst +2 -2
index c9fe0915dc..ec5aaf14fd 100644
@@ -158,14 +158,14 @@ interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by:
   $ qemu-system-ppc64 -M ppce500 -smp 4 -m 2G \
                       -display none -serial stdio \
                       -bios u-boot \
-                      -nic tap,ifname=tap0,script=no,downscript=no,model=e1000
+                      -nic tap,ifname=tap0,script=,downscript=,model=e1000
 
 The QEMU ``ppce500`` machine can also dynamically instantiate an eTSEC device
 if “-device eTSEC” is given to QEMU:
 
 .. code-block:: bash
 
-  -netdev tap,ifname=tap0,script=no,downscript=no,id=net0 -device eTSEC,netdev=net0
+  -netdev tap,ifname=tap0,script=,downscript=,id=net0 -device eTSEC,netdev=net0
 
 Root file system on flash drive
 -------------------------------
docs/system/riscv/microchip-icicle-kit.rst +1 -1
index 9809e94b84..7fdb96601a 100644
@@ -84,7 +84,7 @@ Then we can boot the machine by:
   $ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 -m 2G \
       -sd path/to/sdcard.img \
       -nic user,model=cadence_gem \
-      -nic tap,ifname=tap,model=cadence_gem,script=no \
+      -nic tap,ifname=tap,model=cadence_gem,script= \
       -display none -serial stdio \
       -kernel path/to/u-boot/build/dir/u-boot.bin \
       -dtb path/to/u-boot/build/dir/u-boot.dtb
docs/system/riscv/sifive_u.rst +1 -1
index 8f55ae8e31..0e4dcf3e70 100644
@@ -199,7 +199,7 @@ To boot the VxWorks kernel in QEMU with the ``sifive_u`` machine, use:
 
   $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \
       -display none -serial stdio \
-      -nic tap,ifname=tap0,script=no,downscript=no \
+      -nic tap,ifname=tap0,script=,downscript= \
       -kernel /path/to/vxWorks \
       -append "gem(0,0)host:vxWorks h=192.168.200.1 e=192.168.200.2:ffffff00 u=target pw=vxTarget f=0x01"
 
qapi/net.json +10 -4
index ab8ed9c086..dccf95bbbc 100644
@@ -399,15 +399,21 @@
 # @fds: multiple file descriptors of already opened multiqueue capable
 #     tap
 #
-# @script: script to initialize the interface.  An empty string or
-#     "no" disables script execution.  Defaults to
+# @script: script to initialize the interface.  An empty string
+#     disables script execution.  Defaults to
 #     ``<sysconfdir>/qemu-ifup``, where ``<sysconfdir>`` is the
 #     system configuration directory at build time (typically /etc).
+#     Using "no" to disable script execution is deprecated (since
+#     11.2); use an empty string instead.  In a future version, "no"
+#     will be treated as a plain file name.
 #
-# @downscript: script to shut down the interface.  An empty string or
-#     "no" disables script execution.  Defaults to
+# @downscript: script to shut down the interface.  An empty string
+#     disables script execution.  Defaults to
 #     ``<sysconfdir>/qemu-ifdown``, where ``<sysconfdir>`` is the
 #     system configuration directory at build time (typically /etc).
+#     Using "no" to disable script execution is deprecated (since
+#     11.2); use an empty string instead.  In a future version, "no"
+#     will be treated as a plain file name.
 #
 # @br: bridge name (since 2.8)
 #
net/tap.c +11 -6
index 2076f5b780..f4051e8d4b 100644
@@ -92,7 +92,8 @@ static void launch_script(const char *setup_script, const char *ifname,
 static void tap_send(void *opaque);
 static void tap_writable(void *opaque);
 
-static bool tap_is_explicit_no_script(const char *script_arg_value)
+static bool tap_is_explicit_no_script(const char *script_arg_name,
+                                      const char *script_arg_value)
 {
     if (!script_arg_value) {
         return false;
@@ -103,16 +104,19 @@ static bool tap_is_explicit_no_script(const char *script_arg_value)
     }
 
     if (strcmp(script_arg_value, "no") == 0) {
+        warn_report("'%s=no' is deprecated; use '%s=' instead",
+                    script_arg_name, script_arg_name);
         return true;
     }
 
     return false;
 }
 
-static char *tap_parse_script(const char *script_arg_value,
+static char *tap_parse_script(const char *script_arg_name,
+                              const char *script_arg_value,
                               const char *default_path)
 {
-    if (tap_is_explicit_no_script(script_arg_value)) {
+    if (tap_is_explicit_no_script(script_arg_name, script_arg_value)) {
         return NULL;
     }
 
@@ -741,7 +745,7 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
         qemu_set_info_str(&s->nc, "helper=%s", tap->helper);
     } else {
         qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname,
-                          script ?: "no", downscript ?: "no");
+                          script ?: "", downscript ?: "");
 
         if (downscript) {
             snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
@@ -947,9 +951,10 @@ int net_init_tap(const Netdev *netdev, const char *name,
         }
     } else {
         g_autofree char *script =
-            tap_parse_script(tap->script, DEFAULT_NETWORK_SCRIPT);
+            tap_parse_script("script", tap->script, DEFAULT_NETWORK_SCRIPT);
         g_autofree char *downscript =
-            tap_parse_script(tap->downscript, DEFAULT_NETWORK_DOWN_SCRIPT);
+            tap_parse_script("downscript", tap->downscript,
+                             DEFAULT_NETWORK_DOWN_SCRIPT);
 
         if (tap->ifname) {
             pstrcpy(ifname, sizeof ifname, tap->ifname);
qemu-options.hx +6 -2
index 16ef7d5455..2f6863180b 100644
@@ -3022,7 +3022,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "                use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
     "                to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
     "                to deconfigure it\n"
-    "                use '[down]script=no' or '[down]script=' to disable script execution\n"
+    "                use '[down]script=' to disable script execution\n"
+    "                ('[down]script=no' is deprecated and will be treated as a file name in future)\n"
     "                use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
     "                configure it\n"
     "                use 'fd=h' to connect to an already opened TAP interface\n"
@@ -3561,7 +3562,10 @@ SRST
     ``<sysconfdir>/qemu-ifup`` and the default network deconfigure script is
     ``<sysconfdir>/qemu-ifdown``, where ``<sysconfdir>`` is the system
     configuration directory at build time (typically ``/etc``).
-    Use ``[down]script=no`` or ``[down]script=`` to disable script execution.
+    Use ``[down]script=`` to disable script execution.
+    Using ``[down]script=no`` is deprecated; it disables script
+    execution now, but in a future version it will be treated as a
+    plain file name.
 
     If running QEMU as an unprivileged user, use the network helper
     to configure the TAP interface and attach it to the bridge.
Signature · 1 line
MST
#3 lore raw

[PULL 42/90] hw/cxl: Add configurable CXL Fixed Memory Window restriction flags

In reply to Michael S. Tsirkin

From: Davidlohr Bueso <[email protected]>

Expose the CFMWS "Window Restrictions" (CXL r4.0 9.18.1.3) as named per-window machine properties -- device-coherent, host-only, volatile, persistent, fixed-config and back-invalidate -- so the advertised restrictions can be configured per window rather than left at the default.

No changes in default options. HDM-D and HDM-H are advertised by default; disabling one (device-coherent=off or host-only=off) narrows the window to the other. back-invalidate implies device-coherent (HDM-DB) and suppresses the host-only default. host-only coherent combined with back-invalidate is rejected as undefined behavior per the spec.

Message-ID: <[email protected]>

---
 docs/system/devices/cxl.rst | 25 ++++++++++++--------
 qapi/machine.json           | 28 ++++++++++++++++++++++
 include/hw/cxl/cxl.h        | 12 ++++++++++
 hw/acpi/cxl.c               |  2 +-
 hw/cxl/cxl-host.c           | 46 +++++++++++++++++++++++++++++++++++++
 5 files changed, 102 insertions(+), 11 deletions(-)
docs/system/devices/cxl.rst +15 -10
index 9d0771cdfd..6bee339cea 100644
@@ -384,8 +384,13 @@ An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave::
   -device cxl-type3,bus=swport3,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3,sn=0x4 \
   -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
 
-An example of 4 type3 devices with volatile memory below a switch. Two of the devices
-use HDM-DB for coherence, which requires operating in Flit mode::
+An example of a mixed configuration across two host bridges, each with its
+own CXL window. Below cxl.1, two type3 volatile devices behind a switch use
+HDM-DB for coherence, which requires operating in Flit mode and a window
+that permits the device-coherent Back-Invalidate model. Below cxl.2, two
+plain host-only devices are directly attached and use the default window.
+Because a window targets a host bridge, giving each coherency model its own
+bridge keeps the window-to-device mapping explicit::
 
   qemu-system-x86_64 -M q35,cxl=on -m 4G,maxmem=8G,slots=8 -smp 4 \
   ...
@@ -395,17 +400,17 @@ use HDM-DB for coherence, which requires operating in Flit mode::
   -object memory-backend-ram,id=cxl-mem3,share=on,size=256M \
   -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
   -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0 \
-  -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1 \
   -device cxl-upstream,bus=root_port0,id=us0,x-256b-flit=on \
   -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
-  -device cxl-type3,bus=swport0,volatile-memdev=cxl-mem0,id=cxl-mem0,sn=0x1,x-256b-flit=on,hdm-db=on \
+  -device cxl-type3,bus=swport0,volatile-memdev=cxl-mem0,id=cxl-vmem0,sn=0x1,x-256b-flit=on,hdm-db=on \
   -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
-  -device cxl-type3,bus=swport1,volatile-memdev=cxl-mem1,id=cxl-mem1,sn=0x2,x-256b-flit=on,hdm-db=on \
-  -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6 \
-  -device cxl-type3,bus=swport2,volatile-memdev=cxl-mem2,id=cxl-mem2,sn=0x3 \
-  -device cxl-downstream,port=3,bus=us0,id=swport3,chassis=0,slot=7 \
-  -device cxl-type3,bus=swport3,volatile-memdev=cxl-mem3,id=cxl-mem3,sn=0x4 \
-  -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
+  -device cxl-type3,bus=swport1,volatile-memdev=cxl-mem1,id=cxl-vmem1,sn=0x2,x-256b-flit=on,hdm-db=on \
+  -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2 \
+  -device cxl-rp,port=0,bus=cxl.2,id=root_port1,chassis=0,slot=6 \
+  -device cxl-type3,bus=root_port1,volatile-memdev=cxl-mem2,id=cxl-vmem2,sn=0x3 \
+  -device cxl-rp,port=1,bus=cxl.2,id=root_port2,chassis=0,slot=7 \
+  -device cxl-type3,bus=root_port2,volatile-memdev=cxl-mem3,id=cxl-vmem3,sn=0x4 \
+  -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k,cxl-fmw.0.back-invalidate=on,cxl-fmw.1.targets.0=cxl.2,cxl-fmw.1.size=4G,cxl-fmw.1.interleave-granularity=4k
 
 A simple arm/virt example featuring a single direct connected CXL Type 3
 Volatile Memory device::
qapi/machine.json +28 -0
index 2d63c1bac3..de6460f091 100644
@@ -552,15 +552,43 @@
 #     accesses will go to a given interleave target.  Accepted values
 #     [256, 512, 1k, 2k, 4k, 8k, 16k]
 #
+# @device-coherent: Window permits device-coherent (minimally HDM-D)
+#     accesses.  (since 11.1)
+#
+# @host-only: Window permits host-only coherent (HDM-H) accesses.
+#     (since 11.1)
+#
+# @volatile: Window permits volatile memory.  (since 11.1)
+#
+# @persistent: Window permits persistent memory.  (since 11.1)
+#
+# @fixed-config: Window has a fixed device configuration.  Advertised
+#     in the CEDT only; not otherwise emulated.  (since 11.1)
+#
+# @back-invalidate: Window permits Back-Invalidate (HDM-DB).  Implies
+#     @device-coherent.  (since 11.1)
+#
 # @targets: Target root bridge IDs from -device ...,id=<ID> for each
 #     root bridge.
 #
+# Coherency defaults to both device-coherent and host-only; disabling
+# one (host-only=off or device-coherent=off) narrows to the other.
+# @back-invalidate implies device-coherent and is not host-only.
+# @volatile and @persistent default on.  host-only coherent combined
+# with @back-invalidate is rejected as undefined behavior.
+#
 # Since: 7.1
 ##
 { 'struct': 'CXLFixedMemoryWindowOptions',
   'data': {
       'size': 'size',
       '*interleave-granularity': 'size',
+      '*device-coherent': 'bool',
+      '*host-only': 'bool',
+      '*volatile': 'bool',
+      '*persistent': 'bool',
+      '*fixed-config': 'bool',
+      '*back-invalidate': 'bool',
       'targets': ['str'] }}
 
 ##
include/hw/cxl/cxl.h +12 -0
index d8cd8359d2..7cf3dc622c 100644
@@ -27,6 +27,17 @@
 
 typedef struct PXBCXLDev PXBCXLDev;
 
+/*
+ * CEDT CFMWS "Window Restrictions" bits (CXL r4.0 9.18.1.3), advertising
+ * which capabilities the host bridges below this window support.
+ */
+#define CXL_FMW_DEVICE_COHERENT (1 << 0) /* HDM-D */
+#define CXL_FMW_HOST_ONLY       (1 << 1) /* HDM-H */
+#define CXL_FMW_VOLATILE        (1 << 2)
+#define CXL_FMW_PERSISTENT      (1 << 3)
+#define CXL_FMW_FIXED_CONFIG    (1 << 4)
+#define CXL_FMW_BI              (1 << 5) /* HDM-DB, Back-Invalidate */
+
 typedef struct CXLFixedWindow {
     SysBusDevice parent_obj;
     int index;
@@ -36,6 +47,7 @@ typedef struct CXLFixedWindow {
     uint8_t num_targets;
     uint8_t enc_int_ways;
     uint8_t enc_int_gran;
+    uint16_t restrictions;
     /* Todo: XOR based interleaving */
     MemoryRegion mr;
     hwaddr base;
hw/acpi/cxl.c +1 -1
index 75edb2c0a6..77c1db6561 100644
@@ -172,7 +172,7 @@ static void cedt_build_cfmws(CXLFixedWindow *fw, Aml *cedt)
     build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
 
     /* Window Restrictions */
-    build_append_int_noprefix(table_data, 0x0f, 2);
+    build_append_int_noprefix(table_data, fw->restrictions, 2);
 
     /* QTG ID */
     build_append_int_noprefix(table_data, 0, 2);
hw/cxl/cxl-host.c +46 -0

52 lines not on this page · raw message

Signature · 1 line
MST
#4 lore raw

[PULL 70/90] hw/cxl: fix the CDAT DOE overlapping the Flex Bus DVSEC when sn= is set

In reply to Michael S. Tsirkin

From: Junjie Cao <[email protected]>

ct3_realize() adds the CDAT DOE at a fixed 0x190. Since 8700ee15de the four DVSECs take 0x90 bytes, which from 0x100 ends exactly at 0x190. With sn= the Device Serial Number capability pushes the block to 0x10c..0x19c, and the DOE, added later, overwrites the last 12 bytes of the Flex Bus Port DVSEC: Capability2, Control2 and Status2. Nothing catches this -- pcie_add_capability() checks bounds, not overlap, and the chain still walks because the DVSEC's next pointer becomes 0x190, inside its own body. Most cxl-type3 examples in docs/system/devices/cxl.rst set sn=.

Derive the offset from the DVSEC block instead, as cxl_upstream.c already does. Without sn= the layout is unchanged byte for byte; with sn= the DOE moves to 0x19c, below the AER capability at 0x200. The type 3 device has no VMStateDescription, so its config space never reaches the migration stream.

Fixes 8700ee15de ("hw/cxl: Standardize all references on CXL r3.1 and minor updates")

Message-ID: <[email protected]>

---
 hw/mem/cxl_type3.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
hw/mem/cxl_type3.c +2 -2
index 6f44770db6..a04dc74ecc 100644
@@ -936,8 +936,8 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
     }
 
     /* DOE Initialization */
-    pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true,
-                  CXL_T3_MSIX_PCIE_DOE_TABLE_ACCESS);
+    pcie_doe_init(pci_dev, &ct3d->doe_cdat, cxl_cstate->dvsec_offset,
+                  doe_cdat_prot, true, CXL_T3_MSIX_PCIE_DOE_TABLE_ACCESS);
 
     cxl_cstate->cdat.build_cdat_table = ct3_build_cdat_table;
     cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table;
Signature · 1 line
MST
#5 lore raw

[PULL 84/90] vhost-user: add skip_drain param to do_vhost_virtqueue_stop

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

Currently do_vhost_virtqueue_stop always sends GET_VRING_BASE to the back-end, which requires the back-end to drain all in-flight I/O before stopping the vring.

Add a skip_drain parameter to do_vhost_virtqueue_stop and propagate it up through vhost_virtqueue_stop, vhost_dev_stop and their callers. The parameter will be used in a follow-up commit to send a new protocol message that instructs the back-end to suspend in-flight I/O immediately instead of draining it.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost.h      |  7 +++++--
 backends/cryptodev-vhost.c     |  2 +-
 backends/vhost-user.c          |  2 +-
 hw/block/vhost-user-blk.c      |  2 +-
 hw/display/vhost-user-media.c  |  2 +-
 hw/net/vhost_net.c             |  9 +++++----
 hw/scsi/vhost-scsi-common.c    |  2 +-
 hw/virtio/vdpa-dev.c           |  2 +-
 hw/virtio/vhost-user-base.c    |  2 +-
 hw/virtio/vhost-user-fs.c      |  2 +-
 hw/virtio/vhost-user-scmi.c    |  2 +-
 hw/virtio/vhost-vsock-common.c |  2 +-
 hw/virtio/vhost.c              | 28 +++++++++++++++++++---------
 13 files changed, 39 insertions(+), 25 deletions(-)
include/hw/virtio/vhost.h +5 -2
index cd012b99a2..cd6e200538 100644
@@ -277,6 +277,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings);
  * @hdev: common vhost_dev structure
  * @vdev: the VirtIODevice structure
  * @vrings: true to have vrings disabled in this call
+ * @skip_drain: true to notice back-end to skip draining all in-flight requests
  *
  * Stop the vhost device. After the device is stopped the notifiers
  * can be disabled (@vhost_dev_disable_notifiers) and the device can
@@ -284,7 +285,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings);
  *
  * Return: 0 on success, != 0 on error when stopping dev.
  */
-int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings);
+int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings,
+                   bool skip_drain);
 
 /**
  * vhost_dev_force_stop() - force stop the vhost device
@@ -445,7 +447,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write);
 int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev,
                           struct vhost_virtqueue *vq, unsigned idx);
 int vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev,
-                         struct vhost_virtqueue *vq, unsigned idx);
+                         struct vhost_virtqueue *vq, unsigned idx,
+                         bool skip_drain);
 
 void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
 void vhost_dev_free_inflight(struct vhost_inflight *inflight);
backends/cryptodev-vhost.c +1 -1
index c6069f4e5b..f1ca6bcd4e 100644
@@ -109,7 +109,7 @@ static void
 cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto,
                                  VirtIODevice *dev)
 {
-    vhost_dev_stop(&crypto->dev, dev, false);
+    vhost_dev_stop(&crypto->dev, dev, false, false);
     vhost_dev_disable_notifiers(&crypto->dev, dev);
 }
 
backends/vhost-user.c +1 -1
index 46dadb7480..de6b1ba267 100644
@@ -108,7 +108,7 @@ vhost_user_backend_stop(VhostUserBackend *b)
         return 0;
     }
 
-    ret = vhost_dev_stop(&b->dev, b->vdev, true);
+    ret = vhost_dev_stop(&b->dev, b->vdev, true, false);
 
     if (k->set_guest_notifiers &&
         (err = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false)) < 0) {
hw/block/vhost-user-blk.c +1 -1
index 2e5b3ae1b1..c3e3c37f8c 100644
@@ -238,7 +238,7 @@ static int vhost_user_blk_stop(VirtIODevice *vdev)
                  qemu_force_shutdown_requested();
 
     ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) :
-                       vhost_dev_stop(&s->dev, vdev, true);
+                       vhost_dev_stop(&s->dev, vdev, true, false);
 
     err = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
     if (err < 0) {
hw/display/vhost-user-media.c +1 -1
index eaf99dc6a2..851af8ddc2 100644
@@ -110,7 +110,7 @@ static void vu_media_stop(VirtIODevice *vdev)
         return;
     }
 
-    vhost_dev_stop(&media->vhost_dev, vdev, true);
+    vhost_dev_stop(&media->vhost_dev, vdev, true, false);
 
     ret = k->set_guest_notifiers(qbus->parent, media->vhost_dev.nvqs, false);
     if (ret < 0) {
hw/net/vhost_net.c +5 -4
index 323d117735..6e05c995f1 100644
@@ -384,7 +384,7 @@ fail:
     if (net->nc->info->poll) {
         net->nc->info->poll(net->nc, true);
     }
-    vhost_dev_stop(&net->dev, dev, false);
+    vhost_dev_stop(&net->dev, dev, false, false);
 fail_start:
     return r;
 }
@@ -403,7 +403,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
     if (net->nc->info->poll) {
         net->nc->info->poll(net->nc, true);
     }
-    vhost_dev_stop(&net->dev, dev, false);
+    vhost_dev_stop(&net->dev, dev, false, false);
     if (net->nc->info->stop) {
         net->nc->info->stop(net->nc);
     }
@@ -636,7 +636,8 @@ void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
     vhost_virtqueue_stop(&net->dev,
                          vdev,
                          net->dev.vqs + idx,
-                         net->dev.vq_index + idx);
+                         net->dev.vq_index + idx,
+                         false);
 }
 
 int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
@@ -686,7 +687,7 @@ err_start:
         assert(ret >= 0);
     }
 
-    vhost_dev_stop(&net->dev, vdev, false);
+    vhost_dev_stop(&net->dev, vdev, false, false);
 
     return r;
 }
hw/scsi/vhost-scsi-common.c +1 -1
index e19800a0bc..e546a6dc75 100644
@@ -108,7 +108,7 @@ int vhost_scsi_common_stop(VHostSCSICommon *vsc)
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     int ret = 0;
 
-    ret = vhost_dev_stop(&vsc->dev, vdev, true);
+    ret = vhost_dev_stop(&vsc->dev, vdev, true, false);
 
     if (k->set_guest_notifiers) {
         int r = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
hw/virtio/vdpa-dev.c +1 -1
index 6dc684ab09..7e5cc040e9 100644
@@ -301,7 +301,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev)
         return;
     }
 
-    vhost_dev_stop(&s->dev, vdev, false);
+    vhost_dev_stop(&s->dev, vdev, false, false);
 
     ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
     if (ret < 0) {
hw/virtio/vhost-user-base.c +1 -1
index 478ec68f09..1a377016e7 100644
@@ -78,7 +78,7 @@ static int vub_stop(VirtIODevice *vdev)
         return 0;
     }
 
-    ret = vhost_dev_stop(&vub->vhost_dev, vdev, true);
+    ret = vhost_dev_stop(&vub->vhost_dev, vdev, true, false);
 
     err = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false);
     if (err < 0) {
hw/virtio/vhost-user-fs.c +1 -1
index 209993918a..0d8842817a 100644
@@ -111,7 +111,7 @@ static int vuf_stop(VirtIODevice *vdev)
         return 0;
     }
 
-    ret = vhost_dev_stop(&fs->vhost_dev, vdev, true);
+    ret = vhost_dev_stop(&fs->vhost_dev, vdev, true, false);
 
     err = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
     if (err < 0) {
hw/virtio/vhost-user-scmi.c +1 -1
index 02dc088ea9..c4692bd6aa 100644
@@ -101,7 +101,7 @@ static int vu_scmi_stop(VirtIODevice *vdev)
         return 0;
     }
 
-    ret = vhost_dev_stop(vhost_dev, vdev, true);
+    ret = vhost_dev_stop(vhost_dev, vdev, true, false);
 
     err = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false);
     if (err < 0) {
hw/virtio/vhost-vsock-common.c +1 -1
index b79f4c9ce6..4ef037627b 100644
@@ -106,7 +106,7 @@ int vhost_vsock_common_stop(VirtIODevice *vdev)
         return 0;
     }
 
-    ret = vhost_dev_stop(&vvc->vhost_dev, vdev, true);
+    ret = vhost_dev_stop(&vvc->vhost_dev, vdev, true, false);
 
     err = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false);
     if (err < 0) {
hw/virtio/vhost.c +19 -9
index 6c2612a1dd..17b36366dc 100644
@@ -23,6 +23,7 @@
 #include "qemu/log.h"
 #include "standard-headers/linux/vhost_types.h"
 #include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user.h"
 #include "hw/mem/memory-device.h"
 #include "migration/blocker.h"
 #include "migration/qemu-file-types.h"
@@ -1509,8 +1510,13 @@ fail:
 static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
                                    struct VirtIODevice *vdev,
                                    struct vhost_virtqueue *vq,
-                                   unsigned idx, bool force)
+                                   unsigned idx, bool force,
+                                   bool skip_drain)
 {
+    if (skip_drain) {
+        assert(vhost_user_has_protocol_feature(dev,
+               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT));
+    }
     int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
     struct vhost_vring_state state = {
         .index = vhost_vq_index,
@@ -1560,9 +1566,10 @@ static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
 int vhost_virtqueue_stop(struct vhost_dev *dev,
                          struct VirtIODevice *vdev,
                          struct vhost_virtqueue *vq,
-                         unsigned idx)
+                         unsigned idx,
+                         bool skip_drain)
 {
-    return do_vhost_virtqueue_stop(dev, vdev, vq, idx, false);
+    return do_vhost_virtqueue_stop(dev, vdev, vq, idx, false, skip_drain);
 }
 
 static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
@@ -2350,7 +2357,8 @@ fail_vq:
         vhost_virtqueue_stop(hdev,
                              vdev,
                              hdev->vqs + i,
-                             hdev->vq_index + i);
+                             hdev->vq_index + i,
+                             false);
     }
 
 fail_mem:
@@ -2365,7 +2373,7 @@ fail_features:
 
 /* Host notifiers must be enabled at this point. */
 static int do_vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
-                             bool vrings, bool force)
+                             bool vrings, bool force, bool skip_drain)
 {
     int i;
     int rc = 0;
@@ -2392,7 +2400,8 @@ static int do_vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
                                       vdev,
                                       hdev->vqs + i,
                                       hdev->vq_index + i,
-                                      force);
+                                      force,
+                                      skip_drain);
     }
     if (hdev->vhost_ops->vhost_reset_status) {
         hdev->vhost_ops->vhost_reset_status(hdev);
@@ -2414,15 +2423,16 @@ static int do_vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
     return rc;
 }
 
-int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
+int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings,
+                   bool skip_drain)
 {
-    return do_vhost_dev_stop(hdev, vdev, vrings, false);
+    return do_vhost_dev_stop(hdev, vdev, vrings, false, skip_drain);
 }
 
 int vhost_dev_force_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
                          bool vrings)
 {
-    return do_vhost_dev_stop(hdev, vdev, vrings, true);
+    return do_vhost_dev_stop(hdev, vdev, vrings, true, false);
 }
 
 int vhost_net_set_backend(struct vhost_dev *hdev,
Signature · 1 line
MST
#6 lore raw

[PULL 80/90] hw/hotplug: Constify HotplugHandler

In reply to Michael S. Tsirkin

From: Philippe Mathieu-Daudé <[email protected]>

HotplugHandler value returned from qdev_get_hotplug_handler() points to the handler of and object implementing the TYPE_HOTPLUG_HANDLER interface. That handler mostly points to read-only section which shouldn't not be updated. Better protect it with the const qualifier.

Mechanical change using 'sed' then manually adapted coding style.

Message-ID: <[email protected]>

---
 hw/s390x/ccw-device.h                  |  2 +-
 include/hw/acpi/cpu.h                  |  4 +--
 include/hw/acpi/cpu_hotplug.h          |  2 +-
 include/hw/acpi/generic_event_device.h |  3 +-
 include/hw/acpi/ich9.h                 | 10 +++---
 include/hw/acpi/memory_hotplug.h       |  4 +--
 include/hw/acpi/pcihp.h                |  8 ++---
 include/hw/core/boards.h               |  4 +--
 include/hw/core/hotplug.h              | 13 +++----
 include/hw/core/qdev.h                 | 12 +++----
 include/hw/i386/microvm.h              |  4 +--
 include/hw/i386/x86.h                  | 10 +++---
 include/hw/mem/nvdimm.h                |  2 +-
 include/hw/pci/pci_bridge.h            |  6 ++--
 include/hw/pci/pcie.h                  |  8 ++---
 include/hw/pci/shpc.h                  |  6 ++--
 include/hw/ppc/spapr_nvdimm.h          |  2 +-
 hw/acpi/acpi-cpu-hotplug-stub.c        |  4 +--
 hw/acpi/acpi-mem-hotplug-stub.c        |  4 +--
 hw/acpi/acpi-nvdimm-stub.c             |  2 +-
 hw/acpi/acpi-pci-hotplug-stub.c        |  8 ++---
 hw/acpi/cpu.c                          |  6 ++--
 hw/acpi/generic_event_device.c         | 11 +++---
 hw/acpi/ich9.c                         | 10 +++---
 hw/acpi/memory_hotplug.c               |  6 ++--
 hw/acpi/nvdimm.c                       |  2 +-
 hw/acpi/pcihp.c                        | 10 +++---
 hw/acpi/piix4.c                        | 12 +++----
 hw/arm/virt.c                          | 23 ++++++------
 hw/char/virtio-serial-bus.c            |  2 +-
 hw/core/hotplug.c                      |  8 ++---
 hw/core/qdev-hotplug.c                 | 10 +++---
 hw/core/qdev.c                         |  2 +-
 hw/i386/microvm.c                      | 12 +++----
 hw/i386/pc.c                           | 28 +++++++--------
 hw/i386/x86-common.c                   |  8 ++---
 hw/intc/loongarch_dintc.c              |  8 ++---
 hw/intc/loongarch_extioi_common.c      |  4 +--
 hw/intc/loongarch_ipi.c                |  4 +--
 hw/loongarch/virt.c                    | 44 +++++++++++------------
 hw/net/virtio-net.c                    |  4 +--
 hw/nvme/ctrl.c                         |  8 ++---
 hw/pci-bridge/pci_bridge_dev.c         |  6 ++--
 hw/pci/pcie.c                          | 10 +++---
 hw/pci/pcie_port.c                     |  2 +-
 hw/pci/shpc.c                          | 10 +++---
 hw/ppc/e500plat.c                      |  4 +--
 hw/ppc/spapr.c                         | 48 +++++++++++++-------------
 hw/ppc/spapr_nvdimm.c                  |  2 +-
 hw/ppc/spapr_pci.c                     | 12 +++----
 hw/remote/machine.c                    |  2 +-
 hw/riscv/virt.c                        |  6 ++--
 hw/s390x/css-bridge.c                  |  2 +-
 hw/s390x/s390-pci-bus.c                | 12 +++----
 hw/s390x/s390-virtio-ccw.c             | 16 ++++-----
 hw/s390x/virtio-ccw-md.c               |  8 ++---
 hw/s390x/virtio-ccw.c                  |  2 +-
 hw/scsi/virtio-scsi.c                  |  6 ++--
 hw/scsi/vmw_pvscsi.c                   |  4 +--
 hw/virtio/virtio-md-pci.c              |  8 ++---
 hw/xen/xen-bus.c                       |  2 +-
 stubs/hotplug-stubs.c                  |  6 ++--
 system/qdev-monitor.c                  |  2 +-
 63 files changed, 257 insertions(+), 253 deletions(-)
hw/s390x/ccw-device.h +1 -1
index 15f64cfb63..c303f1de42 100644
@@ -37,7 +37,7 @@ extern const VMStateDescription vmstate_ccw_dev;
 
 struct CCWDeviceClass {
     DeviceClass parent_class;
-    void (*unplug)(HotplugHandler *, DeviceState *, Error **);
+    void (*unplug)(const HotplugHandler *, DeviceState *, Error **);
     bool (*realize)(CcwDevice *, Error **);
     void (*refill_ids)(CcwDevice *);
 };
include/hw/acpi/cpu.h +2 -2
index 04c821d2b9..3664ac7a52 100644
@@ -39,10 +39,10 @@ typedef struct CPUHotplugState {
     AcpiCpuStatus *devs;
 } CPUHotplugState;
 
-void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_plug_cb(const HotplugHandler *hotplug_dev,
                       CPUHotplugState *cpu_st, DeviceState *dev, Error **errp);
 
-void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                 CPUHotplugState *cpu_st,
                                 DeviceState *dev, Error **errp);
 
include/hw/acpi/cpu_hotplug.h +1 -1
index 5b670b04eb..bac40ccfa0 100644
@@ -25,7 +25,7 @@ typedef struct AcpiCpuHotplug {
     uint8_t sts[ACPI_GPE_PROC_LEN];
 } AcpiCpuHotplug;
 
-void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
+void legacy_acpi_cpu_plug_cb(const HotplugHandler *hotplug_dev,
                              AcpiCpuHotplug *g, DeviceState *dev, Error **errp);
 
 void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
include/hw/acpi/generic_event_device.h +2 -1
index 7cbfb5fe7d..42a8033a23 100644
@@ -136,7 +136,8 @@ typedef struct AcpiGedClass {
     ResettablePhases parent_phases;
 } AcpiGedClass;
 
-void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
+void build_ged_aml(Aml *table, const char *name,
+                   const HotplugHandler *hotplug_dev,
                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
 void acpi_dsdt_add_power_button(Aml *scope);
 
include/hw/acpi/ich9.h +5 -5
index 6d14544751..6956b2b9c9 100644
@@ -85,15 +85,15 @@ void ich9_pm_reset_properties(ICH9LPCPMRegs *pm);
 
 void ich9_pm_add_class_properties(ObjectClass *oc, ptrdiff_t pm_offset);
 
-void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_pre_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                 Error **errp);
-void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                             Error **errp);
-void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void ich9_pm_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp);
-void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                               Error **errp);
-bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus);
+bool ich9_pm_is_hotpluggable_bus(const HotplugHandler *hotplug_dev, BusState *bus);
 
 void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list);
 #endif /* HW_ACPI_ICH9_H */
include/hw/acpi/memory_hotplug.h +2 -2
index eb7f460afe..6e4f82bcf9 100644
@@ -36,9 +36,9 @@ typedef struct MemHotplugState {
 void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
                               MemHotplugState *state, hwaddr io_base);
 
-void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
+void acpi_memory_plug_cb(const HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
                          DeviceState *dev, Error **errp);
-void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_memory_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                    MemHotplugState *mem_st,
                                    DeviceState *dev, Error **errp);
 void acpi_memory_unplug_cb(MemHotplugState *mem_st,
include/hw/acpi/pcihp.h +4 -4
index efce5fd2e1..21c0b72355 100644
@@ -66,13 +66,13 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *,
                      MemoryRegion *io, uint16_t io_base);
 
 bool acpi_pcihp_is_hotpluggable_bus(AcpiPciHpState *s, BusState *bus);
-void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp);
-void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_plug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                DeviceState *dev, Error **errp);
-void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_unplug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                  DeviceState *dev, Error **errp);
-void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                          AcpiPciHpState *s, DeviceState *dev,
                                          Error **errp);
 
include/hw/core/boards.h +2 -2
index a436d48c8e..dba465efc2 100644
@@ -322,8 +322,8 @@ struct MachineClass {
     SMPCompatProps smp_props;
     const char *default_ram_id;
 
-    HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
-                                           DeviceState *dev);
+    const HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
+                                                 DeviceState *dev);
     bool (*hotplug_allowed)(MachineState *state, DeviceState *dev,
                             Error **errp);
     CpuInstanceProperties (*cpu_index_to_instance_props)(MachineState *machine,
include/hw/core/hotplug.h +7 -6
index a9840ed485..0c69be60ee 100644
@@ -30,7 +30,7 @@ typedef struct HotplugHandler HotplugHandler;
  * @plugged_dev: a device that has been (un)plugged
  * @errp: returns an error if this function fails
  */
-typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
+typedef void (*hotplug_fn)(const HotplugHandler *plug_handler,
                            DeviceState *plugged_dev, Error **errp);
 
 /**
@@ -59,7 +59,8 @@ struct HotplugHandlerClass {
     hotplug_fn plug;
     hotplug_fn unplug_request;
     hotplug_fn unplug;
-    bool (*is_hotpluggable_bus)(HotplugHandler *plug_handler, BusState *bus);
+    bool (*is_hotpluggable_bus)(const HotplugHandler *plug_handler,
+                                BusState *bus);
 };
 
 /**
@@ -67,7 +68,7 @@ struct HotplugHandlerClass {
  *
  * Call #HotplugHandlerClass.plug callback of @plug_handler.
  */
-void hotplug_handler_plug(HotplugHandler *plug_handler,
+void hotplug_handler_plug(const HotplugHandler *plug_handler,
                           DeviceState *plugged_dev,
                           Error **errp);
 
@@ -76,7 +77,7 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
  *
  * Call #HotplugHandlerClass.pre_plug callback of @plug_handler.
  */
-void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
+void hotplug_handler_pre_plug(const HotplugHandler *plug_handler,
                               DeviceState *plugged_dev,
                               Error **errp);
 
@@ -85,7 +86,7 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
  *
  * Calls #HotplugHandlerClass.unplug_request callback of @plug_handler.
  */
-void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
+void hotplug_handler_unplug_request(const HotplugHandler *plug_handler,
                                     DeviceState *plugged_dev,
                                     Error **errp);
 /**
@@ -93,7 +94,7 @@ void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
  *
  * Calls #HotplugHandlerClass.unplug callback of @plug_handler.
  */
-void hotplug_handler_unplug(HotplugHandler *plug_handler,
+void hotplug_handler_unplug(const HotplugHandler *plug_handler,
                             DeviceState *plugged_dev,
                             Error **errp);
 #endif
include/hw/core/qdev.h +6 -6
index e4cb027ab3..1f6bf3fc1a 100644
@@ -386,7 +386,7 @@ struct BusState {
     /* public: */
     DeviceState *parent;
     char *name;
-    HotplugHandler *hotplug_handler;
+    const HotplugHandler *hotplug_handler;
     int max_index;
     bool realized;
     bool full;
@@ -514,8 +514,8 @@ bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
 void qdev_unrealize(DeviceState *dev);
 void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                  int required_for_version);
-HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
-HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
+const HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
+const HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
 bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp);
 bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp);
 
@@ -529,10 +529,10 @@ bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp);
  * Return: pointer to object that implements TYPE_HOTPLUG_HANDLER interface
  * or NULL if there aren't any.
  */
-HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
+const HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
 void qdev_unplug(DeviceState *dev, Error **errp);
 int qdev_sync_config(DeviceState *dev, Error **errp);
-void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
+void qdev_simple_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                   DeviceState *dev, Error **errp);
 void qdev_machine_creation_done(void);
 bool qdev_machine_modified(void);
@@ -1065,7 +1065,7 @@ void qbus_set_bus_hotplug_handler(BusState *bus);
 
 static inline bool qbus_is_hotpluggable(BusState *bus)
 {
-    HotplugHandler *plug_handler = bus->hotplug_handler;
+    const HotplugHandler *plug_handler = bus->hotplug_handler;
     bool ret = !!plug_handler;
 
     if (plug_handler) {
include/hw/i386/microvm.h +2 -2
index 184b7a8c09..5d5eacd1c6 100644
@@ -76,8 +76,8 @@
 
 struct MicrovmMachineClass {
     X86MachineClass parent;
-    HotplugHandler *(*orig_hotplug_handler)(MachineState *machine,
-                                           DeviceState *dev);
+    const HotplugHandler *(*orig_hotplug_handler)(MachineState *machine,
+                                                  DeviceState *dev);
     void (*x86_load_linux)(X86MachineState *x86ms, FWCfgState *fw_cfg,
                            int acpi_data_size);
 };
include/hw/i386/x86.h +5 -5
index 71fe6b5e12..abb073ca47 100644
@@ -46,7 +46,7 @@ struct X86MachineState {
     qemu_irq *gsi;
     DeviceState *ioapic2;
     GMappedFile *initrd_mapped_file;
-    HotplugHandler *acpi_dev;
+    const HotplugHandler *acpi_dev;
 
     /*
      * Map the whole BIOS just underneath the 4 GiB address boundary. Only used
@@ -112,13 +112,13 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,
 
 void x86_cpus_init(X86MachineState *pcms, int default_cpu_version);
 void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count);
-void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
+void x86_cpu_pre_plug(const HotplugHandler *hotplug_dev,
                       DeviceState *dev, Error **errp);
-void x86_cpu_plug(HotplugHandler *hotplug_dev,
+void x86_cpu_plug(const HotplugHandler *hotplug_dev,
                   DeviceState *dev, Error **errp);
-void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
+void x86_cpu_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                DeviceState *dev, Error **errp);
-void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev,
+void x86_cpu_unplug_cb(const HotplugHandler *hotplug_dev,
                        DeviceState *dev, Error **errp);
 
 void x86_isa_bios_init(MemoryRegion *isa_bios, MemoryRegion *isa_memory,
include/hw/mem/nvdimm.h +1 -1
index d3b763453a..169a943e3c 100644
@@ -157,5 +157,5 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
                        uint32_t ram_slots, const char *oem_id,
                        const char *oem_table_id);
 void nvdimm_plug(NVDIMMState *state);
-void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev);
+void nvdimm_acpi_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev);
 #endif
include/hw/pci/pci_bridge.h +3 -3
index b61360b900..f114f0a651 100644
@@ -141,11 +141,11 @@ void pci_bridge_reset(DeviceState *qdev);
 void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
 void pci_bridge_exitfn(PCIDevice *pci_dev);
 
-void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pci_bridge_dev_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                             Error **errp);
-void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pci_bridge_dev_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                               Error **errp);
-void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
+void pci_bridge_dev_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp);
 
 /*
include/hw/pci/pcie.h +4 -4
index 71ba94874b..ec25e7a7de 100644
@@ -146,13 +146,13 @@ void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned);
 void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
                                PCIExpLinkSpeed speed, bool flitmode);
 
-void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_pre_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp);
-void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                            Error **errp);
-void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                              Error **errp);
-void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
+void pcie_cap_slot_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp);
 
 void pcie_pasid_common_init(PCIDevice *dev, uint16_t offset,
include/hw/pci/shpc.h +3 -3
index fce5bdd3bc..67becb5c56 100644
@@ -45,11 +45,11 @@ void shpc_free(PCIDevice *dev);
 void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
 
 
-void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void shpc_device_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                          Error **errp);
-void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void shpc_device_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                            Error **errp);
-void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void shpc_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp);
 
 extern const VMStateInfo shpc_vmstate_info;
include/hw/ppc/spapr_nvdimm.h +1 -1
index e9436cb6ef..386da92042 100644
@@ -18,7 +18,7 @@ typedef struct SpaprMachineState SpaprMachineState;
 int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
                            void *fdt, int *fdt_start_offset, Error **errp);
 void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt);
-bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
+bool spapr_nvdimm_validate(const HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
                            uint64_t size, Error **errp);
 void spapr_add_nvdimm(DeviceState *dev, uint64_t slot);
 void spapr_nvdimm_finish_flushes(void);
hw/acpi/acpi-cpu-hotplug-stub.c +2 -2
index 72c5f05f5c..2e05d7100b 100644
@@ -14,7 +14,7 @@ void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
 {
 }
 
-void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_plug_cb(const HotplugHandler *hotplug_dev,
                       CPUHotplugState *cpu_st, DeviceState *dev, Error **errp)
 {
 }
@@ -24,7 +24,7 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st,
 {
 }
 
-void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                 CPUHotplugState *cpu_st,
                                 DeviceState *dev, Error **errp)
 {
hw/acpi/acpi-mem-hotplug-stub.c +2 -2
index 7ad0fdcdf2..c218813fd1 100644
@@ -13,7 +13,7 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
 {
 }
 
-void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
+void acpi_memory_plug_cb(const HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
                          DeviceState *dev, Error **errp)
 {
 }
@@ -23,7 +23,7 @@ void acpi_memory_unplug_cb(MemHotplugState *mem_st,
 {
 }
 
-void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_memory_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                    MemHotplugState *mem_st,
                                    DeviceState *dev, Error **errp)
 {
hw/acpi/acpi-nvdimm-stub.c +1 -1
index 22ba17f511..0120bacaac 100644
@@ -2,6 +2,6 @@
 #include "hw/mem/nvdimm.h"
 #include "hw/core/hotplug.h"
 
-void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev)
+void nvdimm_acpi_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev)
 {
 }
hw/acpi/acpi-pci-hotplug-stub.c +4 -4
index d58ea726a8..20625c7ed7 100644
@@ -9,22 +9,22 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s,
 {
 }
 
-void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_plug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                DeviceState *dev, Error **errp)
 {
 }
 
-void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
 }
 
-void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_unplug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                  DeviceState *dev, Error **errp)
 {
 }
 
-void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                          AcpiPciHpState *s, DeviceState *dev,
                                          Error **errp)
 {
hw/acpi/cpu.c +3 -3
index d63ca83c1b..ef97ed779a 100644
@@ -132,7 +132,7 @@ static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
             trace_cpuhp_acpi_clear_remove_evt(cpu_st->selector);
         } else if (data & 8) {
             DeviceState *dev = NULL;
-            HotplugHandler *hotplug_ctrl = NULL;
+            const HotplugHandler *hotplug_ctrl;
 
             if (!cdev->cpu || cdev->cpu == first_cpu) {
                 trace_cpuhp_acpi_ejecting_invalid_cpu(cpu_st->selector);
@@ -247,7 +247,7 @@ static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
     return NULL;
 }
 
-void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_plug_cb(const HotplugHandler *hotplug_dev,
                       CPUHotplugState *cpu_st, DeviceState *dev, Error **errp)
 {
     AcpiCpuStatus *cdev;
@@ -264,7 +264,7 @@ void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_cpu_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                 CPUHotplugState *cpu_st,
                                 DeviceState *dev, Error **errp)
 {
hw/acpi/generic_event_device.c +6 -5
index 5225e32513..65a5d1612f 100644
@@ -45,7 +45,8 @@ static const uint32_t ged_supported_events[] = {
  * affected by the interrupt. This way, we can support up to 32 events
  * with a unique interrupt.
  */
-void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
+void build_ged_aml(Aml *table, const char *name,
+                   const HotplugHandler *hotplug_dev,
                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
 {
     const AcpiGedState *s = ACPI_GED(hotplug_dev);
@@ -250,7 +251,7 @@ static const MemoryRegionOps ged_regs_ops = {
     },
 };
 
-static void acpi_ged_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+static void acpi_ged_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
@@ -258,7 +259,7 @@ static void acpi_ged_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
+static void acpi_ged_device_plug_cb(const HotplugHandler *hotplug_dev,
                                     DeviceState *dev, Error **errp)
 {
     AcpiGedState *s = ACPI_GED(hotplug_dev);
@@ -279,7 +280,7 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
+static void acpi_ged_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                        DeviceState *dev, Error **errp)
 {
     AcpiGedState *s = ACPI_GED(hotplug_dev);
@@ -298,7 +299,7 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
+static void acpi_ged_unplug_cb(const HotplugHandler *hotplug_dev,
                                DeviceState *dev, Error **errp)
 {
     AcpiGedState *s = ACPI_GED(hotplug_dev);
hw/acpi/ich9.c +5 -5
index 8082eae428..6d421b990c 100644
@@ -410,7 +410,7 @@ void ich9_pm_add_class_properties(ObjectClass *oc, ptrdiff_t pm_offset)
 
 #undef PM_REG_FIELD
 
-void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_pre_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                 Error **errp)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
@@ -432,7 +432,7 @@ void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                             Error **errp)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
@@ -455,7 +455,7 @@ void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void ich9_pm_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
@@ -489,7 +489,7 @@ void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void ich9_pm_device_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                               Error **errp)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
@@ -507,7 +507,7 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
+bool ich9_pm_is_hotpluggable_bus(const HotplugHandler *hotplug_dev, BusState *bus)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
     return acpi_pcihp_is_hotpluggable_bus(&lpc->pm.acpi_pci_hotplug, bus);
hw/acpi/memory_hotplug.c +3 -3
index f482c835a1..b5b6d6ada6 100644
@@ -166,7 +166,7 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
             mdev->is_removing = false;
             trace_mhp_acpi_clear_remove_evt(mem_st->selector);
         } else if (data & 8) {
-            HotplugHandler *hotplug_ctrl;
+            const HotplugHandler *hotplug_ctrl;
 
             if (!mdev->is_enabled) {
                 trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
@@ -254,7 +254,7 @@ acpi_memory_slot_status(MemHotplugState *mem_st,
     return &mem_st->devs[slot];
 }
 
-void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
+void acpi_memory_plug_cb(const HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
                          DeviceState *dev, Error **errp)
 {
     MemStatus *mdev;
@@ -277,7 +277,7 @@ void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
     }
 }
 
-void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_memory_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                    MemHotplugState *mem_st,
                                    DeviceState *dev, Error **errp)
 {
hw/acpi/nvdimm.c +1 -1
index 703e854951..5a7ff1ede8 100644
@@ -887,7 +887,7 @@ static const MemoryRegionOps nvdimm_dsm_ops = {
     },
 };
 
-void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev)
+void nvdimm_acpi_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev)
 {
     if (dev->hotplugged) {
         acpi_send_event(DEVICE(hotplug_dev), ACPI_NVDIMM_HOTPLUG_STATUS);
hw/acpi/pcihp.c +5 -5
index 336ebe1a13..b69379a18b 100644
@@ -209,7 +209,7 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
                      */
                     qdev->pending_deleted_event = false;
                 } else {
-                    HotplugHandler *hotplug_ctrl;
+                    const HotplugHandler *hotplug_ctrl;
 
                     hotplug_ctrl = qdev_get_hotplug_handler(qdev);
                     hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
@@ -261,7 +261,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s)
     acpi_pcihp_update(s);
 }
 
-void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     PCIDevice *pdev = PCI_DEVICE(dev);
@@ -275,7 +275,7 @@ void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_plug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                DeviceState *dev, Error **errp)
 {
     PCIDevice *pdev = PCI_DEVICE(dev);
@@ -317,7 +317,7 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
     acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
 }
 
-void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+void acpi_pcihp_device_unplug_cb(const HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                  DeviceState *dev, Error **errp)
 {
     PCIDevice *pdev = PCI_DEVICE(dev);
@@ -328,7 +328,7 @@ void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
     qdev_unrealize(dev);
 }
 
-void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void acpi_pcihp_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                          AcpiPciHpState *s, DeviceState *dev,
                                          Error **errp)
 {
hw/acpi/piix4.c +6 -6
index 52bd61667f..a7d5356340 100644
@@ -303,8 +303,8 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
     acpi_pm1_evt_power_down(&s->ar);
 }
 
-static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
-                                    DeviceState *dev, Error **errp)
+static void piix4_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
+                                     DeviceState *dev, Error **errp)
 {
     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
 
@@ -323,7 +323,7 @@ static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
+static void piix4_device_plug_cb(const HotplugHandler *hotplug_dev,
                                  DeviceState *dev, Error **errp)
 {
     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
@@ -344,7 +344,7 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+static void piix4_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                            DeviceState *dev, Error **errp)
 {
     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
@@ -364,7 +364,7 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
+static void piix4_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
@@ -383,7 +383,7 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static bool piix4_is_hotpluggable_bus(HotplugHandler *hotplug_dev,
+static bool piix4_is_hotpluggable_bus(const HotplugHandler *hotplug_dev,
                                       BusState *bus)
 {
     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
hw/arm/virt.c +12 -11
index 0871a35e11..3eecf094bc 100644
@@ -3753,7 +3753,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
     return ms->possible_cpus;
 }
 
-static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void virt_memory_pre_plug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                  Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3779,7 +3779,7 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), errp);
 }
 
-static void virt_memory_plug(HotplugHandler *hotplug_dev,
+static void virt_memory_plug(const HotplugHandler *hotplug_dev,
                              DeviceState *dev, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3798,7 +3798,7 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev,
     }
 }
 
-static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+static void virt_machine_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                             DeviceState *dev, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3896,7 +3896,7 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+static void virt_machine_device_plug_cb(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3957,7 +3957,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev,
+static void virt_dimm_unplug_request(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3977,7 +3977,7 @@ static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev,
                                    errp);
 }
 
-static void virt_dimm_unplug(HotplugHandler *hotplug_dev,
+static void virt_dimm_unplug(const HotplugHandler *hotplug_dev,
                              DeviceState *dev, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
@@ -3995,8 +3995,9 @@ out:
     error_propagate(errp, local_err);
 }
 
-static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
-                                          DeviceState *dev, Error **errp)
+static void
+virt_machine_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
+                                      DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
         virt_dimm_unplug_request(hotplug_dev, dev, errp);
@@ -4009,7 +4010,7 @@ static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
+static void virt_machine_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                           DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
@@ -4022,8 +4023,8 @@ static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
-                                                        DeviceState *dev)
+static const HotplugHandler *
+virt_machine_get_hotplug_handler(MachineState *machine, DeviceState *dev)
 {
     MachineClass *mc = MACHINE_GET_CLASS(machine);
 
hw/char/virtio-serial-bus.c +1 -1
index 81db0bdc91..c36e18a4cf 100644
@@ -979,7 +979,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
     port->elem = NULL;
 }
 
-static void virtser_port_device_plug(HotplugHandler *hotplug_dev,
+static void virtser_port_device_plug(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
hw/core/hotplug.c +4 -4
index 00e80a67c8..3aca068840 100644
@@ -13,7 +13,7 @@
 #include "hw/core/hotplug.h"
 #include "qemu/module.h"
 
-void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
+void hotplug_handler_pre_plug(const HotplugHandler *plug_handler,
                               DeviceState *plugged_dev,
                               Error **errp)
 {
@@ -24,7 +24,7 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
     }
 }
 
-void hotplug_handler_plug(HotplugHandler *plug_handler,
+void hotplug_handler_plug(const HotplugHandler *plug_handler,
                           DeviceState *plugged_dev,
                           Error **errp)
 {
@@ -35,7 +35,7 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
     }
 }
 
-void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
+void hotplug_handler_unplug_request(const HotplugHandler *plug_handler,
                                     DeviceState *plugged_dev,
                                     Error **errp)
 {
@@ -46,7 +46,7 @@ void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
     }
 }
 
-void hotplug_handler_unplug(HotplugHandler *plug_handler,
+void hotplug_handler_unplug(const HotplugHandler *plug_handler,
                             DeviceState *plugged_dev,
                             Error **errp)
 {
hw/core/qdev-hotplug.c +5 -5
index 1d547e0dbd..d7fa8a5ed2 100644
@@ -14,7 +14,7 @@
 #include "hw/core/boards.h"
 #include "qapi/error.h"
 
-HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
+const HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
 {
     MachineState *machine;
     MachineClass *mc;
@@ -90,7 +90,7 @@ bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp)
            qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp);
 }
 
-HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
+const HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
 {
     if (dev->parent_bus) {
         return dev->parent_bus->hotplug_handler;
@@ -98,9 +98,9 @@ HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
     return NULL;
 }
 
-HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
+const HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
 {
-    HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
+    const HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
 
     if (hotplug_ctrl == NULL && dev->parent_bus) {
         hotplug_ctrl = qdev_get_bus_hotplug_handler(dev);
@@ -109,7 +109,7 @@ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
 }
 
 /* can be used as ->unplug() callback for the simple cases */
-void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
+void qdev_simple_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                   DeviceState *dev, Error **errp)
 {
     qdev_unrealize(dev);
hw/core/qdev.c +1 -1
index 0b0f2f47fa..c6540bec56 100644
@@ -501,7 +501,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
 {
     DeviceState *dev = DEVICE(obj);
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    HotplugHandler *hotplug_ctrl;
+    const HotplugHandler *hotplug_ctrl;
     BusState *bus;
     NamedClockList *ncl;
     Error *local_err = NULL;
hw/i386/microvm.c +6 -6
index e7adab7d2e..a49de33749 100644
@@ -416,7 +416,7 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
     g_free(cmdline);
 }
 
-static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+static void microvm_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                        DeviceState *dev, Error **errp)
 {
     X86CPU *cpu = X86_CPU(dev);
@@ -425,26 +425,26 @@ static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     x86_cpu_pre_plug(hotplug_dev, dev, errp);
 }
 
-static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
+static void microvm_device_plug_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     x86_cpu_plug(hotplug_dev, dev, errp);
 }
 
-static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+static void microvm_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                              DeviceState *dev, Error **errp)
 {
     error_setg(errp, "unplug not supported by microvm");
 }
 
-static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev,
+static void microvm_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     error_setg(errp, "unplug not supported by microvm");
 }
 
-static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
-                                                   DeviceState *dev)
+static const HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
+                                                         DeviceState *dev)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
         return HOTPLUG_HANDLER(machine);
hw/i386/pc.c +14 -14
index e9e4fc262b..9006e7c29e 100644
@@ -1181,7 +1181,7 @@ void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs)
     g_free(i8259);
 }
 
-static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void pc_memory_pre_plug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp)
 {
     const X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
@@ -1214,7 +1214,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), errp);
 }
 
-static void pc_memory_plug(HotplugHandler *hotplug_dev,
+static void pc_memory_plug(const HotplugHandler *hotplug_dev,
                            DeviceState *dev, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
@@ -1231,7 +1231,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
     hotplug_handler_plug(x86ms->acpi_dev, dev, &error_abort);
 }
 
-static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
+static void pc_memory_unplug_request(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
@@ -1256,7 +1256,7 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
                                    errp);
 }
 
-static void pc_memory_unplug(HotplugHandler *hotplug_dev,
+static void pc_memory_unplug(const HotplugHandler *hotplug_dev,
                              DeviceState *dev, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(hotplug_dev);
@@ -1274,7 +1274,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
     error_propagate(errp, local_err);
 }
 
-static void pc_hv_balloon_pre_plug(HotplugHandler *hotplug_dev,
+static void pc_hv_balloon_pre_plug(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     /* The vmbus handler has no hotplug handler; we should never end up here. */
@@ -1282,13 +1282,13 @@ static void pc_hv_balloon_pre_plug(HotplugHandler *hotplug_dev,
     memory_device_pre_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev), errp);
 }
 
-static void pc_hv_balloon_plug(HotplugHandler *hotplug_dev,
+static void pc_hv_balloon_plug(const HotplugHandler *hotplug_dev,
                                DeviceState *dev, Error **errp)
 {
     memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
 }
 
-static void pc_sp_mem_pre_plug(HotplugHandler *hotplug_dev,
+static void pc_sp_mem_pre_plug(const HotplugHandler *hotplug_dev,
                                DeviceState *dev, Error **errp)
 {
     MachineState *ms = MACHINE(hotplug_dev);
@@ -1304,7 +1304,7 @@ static void pc_sp_mem_pre_plug(HotplugHandler *hotplug_dev,
     memory_device_pre_plug(MEMORY_DEVICE(dev), ms, errp);
 }
 
-static void pc_sp_mem_plug(HotplugHandler *hotplug_dev,
+static void pc_sp_mem_plug(const HotplugHandler *hotplug_dev,
                            DeviceState *dev, Error **errp)
 {
     SpMemDevice *spm = SP_MEM(dev);
@@ -1318,7 +1318,7 @@ static void pc_sp_mem_plug(HotplugHandler *hotplug_dev,
     e820_add_entry(addr, size, E820_SOFT_RESERVED);
 }
 
-static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+static void pc_machine_device_pre_plug_cb(const HotplugHandler *hotplug_dev,
                                           DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
@@ -1356,7 +1356,7 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+static void pc_machine_device_plug_cb(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
@@ -1372,7 +1372,7 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+static void pc_machine_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                                 DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
@@ -1388,7 +1388,7 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
+static void pc_machine_device_unplug_cb(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
@@ -1403,8 +1403,8 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
-                                             DeviceState *dev)
+static const HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
+                                                    DeviceState *dev)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
         object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM) ||
hw/i386/x86-common.c +4 -4
index 8f9419e7d3..ae58352760 100644
@@ -158,7 +158,7 @@ static CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
     return found_cpu;
 }
 
-void x86_cpu_plug(HotplugHandler *hotplug_dev,
+void x86_cpu_plug(const HotplugHandler *hotplug_dev,
                   DeviceState *dev, Error **errp)
 {
     CPUArchId *found_cpu;
@@ -199,7 +199,7 @@ out:
     error_propagate(errp, local_err);
 }
 
-void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
+void x86_cpu_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                DeviceState *dev, Error **errp)
 {
     int idx = -1;
@@ -222,7 +222,7 @@ void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
                                    errp);
 }
 
-void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev,
+void x86_cpu_unplug_cb(const HotplugHandler *hotplug_dev,
                        DeviceState *dev, Error **errp)
 {
     CPUArchId *found_cpu;
@@ -248,7 +248,7 @@ void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev,
     error_propagate(errp, local_err);
 }
 
-void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
+void x86_cpu_pre_plug(const HotplugHandler *hotplug_dev,
                       DeviceState *dev, Error **errp)
 {
     int idx;
hw/intc/loongarch_dintc.c +4 -4
index c01f1fe07e..1bedfbce43 100644
@@ -168,8 +168,8 @@ static DINTCCore *loongarch_dintc_get_cpu(LoongArchDINTCState *s,
     return loongarch_dintc_cpu_by_arch_id(s, arch_id);
 }
 
-static void loongarch_dintc_cpu_plug(HotplugHandler *hotplug_dev,
-                                   DeviceState *dev, Error **errp)
+static void loongarch_dintc_cpu_plug(const HotplugHandler *hotplug_dev,
+                                     DeviceState *dev, Error **errp)
 {
     LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev);
     Object *obj = OBJECT(dev);
@@ -194,8 +194,8 @@ static void loongarch_dintc_cpu_plug(HotplugHandler *hotplug_dev,
     return;
 }
 
-static void loongarch_dintc_cpu_unplug(HotplugHandler *hotplug_dev,
-                                     DeviceState *dev, Error **errp)
+static void loongarch_dintc_cpu_unplug(const HotplugHandler *hotplug_dev,
+                                       DeviceState *dev, Error **errp)
 {
     LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev);
     Object *obj = OBJECT(dev);
hw/intc/loongarch_extioi_common.c +2 -2
index 5cb0d396c6..22cbb7a097 100644
@@ -28,7 +28,7 @@ static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s,
     return NULL;
 }
 
-static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev,
+static void loongarch_extioi_cpu_plug(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp)
 {
     LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
@@ -60,7 +60,7 @@ static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev,
     }
 }
 
-static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev,
+static void loongarch_extioi_cpu_unplug(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
     LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
hw/intc/loongarch_ipi.c +2 -2
index 28d816e3f5..c8f775a93e 100644
@@ -129,7 +129,7 @@ static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
     }
 }
 
-static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
+static void loongarch_ipi_cpu_plug(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
@@ -155,7 +155,7 @@ static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
     qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI));
 }
 
-static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
+static void loongarch_ipi_cpu_unplug(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
hw/loongarch/virt.c +22 -22

120 lines not on this page · raw message

hw/net/virtio-net.c +2 -2
index 23c26aa08c..986ceff514 100644
@@ -3816,7 +3816,7 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
 
 static bool failover_unplug_primary(VirtIONet *n, DeviceState *dev)
 {
-    HotplugHandler *hotplug_ctrl;
+    const HotplugHandler *hotplug_ctrl;
     PCIDevice *pci_dev;
     Error *err = NULL;
 
@@ -3839,7 +3839,7 @@ static bool failover_replug_primary(VirtIONet *n, DeviceState *dev,
                                     Error **errp)
 {
     Error *err = NULL;
-    HotplugHandler *hotplug_ctrl;
+    const HotplugHandler *hotplug_ctrl;
     PCIDevice *pdev = PCI_DEVICE(dev);
     BusState *primary_bus;
 
hw/nvme/ctrl.c +4 -4
index 7478f0b33a..c641226e27 100644
@@ -10615,8 +10615,8 @@ static const TypeInfo nvme_info = {
     },
 };
 
-static void nvme_ns_hot_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
-                              Error **errp)
+static void nvme_ns_hot_plug(const HotplugHandler *hotplug_dev,
+                             DeviceState *dev, Error **errp)
 {
     NvmeNamespace *ns = NVME_NS(dev);
     NvmeSubsystem *subsys = ns->subsys;
@@ -10647,8 +10647,8 @@ static void nvme_ns_hot_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-static void nvme_ns_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
-                               Error **errp)
+static void nvme_ns_hot_unplug(const HotplugHandler *hotplug_dev,
+                               DeviceState *dev, Error **errp)
 {
     NvmeNamespace *ns = NVME_NS(dev);
     NvmeSubsystem *subsys = ns->subsys;
hw/pci-bridge/pci_bridge_dev.c +3 -3
index 0c1383562d..bc53bcb69d 100644
@@ -205,7 +205,7 @@ static const VMStateDescription pci_bridge_dev_vmstate = {
     }
 };
 
-void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pci_bridge_dev_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                             Error **errp)
 {
     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
@@ -218,7 +218,7 @@ void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     shpc_device_plug_cb(hotplug_dev, dev, errp);
 }
 
-void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pci_bridge_dev_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                               Error **errp)
 {
     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
@@ -227,7 +227,7 @@ void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     shpc_device_unplug_cb(hotplug_dev, dev, errp);
 }
 
-void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
+void pci_bridge_dev_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp)
 {
     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
hw/pci/pcie.c +5 -5
index 4622c75e48..42bcb9206d 100644
@@ -508,7 +508,7 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
     }
 }
 
-void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_pre_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                Error **errp)
 {
     PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
@@ -525,7 +525,7 @@ void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp);
 }
 
-void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_plug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                            Error **errp)
 {
     PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
@@ -571,7 +571,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void pcie_cap_slot_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                              Error **errp)
 {
     qdev_unrealize(dev);
@@ -579,7 +579,7 @@ void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
 
 static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
 {
-    HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
+    const HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
 
     if (dev->partially_hotplugged) {
         dev->qdev.pending_deleted_event = false;
@@ -608,7 +608,7 @@ static void pcie_cap_slot_do_unplug(PCIDevice *dev)
                                PCI_EXP_SLTSTA_PDC);
 }
 
-void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
+void pcie_cap_slot_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     Error *local_err = NULL;
hw/pci/pcie_port.c +1 -1
index dbb6032160..57fcc9079a 100644
@@ -188,7 +188,7 @@ int pcie_count_ds_ports(PCIBus *bus)
     return dsp_count;
 }
 
-static bool pcie_slot_is_hotpluggable_bus(HotplugHandler *plug_handler,
+static bool pcie_slot_is_hotpluggable_bus(const HotplugHandler *plug_handler,
                                           BusState *bus)
 {
     PCIESlot *s = PCIE_SLOT(bus->parent);
hw/pci/shpc.c +5 -5
index 1198e1ab8c..3f24ca84f5 100644
@@ -278,7 +278,7 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
          ++devfn) {
         PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
         if (affected_dev) {
-            HotplugHandler *hotplug_ctrl;
+            const HotplugHandler *hotplug_ctrl;
 
             hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev));
             hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev),
@@ -561,8 +561,8 @@ static bool shpc_device_get_slot(PCIDevice *affected_dev, int *slot,
     return true;
 }
 
-void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
-                            Error **errp)
+void shpc_device_plug_cb(const HotplugHandler *hotplug_dev,
+                         DeviceState *dev, Error **errp)
 {
     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
     SHPCDevice *shpc = pci_hotplug_dev->shpc;
@@ -601,13 +601,13 @@ void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
     shpc_interrupt_update(pci_hotplug_dev);
 }
 
-void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void shpc_device_unplug_cb(const HotplugHandler *hotplug_dev, DeviceState *dev,
                            Error **errp)
 {
     qdev_unrealize(dev);
 }
 
-void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+void shpc_device_unplug_request_cb(const HotplugHandler *hotplug_dev,
                                    DeviceState *dev, Error **errp)
 {
     PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
hw/ppc/e500plat.c +2 -2
index 85cec810d9..4bc1426dc8 100644
@@ -42,7 +42,7 @@ static void e500plat_init(MachineState *machine)
     ppce500_init(machine);
 }
 
-static void e500plat_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+static void e500plat_machine_device_plug_cb(const HotplugHandler *hotplug_dev,
                                             DeviceState *dev, Error **errp)
 {
     PPCE500MachineState *pms = PPCE500_MACHINE(hotplug_dev);
@@ -53,7 +53,7 @@ static void e500plat_machine_device_plug_cb(HotplugHandler *hotplug_dev,
     }
 }
 
-static
+static const
 HotplugHandler *e500plat_machine_get_hotpug_handler(MachineState *machine,
                                                     DeviceState *dev)
 {
hw/ppc/spapr.c +24 -24

183 lines not on this page · raw message

hw/ppc/spapr_nvdimm.c +1 -1
index 6647428391..542ed79497 100644
@@ -64,7 +64,7 @@ struct SPAPRNVDIMMClass {
     void (*unrealize)(NVDIMMDevice *dimm, Error **errp);
 };
 
-bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
+bool spapr_nvdimm_validate(const HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
                            uint64_t size, Error **errp)
 {
     const MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
hw/ppc/spapr_pci.c +6 -6
index c1d4b7806e..f7fc544d35 100644
@@ -1445,7 +1445,7 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
 /* Callback to be called during DRC release. */
 void spapr_phb_remove_pci_device_cb(DeviceState *dev)
 {
-    HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
+    const HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
 
     hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
     object_unparent(OBJECT(dev));
@@ -1454,7 +1454,7 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev)
 int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
                           void *fdt, int *fdt_start_offset, Error **errp)
 {
-    HotplugHandler *plug_handler = qdev_get_hotplug_handler(drc->dev);
+    const HotplugHandler *plug_handler = qdev_get_hotplug_handler(drc->dev);
     SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(plug_handler);
     PCIDevice *pdev = PCI_DEVICE(drc->dev);
 
@@ -1521,7 +1521,7 @@ static bool bridge_has_valid_chassis_nr(Object *bridge, Error **errp)
     return true;
 }
 
-static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
+static void spapr_pci_pre_plug(const HotplugHandler *plug_handler,
                                DeviceState *plugged_dev, Error **errp)
 {
     SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
@@ -1556,7 +1556,7 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
     }
 }
 
-static void spapr_pci_plug(HotplugHandler *plug_handler,
+static void spapr_pci_plug(const HotplugHandler *plug_handler,
                            DeviceState *plugged_dev, Error **errp)
 {
     SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
@@ -1614,7 +1614,7 @@ static void spapr_pci_bridge_unplug(SpaprPhbState *phb,
     remove_drcs(phb, bus);
 }
 
-static void spapr_pci_unplug(HotplugHandler *plug_handler,
+static void spapr_pci_unplug(const HotplugHandler *plug_handler,
                              DeviceState *plugged_dev, Error **errp)
 {
     SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
@@ -1639,7 +1639,7 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler,
     qdev_unrealize(plugged_dev);
 }
 
-static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
+static void spapr_pci_unplug_request(const HotplugHandler *plug_handler,
                                      DeviceState *plugged_dev, Error **errp)
 {
     SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
hw/remote/machine.c +1 -1
index ced782f6a9..f79f5a0565 100644
@@ -111,7 +111,7 @@ static void remote_machine_instance_init(Object *obj)
     s->auto_shutdown = true;
 }
 
-static void remote_machine_dev_unplug_cb(HotplugHandler *hotplug_dev,
+static void remote_machine_dev_unplug_cb(const HotplugHandler *hotplug_dev,
                                          DeviceState *dev, Error **errp)
 {
     qdev_unrealize(dev);
hw/riscv/virt.c +3 -3
index f3a1cc5ba3..d4b501802f 100644
@@ -1088,8 +1088,8 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name,
     visit_type_OnOffAuto(v, name, &s->acpi, errp);
 }
 
-static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
-                                                        DeviceState *dev)
+static const HotplugHandler *
+virt_machine_get_hotplug_handler(MachineState *machine, DeviceState *dev)
 {
     MachineClass *mc = MACHINE_GET_CLASS(machine);
     RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
@@ -1104,7 +1104,7 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
     return NULL;
 }
 
-static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
+static void virt_machine_device_plug_cb(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev, Error **errp)
 {
     RISCVVirtState *s = RISCV_VIRT_MACHINE(hotplug_dev);
hw/s390x/css-bridge.c +1 -1
index 440fefb7d0..e7cd9ac7b6 100644
@@ -26,7 +26,7 @@
  * (including sending a channel report to the guest) and remove the
  * device from the virtual css bus.
  */
-static void ccw_device_unplug(HotplugHandler *hotplug_dev,
+static void ccw_device_unplug(const HotplugHandler *hotplug_dev,
                               DeviceState *dev, Error **errp)
 {
     CcwDevice *ccw_dev = CCW_DEVICE(dev);
hw/s390x/s390-pci-bus.c +6 -6
index eff980fdfe..2eb4e8cec4 100644
@@ -158,7 +158,7 @@ static void s390_pci_shutdown_notifier(Notifier *n, void *opaque)
 
 static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev)
 {
-    HotplugHandler *hotplug_ctrl;
+    const HotplugHandler *hotplug_ctrl;
 
     if (pbdev->pft == ZPCI_PFT_ISM) {
         notifier_remove(&pbdev->shutdown_notifier);
@@ -1005,8 +1005,8 @@ static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
     return true;
 }
 
-static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
-                                   Error **errp)
+static void s390_pcihost_pre_plug(const HotplugHandler *hotplug_dev,
+                                  DeviceState *dev, Error **errp)
 {
     S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
 
@@ -1079,7 +1079,7 @@ static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev)
     return 0;
 }
 
-static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void s390_pcihost_plug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                               Error **errp)
 {
     S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
@@ -1216,7 +1216,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void s390_pcihost_unplug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                 Error **errp)
 {
     S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
@@ -1255,7 +1255,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-static void s390_pcihost_unplug_request(HotplugHandler *hotplug_dev,
+static void s390_pcihost_unplug_request(const HotplugHandler *hotplug_dev,
                                         DeviceState *dev,
                                         Error **errp)
 {
hw/s390x/s390-virtio-ccw.c +8 -8
index 17266779a6..7fb78d8fa1 100644
@@ -343,8 +343,8 @@ static void ccw_init(MachineState *machine)
 
 }
 
-static void s390_cpu_plug(HotplugHandler *hotplug_dev,
-                        DeviceState *dev, Error **errp)
+static void s390_cpu_plug(const HotplugHandler *hotplug_dev,
+                          DeviceState *dev, Error **errp)
 {
     ERRP_GUARD();
     MachineState *ms = MACHINE(hotplug_dev);
@@ -608,7 +608,7 @@ out_lock:
     bql_lock();
 }
 
-static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
+static void s390_machine_device_pre_plug(const HotplugHandler *hotplug_dev,
                                          DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
@@ -618,7 +618,7 @@ static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
     }
 }
 
-static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
+static void s390_machine_device_plug(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
@@ -648,7 +648,7 @@ static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
     }
 }
 
-static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
+static void s390_machine_device_unplug_request(const HotplugHandler *hotplug_dev,
                                                DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
@@ -662,7 +662,7 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
     }
 }
 
-static void s390_machine_device_unplug(HotplugHandler *hotplug_dev,
+static void s390_machine_device_unplug(const HotplugHandler *hotplug_dev,
                                        DeviceState *dev, Error **errp)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
@@ -715,8 +715,8 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
     return ms->possible_cpus;
 }
 
-static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
-                                                DeviceState *dev)
+static const HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
+                                                      DeviceState *dev)
 {
     if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
         object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
hw/s390x/virtio-ccw-md.c +4 -4
index 0b18b49bc4..70dbea819a 100644
@@ -19,7 +19,7 @@
 void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
@@ -48,7 +48,7 @@ void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
 void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
@@ -72,7 +72,7 @@ void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
 {
     VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
@@ -112,7 +112,7 @@ void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
 void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
hw/s390x/virtio-ccw.c +1 -1
index d82874ed27..30fb2c0681 100644
@@ -1235,7 +1235,7 @@ static void virtio_ccw_busdev_unrealize(DeviceState *dev)
     virtio_ccw_device_unrealize(_dev);
 }
 
-static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
+static void virtio_ccw_busdev_unplug(const HotplugHandler *hotplug_dev,
                                      DeviceState *dev, Error **errp)
 {
     VirtioCcwDevice *_dev = to_virtio_ccw_dev_fast(dev);
hw/scsi/virtio-scsi.c +3 -3
index 132f833226..d7e2662aa7 100644
@@ -1144,14 +1144,14 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
     }
 }
 
-static void virtio_scsi_pre_hotplug(HotplugHandler *hotplug_dev,
+static void virtio_scsi_pre_hotplug(const HotplugHandler *hotplug_dev,
                                     DeviceState *dev, Error **errp)
 {
     SCSIDevice *sd = SCSI_DEVICE(dev);
     sd->hba_supports_iothread = true;
 }
 
-static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void virtio_scsi_hotplug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                 Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
@@ -1183,7 +1183,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
     }
 }
 
-static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+static void virtio_scsi_hotunplug(const HotplugHandler *hotplug_dev, DeviceState *dev,
                                   Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
hw/scsi/vmw_pvscsi.c +2 -2
index 05f93171cd..77c9b843b4 100644
@@ -612,7 +612,7 @@ pvscsi_send_msg(PVSCSIState *s, SCSIDevice *dev, uint32_t msg_type)
 }
 
 static void
-pvscsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
+pvscsi_hotplug(const HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
 {
     PVSCSIState *s = PVSCSI(hotplug_dev);
 
@@ -620,7 +620,7 @@ pvscsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
 }
 
 static void
-pvscsi_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
+pvscsi_hot_unplug(const HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
 {
     PVSCSIState *s = PVSCSI(hotplug_dev);
 
hw/virtio/virtio-md-pci.c +4 -4
index aa5b11c0f6..97ea0ec7b3 100644
@@ -19,7 +19,7 @@
 void virtio_md_pci_pre_plug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
@@ -47,7 +47,7 @@ void virtio_md_pci_pre_plug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
 void virtio_md_pci_plug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
@@ -71,7 +71,7 @@ void virtio_md_pci_unplug_request(VirtIOMDPCI *vmd, MachineState *ms,
 {
     VirtIOMDPCIClass *vmdc = VIRTIO_MD_PCI_GET_CLASS(vmd);
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
@@ -110,7 +110,7 @@ void virtio_md_pci_unplug_request(VirtIOMDPCI *vmd, MachineState *ms,
 void virtio_md_pci_unplug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
 {
     DeviceState *dev = DEVICE(vmd);
-    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
+    const HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
     Error *local_err = NULL;
 
hw/xen/xen-bus.c +1 -1
index 1762816bf4..8def3bb68b 100644
@@ -374,7 +374,7 @@ fail:
     g_free(key);
 }
 
-static void xen_bus_unplug_request(HotplugHandler *hotplug,
+static void xen_bus_unplug_request(const HotplugHandler *hotplug,
                                    DeviceState *dev,
                                    Error **errp)
 {
stubs/hotplug-stubs.c +3 -3
index 0f592ee139..32b4af7997 100644
@@ -14,19 +14,19 @@
 #include "qemu/osdep.h"
 #include "hw/core/qdev.h"
 
-HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
+const HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
 {
     return NULL;
 }
 
-void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
+void hotplug_handler_pre_plug(const HotplugHandler *plug_handler,
                               DeviceState *plugged_dev,
                               Error **errp)
 {
     g_assert_not_reached();
 }
 
-void hotplug_handler_plug(HotplugHandler *plug_handler,
+void hotplug_handler_plug(const HotplugHandler *plug_handler,
                           DeviceState *plugged_dev,
                           Error **errp)
 {
system/qdev-monitor.c +1 -1
index 0c5502d45b..a62ad23ecf 100644
@@ -917,7 +917,7 @@ static DeviceState *find_device_state(const char *id, bool use_generic_error,
 
 void qdev_unplug(DeviceState *dev, Error **errp)
 {
-    HotplugHandler *hotplug_ctrl;
+    const HotplugHandler *hotplug_ctrl;
     const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
Signature · 1 line
MST
#7 lore raw

[PULL 52/90] hw/net/virtio-net: strip trailing padding when caching RSC segment

In reply to Michael S. Tsirkin

From: Laurent Vivier <[email protected]>

When an RSC candidate packet has trailing padding bytes beyond the declared IP payload, virtio_net_rsc_cache_buf() copies the full wire size into the coalescing buffer and sets seg->size to that value. The bounds check in virtio_net_rsc_coalesce_data() uses the IP length field (o_ip_len) which does not include the padding, so the check can pass while the subsequent memmove() overflows the buffer.

Fix this by computing the actual IP packet size from the IP header and using it for both the memcpy and seg->size, so that seg->size stays in sync with the IP length field. virtio_net_rsc_sanity_check4/6() guarantees that ip_size <= size.

Fixes CVE-2026-66900
Fixes 2974e916df87 ("virtio-net: support RSC v4/v6 tcp traffic for Windows HCK")
Cc Yuri Benditovich <[email protected]>

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3879

Message-ID: <[email protected]>

---
 hw/net/virtio-net.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)
hw/net/virtio-net.c +20 -2
index f3f375e1b2..23c26aa08c 100644
@@ -2200,13 +2200,31 @@ static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain,
 {
     uint16_t hdr_len;
     VirtioNetRscSeg *seg;
+    size_t ip_size;
 
     hdr_len = chain->n->guest_hdr_len;
+
+    /*
+     * Strip any trailing padding beyond the IP payload so that seg->size
+     * stays in sync with the IP length field used by the bounds check in
+     * virtio_net_rsc_coalesce_data(). virtio_net_rsc_sanity_check4/6()
+     * guarantees that ip_size <= size.
+     */
+    ip_size = hdr_len + sizeof(struct eth_header);
+    if (chain->proto == ETH_P_IP) {
+        struct ip_header *ip = (struct ip_header *)(buf + ip_size);
+        ip_size += htons(ip->ip_len);
+    } else {
+        struct ip6_header *ip6 = (struct ip6_header *)(buf + ip_size);
+        ip_size += sizeof(struct ip6_header)
+                   + htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+    }
+
     seg = g_new(VirtioNetRscSeg, 1);
     seg->buf = g_malloc(hdr_len + sizeof(struct eth_header)
         + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD);
-    memcpy(seg->buf, buf, size);
-    seg->size = size;
+    memcpy(seg->buf, buf, ip_size);
+    seg->size = ip_size;
     seg->packets = 1;
     seg->dup_ack = 0;
     seg->is_coalesced = 0;
Signature · 1 line
MST
#8 lore raw

[PULL 76/90] pci: load a device's config inside one memory transaction

In reply to Michael S. Tsirkin

From: "Denis V. Lunev" <[email protected]>

Restoring config space remaps the BARs, updates the bridge windows when the device is a bridge, and toggles the bus master region. Each of those commits a transaction of its own, so one device costs several flatview rebuilds where one would do, and the cost of a rebuild grows with the number of regions in the machine.

Nothing between them touches an address space, so the three can share a transaction. The saving scales with the number of PCI devices.

Message-ID: <[email protected]>

---
 hw/pci/pci.c | 4 ++++
 1 file changed, 4 insertions(+)
hw/pci/pci.c +4 -0
index 14c78e3c62..0efb4eb4bb 100644
@@ -840,6 +840,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size,
     }
     memcpy(s->config, config, size);
 
+    memory_region_transaction_begin();
+
     pci_update_mappings(s);
     if (IS_PCI_BRIDGE(s)) {
         pci_bridge_update_mappings(PCI_BRIDGE(s));
@@ -848,6 +850,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size,
     pci_set_master(s, pci_get_word(s->config + PCI_COMMAND)
                       & PCI_COMMAND_MASTER);
 
+    memory_region_transaction_commit();
+
     g_free(config);
     return 0;
 }
Signature · 1 line
MST
#9 lore raw

[PULL 77/90] hw/acpi: Make AcpiGedState const in build_ged_aml()

In reply to Michael S. Tsirkin

From: Philippe Mathieu-Daudé <[email protected]>

build_ged_aml() do not modify the AcpiGedState structure.

Message-ID: <[email protected]>

---
 hw/acpi/generic_event_device.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/acpi/generic_event_device.c +1 -1
index 67c9e9b3e8..5225e32513 100644
@@ -48,7 +48,7 @@ static const uint32_t ged_supported_events[] = {
 void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
 {
-    AcpiGedState *s = ACPI_GED(hotplug_dev);
+    const AcpiGedState *s = ACPI_GED(hotplug_dev);
     Aml *crs = aml_resource_template();
     Aml *evt, *field;
     Aml *dev = aml_device("%s", name);
Signature · 1 line
MST
#10 lore raw

[PULL 41/90] tests/acpi/cxl: Update CEDT.cxl for the default CFMW restrictions

In reply to Michael S. Tsirkin

From: Davidlohr Bueso <[email protected]>

With the default CXL Fixed Memory Window restrictions changed to drop Back-Invalidate (keeping device-coherent and host-only), update the expected CEDT to advertise 0x0f instead of 0x2f.

[064h 0100 001h] Subtable Type : 01 [CXL Fixed Memory Window Structure]
[065h 0101 001h] Reserved : 00
[066h 0102 002h] Length : 0028
[068h 0104 004h] Reserved : 00000000
[06Ch 0108 008h] Window base address : 0000000110000000
[074h 0116 008h] Window size : 0000000100000000
[07Ch 0124 001h] Interleave Members : 00
[07Dh 0125 001h] Interleave Arithmetic : 00
[07Eh 0126 002h] Reserved : 0000
[080h 0128 004h] Granularity : 00000005
[084h 0132 002h] Restrictions : 000F
[086h 0134 002h] QtgId : 0000
[088h 0136 004h] First Target : 0000000C

Message-ID: <[email protected]>

---
 tests/qtest/bios-tables-test-allowed-diff.h |   1 -
 tests/data/acpi/x86/q35/CEDT.cxl            | Bin 184 -> 184 bytes
 2 files changed, 1 deletion(-)
tests/qtest/bios-tables-test-allowed-diff.h +0 -1
index b4646b5b31..dfb8523c8b 100644
@@ -1,2 +1 @@
 /* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/x86/q35/CEDT.cxl",
tests/data/acpi/x86/q35/CEDT.cxl binary +0 -0
index c35f3882eee67aa5613af427234d1ccd196aa249..ff8203af070241bd23dd0eb8a51460692bb7d229 100644
GIT binary patch
Signature · 1 line
MST
#11 lore raw

[PULL 45/90] hw/virtio-blk: Account discard operations

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

The acct_failed argument to virtio_blk_handle_rw_error() tells whether there is accounting for this operation or not. The only operation for which there is none is discarding, which seems to be because at the time of the introducing commit 37b06f8d46f ("virtio-blk: add DISCARD and WRITE_ZEROES features"), BlockAcctType did not yet have a BLOCK_ACCT_UNMAP variant.

It does have that now, though, so we may as well track those discard operations with it, and can thus remove the acct_failed parameter.

Message-ID: <[email protected]>

---
 hw/block/virtio-blk.c | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)
hw/block/virtio-blk.c +11 -15
index cb6a276a82..4110380392 100644
@@ -69,7 +69,7 @@ void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
 }
 
 static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
-    bool is_read, bool acct_failed)
+                                      bool is_read)
 {
     VirtIOBlock *s = req->dev;
     BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
@@ -85,9 +85,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
         }
     } else if (action == BLOCK_ERROR_ACTION_REPORT) {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
-        if (acct_failed) {
-            block_acct_failed(blk_get_stats(s->blk), &req->acct);
-        }
+        block_acct_failed(blk_get_stats(s->blk), &req->acct);
         g_free(req);
     }
 
@@ -124,7 +122,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
              * the memory until the request is completed (which will
              * happen on the other side of the migration).
              */
-            if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) {
+            if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
                 continue;
             }
         }
@@ -140,7 +138,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
     VirtIOBlockReq *req = opaque;
     VirtIOBlock *s = req->dev;
 
-    if (ret && virtio_blk_handle_rw_error(req, -ret, 0, true)) {
+    if (ret && virtio_blk_handle_rw_error(req, -ret, 0)) {
         return;
     }
 
@@ -153,17 +151,13 @@ static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
 {
     VirtIOBlockReq *req = opaque;
     VirtIOBlock *s = req->dev;
-    bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) &
-                            ~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES;
 
-    if (ret && virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) {
+    if (ret && virtio_blk_handle_rw_error(req, -ret, false)) {
         return;
     }
 
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-    if (is_write_zeroes) {
-        block_acct_done(blk_get_stats(s->blk), &req->acct);
-    }
+    block_acct_done(blk_get_stats(s->blk), &req->acct);
     g_free(req);
 }
 
@@ -443,6 +437,9 @@ static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req,
             goto err;
         }
 
+        block_acct_start(blk_get_stats(s->blk), &req->acct, bytes,
+                         BLOCK_ACCT_UNMAP);
+
         blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes,
                          virtio_blk_discard_write_zeroes_complete, req);
     }
@@ -450,9 +447,8 @@ static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req,
     return VIRTIO_BLK_S_OK;
 
 err:
-    if (is_write_zeroes) {
-        block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
-    }
+    block_acct_invalid(blk_get_stats(s->blk),
+                       is_write_zeroes ? BLOCK_ACCT_WRITE : BLOCK_ACCT_UNMAP);
     return err_status;
 }
 
Signature · 1 line
MST
#12 lore raw

[PULL 63/90] acpi_build: Build IVRS feature report using extended feature register

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

Currently IVRS feature report values are hardcoded, this is difficult to maintain as any updates to extended feature must be synced. Along with it, current feature report does not have GATS and HATS set. Hence use the extended feature registers to build the IVRS feature report.

Message-ID: <[email protected]>

---
 hw/i386/amd_iommu.h  | 11 ++++++++++
 hw/i386/acpi-build.c | 48 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 47 insertions(+), 12 deletions(-)
hw/i386/amd_iommu.h +11 -0
index d01f9b41df..319db18618 100644
@@ -174,7 +174,11 @@
 #define AMDVI_DTE_QUAD3_RESERVED        (GENMASK64(14, 0) | GENMASK64(53, 48))
 
 /* AMDVI paging mode */
+#define AMDVI_GATS_MODE_SHIFT           (12)
+#define AMDVI_GATS_MODE_MASK            (3ULL <<  12)
 #define AMDVI_GATS_MODE                 (2ULL <<  12)
+#define AMDVI_HATS_MODE_SHIFT           (10)
+#define AMDVI_HATS_MODE_MASK            (3ULL <<  10)
 #define AMDVI_HATS_MODE                 (2ULL <<  10)
 #define AMDVI_HATS_MODE_RESERVED        (3ULL <<  10)
 
@@ -296,6 +300,13 @@
 #define AMDVI_DEV_LINT0_PASS_MASK       (1ULL << 62)
 #define AMDVI_DEV_LINT1_PASS_MASK       (1ULL << 63)
 
+#define AMDVI_IVHD_FEATURE_REPORT_HATS_SHIFT        (30)
+#define AMDVI_IVHD_FEATURE_REPORT_GATS_SHIFT        (28)
+#define AMDVI_IVHD_FEATURE_REPORT_GA_SUP_SHIFT      (6)
+#define AMDVI_IVHD_FEATURE_REPORT_IA_SUP_SHIFT      (5)
+#define AMDVI_IVHD_FEATURE_REPORT_GT_SUP_SHIFT      (2)
+#define AMDVI_IVHD_FEATURE_REPORT_XT_SUP_SHIFT      (0)
+
 #define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
 OBJECT_DECLARE_SIMPLE_TYPE(AMDVIState, AMD_IOMMU_DEVICE)
 
hw/i386/acpi-build.c +36 -12

73 lines not on this page · raw message

Signature · 1 line
MST
#13 lore raw

[PULL 53/90] virtio-crypto: clean up every data queue

In reply to Michael S. Tsirkin

From: GuoHan Zhao <[email protected]>

realize() creates max_queues data queues and one BH for each of them. unrealize() decides how many to tear down from multiqueue, but nothing ever sets that field, so it only deletes the first queue and BH.

It does not matter how many queues the guest used here. unrealize() must undo all the allocations made by realize(), so loop over max_queues.

Fixes 20cb2ffd5ff3 ("virtio-crypto: using bh to handle dataq's requests")

Message-ID: <[email protected]>

---
 hw/virtio/virtio-crypto.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
hw/virtio/virtio-crypto.c +2 -3
index 79e2acb56c..85c7279aae 100644
@@ -1114,10 +1114,9 @@ static void virtio_crypto_device_unrealize(DeviceState *dev)
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
     VirtIOCryptoQueue *q;
-    int i, max_queues;
+    int i;
 
-    max_queues = vcrypto->multiqueue ? vcrypto->max_queues : 1;
-    for (i = 0; i < max_queues; i++) {
+    for (i = 0; i < vcrypto->max_queues; i++) {
         virtio_delete_queue(vcrypto->vqs[i].dataq);
         q = &vcrypto->vqs[i];
         qemu_bh_delete(q->dataq_bh);
Signature · 1 line
MST
#14 lore raw

[PULL 66/90] libvhost-user: accept the postcopy client base ack in vu_add_mem_reg()

In reply to Michael S. Tsirkin

From: Bin Guo <[email protected]>

In postcopy mode QEMU signals that it has collected all the postcopy client bases by sending a VHOST_USER_ADD_MEM_REG message with a u64 payload of 0 and no file descriptor (see vhost_user_add_remove_regions()). vu_add_mem_reg() has a case for that message, but only reaches it after validating the fd count of a regular region, so the ack is rejected first:

VHOST_USER_ADD_MEM_REG received 0 fds - only 1 fd should be sent for this message type

This kills the backend during memory table setup, making postcopy unusable for any libvhost-user backend that negotiates VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS.

Recognise the ack before validating the fd count.

Fixes 9f4e63491b ("libvhost-user: Add vu_add_mem_reg input validation")

Message-ID: <[email protected]>

---
 subprojects/libvhost-user/libvhost-user.c | 26 ++++++++++++-----------
 1 file changed, 14 insertions(+), 12 deletions(-)
subprojects/libvhost-user/libvhost-user.c +14 -12
index a74d814bb4..248550aae1 100644
@@ -948,6 +948,20 @@ static bool
 vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
     VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
 
+    /*
+     * If we are in postcopy mode and we receive a u64 payload with a 0 value
+     * we know all the postcopy client bases have been received, and we
+     * should start generating faults.  This message carries no file
+     * descriptor, so it has to be recognised before the fd count of a real
+     * region is validated below.
+     */
+    if (dev->postcopy_listening &&
+        vmsg->size == sizeof(vmsg->payload.u64) &&
+        vmsg->payload.u64 == 0) {
+        (void)generate_faults(dev);
+        return false;
+    }
+
     if (vmsg->fd_num != 1) {
         vmsg_close_fds(vmsg);
         vu_panic(dev, "VHOST_USER_ADD_MEM_REG received %d fds - only 1 fd "
@@ -971,18 +985,6 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
         return false;
     }
 
-    /*
-     * If we are in postcopy mode and we receive a u64 payload with a 0 value
-     * we know all the postcopy client bases have been received, and we
-     * should start generating faults.
-     */
-    if (dev->postcopy_listening &&
-        vmsg->size == sizeof(vmsg->payload.u64) &&
-        vmsg->payload.u64 == 0) {
-        (void)generate_faults(dev);
-        return false;
-    }
-
     _vu_add_mem_reg(dev, msg_region, vmsg->fds[0]);
     close(vmsg->fds[0]);
 
Signature · 1 line
MST
#15 lore raw

[PULL 75/90] pci: batch BAR remapping into one memory transaction

In reply to Michael S. Tsirkin

From: "Denis V. Lunev" <[email protected]>

pci_update_mappings() deletes and re-adds a subregion for each BAR whose address changed, and both of those commit their own transaction, so one BAR move costs two full flatview rebuilds.

Nothing between the delete and the add touches an address space, so the walk can run inside a single transaction. pci_bridge_update_mappings() already does this for the bridge windows.

Message-ID: <[email protected]>

---
 hw/pci/pci.c | 4 ++++
 1 file changed, 4 insertions(+)
hw/pci/pci.c +4 -0
index c15f2b9f08..14c78e3c62 100644
@@ -1742,6 +1742,8 @@ static void pci_update_mappings(PCIDevice *d)
     int i;
     pcibus_t new_addr;
 
+    memory_region_transaction_begin();
+
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
 
@@ -1778,6 +1780,8 @@ static void pci_update_mappings(PCIDevice *d)
     }
 
     pci_update_vga(d);
+
+    memory_region_transaction_commit();
 }
 
 int pci_irq_disabled(PCIDevice *d)
Signature · 1 line
MST
#16 lore raw

[PULL 23/90] net/tap: move vhost initialization to tap_setup_vhost()

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Make a new helper function in a way it can be reused later for TAP fd-migration feature: we'll need to initialize vhost in a later point when we doesn't have access to QAPI parameters.

Based-on: <[email protected]>
Based-on: <[email protected]>

Message-ID: <[email protected]>

---
 net/tap.c | 62 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 24 deletions(-)
net/tap.c +38 -24
index bec2cd48fd..f2b571dd11 100644
@@ -71,6 +71,8 @@ static const int kernel_feature_bits[] = {
 typedef struct TAPState {
     NetClientState nc;
     int fd;
+    int vhostfd;
+    uint32_t vhost_busyloop_timeout;
     char down_script[1024];
     char down_script_arg[128];
     uint8_t buf[NET_BUFSIZE];
@@ -722,6 +724,38 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr,
     return fd;
 }
 
+static bool tap_setup_vhost(TAPState *s, Error **errp)
+{
+    VhostNetOptions options;
+
+    if (s->vhostfd == -1) {
+        return true;
+    }
+
+    options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
+    options.net_backend = &s->nc;
+    options.busyloop_timeout = s->vhost_busyloop_timeout;
+    options.opaque = (void *)(uintptr_t)s->vhostfd;
+    options.nvqs = 2;
+    options.feature_bits = kernel_feature_bits;
+    options.get_acked_features = NULL;
+    options.save_acked_features = NULL;
+    options.max_tx_queue_size = 0;
+    options.is_vhost_user = false;
+
+    s->vhost_net = vhost_net_init(&options);
+    if (!s->vhost_net) {
+        error_setg(errp,
+                   "vhost-net requested but could not be initialized");
+        return false;
+    }
+
+    /* vhostfd ownership is passed to s->vhost_net */
+    s->vhostfd = -1;
+
+    return true;
+}
+
 static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
                              const char *name,
                              const char *ifname, const char *script,
@@ -756,30 +790,10 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
         }
     }
 
-    if (vhostfd != -1) {
-        VhostNetOptions options;
-
-        options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
-        options.net_backend = &s->nc;
-        if (tap->has_poll_us) {
-            options.busyloop_timeout = tap->poll_us;
-        } else {
-            options.busyloop_timeout = 0;
-        }
-        options.opaque = (void *)(uintptr_t)vhostfd;
-        options.nvqs = 2;
-        options.feature_bits = kernel_feature_bits;
-        options.get_acked_features = NULL;
-        options.save_acked_features = NULL;
-        options.max_tx_queue_size = 0;
-        options.is_vhost_user = false;
-
-        s->vhost_net = vhost_net_init(&options);
-        if (!s->vhost_net) {
-            error_setg(errp,
-                       "vhost-net requested but could not be initialized");
-            goto failed;
-        }
+    s->vhostfd = vhostfd;
+    s->vhost_busyloop_timeout = tap->has_poll_us ? tap->poll_us : 0;
+    if (!tap_setup_vhost(s, errp)) {
+        return false;
     }
 
     return true;
Signature · 1 line
MST
#17 lore raw

[PULL 71/90] virtio-rtc: Report smeared UTC clock type

In reply to Michael S. Tsirkin

From: Kuan-Wei Chiu <[email protected]>

The Linux virtio_rtc driver only registers an RTC class device when the clock type is VIRTIO_RTC_CLOCK_UTC_SMEARED to avoid leap second steps on pure UTC clocks.

Report VIRTIO_RTC_CLOCK_UTC_SMEARED in clock capabilities so the guest can expose the device as an RTC device.

Message-ID: <[email protected]>

---
 hw/virtio/virtio-rtc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
hw/virtio/virtio-rtc.c +2 -1
index 32de9c1650..0dcbe94758 100644
@@ -62,7 +62,8 @@ static void virtio_rtc_handle_request(VirtIODevice *vdev, VirtQueue *vq)
                 resp.head.status = VIRTIO_RTC_S_ENODEV;
             } else {
                 resp.head.status = VIRTIO_RTC_S_OK;
-                resp.type = VIRTIO_RTC_CLOCK_UTC;
+                resp.type = VIRTIO_RTC_CLOCK_UTC_SMEARED;
+                resp.leap_second_smearing = VIRTIO_RTC_SMEAR_UNSPECIFIED;
             }
             written = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp,
                                    sizeof(resp));
Signature · 1 line
MST
#18 lore raw

[PULL 34/90] tests/functional: add test_tap_migration

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Add test for a new local-migration migration of virtio-net/tap, with fd passing through UNIX socket.

Message-ID: <[email protected]>

---
 tests/functional/x86_64/meson.build           |   1 +
 tests/functional/x86_64/test_tap_migration.py | 461 ++++++++++++++++++
 2 files changed, 462 insertions(+)
 create mode 100755 tests/functional/x86_64/test_tap_migration.py
tests/functional/x86_64/meson.build +1 -0
index 0353b2af8e..6254149239 100644
@@ -51,4 +51,5 @@ tests_x86_64_system_thorough = [
   'virtio_balloon',
   'virtio_gpu',
   'rebuild_vmfd',
+  'tap_migration',
 ]
tests/functional/x86_64/test_tap_migration.py new file +461 -0

461 lines not on this page · raw message

Signature · 1 line
MST
#19 lore raw

[PULL 36/90] vhost: Fix SHMEM_MAP transaction ordering and resulting deadlock

In reply to Michael S. Tsirkin

From: Dorinda Bassey <[email protected]>

Commit the memory region transaction before sending the SHMEM_MAP reply so the KVM memory slot exists before the guest can access the mapped region.

This moves the commit to while the backend is still blocked waiting for the reply, which can trigger ADD_MEM_REG back to the backend and deadlock. Filter shmem mapping regions out of vhost_section() by checking the MR owner type to prevent this.

The explicit transaction begin/commit wrapping is dropped since virtio_add_shmem_map() already commits via memory_region_add_subregion(). The unmap handler keeps the original ordering: reply before delete, so the backend is unblocked before the transaction commit.

Fixes b52e1896e764 ("vhost-user: Add VirtIO Shared Memory map request")

Message-ID: <[email protected]>

---
 hw/virtio/vhost-user.c | 20 ++------------------
 hw/virtio/vhost.c      | 10 ++++++++++
 2 files changed, 12 insertions(+), 18 deletions(-)
hw/virtio/vhost-user.c +2 -18
index 2881cec72d..fac02a1ffc 100644
@@ -1980,8 +1980,6 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
         }
     }
 
-    memory_region_transaction_begin();
-
     /* Create VirtioSharedMemoryMapping object */
     VirtioSharedMemoryMapping *mapping = virtio_shared_memory_mapping_new(
         vu_mmap->shmid, fd, vu_mmap->fd_offset, vu_mmap->shm_offset,
@@ -1989,7 +1987,7 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
 
     if (!mapping) {
         ret = -EFAULT;
-        goto send_reply_commit;
+        goto send_reply;
     }
 
     /* Add the mapping to the shared memory region */
@@ -1997,23 +1995,9 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
         error_report("Failed to add shared memory mapping");
         object_unref(OBJECT(mapping));
         ret = -EFAULT;
-        goto send_reply_commit;
+        goto send_reply;
     }
 
-send_reply_commit:
-    /* Send reply and commit after transaction started */
-    if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) {
-        payload->u64 = !!ret;
-        hdr->size = sizeof(payload->u64);
-        if (!vhost_user_send_resp(ioc, hdr, payload, &local_err)) {
-            error_report_err(local_err);
-            memory_region_transaction_commit();
-            return -EFAULT;
-        }
-    }
-    memory_region_transaction_commit();
-    return 0;
-
 send_reply:
     if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) {
         payload->u64 = !!ret;
hw/virtio/vhost.c +10 -0
index a81cd94f90..838b1da739 100644
@@ -636,6 +636,16 @@ static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section)
 {
     MemoryRegion *mr = section->mr;
 
+    /*
+     * Skip shmem mapping regions, they are managed via SHMEM_MAP/UNMAP.
+     * Including them triggers ADD_MEM_REG during the SHMEM_MAP transaction
+     * commit, deadlocking the backend.
+     */
+    if (object_dynamic_cast(memory_region_owner(mr),
+                            TYPE_VIRTIO_SHARED_MEMORY_MAPPING)) {
+        return false;
+    }
+
     if (memory_region_is_ram(mr) && !memory_region_is_rom(mr)) {
         uint8_t dirty_mask = memory_region_get_dirty_log_mask(mr);
         uint8_t handled_dirty;
Signature · 1 line
MST
#20 lore raw

[PULL 78/90] hw/hotplug: Mark various HotplugHandlerClass variables as const

In reply to Michael S. Tsirkin

From: Philippe Mathieu-Daudé <[email protected]>

The HotplugHandlerClass pointers are only dereferenced, not updated.

Message-ID: <[email protected]>

---
 include/hw/core/qdev.h    | 2 +-
 hw/core/hotplug.c         | 8 ++++----
 hw/s390x/virtio-ccw-md.c  | 2 +-
 hw/virtio/virtio-md-pci.c | 2 +-
 system/qdev-monitor.c     | 2 +-
 5 files changed, 8 insertions(+), 8 deletions(-)
include/hw/core/qdev.h +1 -1
index f054a214fc..e4cb027ab3 100644
@@ -1069,7 +1069,7 @@ static inline bool qbus_is_hotpluggable(BusState *bus)
     bool ret = !!plug_handler;
 
     if (plug_handler) {
-        HotplugHandlerClass *hdc;
+        const HotplugHandlerClass *hdc;
 
         hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
         if (hdc->is_hotpluggable_bus) {
hw/core/hotplug.c +4 -4
index 68aabad8ae..00e80a67c8 100644
@@ -17,7 +17,7 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
                               DeviceState *plugged_dev,
                               Error **errp)
 {
-    HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+    const HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
 
     if (hdc->pre_plug) {
         hdc->pre_plug(plug_handler, plugged_dev, errp);
@@ -28,7 +28,7 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
                           DeviceState *plugged_dev,
                           Error **errp)
 {
-    HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+    const HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
 
     if (hdc->plug) {
         hdc->plug(plug_handler, plugged_dev, errp);
@@ -39,7 +39,7 @@ void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
                                     DeviceState *plugged_dev,
                                     Error **errp)
 {
-    HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+    const HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
 
     if (hdc->unplug_request) {
         hdc->unplug_request(plug_handler, plugged_dev, errp);
@@ -50,7 +50,7 @@ void hotplug_handler_unplug(HotplugHandler *plug_handler,
                             DeviceState *plugged_dev,
                             Error **errp)
 {
-    HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+    const HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
 
     if (hdc->unplug) {
         hdc->unplug(plug_handler, plugged_dev, errp);
hw/s390x/virtio-ccw-md.c +1 -1
index 0370f58450..0b18b49bc4 100644
@@ -73,7 +73,7 @@ void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
     VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
     DeviceState *dev = DEVICE(vmd);
     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
-    HotplugHandlerClass *hdc;
+    const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
     if (!vmdc->unplug_request_check) {
hw/virtio/virtio-md-pci.c +1 -1
index 9278b32cf8..aa5b11c0f6 100644
@@ -72,7 +72,7 @@ void virtio_md_pci_unplug_request(VirtIOMDPCI *vmd, MachineState *ms,
     VirtIOMDPCIClass *vmdc = VIRTIO_MD_PCI_GET_CLASS(vmd);
     DeviceState *dev = DEVICE(vmd);
     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
-    HotplugHandlerClass *hdc;
+    const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
     if (!vmdc->unplug_request_check) {
system/qdev-monitor.c +1 -1
index 5c87fda509..0c5502d45b 100644
@@ -918,7 +918,7 @@ static DeviceState *find_device_state(const char *id, bool use_generic_error,
 void qdev_unplug(DeviceState *dev, Error **errp)
 {
     HotplugHandler *hotplug_ctrl;
-    HotplugHandlerClass *hdc;
+    const HotplugHandlerClass *hdc;
     Error *local_err = NULL;
 
     if (!qdev_hotunplug_allowed(dev, errp)) {
Signature · 1 line
MST
#21 lore raw

[PULL 65/90] tests/acpi: x86: update golden masters for IVRS

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

Differences between disassembled ASL files for IVRS:

/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20200925 (64-bit version)
* Copyright (c) 2000 - 2020 Intel Corporation
*
- * Disassembly of tests/data/acpi/x86/q35/IVRS.ivrs, Mon May 11 11:21:47 2026
+ * Disassembly of /tmp/aml-NGQ9O3, Mon May 11 11:21:47 2026
*
* ACPI Data Table [IVRS]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue */

 [000h 0000   4]                    Signature : "IVRS"    [I/O Virtualization Reporting Structure]
 [004h 0004   4]                 Table Length : 000000B0
 [008h 0008   1]                     Revision : 01
-[009h 0009   1]                     Checksum : 74
+[009h 0009   1]                     Checksum : CB
 [00Ah 0010   6]                       Oem ID : "BOCHS "
 [010h 0016   8]                 Oem Table ID : "BXPC    "
 [018h 0024   4]                 Oem Revision : 00000001
 [01Ch 0028   4]              Asl Compiler ID : "BXPC"
 [020h 0032   4]        Asl Compiler Revision : 00000001
-[024h 0036   4]          Virtualization Info : 00002801
+[024h 0036   4]          Virtualization Info : 00203441
 [028h 0040   8]                     Reserved : 0000000000000000
 [030h 0048   1]                Subtable Type : 10 [Hardware Definition Block]
-[031h 0049   1]                        Flags : D1
+[031h 0049   1]                        Flags : 51
 [032h 0050   2]                       Length : 0038
 [034h 0052   2]                     DeviceId : 0010
 [036h 0054   2]            Capability Offset : 0040
 [038h 0056   8]                 Base Address : 00000000FED80000
 [040h 0064   2]            PCI Segment Group : 0000
 [042h 0066   2]          Virtualization Info : 0000
-[044h 0068   4]            Feature Reporting : 00000044
+[044h 0068   4]            Feature Reporting : A0000064
 [048h 0072   1]                   Entry Type : 02
 [049h 0073   2]                    Device ID : 0000
 [04Bh 0075   1]                 Data Setting : 00
 [04Ch 0076   1]                   Entry Type : 02
 [04Dh 0077   2]                    Device ID : 0008
 [04Fh 0079   1]                 Data Setting : 00
 [050h 0080   1]                   Entry Type : 02
 [051h 0081   2]                    Device ID : 0010
 [053h 0083   1]                 Data Setting : 00
 [054h 0084   1]                   Entry Type : 02
 [055h 0085   2]                    Device ID : 00F8
 [057h 0087   1]                 Data Setting : 00
@@ -62,33 +62,33 @@
 [061h 0097   2]                    Device ID : 0000
 [063h 0099   1]                 Data Setting : 00
 [064h 0100   1]                       Handle : 00
 [065h 0101   2]        Source Used Device ID : 00A0
 [067h 0103   1]                      Variety : 01
 [068h 0104   1]                Subtable Type : 11 [Hardware Definition Block]
 [069h 0105   1]                        Flags : 11
 [06Ah 0106   2]                       Length : 0048
 [06Ch 0108   2]                     DeviceId : 0010
 [06Eh 0110   2]            Capability Offset : 0040
 [070h 0112   8]                 Base Address : 00000000FED80000
 [078h 0120   2]            PCI Segment Group : 0000
 [07Ah 0122   2]          Virtualization Info : 0000
 [07Ch 0124   4]                   Attributes : 00000000
-[080h 0128   8]                    EFR Image : 00000000000029D3
+[080h 0128   8]                    EFR Image : 00000000000028D1
 [088h 0136   8]                     Reserved : 0000000000000000
 [090h 0144   1]                   Entry Type : 02
 [091h 0145   2]                    Device ID : 0000
 [093h 0147   1]                 Data Setting : 00
 [094h 0148   1]                   Entry Type : 02
 [095h 0149   2]                    Device ID : 0008
 [097h 0151   1]                 Data Setting : 00
 [098h 0152   1]                   Entry Type : 02
 [099h 0153   2]                    Device ID : 0010
 [09Bh 0155   1]                 Data Setting : 00

[09Ch 0156 1] Entry Type : 02
[09Dh 0157 2] Device ID : 00F8
@@ -98,27 +98,27 @@
[0A1h 0161 2] Device ID : 00FA
[0A3h 0163 1] Data Setting : 00

 [0A4h 0164   1]                   Entry Type : 02
 [0A5h 0165   2]                    Device ID : 00FB
 [0A7h 0167   1]                 Data Setting : 00
 [0A8h 0168   1]                   Entry Type : 48
 [0A9h 0169   2]                    Device ID : 0000
 [0ABh 0171   1]                 Data Setting : 00
 [0ACh 0172   1]                       Handle : 00
 [0ADh 0173   2]        Source Used Device ID : 00A0
 [0AFh 0175   1]                      Variety : 01

Message-ID: <[email protected]>

---
 tests/qtest/bios-tables-test-allowed-diff.h |   1 -
 tests/data/acpi/x86/q35/IVRS.ivrs           | Bin 176 -> 176 bytes
 2 files changed, 1 deletion(-)
tests/qtest/bios-tables-test-allowed-diff.h +0 -1
index 33e9981655..dfb8523c8b 100644
@@ -1,2 +1 @@
 /* List of comma-separated changed AML files to ignore */
-tests/data/acpi/x86/q35/IVRS.ivrs
tests/data/acpi/x86/q35/IVRS.ivrs binary +0 -0
index 7f9e91aabc0b7777a7efc9f219587a4f91f0edb1..b3b809c65f026fde0a49a2243a3216e7b8c87502 100644
GIT binary patch
Signature · 1 line
MST
#22 lore raw

[PULL 57/90] vhost-user: Reject SHMEM_MAP when no KVM memory slot is left

In reply to Michael S. Tsirkin

From: Feifan Qian <[email protected]>

Each SHMEM_MAP request creates a separate RAM MemoryRegion that consumes a KVM memory slot. Once all KVM slots are in use, processing another SHMEM_MAP request would make the KVM memory listener fail while registering the new region.

Shared memory mappings are filtered out of the vhost memory table (vhost_section() skips TYPE_VIRTIO_SHARED_MEMORY_MAPPING regions), so they never count against the negotiated vhost-user slot limit; only the KVM slot budget applies. Reject the request with ENOSPC before changing the memory topology when KVM has no free slot left.

Also validate each vhost memory table against the slot limit negotiated with the backend before sending regions via SET_MEM_TABLE or ADD_MEM_REG.

Fixes b52e1896e764 ("vhost-user: Add VirtIO Shared Memory map request")

Message-ID: <HXrBMZ9Gx9L-VxdMEr26ORPUYQn99p4rgEYVkeMHA4-5M49Ax3_mx1euIWe7uj33nl5mZ19sZeUDyksqxKT7H1WPxWhYtxdomofcVTyMTjo=@proton.me>

---
 hw/virtio/vhost-user.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
hw/virtio/vhost-user.c +18 -0
index fac02a1ffc..f737a05d07 100644
@@ -1126,6 +1126,13 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
             dev, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS);
     int ret;
 
+    if (mem->nregions > u->user->memory_slots) {
+        error_report("vhost-user memory table has %u regions, "
+                     "but the backend supports only %d",
+                     mem->nregions, u->user->memory_slots);
+        return -ENOSPC;
+    }
+
     if (do_postcopy) {
         /*
          * Postcopy has enough differences that it's best done in it's own
@@ -1980,6 +1987,17 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
         }
     }
 
+    /*
+     * Each SHMEM mapping becomes a separate RAM MemoryRegion and thus
+     * consumes a KVM memory slot. Reject the request before changing the
+     * memory topology if no slot is left.
+     */
+    if (kvm_enabled() && !kvm_get_free_memslots()) {
+        error_report("No free KVM memory slots for shared memory mapping");
+        ret = -ENOSPC;
+        goto send_reply;
+    }
+
     /* Create VirtioSharedMemoryMapping object */
     VirtioSharedMemoryMapping *mapping = virtio_shared_memory_mapping_new(
         vu_mmap->shmid, fd, vu_mmap->fd_offset, vu_mmap->shm_offset,
Signature · 1 line
MST
#23 lore raw

[PULL 64/90] amd_iommu: acpi-build: Remove unsupported PPR and HE feature

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

AMD IOMMU does not support ppr and hardware error registers. Hence do not publish these features to guest through extended feature MMIO register and IVHD 10h flags field.

Message-ID: <[email protected]>

---
 hw/i386/amd_iommu.h  | 5 ++---
 hw/i386/acpi-build.c | 3 +--
 2 files changed, 3 insertions(+), 5 deletions(-)
hw/i386/amd_iommu.h +2 -3
index 319db18618..c5b346cc35 100644
@@ -227,9 +227,8 @@
 
 /* default extended feature */
 #define AMDVI_DEFAULT_EXT_FEATURES \
-        (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \
-        AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_HE | \
-        AMDVI_GATS_MODE | AMDVI_HATS_MODE | AMDVI_FEATURE_GA)
+        (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | \
+         AMDVI_GATS_MODE | AMDVI_HATS_MODE | AMDVI_FEATURE_GA)
 
 /* capabilities header */
 #define AMDVI_CAPAB_FEATURES (AMDVI_CAPAB_FLAT_EXT | \
hw/i386/acpi-build.c +1 -2
index 7bf3858b63..6d7308b4e4 100644
@@ -1938,8 +1938,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     build_append_int_noprefix(table_data,
                              (1UL << 0) | /* HtTunEn      */
                              (1UL << 4) | /* iotblSup     */
-                             (1UL << 6) | /* PrefSup      */
-                             (1UL << 7),  /* PPRSup       */
+                             (1UL << 6),  /* PrefSup      */
                              1);
 
     /* IVHD length */
Signature · 1 line
MST
#24 lore raw

[PULL 47/90] hw/nvme: Fix block accounting in nvme_copy()

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

In nvme_copy(), we start accounting for each of the copied ranges, but only end it once (in nvme_copy_done()). We should end it after each read/write operation is done instead, so they are properly accounted for.

We should also actually pass the number of bytes we are reading/writing (instead of 0), and probably account for the metadata operations also, as they are block operations we execute.

Message-ID: <[email protected]>

---
 hw/nvme/ctrl.c | 53 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 20 deletions(-)
hw/nvme/ctrl.c +33 -20
index c662d968db..c56725947a 100644
@@ -2802,8 +2802,6 @@ static const AIOCBInfo nvme_copy_aiocb_info = {
 static void nvme_copy_done(NvmeCopyAIOCB *iocb)
 {
     NvmeRequest *req = iocb->req;
-    NvmeNamespace *ns = req->ns;
-    BlockAcctStats *stats = blk_get_stats(ns->blkconf.blk);
 
     if (iocb->idx != iocb->nr) {
         req->cqe.result = cpu_to_le32(iocb->idx);
@@ -2813,14 +2811,6 @@ static void nvme_copy_done(NvmeCopyAIOCB *iocb)
     g_free(iocb->bounce);
     g_free(iocb->ranges);
 
-    if (iocb->ret < 0) {
-        block_acct_failed(stats, &iocb->acct.read);
-        block_acct_failed(stats, &iocb->acct.write);
-    } else {
-        block_acct_done(stats, &iocb->acct.read);
-        block_acct_done(stats, &iocb->acct.write);
-    }
-
     iocb->common.cb(iocb->common.opaque, iocb->ret);
     qemu_aio_unref(iocb);
 }
@@ -2951,6 +2941,7 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
     NvmeCopyAIOCB *iocb = opaque;
     NvmeRequest *req = iocb->req;
     NvmeNamespace *dns = req->ns;
+    BlockAcctStats *stats = blk_get_stats(dns->blkconf.blk);
     uint32_t nlb;
 
     nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
@@ -2959,10 +2950,12 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
     if (ret < 0) {
         iocb->ret = ret;
         req->status = NVME_WRITE_FAULT;
-        goto out;
-    } else if (iocb->ret < 0) {
+    }
+    if (iocb->ret < 0) {
+        block_acct_failed(stats, &iocb->acct.write);
         goto out;
     }
+    block_acct_done(stats, &iocb->acct.write);
 
     if (dns->params.zoned) {
         nvme_advance_zone_wp(dns, iocb->zone, nlb);
@@ -2979,11 +2972,18 @@ static void nvme_copy_out_cb(void *opaque, int ret)
     NvmeCopyAIOCB *iocb = opaque;
     NvmeRequest *req = iocb->req;
     NvmeNamespace *dns = req->ns;
+    BlockAcctStats *stats = blk_get_stats(dns->blkconf.blk);
     uint32_t nlb;
     size_t mlen;
     uint8_t *mbounce;
 
-    if (ret < 0 || iocb->ret < 0 || !dns->lbaf.ms) {
+    if (ret < 0 || iocb->ret < 0) {
+        block_acct_failed(stats, &iocb->acct.write);
+        goto out;
+    }
+    block_acct_done(stats, &iocb->acct.write);
+
+    if (!dns->lbaf.ms) {
         goto out;
     }
 
@@ -2996,6 +2996,7 @@ static void nvme_copy_out_cb(void *opaque, int ret)
     qemu_iovec_reset(&iocb->iov);
     qemu_iovec_add(&iocb->iov, mbounce, mlen);
 
+    block_acct_start(stats, &iocb->acct.write, mlen, BLOCK_ACCT_WRITE);
     iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_moff(dns, iocb->slba),
                                   &iocb->iov, 0, nvme_copy_out_completed_cb,
                                   iocb);
@@ -3012,6 +3013,7 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
     NvmeRequest *req = iocb->req;
     NvmeNamespace *sns = iocb->sns;
     NvmeNamespace *dns = req->ns;
+    BlockAcctStats *sstats = blk_get_stats(sns->blkconf.blk);
     NvmeCopyCmd *copy = NULL;
     uint8_t *mbounce = NULL;
     uint32_t nlb;
@@ -3024,10 +3026,12 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
     if (ret < 0) {
         iocb->ret = ret;
         req->status = NVME_UNRECOVERED_READ;
-        goto out;
-    } else if (iocb->ret < 0) {
+    }
+    if (iocb->ret < 0) {
+        block_acct_failed(sstats, &iocb->acct.read);
         goto out;
     }
+    block_acct_done(sstats, &iocb->acct.read);
 
     nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
                                  &nlb, NULL, &apptag, &appmask, &reftag);
@@ -3102,7 +3106,7 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
     qemu_iovec_reset(&iocb->iov);
     qemu_iovec_add(&iocb->iov, iocb->bounce, len);
 
-    block_acct_start(blk_get_stats(dns->blkconf.blk), &iocb->acct.write, 0,
+    block_acct_start(blk_get_stats(dns->blkconf.blk), &iocb->acct.write, len,
                      BLOCK_ACCT_WRITE);
 
     iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_l2b(dns, iocb->slba),
@@ -3121,20 +3125,29 @@ static void nvme_copy_in_cb(void *opaque, int ret)
 {
     NvmeCopyAIOCB *iocb = opaque;
     NvmeNamespace *sns = iocb->sns;
+    BlockAcctStats *stats = blk_get_stats(sns->blkconf.blk);
     uint64_t slba;
     uint32_t nlb;
+    size_t mlen;
 
-    if (ret < 0 || iocb->ret < 0 || !sns->lbaf.ms) {
+    if (ret < 0 || iocb->ret < 0) {
+        block_acct_failed(stats, &iocb->acct.read);
+        goto out;
+    }
+    block_acct_done(stats, &iocb->acct.read);
+
+    if (!sns->lbaf.ms) {
         goto out;
     }
 
     nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
                                  &nlb, NULL, NULL, NULL, NULL);
 
+    mlen = nvme_m2b(sns, nlb);
     qemu_iovec_reset(&iocb->iov);
-    qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(sns, nlb),
-                   nvme_m2b(sns, nlb));
+    qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(sns, nlb), mlen);
 
+    block_acct_start(stats, &iocb->acct.read, mlen, BLOCK_ACCT_READ);
     iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_moff(sns, slba),
                                  &iocb->iov, 0, nvme_copy_in_completed_cb,
                                  iocb);
@@ -3342,7 +3355,7 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
     assert(len <= blen);
     qemu_iovec_add(&iocb->iov, iocb->bounce, len);
 
-    block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,
+    block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, len,
                      BLOCK_ACCT_READ);
 
     iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_l2b(sns, slba),
Signature · 1 line
MST
#25 lore raw

[PULL 26/90] net/tap: add TYPE_VMSTATE_IF interface

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

We'll need it to implement TAP backend live migration.

Message-ID: <[email protected]>

---
 net/tap.c | 43 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 9 deletions(-)
net/tap.c +34 -9
index 7392344200..dd0d134875 100644
@@ -43,7 +43,6 @@
 #include "qemu/main-loop.h"
 #include "qemu/sockets.h"
 #include "hw/virtio/vhost.h"
-#include "qom/object.h"
 
 #include "net/tap.h"
 #include "net/util.h"
@@ -91,6 +90,8 @@ struct TAPState {
     VHostNetState *vhost_net;
     unsigned host_vnet_hdr_len;
     Notifier exit;
+
+    int queue_index;
 };
 
 static void launch_script(const char *setup_script, const char *ifname,
@@ -419,10 +420,29 @@ static VHostNetState *tap_get_vhost_net(NetClientState *nc)
 }
 
 
+static char *tap_vmstate_if_get_id(VMStateIf *obj)
+{
+    TAPState *s = TAP_NETDEV(obj);
+    char *res = g_strdup_printf("%s/%d", s->nc.name, s->queue_index);
+    return res;
+}
+
+static void tap_class_init(ObjectClass *klass, const void *data)
+{
+    VMStateIfClass *vc = VMSTATE_IF_CLASS(klass);
+
+    vc->get_id = tap_vmstate_if_get_id;
+}
+
 static const TypeInfo tap_netdev_info = {
     .name = TYPE_TAP_NETDEV,
     .parent = TYPE_OBJECT,
     .instance_size = sizeof(TAPState),
+    .class_init = tap_class_init,
+    .interfaces = (const InterfaceInfo[]) {
+        { TYPE_VMSTATE_IF },
+        { }
+    },
 };
 
 static void tap_net_client_destructor(NetClientState *nc)
@@ -455,13 +475,16 @@ static NetClientInfo net_tap_info = {
 
 static TAPState *new_tap(NetClientState *peer,
                          const char *model,
-                         const char *name)
+                         const char *name,
+                         int queue_index)
 {
     TAPState *s = TAP_NETDEV(object_new(TYPE_TAP_NETDEV));
 
     qemu_net_client_setup(&s->nc, &net_tap_info, peer, model, name,
                           tap_net_client_destructor, true);
 
+    s->queue_index = queue_index;
+
     return s;
 }
 
@@ -469,10 +492,11 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
                                  const char *model,
                                  const char *name,
                                  int fd,
-                                 int vnet_hdr)
+                                 int vnet_hdr,
+                                 int queue_index)
 {
     NetOffloads ol = {};
-    TAPState *s = new_tap(peer, model, name);
+    TAPState *s = new_tap(peer, model, name, queue_index);
 
     s->fd = fd;
     s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
@@ -709,7 +733,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
         close(fd);
         return -1;
     }
-    s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
+    s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr, 0);
 
     qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
 
@@ -785,10 +809,11 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
                              const char *name,
                              const char *ifname, const char *script,
                              const char *downscript, int vhostfd,
-                             int vnet_hdr, int fd, Error **errp)
+                             int vnet_hdr, int fd, int queue_index,
+                             Error **errp)
 {
     TAPState *s = net_tap_fd_init(peer, tap->helper ? "bridge" : "tap",
-                                  name, fd, vnet_hdr);
+                                  name, fd, vnet_hdr, queue_index);
     bool sndbuf_required = tap->has_sndbuf;
     int sndbuf =
         (tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
@@ -989,7 +1014,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
             if (!net_init_tap_one(tap, peer, name, ifname,
                                   NULL, NULL,
                                   vhost_fds ? vhost_fds[i] : -1,
-                                  vnet_hdr, fds[i], errp)) {
+                                  vnet_hdr, fds[i], i, errp)) {
                 goto fail;
             }
         }
@@ -1024,7 +1049,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
                                   i >= 1 ? NULL : script,
                                   i >= 1 ? NULL : downscript,
                                   vhost_fds ? vhost_fds[i] : -1,
-                                  vnet_hdr, fd, errp)) {
+                                  vnet_hdr, fd, i, errp)) {
                 goto fail;
             }
         }
Signature · 1 line
MST
#26 lore raw

[PULL 72/90] intel_iommu: Support concurrent page fault handling with PRI

In reply to Michael S. Tsirkin

From: Clément MATHIEU--DRIF <[email protected]>

PRQ slot allocation must be thread safe to avoid posting multiple commands in the same slot so we take a lock in vtd_pri_request_page.

This allows multiple devices to call the page request interface of the same iommu instance.

Message-ID: <[email protected]>

---
 hw/i386/intel_iommu.c | 103 ++++++++++++++++++++++++++----------------
 1 file changed, 63 insertions(+), 40 deletions(-)
hw/i386/intel_iommu.c +63 -40
index 82c3c3b2c3..7c442a86ca 100644
@@ -3627,15 +3627,26 @@ static void vtd_handle_iectl_write(IntelIOMMUState *s)
 
 static void vtd_handle_prs_write(IntelIOMMUState *s)
 {
-    uint32_t prs = vtd_get_long_raw(s, DMAR_PRS_REG);
+    uint32_t prs;
+
+    vtd_iommu_lock(s);
+
+    prs = vtd_get_long_raw(s, DMAR_PRS_REG);
     if (!(prs & VTD_PR_STATUS_PPR) && !(prs & VTD_PR_STATUS_PRO)) {
         vtd_set_clear_mask_long(s, DMAR_PECTL_REG, VTD_PR_PECTL_IP, 0);
     }
+
+    vtd_iommu_unlock(s);
 }
 
 static void vtd_handle_pectl_write(IntelIOMMUState *s)
 {
-    uint32_t pectl = vtd_get_long_raw(s, DMAR_PECTL_REG);
+    uint32_t pectl;
+
+    vtd_iommu_lock(s);
+
+    pectl = vtd_get_long_raw(s, DMAR_PECTL_REG);
+
     if ((pectl & VTD_PR_PECTL_IP) && !(pectl & VTD_PR_PECTL_IM)) {
         /*
          * If IP field was 1 when software clears the IM field,
@@ -3644,6 +3655,8 @@ static void vtd_handle_pectl_write(IntelIOMMUState *s)
         vtd_set_clear_mask_long(s, DMAR_PECTL_REG, VTD_PR_PECTL_IP, 0);
         vtd_generate_interrupt(s, DMAR_PEADDR_REG, DMAR_PEDATA_REG);
     }
+
+    vtd_iommu_unlock(s);
 }
 
 static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size)
@@ -5377,19 +5390,18 @@ static int vtd_pri_request_page(PCIBus *bus, void *opaque, int devfn,
 {
     IntelIOMMUState *s = opaque;
     VTDAddressSpace *vtd_as;
+    uint64_t queue_addr_reg;
+    uint64_t queue_tail_offset_reg;
+    uint64_t new_queue_tail_offset;
+    uint64_t queue_head_offset_reg;
+    hwaddr queue_tail;
+    uint32_t old_pr_status;
+    uint16_t sid;
+    VTDPRDesc desc;
+    int ret = 0;
 
     vtd_as = vtd_find_add_as(s, bus, devfn, pasid);
-
-    uint64_t queue_addr_reg = vtd_get_quad(s, DMAR_PQA_REG);
-    uint64_t queue_tail_offset_reg = vtd_get_quad(s, DMAR_PQT_REG);
-    uint64_t new_queue_tail_offset = (
-                                (queue_tail_offset_reg + VTD_PQA_ENTRY_SIZE) %
-                                (vtd_prq_size(s) * VTD_PQA_ENTRY_SIZE));
-    uint64_t queue_head_offset_reg = vtd_get_quad(s, DMAR_PQH_REG);
-    hwaddr queue_tail = (queue_addr_reg & VTD_PQA_ADDR) + queue_tail_offset_reg;
-    uint32_t old_pr_status = vtd_get_long(s, DMAR_PRS_REG);
-    uint16_t sid = PCI_BUILD_BDF(pci_bus_num(vtd_as->bus), vtd_as->devfn);
-    VTDPRDesc desc;
+    sid = PCI_BUILD_BDF(pci_bus_num(vtd_as->bus), vtd_as->devfn);
 
     if (!(s->ecap & VTD_ECAP_PRS)) {
         return -EPERM;
@@ -5413,25 +5425,7 @@ static int vtd_pri_request_page(PCIBus *bus, void *opaque, int devfn,
         return -EPERM;
     }
 
-    if (old_pr_status & VTD_PR_STATUS_PRO) {
-        /*
-         * No action is taken by hardware to report a fault
-         * or generate an event
-         */
-        return -ENOSPC;
-    }
-
-    /* Check for overflow */
-    if (new_queue_tail_offset == queue_head_offset_reg) {
-        vtd_set_clear_mask_long(s, DMAR_PRS_REG, 0, VTD_PR_STATUS_PRO);
-        vtd_generate_page_request_event(s, old_pr_status);
-        return -ENOSPC;
-    }
-
-    if (vtd_pri_perform_implicit_invalidation(vtd_as, addr)) {
-        return -EINVAL;
-    }
-
+    /* Prepare the descriptor */
     desc.lo = VTD_PRD_TYPE | VTD_PRD_PP(true) | VTD_PRD_RID(sid) |
               VTD_PRD_PASID(vtd_as->pasid) | VTD_PRD_PMR(priv_req);
     desc.hi = VTD_PRD_RDR(is_read) | VTD_PRD_WRR(is_write) |
@@ -5439,26 +5433,55 @@ static int vtd_pri_request_page(PCIBus *bus, void *opaque, int devfn,
 
     desc.lo = cpu_to_le64(desc.lo);
     desc.hi = cpu_to_le64(desc.hi);
+
+    if (vtd_pri_perform_implicit_invalidation(vtd_as, addr)) {
+        return -EINVAL;
+    }
+
+    vtd_iommu_lock(s);
+
+    queue_addr_reg = vtd_get_quad(s, DMAR_PQA_REG);
+    queue_tail_offset_reg = vtd_get_quad(s, DMAR_PQT_REG);
+    new_queue_tail_offset = ((queue_tail_offset_reg + VTD_PQA_ENTRY_SIZE) %
+                            (vtd_prq_size(s) * VTD_PQA_ENTRY_SIZE));
+    queue_head_offset_reg = vtd_get_quad(s, DMAR_PQH_REG);
+    queue_tail = (queue_addr_reg & VTD_PQA_ADDR) + queue_tail_offset_reg;
+    old_pr_status = vtd_get_long(s, DMAR_PRS_REG);
+
+    if (old_pr_status & VTD_PR_STATUS_PRO) {
+        /*
+         * No action is taken by hardware to report a fault
+         * or generate an event
+         */
+        ret = -ENOSPC;
+        goto out;
+    }
+
+    /* Check for overflow */
+    if (new_queue_tail_offset == queue_head_offset_reg) {
+        vtd_set_clear_mask_long(s, DMAR_PRS_REG, 0, VTD_PR_STATUS_PRO);
+        vtd_generate_page_request_event(s, old_pr_status);
+        ret = -ENOSPC;
+        goto out;
+    }
+
     if (dma_memory_write(&address_space_memory, queue_tail, &desc, sizeof(desc),
                          MEMTXATTRS_UNSPECIFIED)) {
         error_report_once("IO error, the PQ tail cannot be updated");
-        return -EIO;
+        ret = -EIO;
+        goto out;
     }
 
     /* increment the tail register and set the pending request bit */
     vtd_set_quad(s, DMAR_PQT_REG, new_queue_tail_offset);
-    /*
-     * read status again so that the kernel does not miss a request.
-     * in some cases, we can trigger an unecessary interrupt but this strategy
-     * drastically improves performance as we don't need to take a lock.
-     */
-    old_pr_status = vtd_get_long(s, DMAR_PRS_REG);
     if (!(old_pr_status & VTD_PR_STATUS_PPR)) {
         vtd_set_clear_mask_long(s, DMAR_PRS_REG, 0, VTD_PR_STATUS_PPR);
         vtd_generate_page_request_event(s, old_pr_status);
     }
 
-    return 0;
+out:
+    vtd_iommu_unlock(s);
+    return ret;
 }
 
 static void vtd_init_iotlb_notifier(PCIBus *bus, void *opaque, int devfn,
Signature · 1 line
MST
#27 lore raw

[PULL 29/90] migration/fd: add errp parameter to migration_fd_valid()

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Let migration_fd_valid() report the error itself, instead of duplicating the error message in both callers. This also prepares for adding one more check (with a different error message) to the function.

Message-ID: <[email protected]>

---
 migration/fd.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)
migration/fd.c +6 -12
index 02b39b150e..78a27caca2 100644
@@ -37,16 +37,14 @@ static bool fd_is_pipe(int fd)
     return S_ISFIFO(statbuf.st_mode);
 }
 
-static bool migration_fd_valid(int fd)
+static bool migration_fd_valid(int fd, Error **errp)
 {
-    if (fd_is_socket(fd)) {
-        return true;
-    }
-
-    if (fd_is_pipe(fd)) {
+    if (fd_is_socket(fd) || fd_is_pipe(fd)) {
         return true;
     }
 
+    error_setg(errp, "fd: migration to a file is not supported."
+               " Use file: instead.");
     return false;
 }
 
@@ -59,9 +57,7 @@ QIOChannel *fd_connect_outgoing(MigrationState *s, const char *fdname,
         goto out;
     }
 
-    if (!migration_fd_valid(fd)) {
-        error_setg(errp, "fd: migration to a file is not supported."
-                   " Use file: instead.");
+    if (!migration_fd_valid(fd, errp)) {
         close(fd);
         goto out;
     }
@@ -95,9 +91,7 @@ void fd_connect_incoming(const char *fdname, Error **errp)
         return;
     }
 
-    if (!migration_fd_valid(fd)) {
-        error_setg(errp, "fd: migration to a file is not supported."
-                   " Use file: instead.");
+    if (!migration_fd_valid(fd, errp)) {
         close(fd);
         return;
     }
Signature · 1 line
MST
#28 lore raw

[PULL 56/90] vhost-user.rst: fix typo

In reply to Michael S. Tsirkin

From: Alyssa Ross <[email protected]>

The protocol feature is named SHMEM. SHMEM_MAP is one of the requests.

Fixes 588acb45c2 ("vhost_user.rst: Add SHMEM_MAP/_UNMAP to spec")

Message-ID: <[email protected]>

---
 docs/interop/vhost-user.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
docs/interop/vhost-user.rst +1 -1
index ae8c7ed995..fbfb9d01c6 100644
@@ -1158,7 +1158,7 @@ Protocol features
   #define VHOST_USER_PROTOCOL_F_DEVICE_STATE            19
   #define VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT 20
   #define VHOST_USER_PROTOCOL_F_GPA_ADDRESSES           21
-  #define VHOST_USER_PROTOCOL_F_SHMEM_MAP               22
+  #define VHOST_USER_PROTOCOL_F_SHMEM                   22
 
 Front-end message types
 -----------------------
Signature · 1 line
MST
#29 lore raw

[PULL 33/90] net/tap: support local migration with virtio-net

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Support transferring of TAP state (including open fd).

Add new property "x-permit-local-migration", which defines whether local migration is actually permitted for this TAP device.

Note that local-migration is enabled by global "local" migration parameter, but individual devices may have additional options to enable/disable it per device.

The tricky thing is that we need to know whether to call open/connect in TAP initialization code, i.e. we need to know the value of migration parameter "local" when creating the TAP device. For incoming migration, we can know only for TAP devices created with QMP after setting the migration parameter with QMP.

So the full picture is:

On source, to start outgoing "local" migration you need:

- migration parameter "local" set to true
- "x-permit-local-migration" TAP option set to true

If at least one of these options is not set, TAP backend doesn't participate in migration.

On target, things are more difficult:

Same, you need both "local" and "x-permit-local-migration" be set. And same, if one of them is not set, TAP backend is initialized as usual, and doesn't accept any incoming state.

Additionally, if you are going to set "local", it must be set before creating the TAP device. If TAP device created with "local" unset, it initializes as usual. If you enable "local" after it and start incoming migration, it will fail in .pre_load handler of TAP backend.

Moreover, there are interface restrictions: if you create TAP device when QEMU is in INCOMING state, and both "local" and "x-permit-local-migration" set, most of TAP options are not allowed, and script/downscript are required to be explicitly disabled.

Message-ID: <[email protected]>

---
 qapi/net.json |  29 ++++++++-
 net/tap.c     | 167 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 189 insertions(+), 7 deletions(-)
qapi/net.json +28 -1
index dccf95bbbc..64c0ef1f6d 100644
@@ -437,6 +437,31 @@
 # @poll-us: maximum number of microseconds that could be spent on busy
 #     polling for tap (since 2.7)
 #
+# @x-permit-local-migration: permit local migration for this TAP
+#     backend.  When set, local migration is enabled/disabled by
+#     migration parameter @local for this TAP backend.  When unset,
+#     migration parameter @local is ignored for this TAP backend.
+#
+#     To be able to do incoming local migration of a TAP backend,
+#     migration parameter @local must be set _before_ creating the
+#     TAP backend.  Otherwise, TAP backend is initialized as usual,
+#     opening/creating TAP devices in kernel.  In this case further
+#     local incoming migration (with migration parameter @local set
+#     after creating TAP backend with @x-permit-local-migration
+#     parameter set) will simply fail.
+#
+#     Moreover, when QEMU is in incoming migration state, migration
+#     parameter @local is set and @x-permit-local-migration is set,
+#     the following options are not supported and must not be set:
+#     @fd, @fds, @helper, @br, @ifname, @sndbuf, @vnet_hdr.
+#     Additionally, @script and @downscript must be explicitly
+#     disabled then.
+#     (default: false, since 11.2)
+#
+# Features:
+#
+# @unstable: Member @x-permit-local-migration is experimental.
+#
 # Since: 1.2
 ##
 { 'struct': 'NetdevTapOptions',
@@ -455,7 +480,9 @@
     '*vhostfds':   'str',
     '*vhostforce': 'bool',
     '*queues':     'uint32',
-    '*poll-us':    'uint32'} }
+    '*poll-us':    'uint32',
+    '*x-permit-local-migration': {
+      'type': 'bool', 'features' : [ 'unstable'] } } }
 
 ##
 # @NetdevSocketOptions:
net/tap.c +161 -6

276 lines not on this page · raw message

Signature · 1 line
MST
#30 lore raw

[PULL 28/90] migration/fd: fix fd leak when fd is not valid for migration

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Both fd_connect_outgoing() and fd_connect_incoming() own the file descriptor after resolving it from the monitor, but forget to close it when migration_fd_valid() check fails.

Fixes f1fcc1c101 ("migration: Remove fd: support on files")

Message-ID: <[email protected]>

---
 migration/fd.c | 2 ++
 1 file changed, 2 insertions(+)
migration/fd.c +2 -0
index f05f95992f..02b39b150e 100644
@@ -62,6 +62,7 @@ QIOChannel *fd_connect_outgoing(MigrationState *s, const char *fdname,
     if (!migration_fd_valid(fd)) {
         error_setg(errp, "fd: migration to a file is not supported."
                    " Use file: instead.");
+        close(fd);
         goto out;
     }
 
@@ -97,6 +98,7 @@ void fd_connect_incoming(const char *fdname, Error **errp)
     if (!migration_fd_valid(fd)) {
         error_setg(errp, "fd: migration to a file is not supported."
                    " Use file: instead.");
+        close(fd);
         return;
     }
 
Signature · 1 line
MST
#31 lore raw

[PULL 82/90] virtio-net: validate IHL in virtio_net_rsc_extract_unit4 before use

In reply to Michael S. Tsirkin

virtio_net_rsc_extract_unit4() uses the IPv4 IHL nibble from the wire to compute the TCP header offset, but the caller's length check only guarantees space for a minimum 20-byte IP header. A crafted IHL of 15 causes a read 32 bytes past a 66-byte buffer when the frame was parked in net/queue.c's exact-size allocation.

virtio_net_rsc_sanity_check4() rejects IHL != 5 on the next line, but runs after the OOB read already happened.

Validate IHL before using it as an offset. Since virtio_net_rsc_sanity_check4() only accepts IHL == 5 anyway, reject anything else early and let the caller fall through to the bypass path.

Fixes 2974e916df ("virtio-net: support RSC v4/v6 tcp traffic for Windows HCK")
Cc Jason Wang <[email protected]>
Cc Yuri Benditovich <[email protected]>

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4166

---
 hw/net/virtio-net.c | 8 ++++++++
 1 file changed, 8 insertions(+)
hw/net/virtio-net.c +8 -0
index 986ceff514..19f453fb7d 100644
@@ -2104,6 +2104,14 @@ static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
     unit->ip = (void *)ip;
     ip_hdrlen = (ip->ip_ver_len & 0xF) << 2;
     unit->ip_plen = &ip->ip_len;
+
+    if (ip_hdrlen != sizeof(struct ip_header)) {
+        unit->tcp = NULL;
+        unit->tcp_hdrlen = 0;
+        unit->payload = 0;
+        return;
+    }
+
     unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen);
     unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
     unit->payload = read_unit_ip_len(unit) - ip_hdrlen - unit->tcp_hdrlen;
Signature · 1 line
MST
#32 lore raw

[PULL 24/90] net/tap: use container_of instead of DO_UPCAST

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

We are going to QOMify tap backend, which includes deriving TAPState from Object. So "NetClientState nc" will not be a first member. Let's parepare for this change, and use container_of(), which will work regardless position of "nc" field.

Message-ID: <[email protected]>

---
 net/tap.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
net/tap.c +18 -18
index f2b571dd11..bfed74717e 100644
@@ -175,7 +175,7 @@ static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt
 static ssize_t tap_receive_iov(NetClientState *nc, const struct iovec *iov,
                                int iovcnt)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     const struct iovec *iovp = iov;
     g_autofree struct iovec *iov_copy = NULL;
     struct virtio_net_hdr hdr = { };
@@ -211,7 +211,7 @@ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
 
 static void tap_send_completed(NetClientState *nc, ssize_t len)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     tap_read_poll(s, true);
 }
 
@@ -271,7 +271,7 @@ static void tap_send(void *opaque)
 
 static bool tap_has_ufo(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
 
@@ -280,7 +280,7 @@ static bool tap_has_ufo(NetClientState *nc)
 
 static bool tap_has_uso(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
 
@@ -289,7 +289,7 @@ static bool tap_has_uso(NetClientState *nc)
 
 static bool tap_has_tunnel(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     return s->has_tunnel;
@@ -297,7 +297,7 @@ static bool tap_has_tunnel(NetClientState *nc)
 
 static bool tap_has_vnet_hdr(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
 
@@ -311,7 +311,7 @@ static bool tap_has_vnet_hdr_len(NetClientState *nc, int len)
 
 static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
 
@@ -322,21 +322,21 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
 
 static int tap_set_vnet_le(NetClientState *nc, bool is_le)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     return tap_fd_set_vnet_le(s->fd, is_le);
 }
 
 static int tap_set_vnet_be(NetClientState *nc, bool is_be)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     return tap_fd_set_vnet_be(s->fd, is_be);
 }
 
 static void tap_set_offload(NetClientState *nc, const NetOffloads *ol)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     if (s->fd < 0) {
         return;
     }
@@ -357,7 +357,7 @@ static void tap_exit_notify(Notifier *notifier, void *data)
 
 static void tap_cleanup(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
 
     if (s->vhost_net) {
         vhost_net_cleanup(s->vhost_net);
@@ -381,14 +381,14 @@ static void tap_cleanup(NetClientState *nc)
 
 static void tap_poll(NetClientState *nc, bool enable)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     tap_read_poll(s, enable);
     tap_write_poll(s, enable);
 }
 
 static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
 
     return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
@@ -396,7 +396,7 @@ static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
 
 int tap_get_fd(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     return s->fd;
 }
@@ -408,7 +408,7 @@ int tap_get_fd(NetClientState *nc)
  */
 static VHostNetState *tap_get_vhost_net(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     return s->vhost_net;
 }
@@ -447,7 +447,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
 
     nc = qemu_new_net_client(&net_tap_info, peer, model, name);
 
-    s = DO_UPCAST(TAPState, nc, nc);
+    s = container_of(nc, TAPState, nc);
 
     s->fd = fd;
     s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
@@ -1016,7 +1016,7 @@ fail:
 
 int tap_enable(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     int ret;
 
     if (s->enabled) {
@@ -1033,7 +1033,7 @@ int tap_enable(NetClientState *nc)
 
 int tap_disable(NetClientState *nc)
 {
-    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    TAPState *s = container_of(nc, TAPState, nc);
     int ret;
 
     if (s->enabled == 0) {
Signature · 1 line
MST
#33 lore raw

[PULL 09/90] vhost-vsock: preserve vhost FD during CPR

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

During CPR (checkpoint-restore) migration the guest keeps running on the same host, so instead of reopening /dev/vhost-vsock on the destination, we should reuse the FD from the source. The FD is saved in the CPR namespace (hash table) with cpr_save_fd() and then reclaimed on the target via cpr_find_fd().

Since the key in CPR hash table is device ID, CPR needs a unique ID. Thus we only preserve the FD with cpr_{save,find} if this ID is present. In a following patch, when we lift the CPR migration blocker, we're going to condition it on the presence of ID.

vhost_dev_init() (and thus VHOST_SET_OWNER) still runs in realize() here. Deferring the ownership handoff to pre_save/post_load is done in a following patch. Until then CPR remains blocked, so the restore path added here is not reachable yet.

Message-ID: <[email protected]>

---
 hw/virtio/vhost-vsock.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
hw/virtio/vhost-vsock.c +23 -1
index 3ec20d8760..cec2c31f0c 100644
@@ -143,6 +143,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VHostVSock *vsock = VHOST_VSOCK(dev);
+    DeviceState *proxy = qdev_get_parent_bus(DEVICE(vsock))->parent;
     int vhostfd;
     int ret;
 
@@ -170,7 +171,19 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (vsock->conf.vhostfd) {
+    if (cpr_is_incoming()) {
+        /* Reuse the fd handed over from the source QEMU. */
+        if (!proxy->id) {
+            error_setg(errp, "vhost-vsock: device ID is required for "
+                       "CPR migration");
+            goto err_blocker;
+        }
+        vhostfd = cpr_find_fd(proxy->id, 0);
+        if (vhostfd < 0) {
+            error_setg(errp, "vhost-vsock: could not find restored vhost FD");
+            goto err_blocker;
+        }
+    } else if (vsock->conf.vhostfd) {
         vhostfd = monitor_fd_param(monitor_cur(), vsock->conf.vhostfd, errp);
         if (vhostfd == -1) {
             error_prepend(errp, "vhost-vsock: unable to parse vhostfd: ");
@@ -207,6 +220,11 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
         goto err_vhost_dev;
     }
 
+    /* Register the fd for a future CPR after a fully successful realize */
+    if (proxy->id) {
+        cpr_save_fd(proxy->id, 0, vhostfd);
+    }
+
     return;
 
 err_vhost_dev:
@@ -223,10 +241,14 @@ static void vhost_vsock_device_unrealize(DeviceState *dev)
     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VHostVSock *vsock = VHOST_VSOCK(dev);
+    DeviceState *proxy = qdev_get_parent_bus(dev)->parent;
 
     /* This will stop vhost backend if appropriate. */
     vhost_vsock_set_status(vdev, 0);
 
+    if (proxy->id) {
+        cpr_delete_fd(proxy->id, 0);
+    }
     migrate_del_blocker(&vsock->migration_blocker);
     vhost_dev_cleanup(&vvc->vhost_dev);
     vhost_vsock_common_unrealize(vdev);
Signature · 1 line
MST
#34 lore raw

[PULL 54/90] hw/virtio: reject inverted virtio-iommu IOVA ranges

In reply to Michael S. Tsirkin

From: Jia Jia <[email protected]>

Guest MAP and UNMAP requests can set virt_end below virt_start. Since virt_end is inclusive, this is not a valid interval. MAP nevertheless stores it in domain->mappings, but interval_cmp() assumes low <= high. For an inverted key, interval_cmp(key, key) returns -1. A covering UNMAP can therefore find the key but fail to remove it and repeat forever while holding s->mutex.

Reject inverted request ranges with VIRTIO_IOMMU_S_INVAL and make the notifier range decomposition skip invalid ranges. Keep the existing notifier-before-remove ordering, but return VIRTIO_IOMMU_S_DEVERR if g_tree_remove() fails.

Fixes fe2cacae2438 ("virtio-iommu: Implement map/unmap")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4104

Message-ID: <[email protected]>

---
 hw/virtio/virtio-iommu.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
hw/virtio/virtio-iommu.c +16 -1
index 533bd5073f..208815096f 100644
@@ -212,6 +212,10 @@ static void virtio_iommu_notify_map_unmap(IOMMUMemoryRegion *mr,
 {
     uint64_t delta = virt_end - virt_start;
 
+    if (virt_end < virt_start) {
+        return;
+    }
+
     event->entry.iova = virt_start;
     event->entry.addr_mask = delta;
 
@@ -807,6 +811,10 @@ static int virtio_iommu_map(VirtIOIOMMU *s,
         return VIRTIO_IOMMU_S_INVAL;
     }
 
+    if (virt_end < virt_start) {
+        return VIRTIO_IOMMU_S_INVAL;
+    }
+
     domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id));
     if (!domain) {
         return VIRTIO_IOMMU_S_NOENT;
@@ -857,6 +865,10 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s,
 
     trace_virtio_iommu_unmap(domain_id, virt_start, virt_end);
 
+    if (virt_end < virt_start) {
+        return VIRTIO_IOMMU_S_INVAL;
+    }
+
     domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id));
     if (!domain) {
         return VIRTIO_IOMMU_S_NOENT;
@@ -879,7 +891,10 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s,
                 virtio_iommu_notify_unmap(ep->iommu_mr, current_low,
                                           current_high);
             }
-            g_tree_remove(domain->mappings, iter_key);
+            if (!g_tree_remove(domain->mappings, iter_key)) {
+                ret = VIRTIO_IOMMU_S_DEVERR;
+                break;
+            }
             trace_virtio_iommu_unmap_done(domain_id, current_low, current_high);
         } else {
             ret = VIRTIO_IOMMU_S_RANGE;
Signature · 1 line
MST
#35 lore raw

[PULL 13/90] vhost: add vhost_dev_is_initialized() helper

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

The upcoming CPR support for vhost-vsock defers the full vhost_dev_init() to .post_load(). On an incoming CPR .realize() only sets up the backend, so we need a way to tell a fully initialized vhost device from a partially initialized one.

Add an explicit 'bool initialized' field, set once vhost_dev_init() succeeds, and cleared only in vhost_dev_cleanup() (by memset(0)). Also add a public vhost_dev_is_initialized() helper.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost.h | 14 ++++++++++++++
 hw/virtio/vhost.c         |  2 ++
 2 files changed, 16 insertions(+)
include/hw/virtio/vhost.h +14 -0
index 44e65968d9..7c4f032996 100644
@@ -109,6 +109,8 @@ struct vhost_dev {
     uint64_t backend_cap;
     /* @started: is the vhost device started? */
     bool started;
+    /* @initialized: has the full vhost_dev_init() completed? */
+    bool initialized;
     bool log_enabled;
     uint64_t log_size;
     Error *migration_blocker;
@@ -236,6 +238,18 @@ static inline bool vhost_dev_is_started(struct vhost_dev *hdev)
     return hdev->started;
 }
 
+/**
+ * vhost_dev_is_initialized() - report init status of vhost device
+ * @hdev: common vhost_dev structure
+ *
+ * Return true if the full vhost_dev_init() has completed successfully
+ * (and vhost_dev_cleanup() has not run since).
+ */
+static inline bool vhost_dev_is_initialized(struct vhost_dev *hdev)
+{
+    return hdev->initialized;
+}
+
 static inline int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable)
 {
     if (!hdev->vhost_ops->vhost_set_vring_enable) {
hw/virtio/vhost.c +2 -0
index ea17bf0108..a81cd94f90 100644
@@ -1821,6 +1821,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
         goto fail;
     }
 
+    hdev->initialized = true;
+
     trace_vhost_dev_init_out(hdev);
 
     return 0;
Signature · 1 line
MST
#36 lore raw

[PULL 58/90] hw/virtio: Propagate vhost_virtqueue_mask errors

In reply to Michael S. Tsirkin

From: Xiong Weimin <[email protected]>

vhost_virtqueue_mask() currently reports failures from vhost_set_vring_call() but always returns void, so callers cannot react. In particular, vhost_virtqueue_start() has a TODO next to the unmask call when !use_guest_notifier_mask.

Make vhost_virtqueue_mask() return the underlying errno, and on failure in vhost_virtqueue_start() jump to the existing fail path which unmaps the vring and propagates the error to the device start caller. Other call sites keep today's behavior by ignoring the return value.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost.h |  9 ++++++---
 hw/virtio/vhost.c         | 10 +++++++---
 2 files changed, 13 insertions(+), 6 deletions(-)
include/hw/virtio/vhost.h +6 -3
index 7c4f032996..cd012b99a2 100644
@@ -359,10 +359,13 @@ void vhost_dev_set_config_notifier(struct vhost_dev *dev,
  */
 bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n);
 
-/* Mask/unmask events from this vq.
+/**
+ * vhost_virtqueue_mask(): mask/unmask events from this vq.
+ *
+ * Returns: 0 on success, a negative errno on failure.
  */
-void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
-                          bool mask);
+int vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
+                         bool mask);
 
 /**
  * vhost_get_features_ex() - sanitize the extended features set
hw/virtio/vhost.c +7 -3
index 838b1da739..6c2612a1dd 100644
@@ -1481,8 +1481,10 @@ int vhost_virtqueue_start(struct vhost_dev *dev,
      * will do it later.
      */
     if (!vdev->use_guest_notifier_mask) {
-        /* TODO: check and handle errors. */
-        vhost_virtqueue_mask(dev, vdev, idx, false);
+        r = vhost_virtqueue_mask(dev, vdev, idx, false);
+        if (r < 0) {
+            goto fail;
+        }
     }
 
     if (k->query_guest_notifiers &&
@@ -1962,7 +1964,7 @@ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
 }
 
 /* Mask/unmask events from this vq. */
-void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
+int vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
                          bool mask)
 {
     struct VirtQueue *vvq = virtio_get_queue(vdev, n);
@@ -1983,7 +1985,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
     r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
     if (r < 0) {
         error_report("vhost_set_vring_call failed %d", -r);
+        return r;
     }
+    return 0;
 }
 
 bool vhost_config_pending(struct vhost_dev *hdev)
Signature · 1 line
MST
#37 lore raw

[PULL 46/90] hw/virtio-blk: Complete zone-append cookies

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

virtio_blk_handle_zone_append() starts accounting via block_acct_start(), but this is actually never completed. Do so.

Message-ID: <[email protected]>

---
 hw/block/virtio-blk.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
hw/block/virtio-blk.c +7 -1
index 4110380392..61c341ce2c 100644
@@ -755,7 +755,8 @@ static void virtio_blk_zone_append_complete(void *opaque, int ret)
 {
     ZoneCmdData *data = opaque;
     VirtIOBlockReq *req = data->req;
-    VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
+    VirtIOBlock *s = req->dev;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
     int64_t append_sector, n;
     uint8_t err_status = VIRTIO_BLK_S_OK;
 
@@ -778,6 +779,11 @@ static void virtio_blk_zone_append_complete(void *opaque, int ret)
 
 out:
     virtio_blk_req_complete(req, err_status);
+    if (err_status == VIRTIO_BLK_S_OK) {
+        block_acct_done(blk_get_stats(s->blk), &req->acct);
+    } else {
+        block_acct_failed(blk_get_stats(s->blk), &req->acct);
+    }
     g_free(req);
     g_free(data);
 }
Signature · 1 line
MST
#38 lore raw

[PULL 48/90] hw/nvme: Fix block accounting for compare

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

nvme_compare() starts block accounting for the operation, but nvme_compare_data_cb() (and nvme_compare_mdata_cb()) do not always finalize the cookie. Specifically, there are a lot of error paths that do not call block_acct_failed().

Fix this by putting block_acct_done()/block_acct_failed() under the out labels of nvme_compare_data_cb() and nvme_compare_mdata_cb().

Message-ID: <[email protected]>

---
 hw/nvme/ctrl.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
hw/nvme/ctrl.c +12 -5
index c56725947a..7478f0b33a 100644
@@ -2389,7 +2389,6 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
     trace_pci_nvme_compare_mdata_cb(nvme_cid(req));
 
     if (ret) {
-        block_acct_failed(stats, acct);
         req->status = NVME_UNRECOVERED_READ;
 
         trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
@@ -2444,9 +2443,14 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
         goto out;
     }
 
-    block_acct_done(stats, acct);
 
 out:
+    if (req->status == NVME_SUCCESS) {
+        block_acct_done(stats, acct);
+    } else {
+        block_acct_failed(stats, acct);
+    }
+
     qemu_iovec_destroy(&ctx->data.iov);
     g_free(ctx->data.bounce);
 
@@ -2474,7 +2478,6 @@ static void nvme_compare_data_cb(void *opaque, int ret)
     trace_pci_nvme_compare_data_cb(nvme_cid(req));
 
     if (ret) {
-        block_acct_failed(stats, acct);
         req->status = NVME_UNRECOVERED_READ;
 
         trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), req->status);
@@ -2513,9 +2516,13 @@ static void nvme_compare_data_cb(void *opaque, int ret)
         return;
     }
 
-    block_acct_done(stats, acct);
-
 out:
+    if (req->status == NVME_SUCCESS) {
+        block_acct_done(stats, acct);
+    } else {
+        block_acct_failed(stats, acct);
+    }
+
     qemu_iovec_destroy(&ctx->data.iov);
     g_free(ctx->data.bounce);
     g_free(ctx);
Signature · 1 line
MST
#39 lore raw

[PULL 83/90] intel_iommu: Expose SMPWC when SVM is enabled

In reply to Michael S. Tsirkin

From: Clément MATHIEU--DRIF <[email protected]>

SVM in Linux requires SMPWC. This is free in the current implementation as it is already in line with the expected behaviour.

Message-ID: <[email protected]>

---
 hw/i386/intel_iommu_internal.h | 1 +
 hw/i386/intel_iommu.c          | 3 ++-
 hw/i386/intel_iommu_accel.c    | 6 ++++++
 3 files changed, 9 insertions(+), 1 deletion(-)
hw/i386/intel_iommu_internal.h +1 -0
index 924e91cb8a..df7a0efa6e 100644
@@ -202,6 +202,7 @@
 #define VTD_ECAP_SMTS               (1ULL << 43)
 #define VTD_ECAP_SSTS               (1ULL << 46)
 #define VTD_ECAP_FSTS               (1ULL << 47)
+#define VTD_ECAP_SMPWCS             (1ULL << 48)
 
 /* CAP_REG */
 /* (offset >> 4) << 24 */
hw/i386/intel_iommu.c +2 -1
index 91ab549dbf..350d2b7753 100644
@@ -5121,7 +5121,8 @@ static void vtd_init(IntelIOMMUState *s)
     }
 
     if (s->svm) {
-        s->ecap |= VTD_ECAP_PRS | VTD_ECAP_PDS | VTD_ECAP_NWFS;
+        s->ecap |= VTD_ECAP_PRS | VTD_ECAP_PDS | VTD_ECAP_NWFS |
+                   VTD_ECAP_SMPWCS;
     }
 
     vtd_reset_caches(s);
hw/i386/intel_iommu_accel.c +6 -0
index c03435f8a2..c3677775e9 100644
@@ -37,6 +37,12 @@ bool vtd_check_hiod_accel(IntelIOMMUState *s, VTDHostIOMMUDevice *vtd_hiod,
         return false;
     }
 
+    if ((s->ecap & VTD_ECAP_SMPWCS) && !(vtd->ecap_reg & VTD_ECAP_SMPWCS)) {
+        error_setg(errp,
+                   "Scalable-mode coherent walk is unsupported by host IOMMU");
+        return false;
+    }
+
     if (s->fs1gp && !(vtd->cap_reg & VTD_CAP_FS1GP)) {
         error_setg(errp,
                    "First stage 1GB large page is unsupported by host IOMMU");
Signature · 1 line
MST
#40 lore raw

[PULL 49/90] hw/ide: Have ide_dma_cb() complete accounting

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

ide_sector_start_dma() starts accounting for reading and writing, and ide_dma_cb() is supposed to complete it, but currently does not always:
In one case, it just forgets it altogether, in the other, it uses block_acct_invalid(), which should not be used after a cookie has already been created.

Message-ID: <[email protected]>

---
 hw/ide/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
hw/ide/core.c +2 -1
index ef573798d9..06e6bb6067 100644
@@ -898,6 +898,7 @@ static void ide_dma_cb(void *opaque, int ret)
 
     if (ret == -EINVAL) {
         ide_dma_error(s);
+        block_acct_failed(blk_get_stats(s->blk), &s->acct);
         return;
     }
 
@@ -968,7 +969,7 @@ static void ide_dma_cb(void *opaque, int ret)
     if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
         !ide_sect_range_ok(s, sector_num, n)) {
         ide_dma_error(s);
-        block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
+        block_acct_failed(blk_get_stats(s->blk), &s->acct);
         return;
     }
 
Signature · 1 line
MST
#41 lore raw

[PULL 30/90] migration: check that transfer is UNIX socket when "local" set

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

As documented, for "local", the migration channel must be direct UNIX socket connection from source to target (except for CPR_EXEC mode). We can't check for it being "direct", but let's at least check that we deal with UNIX socket.

Message-ID: <[email protected]>

---
 migration/fd.c        | 14 ++++++++++++++
 migration/migration.c | 13 +++++++++++++
 2 files changed, 27 insertions(+)
migration/fd.c +14 -0
index 78a27caca2..4a891e814a 100644
@@ -39,6 +39,20 @@ static bool fd_is_pipe(int fd)
 
 static bool migration_fd_valid(int fd, Error **errp)
 {
+    if (migrate_local() && migrate_mode() != MIG_MODE_CPR_EXEC) {
+        struct sockaddr_storage ss;
+        socklen_t sslen = sizeof(ss);
+
+        if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0 ||
+            ss.ss_family != AF_UNIX) {
+            error_setg(errp,
+                       "local migration requires a UNIX domain socket channel");
+            return false;
+        }
+
+        return true;
+    }
+
     if (fd_is_socket(fd) || fd_is_pipe(fd)) {
         return true;
     }
migration/migration.c +13 -0
index b413d28622..d8418e4582 100644
@@ -260,6 +260,19 @@ migration_capabilities_and_transport_compatible(MigrationAddress *addr,
                                        errp);
     }
 
+    if (migrate_local() && migrate_mode() != MIG_MODE_CPR_EXEC &&
+        (addr->transport != MIGRATION_ADDRESS_TYPE_SOCKET ||
+         (addr->u.socket.type != SOCKET_ADDRESS_TYPE_UNIX &&
+          addr->u.socket.type != SOCKET_ADDRESS_TYPE_FD))) {
+        /*
+         * For SOCKET_ADDRESS_TYPE_FD we do check the fd itself later
+         * in migration_fd_valid().
+         */
+        error_setg(errp,
+                   "local migration requires a UNIX domain socket channel");
+        return false;
+    }
+
     return true;
 }
 
Signature · 1 line
MST
#42 lore raw

[PULL 20/90] net/tap: improve script/downscript options documentation

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Properly document defaults and special values of "" and "no".

Message-ID: <[email protected]>

---
 qapi/net.json   | 10 ++++++++--
 qemu-options.hx |  9 +++++----
 2 files changed, 13 insertions(+), 6 deletions(-)
qapi/net.json +8 -2
index 85c78710fe..ab8ed9c086 100644
@@ -399,9 +399,15 @@
 # @fds: multiple file descriptors of already opened multiqueue capable
 #     tap
 #
-# @script: script to initialize the interface
+# @script: script to initialize the interface.  An empty string or
+#     "no" disables script execution.  Defaults to
+#     ``<sysconfdir>/qemu-ifup``, where ``<sysconfdir>`` is the
+#     system configuration directory at build time (typically /etc).
 #
-# @downscript: script to shut down the interface
+# @downscript: script to shut down the interface.  An empty string or
+#     "no" disables script execution.  Defaults to
+#     ``<sysconfdir>/qemu-ifdown``, where ``<sysconfdir>`` is the
+#     system configuration directory at build time (typically /etc).
 #
 # @br: bridge name (since 2.8)
 #
qemu-options.hx +5 -4
index 6c1713ed61..16ef7d5455 100644
@@ -3022,7 +3022,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "                use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
     "                to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
     "                to deconfigure it\n"
-    "                use '[down]script=no' to disable script execution\n"
+    "                use '[down]script=no' or '[down]script=' to disable script execution\n"
     "                use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
     "                configure it\n"
     "                use 'fd=h' to connect to an already opened TAP interface\n"
@@ -3558,9 +3558,10 @@ SRST
     Use the network script file to configure it and the network script
     dfile to deconfigure it. If name is not provided, the OS
     automatically provides one. The default network configure script is
-    ``/etc/qemu-ifup`` and the default network deconfigure script is
-    ``/etc/qemu-ifdown``. Use ``script=no`` or ``downscript=no`` to
-    disable script execution.
+    ``<sysconfdir>/qemu-ifup`` and the default network deconfigure script is
+    ``<sysconfdir>/qemu-ifdown``, where ``<sysconfdir>`` is the system
+    configuration directory at build time (typically ``/etc``).
+    Use ``[down]script=no`` or ``[down]script=`` to disable script execution.
 
     If running QEMU as an unprivileged user, use the network helper
     to configure the TAP interface and attach it to the bridge.
Signature · 1 line
MST
#43 lore raw

[PULL 44/90] hw/net/virtio-net: check packet size before VLAN tag access in receive_filter()

In reply to Michael S. Tsirkin

From: Laurent Vivier <[email protected]>

receive_filter() reads ptr[14..15] to extract the VLAN ID without checking the packet is large enough. A short frame with VLAN TPID at bytes 12-13 but no VLAN TCI causes a 2-byte out-of-bounds read.

Add size checks before accessing the Ethernet header and the VLAN tag fields.

Cc: [email protected]
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3788

Fixes f21c0ed97c97 ("qemu:virtio-net: Add VLAN filtering (Alex Williamson)")

Message-ID: <[email protected]>

---
 hw/net/virtio-net.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
hw/net/virtio-net.c +6 -2
index 274fbcb0d6..f3f375e1b2 100644
@@ -1751,12 +1751,16 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
     }
 
     ptr += n->host_hdr_len;
+    size -= n->host_hdr_len;
+
+    if (size < sizeof(struct eth_header)) {
+        return 0;
+    }
 
     if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
         int vid;
 
-        /* Truncated vlan packet */
-        if (size < n->host_hdr_len + 16) {
+        if (size < 16) {
             return 0;
         }
         vid = lduw_be_p(ptr + 14) & 0xfff;
Signature · 1 line
MST
#44 lore raw

[PULL 10/90] vhost: factor out vhost_dev_init_backend()

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

Split the first part of vhost_dev_init(): selecting the backend, calling its .vhost_init() and reading the supported features - into a new vhost_dev_init_backend() helper, and call it from vhost_dev_init().

This is in preparation for CPR restore of vhost-vsock, which needs to learn the backend's features at realize time to negotiate them when loading the incoming virtio state, but also must defer taking ownership of the device to post_load. vhost_dev_init_backend() does exactly the pre-ownership part.

As a result VHOST_SET_OWNER now follows the feature query rather than precedes it. This should be safe, as no backend requires ownership before VHOST_GET_FEATURES - the kernel and vdpa backends do not check ownership for it, and vhost-user already does query features from its .vhost_init() before set_owner().

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost.h | 22 ++++++++++++++++++++++
 hw/virtio/vhost.c         | 33 +++++++++++++++++++++++----------
 2 files changed, 45 insertions(+), 10 deletions(-)
include/hw/virtio/vhost.h +22 -0
index 684bafcaad..9b98d34dd0 100644
@@ -156,6 +156,28 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
                    VhostBackendType backend_type,
                    uint32_t busyloop_timeout, Error **errp);
 
+/**
+ * vhost_dev_init_backend() - set up the backend and query its features
+ * @hdev: the common vhost_dev structure
+ * @opaque: opaque ptr passed to backend (vhost/vhost-user/vdpa)
+ * @backend_type: type of backend
+ * @errp: error handle
+ *
+ * Select the backend, initialise the backend instance and read its supported
+ * features into @hdev, without issuing VHOST_SET_OWNER, setting up the
+ * virtqueues or registering the memory listener.  This is the part of
+ * vhost_dev_init() that precedes taking ownership; it can be used on its own
+ * so feature negotiation can happen before ownership is acquired (e.g. by CPR
+ * restore).
+ *
+ * On failure the backend may be left partially initialised; the caller must
+ * still call vhost_dev_cleanup() to release it.
+ *
+ * Return: 0 on success, non-zero on error while setting errp.
+ */
+int vhost_dev_init_backend(struct vhost_dev *hdev, void *opaque,
+                           VhostBackendType backend_type, Error **errp);
+
 /**
  * vhost_dev_cleanup() - tear down and cleanup vhost interface
  * @hdev: the common vhost_dev structure
hw/virtio/vhost.c +23 -10
index 371dca17dd..f9b54c46f9 100644
@@ -1668,6 +1668,28 @@ static int vhost_dev_init_features(struct vhost_dev *hdev)
     return r;
 }
 
+int vhost_dev_init_backend(struct vhost_dev *hdev, void *opaque,
+                           VhostBackendType backend_type, Error **errp)
+{
+    int r;
+
+    r = vhost_set_backend_type(hdev, backend_type);
+    assert(r >= 0);
+
+    r = hdev->vhost_ops->vhost_init(hdev, opaque, errp);
+    if (r < 0) {
+        return r;
+    }
+
+    r = vhost_dev_init_features(hdev);
+    if (r < 0) {
+        error_setg_errno(errp, -r, "vhost_init_features failed");
+        return r;
+    }
+
+    return 0;
+}
+
 int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
                    VhostBackendType backend_type, uint32_t busyloop_timeout,
                    Error **errp)
@@ -1680,10 +1702,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
     hdev->vdev = NULL;
     hdev->migration_blocker = NULL;
 
-    r = vhost_set_backend_type(hdev, backend_type);
-    assert(r >= 0);
-
-    r = hdev->vhost_ops->vhost_init(hdev, opaque, errp);
+    r = vhost_dev_init_backend(hdev, opaque, backend_type, errp);
     if (r < 0) {
         goto fail;
     }
@@ -1694,12 +1713,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
         goto fail;
     }
 
-    r = vhost_dev_init_features(hdev);
-    if (r < 0) {
-        error_setg_errno(errp, -r, "vhost_init_features failed");
-        goto fail;
-    }
-
     limit = hdev->vhost_ops->vhost_memslots_limit(hdev);
     if (limit < MEMORY_DEVICES_SAFE_MAX_MEMSLOTS &&
         memory_devices_memslot_auto_decision_active()) {
Signature · 1 line
MST
#45 lore raw

[PULL 51/90] meson: disable "maybe uninitilized" errors with -Og

In reply to Michael S. Tsirkin

GCC's "maybe uninitilized" warnings depend on optimizations for code flow analysis, and produce false positive errors with -Og. Default build gives us coverage with that, so let's just disable with -Og.

Message-ID: <f559b622eb2d1a384b4f30583a8af10531f4b032.1785144729.git.mst@redhat.com>

---
 meson.build | 4 ++++
 1 file changed, 4 insertions(+)
meson.build +4 -0
index ec9b05414a..e2da31880b 100644
@@ -746,6 +746,10 @@ warn_flags = [
   '-Wno-typedef-redefinition',
 ]
 
+if get_option('optimization') == 'g'
+  warn_flags += ['-Wno-error=maybe-uninitialized']
+endif
+
 if host_os != 'darwin'
   tsa_has_cleanup = cc.compiles('''
     struct __attribute__((capability("mutex"))) mutex {};
Signature · 1 line
MST
#46 lore raw

[PULL 38/90] vhost-user-gpu: Forward RESOURCE_BLOB and CONTEXT_INIT flags

In reply to Michael S. Tsirkin

From: Matej Hrica <[email protected]>

Forward VIRTIO_GPU_F_RESOURCE_BLOB and VIRTIO_GPU_F_CONTEXT_INIT received from a vhost backend to expose it to the guest.

Use vhost_dev_has_feature() to query the backend features, matching the existing pattern for RESOURCE_UUID.

This allows the guest to negotiate blob resource support and context initialization when the backend (e.g., vhost-device-gpu with Venus) advertises these capabilities.

Message-ID: <[email protected]>

---
 hw/display/vhost-user-gpu.c | 6 ++++++
 1 file changed, 6 insertions(+)
hw/display/vhost-user-gpu.c +6 -0
index 80ab6b773e..a5b4df2c46 100644
@@ -681,6 +681,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
     if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_RESOURCE_UUID)) {
         g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_RESOURCE_UUID_ENABLED;
     }
+    if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_RESOURCE_BLOB)) {
+        g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_BLOB_ENABLED;
+    }
+    if (vhost_dev_has_feature(&g->vhost->dev, VIRTIO_GPU_F_CONTEXT_INIT)) {
+        g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED;
+    }
 
     if (!virtio_gpu_base_device_realize(qdev, NULL, NULL, errp)) {
         return;
Signature · 1 line
MST
#47 lore raw

[PULL 62/90] acpi_build: Use IOMMU pci device to build IOMMU DeviceID

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

Currently, build_amd_iommu() uses "addr" property to build the DeviceID for IOMMU device and advertise it through IVRS. But this property does not encode IOMMU bus number, only the device and function number. This creates an incorrect DeviceID when the IOMMU is attached to a bus other than the default one with bus number 0.

Message-ID: <[email protected]>

---
 hw/i386/acpi-build.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)
hw/i386/acpi-build.c +4 -6
index 05b68d05a8..a28bb2ec63 100644
@@ -1851,6 +1851,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     AcpiTable table = { .sig = "IVRS", .rev = 1, .oem_id = oem_id,
                         .oem_table_id = oem_table_id };
     uint64_t feature_report;
+    uint16_t iommu_devid = pci_get_bdf(&s->pci->dev);
 
     acpi_table_begin(&table, table_data);
     /* IVinfo - IO virtualization information common to all
@@ -1913,9 +1914,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     /* IVHD length */
     build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2);
     /* DeviceID */
-    build_append_int_noprefix(table_data,
-                              object_property_get_int(OBJECT(s->pci), "addr",
-                                                      &error_abort), 2);
+    build_append_int_noprefix(table_data, iommu_devid, 2);
     /* Capability offset */
     build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
     /* IOMMU base address */
@@ -1947,10 +1946,9 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
 
     /* IVHD length */
     build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2);
+
     /* DeviceID */
-    build_append_int_noprefix(table_data,
-                              object_property_get_int(OBJECT(s->pci), "addr",
-                                                      &error_abort), 2);
+    build_append_int_noprefix(table_data, iommu_devid, 2);
     /* Capability offset */
     build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
     /* IOMMU base address */
Signature · 1 line
MST
#48 lore raw

[PULL 43/90] tests/qtest/cxl: Add CXL Fixed Memory Window restriction flag tests

In reply to Michael S. Tsirkin

From: Davidlohr Bueso <[email protected]>

Add a /pci/cxl/cfmw group exercising the configurable CFMWS Window Restrictions.

Message-ID: <[email protected]>

---
 tests/qtest/cxl-test.c | 95 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
tests/qtest/cxl-test.c +95 -0
index 8fb7e58d4f..49d820cde1 100644
@@ -81,6 +81,13 @@
     "-object memory-backend-file,id=lsa3,mem-path=%s,size=256M " \
     "-device cxl-type3,bus=rp3,persistent-memdev=cxl-mem3,lsa=lsa3,id=pmem3 "
 
+/* Single pxb + volatile type3 + one window; base for the CFMW tests. */
+#define QEMU_CFMW \
+    "-machine q35,cxl=on " \
+    "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \
+    QEMU_RP QEMU_T3D_VMEM \
+    "-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.size=4G"
+
 static void cxl_basic_hb(void)
 {
     qtest_start("-machine q35,cxl=on");
@@ -117,6 +124,81 @@ static void cxl_2root_port(void)
     qtest_end();
 }
 
+/*
+ * CFMWS "Window Restrictions" (CXL r4.0 9.18.1.3) are configurable per
+ * window; check that valid restriction sets are accepted.
+ */
+static void cxl_cfmw_default(void)
+{
+    /* No coherency flag advertises both HDM-D and HDM-H. */
+    qtest_start(QEMU_CFMW);
+    qtest_end();
+}
+
+static void cxl_cfmw_host_only_off(void)
+{
+    /* Disabling host-only leaves device-coherent (HDM-D). */
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.host-only=off");
+    qtest_end();
+}
+
+static void cxl_cfmw_device_coherent_off(void)
+{
+    /* Disabling device-coherent leaves host-only (HDM-H). */
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.device-coherent=off");
+    qtest_end();
+}
+
+static void cxl_cfmw_back_invalidate(void)
+{
+    /* Back-Invalidate implies device-coherent (HDM-DB). */
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.back-invalidate=on");
+    qtest_end();
+}
+
+static void cxl_cfmw_fixed_config(void)
+{
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.fixed-config=on");
+    qtest_end();
+}
+
+static void cxl_cfmw_device_and_host(void)
+{
+    /*
+     * device-coherent and host-only may both be advertised (the spec
+     * permits multiple bits set); this must be accepted -- a regression
+     * guard against reinstating a device/host-only mutual exclusion.
+     */
+    qtest_start(QEMU_CFMW
+                ",cxl-fmw.0.device-coherent=on,cxl-fmw.0.host-only=on");
+    qtest_end();
+}
+
+static void cxl_cfmw_volatile_only(void)
+{
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.persistent=off");
+    qtest_end();
+}
+
+static void cxl_cfmw_persistent_only(void)
+{
+    qtest_start(QEMU_CFMW ",cxl-fmw.0.volatile=off");
+    qtest_end();
+}
+
+/* Two windows in one VM: a Back-Invalidate window and a host-only window. */
+static void cxl_cfmw_two_windows(void)
+{
+    qtest_start("-machine q35,cxl=on "
+                "-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 "
+                "-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 "
+                QEMU_RP QEMU_T3D_VMEM
+                "-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.size=4G,"
+                "cxl-fmw.0.back-invalidate=on,"
+                "cxl-fmw.1.targets.0=cxl.1,cxl-fmw.1.size=4G");
+    qtest_end();
+}
+
 #ifdef CONFIG_POSIX
 static void cxl_t3d_deprecated(void)
 {
@@ -233,6 +315,19 @@ int main(int argc, char **argv)
         qtest_add_func("/pci/cxl/pxb_x2_with_window", cxl_2pxb_with_window);
         qtest_add_func("/pci/cxl/rp", cxl_root_port);
         qtest_add_func("/pci/cxl/rp_x2", cxl_2root_port);
+        qtest_add_func("/pci/cxl/cfmw/default", cxl_cfmw_default);
+        qtest_add_func("/pci/cxl/cfmw/host_only_off", cxl_cfmw_host_only_off);
+        qtest_add_func("/pci/cxl/cfmw/device_coherent_off",
+                       cxl_cfmw_device_coherent_off);
+        qtest_add_func("/pci/cxl/cfmw/back_invalidate",
+                       cxl_cfmw_back_invalidate);
+        qtest_add_func("/pci/cxl/cfmw/fixed_config", cxl_cfmw_fixed_config);
+        qtest_add_func("/pci/cxl/cfmw/device_and_host",
+                       cxl_cfmw_device_and_host);
+        qtest_add_func("/pci/cxl/cfmw/volatile_only", cxl_cfmw_volatile_only);
+        qtest_add_func("/pci/cxl/cfmw/persistent_only",
+                       cxl_cfmw_persistent_only);
+        qtest_add_func("/pci/cxl/cfmw/two_windows", cxl_cfmw_two_windows);
 #ifdef CONFIG_POSIX
         qtest_add_func("/pci/cxl/type3_device", cxl_t3d_deprecated);
         qtest_add_func("/pci/cxl/type3_device_pmem", cxl_t3d_persistent);
Signature · 1 line
MST
#49 lore raw

[PULL 86/90] vhost-user: use skip_drain with GET_VRING_BASE_SKIP_DRAIN message

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

Wire up the skip_drain parameter introduced in the previous commit to the new GET_VRING_BASE_SKIP_DRAIN message. When skip_drain is set, send GET_VRING_BASE_SKIP_DRAIN instead of GET_VRING_BASE, instructing the back-end to suspend in-flight I/O immediately.

Message-ID: <[email protected]>

---
 hw/virtio/vhost.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
hw/virtio/vhost.c +5 -1
index 27c78ffabf..68827dc731 100644
@@ -1531,7 +1531,11 @@ static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
     }
 
     if (!force) {
-        r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
+        if (!skip_drain) {
+            r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
+        } else {
+            r = dev->vhost_ops->vhost_get_vring_base_skip_drain(dev, &state);
+        }
         if (r < 0) {
             VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r);
         }
Signature · 1 line
MST
#50 lore raw

[PULL 90/90] MAINTAINERS: add Junjie Cao as CXL reviewer

In reply to Michael S. Tsirkin

From: Junjie Cao <[email protected]>

I have been reviewing, testing and contributing to hw/cxl for the past few months, and would like to be Cc'd on incoming CXL changes to help with review.

Message-ID: <[email protected]>

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index ec313c3259..d5eac4b42d 100644
@@ -3334,6 +3334,7 @@ F: docs/devel/migration/CPR.rst
 
 Compute Express Link
 M: Jonathan Cameron <[email protected]>
+R: Junjie Cao <[email protected]>
 L: [email protected]
 S: Supported
 F: hw/cxl/
Signature · 1 line
MST
#51 lore raw

[PULL 67/90] libvhost-user: return the backend mapping address for added regions

In reply to Michael S. Tsirkin

From: Bin Guo <[email protected]>

In postcopy mode the backend must tell QEMU where it mapped a region, so that QEMU can translate the backend's fault addresses back into a RAMBlock and offset. vu_add_mem_reg() works on a copy of the region and lets _vu_add_mem_reg() fill the mapping address into that copy, but never writes it back into the reply payload. QEMU then stores its own address as the postcopy client base, so fault resolution fails:

vhost_user_postcopy_fault_handler: Failed to find region for fault ...

The VHOST_USER_SET_MEM_TABLE path is unaffected, it fills the payload directly. Put the updated region back into the payload before replying; a pointer into the payload cannot be used instead, as VhostUserMsg is packed.

Fixes ec94c8e621 ("Support adding individual regions in libvhost-user")

Message-ID: <[email protected]>

---
 subprojects/libvhost-user/libvhost-user.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
subprojects/libvhost-user/libvhost-user.c +7 -1
index 248550aae1..2fed792e85 100644
@@ -989,7 +989,13 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
     close(vmsg->fds[0]);
 
     if (dev->postcopy_listening) {
-        /* Send the message back to qemu with the addresses filled in. */
+        /*
+         * Send the message back to qemu with the addresses filled in.
+         * _vu_add_mem_reg() worked on our copy of the region, so it has to be
+         * put back into the message payload.  A pointer into the payload
+         * cannot be handed out instead, VhostUserMsg is packed.
+         */
+        vmsg->payload.memreg.region = m;
         vmsg->fd_num = 0;
         DPRINT("Successfully added new region in postcopy\n");
         return true;
Signature · 1 line
MST
#52 lore raw

[PULL 68/90] linux-headers: Update to Linux v7.3-rc1

In reply to Michael S. Tsirkin

From: Albert Esteve <[email protected]>

VIRTIO_ID_MEDIA was added previously, synchronize the rest of the headers to the same version.

Message-ID: <[email protected]>

---
 include/standard-headers/linux/ethtool.h |  6 +++
 linux-headers/linux/iommufd.h            | 45 ++++++++++++++++++--
 linux-headers/linux/userfaultfd.h        | 54 ++++++++++++++++++++++--
 linux-headers/linux/vduse.h              | 28 ++++++++++++
 linux-headers/linux/vfio.h               | 21 +++++++++
 linux-headers/linux/vfio_zdev.h          |  2 +
 6 files changed, 149 insertions(+), 7 deletions(-)
include/standard-headers/linux/ethtool.h +6 -0
index 55f608c3a7..622d634d04 100644
@@ -2015,7 +2015,13 @@ enum ethtool_link_mode_bit_indices {
 	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT	= 39,
 	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT		= 40,
 	ETHTOOL_LINK_MODE_1000baseX_Full_BIT	= 41,
+
+	/* Despite the "baseCR" in 10000baseCR, this is not an IEEE 802.3 baseCR
+	 * It represents SFF-8431 Appendix-E SFP+ Direct Attach (10G-SFI-DA).
+	 * The name is kept as-is for uAPI backward compatibility.
+	 */
 	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT	= 42,
+
 	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT	= 43,
 	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT	= 44,
 	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT	= 45,
linux-headers/linux/iommufd.h +42 -3

79 lines not on this page · raw message

linux-headers/linux/userfaultfd.h +50 -4

128 lines not on this page · raw message

linux-headers/linux/vduse.h +28 -0
index e19b3c0f51..bab47129db 100644
@@ -14,6 +14,12 @@
 
 #define VDUSE_API_VERSION_1	1
 
+/* The VDUSE instance expects a request for vq ready */
+#define VDUSE_F_QUEUE_READY	0
+
+/* The VDUSE instance expects a request for suspend */
+#define VDUSE_F_SUSPEND		1
+
 /*
  * Get the version of VDUSE API that kernel supported (VDUSE_API_VERSION).
  * This is used for future extension.
@@ -63,6 +69,12 @@ struct vduse_dev_config {
  */
 #define VDUSE_DESTROY_DEV	_IOW(VDUSE_BASE, 0x03, char[VDUSE_NAME_MAX])
 
+/* Get the VDUSE supported features */
+#define VDUSE_GET_FEATURES	_IOR(VDUSE_BASE, 0x04, __u64)
+
+/* Set the VDUSE features */
+#define VDUSE_SET_FEATURES	_IOW(VDUSE_BASE, 0x05, __u64)
+
 /* The ioctls for VDUSE device (/dev/vduse/$NAME) */
 
 /**
@@ -325,6 +337,8 @@ enum vduse_req_type {
 	VDUSE_SET_STATUS,
 	VDUSE_UPDATE_IOTLB,
 	VDUSE_SET_VQ_GROUP_ASID,
+	VDUSE_SET_VQ_READY,
+	VDUSE_SUSPEND,
 };
 
 /**
@@ -372,6 +386,15 @@ struct vduse_iova_range_v2 {
 	__u32 padding;
 };
 
+/**
+ * struct vduse_vq_ready - Virtqueue ready request message
+ * @num: Virtqueue number
+ */
+struct vduse_vq_ready {
+	__u32 num;
+	__u32 ready;
+};
+
 /**
  * struct vduse_dev_request - control request
  * @type: request type
@@ -382,6 +405,7 @@ struct vduse_iova_range_v2 {
  * @iova: IOVA range for updating
  * @iova_v2: IOVA range for updating if API_VERSION >= 1
  * @vq_group_asid: ASID of a virtqueue group
+ * @vq_ready: Virtqueue ready request
  * @padding: padding
  *
  * Structure used by read(2) on /dev/vduse/$NAME.
@@ -399,6 +423,10 @@ struct vduse_dev_request {
 		 */
 		struct vduse_iova_range_v2 iova_v2;
 		struct vduse_vq_group_asid vq_group_asid;
+
+		/* Only if VDUSE_F_QUEUE_READY is negotiated */
+		struct vduse_vq_ready vq_ready;
+
 		__u32 padding[32];
 	};
 };
linux-headers/linux/vfio.h +21 -0
index f3282b8e86..c85dcbfe30 100644
@@ -1534,6 +1534,27 @@ struct vfio_device_feature_dma_buf {
  */
 #define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2  12
 
+/**
+ * VFIO_DEVICE_FEATURE_ZPCI_ERROR feature provides PCI error information to
+ * userspace for vfio-pci devices on s390. On s390, PCI error recovery
+ * involves platform firmware and notification to operating systems is done
+ * by architecture specific mechanism. Exposing this information to
+ * userspace allows it to take appropriate actions to handle an
+ * error on the device.
+ *
+ * Userspace provides an opaque buffer of fixed length, and the kernel
+ * fills it with the zpci_ccdf_err data structure. The length of
+ * zpci_ccdf_err is provided to userspace via the
+ * VFIO_DEVICE_INFO_CAP_ZPCI_BASE capability.
+ *
+ * The ioctl returns -ENOMSG if there are no pending PCI errors.
+ */
+struct vfio_device_feature_zpci_err {
+	__aligned_u64 data;
+};
+
+#define VFIO_DEVICE_FEATURE_ZPCI_ERROR 13
+
 /* -------- API for Type1 VFIO IOMMU -------- */
 
 /**
linux-headers/linux/vfio_zdev.h +2 -0
index 77f2aff1f2..d6c1175c88 100644
@@ -32,6 +32,8 @@ struct vfio_device_info_cap_zpci_base {
 	/* End of version 1 */
 	__u32 fh;		/* PCI function handle */
 	/* End of version 2 */
+	__u32 ccdf_err_length;	/* PCI CCDF length */
+	/* End of version 3 */
 };
 
 /**
Signature · 1 line
MST
#53 lore raw

[PULL 79/90] hw/hotplug: Reduce some HotplugHandler variables scope

In reply to Michael S. Tsirkin

From: Philippe Mathieu-Daudé <[email protected]>

Message-ID: <[email protected]>

---
 hw/acpi/memory_hotplug.c | 3 ++-
 hw/acpi/pcihp.c          | 3 ++-
 hw/pci/shpc.c            | 3 ++-
 3 files changed, 6 insertions(+), 3 deletions(-)
hw/acpi/memory_hotplug.c +2 -1
index 1ddfdd17b7..f482c835a1 100644
@@ -119,7 +119,6 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
     MemStatus *mdev;
     ACPIOSTInfo *info;
     DeviceState *dev = NULL;
-    HotplugHandler *hotplug_ctrl = NULL;
     Error *local_err = NULL;
 
     if (!mem_st->dev_count) {
@@ -167,6 +166,8 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
             mdev->is_removing = false;
             trace_mhp_acpi_clear_remove_evt(mem_st->selector);
         } else if (data & 8) {
+            HotplugHandler *hotplug_ctrl;
+
             if (!mdev->is_enabled) {
                 trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
                 break;
hw/acpi/pcihp.c +2 -1
index b26ddf0a26..336ebe1a13 100644
@@ -173,7 +173,6 @@ static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
 
 static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
 {
-    HotplugHandler *hotplug_ctrl;
     BusChild *kid, *next;
     int slot = ctz32(slots);
     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
@@ -210,6 +209,8 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
                      */
                     qdev->pending_deleted_event = false;
                 } else {
+                    HotplugHandler *hotplug_ctrl;
+
                     hotplug_ctrl = qdev_get_hotplug_handler(qdev);
                     hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
                     object_unparent(OBJECT(qdev));
hw/pci/shpc.c +2 -1
index 938602866d..1198e1ab8c 100644
@@ -271,7 +271,6 @@ static void shpc_invalid_command(SHPCDevice *shpc)
 
 static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
 {
-    HotplugHandler *hotplug_ctrl;
     int devfn;
     int pci_slot = SHPC_IDX_TO_PCI(slot);
     for (devfn = PCI_DEVFN(pci_slot, 0);
@@ -279,6 +278,8 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
          ++devfn) {
         PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
         if (affected_dev) {
+            HotplugHandler *hotplug_ctrl;
+
             hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev));
             hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev),
                                    &error_abort);
Signature · 1 line
MST
#54 lore raw

[PULL 69/90] virtio-scsi: set dataplane_started to false upon failure

In reply to Michael S. Tsirkin

From: Stefan Hajnoczi <[email protected]>

Commit e24a47c5b73e ("virtio-scsi: do not use vring in dataplane") set dataplane_started to true when virtio_scsi_dataplane_start() fails. This is likely a typo since dataplane is not functional after failure.

The non-ioeventfd fallback is broken because dataplane_started is true after virtio_scsi_dataplane_start() failure. As a result, the following assertion failure occurs when a virtio-scsi device exceeds the open file descriptor ulimit when setting up notifiers (eventfds):

  $ ulimit -n 104 # exact number can vary based on QEMU version
  $ qemu-system-x86_64 -M q35,accel=kvm -m 1G -cpu host -smp 14 \
         --blockdev file,node-name=drive0,filename=test.img,cache.direct=on,aio=native \
         --blockdev file,node-name=drive1,filename=data01.img,cache.direct=on,aio=native \
         --device virtio-scsi-pci,id=virtio-scsi-pci0 \
         --device scsi-hd,drive=drive0,bus=virtio-scsi-pci0.0 \
         --device virtio-scsi-pci,id=virtio-scsi-pci1 \
         --device scsi-hd,drive=drive1,bus=virtio-scsi-pci1.0
  qemu: virtio-scsi: Failed to set guest notifiers (-24), ensure -accel kvm is set.
  qemu: virtio_bus_start_ioeventfd: failed. Fallback to userspace (slower).
  qemu-system-x86_64: ../hw/scsi/virtio-scsi.c:1017: virtio_scsi_reset: Assertion `!s->dataplane_started' failed.
  Aborted                    (core dumped)

Message-ID: <[email protected]>

---
 hw/scsi/virtio-scsi-dataplane.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/scsi/virtio-scsi-dataplane.c +1 -1
index 95f13fb7c2..bcb6e44133 100644
@@ -230,7 +230,7 @@ fail_host_notifiers:
 fail_guest_notifiers:
     s->dataplane_fenced = true;
     s->dataplane_starting = false;
-    s->dataplane_started = true;
+    s->dataplane_started = false;
     return -ENOSYS;
 }
 
Signature · 1 line
MST
#55 lore raw

[PULL 25/90] net/tap: QOMify tap backend

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

We prepare for being able to migrate TAP backend. We'll need a user change-able property for it, which can be set from machine type. So, let's QOMify it first.

Message-ID: <[email protected]>

---
 include/net/net.h |  7 +++++++
 include/net/tap.h |  2 ++
 net/net.c         | 14 +++++++-------
 net/tap.c         | 48 +++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 56 insertions(+), 15 deletions(-)
include/net/net.h +7 -0
index 626b997948..ea07760b56 100644
@@ -161,6 +161,13 @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr);
 NetClientState *qemu_find_netdev(const char *id);
 int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
                                  NetClientDriver type, int max);
+void qemu_net_client_setup(NetClientState *nc,
+                           NetClientInfo *info,
+                           NetClientState *peer,
+                           const char *model,
+                           const char *name,
+                           NetClientDestructor *destructor,
+                           bool is_datapath);
 NetClientState *qemu_new_net_client(NetClientInfo *info,
                                     NetClientState *peer,
                                     const char *model,
include/net/tap.h +2 -0
index 6f34f13eae..268570571f 100644
@@ -28,6 +28,8 @@
 
 #include "standard-headers/linux/virtio_net.h"
 
+#define TYPE_TAP_NETDEV "tap-netdev"
+
 int tap_enable(NetClientState *nc);
 int tap_disable(NetClientState *nc);
 
net/net.c +7 -7
index 1161183e18..d7fa637ce5 100644
@@ -261,13 +261,13 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender,
                                        int iovcnt,
                                        void *opaque);
 
-static void qemu_net_client_setup(NetClientState *nc,
-                                  NetClientInfo *info,
-                                  NetClientState *peer,
-                                  const char *model,
-                                  const char *name,
-                                  NetClientDestructor *destructor,
-                                  bool is_datapath)
+void qemu_net_client_setup(NetClientState *nc,
+                           NetClientInfo *info,
+                           NetClientState *peer,
+                           const char *model,
+                           const char *name,
+                           NetClientDestructor *destructor,
+                           bool is_datapath)
 {
     nc->info = info;
     nc->model = g_strdup(model);
net/tap.c +40 -8

87 lines not on this page · raw message

Signature · 1 line
MST
#56 lore raw

[PULL 17/90] hw/display/vhost-user-media: add shared memory region BAR

In reply to Michael S. Tsirkin

From: Albert Esteve <[email protected]>

Expose virtio-media shared memory region 0 (spec 5.22.6.1.6) as a prefetchable 64-bit PCI BAR (BAR 2) with a VirtIO shm capability. The size is obtained through GET_SHMEM_CONFIG and requires at least one shared region. The guest maps host-provisioned MMAP buffers into this window; QEMU creates a container region on realize, not a full-sized RAM allocation.

modern-pio-notify is rejected because it claims BAR 2.

vhost-user still needs shareable guest RAM, e.g.:

    -object memory-backend-memfd,id=mem,size=4G,share=on \
    -numa node,memdev=mem

Message-ID: <[email protected]>

---
 hw/display/vhost-user-media-pci.c | 35 ++++++++++++++++++++++++++
 hw/display/vhost-user-media.c     | 42 ++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)
hw/display/vhost-user-media-pci.c +35 -0
index 3e09fcfdd0..7681f7505d 100644
@@ -13,12 +13,18 @@
 #include "hw/virtio/vhost-user-media.h"
 #include "hw/virtio/virtio-pci.h"
 
+/* BAR 2 is used for the shared memory region exposed to the guest */
+#define VIRTIO_MEDIA_PCI_SHM_BAR 2
+
+#define VIRTIO_MEDIA_PCI_SHMCAP_ID_SHM 0
+
 #define TYPE_VHOST_USER_MEDIA_PCI "vhost-user-media-pci-base"
 OBJECT_DECLARE_SIMPLE_TYPE(VHostUserMEDIAPCI, VHOST_USER_MEDIA_PCI)
 
 struct VHostUserMEDIAPCI {
     VirtIOPCIProxy parent_obj;
     VHostUserMEDIA vdev;
+    MemoryRegion shmbar;
 };
 
 static const Property vumedia_pci_properties[] = {
@@ -32,14 +38,43 @@ static void vumedia_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
 {
     VHostUserMEDIAPCI *dev = VHOST_USER_MEDIA_PCI(vpci_dev);
     DeviceState *dev_state = DEVICE(&dev->vdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev_state);
+    VirtioSharedMemory *shmem;
+    uint64_t shm_size;
 
     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
         vpci_dev->nvectors = 1;
     }
 
+    if (vpci_dev->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY) {
+        error_setg(errp, "modern-pio-notify is not supported due to PCI BAR "
+                         "layout limitations");
+        return;
+    }
+
     if (!qdev_realize(dev_state, BUS(&vpci_dev->bus), errp)) {
         return;
     }
+
+    shmem = virtio_find_shmem_region(vdev, VIRTIO_MEDIA_PCI_SHMCAP_ID_SHM);
+    if (!shmem) {
+        error_setg(errp, "vhost-user-media: missing shared memory region");
+        return;
+    }
+    shm_size = memory_region_size(&shmem->mr);
+
+    memory_region_init(&dev->shmbar, OBJECT(vpci_dev),
+                       "vhost-media-pci-shmbar", shm_size);
+    memory_region_add_subregion(&dev->shmbar, 0, &shmem->mr);
+    virtio_pci_add_shm_cap(vpci_dev, VIRTIO_MEDIA_PCI_SHM_BAR, 0,
+                           shm_size, VIRTIO_MEDIA_PCI_SHMCAP_ID_SHM);
+
+    /* After 'realized' so the memory region exists */
+    pci_register_bar(&vpci_dev->pci_dev, VIRTIO_MEDIA_PCI_SHM_BAR,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY |
+                     PCI_BASE_ADDRESS_MEM_PREFETCH |
+                     PCI_BASE_ADDRESS_MEM_TYPE_64,
+                     &dev->shmbar);
 }
 
 static void vumedia_pci_class_init(ObjectClass *klass, const void *data)
hw/display/vhost-user-media.c +41 -1

64 lines not on this page · raw message

Signature · 1 line
MST
#57 lore raw

[PULL 11/90] vhost: make vhost_dev_cleanup() safe on a partially initialized device

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

A device which only went through vhost_dev_init_backend() has its VQs not yet initialized, so vq->dev is NULL and vhost_virtqueue_cleanup() would crash dereferencing it. Check vq->dev before use, so that vhost_dev_cleanup() can be called to release a device whose full vhost_dev_init() never ran or failed along the way.

Message-ID: <[email protected]>

---
 hw/virtio/vhost.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/virtio/vhost.c +1 -1
index f9b54c46f9..2bb9a23fee 100644
@@ -1648,7 +1648,7 @@ fail_call:
 static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
 {
     event_notifier_cleanup(&vq->masked_notifier);
-    if (vq->dev->vhost_ops->vhost_set_vring_err) {
+    if (vq->dev && vq->dev->vhost_ops->vhost_set_vring_err) {
         event_notifier_set_handler(&vq->error_notifier, NULL);
         event_notifier_cleanup(&vq->error_notifier);
     }
Signature · 1 line
MST
#58 lore raw

[PULL 16/90] hw/display: add vhost-user-media device

In reply to Michael S. Tsirkin

From: Albert Esteve <[email protected]>

Add the QEMU side of the vhost-user-media device, which connects to a virtio-media vhost-user backend daemon implementing the V4L2 API over the virtio-media protocol.

The virtio-media device is specified in the VirtIO specification v1.4, section 5.22:

    https://docs.oasis-open.org/virtio/virtio/v1.4/cs01/virtio-v1.4-cs01.html

Tested with the rust-vmm vhost-device-media backend [1]:

    cargo run -- -s /path/to/media.sock -d /dev/video0 --backend v4l2-proxy

Example invocation:

    qemu-system-x86_64 \
        -chardev socket,path=/path/to/media.sock,id=media \
        -device vhost-user-media-pci,chardev=media,id=media

[1] https://github.com/rust-vmm/vhost-device/tree/main/vhost-device-media

Message-ID: <[email protected]>

---
 MAINTAINERS                          |   6 +
 include/hw/virtio/vhost-user-media.h |  46 ++++
 hw/display/vhost-user-media-pci.c    |  80 ++++++
 hw/display/vhost-user-media.c        | 348 +++++++++++++++++++++++++++
 hw/virtio/virtio.c                   |   3 +-
 hw/display/Kconfig                   |   5 +
 hw/display/meson.build               |   3 +
 7 files changed, 490 insertions(+), 1 deletion(-)
 create mode 100644 include/hw/virtio/vhost-user-media.h
 create mode 100644 hw/display/vhost-user-media-pci.c
 create mode 100644 hw/display/vhost-user-media.c
MAINTAINERS +6 -0
index 7183babd6a..ec313c3259 100644
@@ -2690,6 +2690,12 @@ S: Supported
 F: include/hw/virtio/vhost-user-rtc.h
 F: hw/virtio/vhost-user-rtc*
 
+vhost-user-media
+M: Albert Esteve <[email protected]>
+S: Supported
+F: hw/display/vhost-user-media*
+F: include/hw/virtio/vhost-user-media.h
+
 virtio-crypto
 M: Gonglei <[email protected]>
 S: Supported
include/hw/virtio/vhost-user-media.h new file +46 -0

46 lines not on this page · raw message

hw/display/vhost-user-media-pci.c new file +80 -0

80 lines not on this page · raw message

hw/display/vhost-user-media.c new file +348 -0

348 lines not on this page · raw message

hw/virtio/virtio.c +2 -1
index 848fe8539e..0b2fbbed3f 100644
@@ -198,7 +198,8 @@ const char *virtio_device_names[] = {
     [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
     [VIRTIO_ID_BT] = "virtio-bluetooth",
     [VIRTIO_ID_GPIO] = "virtio-gpio",
-    [VIRTIO_ID_SPI] = "virtio-spi"
+    [VIRTIO_ID_SPI] = "virtio-spi",
+    [VIRTIO_ID_MEDIA] = "virtio-media",
 };
 
 static const char *virtio_id_to_name(uint16_t device_id)
hw/display/Kconfig +5 -0
index b3593fe981..060274b1e6 100644
@@ -120,6 +120,11 @@ config VHOST_USER_VGA
     default y
     depends on VIRTIO_VGA && VHOST_USER_GPU
 
+config VHOST_USER_MEDIA
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config DPCD
     bool
     select AUX
hw/display/meson.build +3 -0
index ffecedbf70..d8b4e121fe 100644
@@ -37,6 +37,9 @@ system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
 system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
 system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
 system_ss.add(when: 'CONFIG_DM163', if_true: files('dm163.c'))
+system_ss.add(when: 'CONFIG_VHOST_USER_MEDIA', if_true: files('vhost-user-media.c'))
+system_ss.add(when: ['CONFIG_VHOST_USER_MEDIA', 'CONFIG_VIRTIO_PCI'],
+  if_true: files('vhost-user-media-pci.c'))
 
 stub_ss.add([files('acpi-vga-stub.c'), pixman])
 if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
Signature · 1 line
MST
#59 lore raw

[PULL 32/90] net/tap: disable read polling for stopped VM

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Polling when VM is stopped doesn't make real sense, as stopped VM can't handle incoming traffic anyway.

And it's critical for introduction of local TAP migration feature in the next commit: the TAP device will be transferred to the target (open fd will be passed through migration channel), and if we continue polling on source, we may get a package, which we'll never handle on source (already stopped), it will be lost. Better is save this package for target VM to handle.

Message-ID: <[email protected]>

---
 net/tap.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
net/tap.c +32 -0
index dd0d134875..51d028d956 100644
@@ -36,6 +36,7 @@
 #include "net/net.h"
 #include "clients.h"
 #include "monitor/monitor.h"
+#include "system/runstate.h"
 #include "system/system.h"
 #include "qapi/error.h"
 #include "qemu/cutils.h"
@@ -92,6 +93,8 @@ struct TAPState {
     Notifier exit;
 
     int queue_index;
+    bool enable_poll_on_resume;
+    VMChangeStateEntry *vmstate;
 };
 
 static void launch_script(const char *setup_script, const char *ifname,
@@ -145,10 +148,31 @@ static void tap_update_fd_handler(TAPState *s)
 
 static void tap_read_poll(TAPState *s, bool enable)
 {
+    if (enable && runstate_check(RUN_STATE_FINISH_MIGRATE)) {
+        s->enable_poll_on_resume = true;
+        return;
+    }
     s->read_poll = enable;
     tap_update_fd_handler(s);
 }
 
+static void tap_vm_state_change(void *opaque, bool running, RunState state)
+{
+    TAPState *s = opaque;
+
+    if (running) {
+        if (s->enable_poll_on_resume) {
+            tap_read_poll(s, true);
+            s->enable_poll_on_resume = false;
+        }
+    } else if (state == RUN_STATE_FINISH_MIGRATE) {
+        if (s->read_poll) {
+            s->enable_poll_on_resume = true;
+            tap_read_poll(s, false);
+        }
+    }
+}
+
 static void tap_write_poll(TAPState *s, bool enable)
 {
     s->write_poll = enable;
@@ -379,6 +403,11 @@ static void tap_cleanup(NetClientState *nc)
         s->exit.notify = NULL;
     }
 
+    if (s->vmstate) {
+        qemu_del_vm_change_state_handler(s->vmstate);
+        s->vmstate = NULL;
+    }
+
     tap_read_poll(s, false);
     tap_write_poll(s, false);
     close(s->fd);
@@ -818,6 +847,9 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
     int sndbuf =
         (tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
 
+    s->enable_poll_on_resume = false;
+    s->vmstate = qemu_add_vm_change_state_handler(tap_vm_state_change, s);
+
     if (!tap_set_sndbuf(fd, sndbuf, sndbuf_required ? errp : NULL) &&
         sndbuf_required) {
         goto failed;
Signature · 1 line
MST
#60 lore raw

[PULL 18/90] virtio: reduce code duplication for split ring

In reply to Michael S. Tsirkin

From: Jia Jia <[email protected]>

virtio_queue_empty_rcu duplicates virtqueue_num_heads for no good reason, let's not do it. As a nice side effect, we gain better handling for misbehaving guests.

The virtio_device_disabled() check in virtio_queue_empty_rcu is redundant because virtqueue_split_pop() is only called through virtqueue_pop(), which already performs the check.

Message-ID: <[email protected]>

---
 hw/virtio/virtio.c | 30 ++++++------------------------
 1 file changed, 6 insertions(+), 24 deletions(-)
hw/virtio/virtio.c +6 -24
index 0b2fbbed3f..c9f9e5b511 100644
@@ -717,26 +717,6 @@ static inline bool is_desc_avail(uint16_t flags, bool wrap_counter)
     return (avail != used) && (avail == wrap_counter);
 }
 
-/* Fetch avail_idx from VQ memory only when we really need to know if
- * guest has added some buffers.
- * Called within rcu_read_lock().  */
-static int virtio_queue_empty_rcu(VirtQueue *vq)
-{
-    if (virtio_device_disabled(vq->vdev)) {
-        return 1;
-    }
-
-    if (unlikely(!vq->vring.avail)) {
-        return 1;
-    }
-
-    if (vq->shadow_avail_idx != vq->last_avail_idx) {
-        return 0;
-    }
-
-    return vring_avail_idx(vq) == vq->last_avail_idx;
-}
-
 static int virtio_queue_split_empty(VirtQueue *vq)
 {
     bool empty;
@@ -1773,12 +1753,14 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
     address_space_cache_init_empty(&indirect_desc_cache);
 
     RCU_READ_LOCK_GUARD();
-    if (virtio_queue_empty_rcu(vq)) {
+    if (unlikely(!vq->vring.avail)) {
+        goto done;
+    }
+
+    rc = virtqueue_num_heads(vq, vq->last_avail_idx);
+    if (rc <= 0) {
         goto done;
     }
-    /* Needed after virtio_queue_empty(), see comment in
-     * virtqueue_num_heads(). */
-    smp_rmb();
 
     /* When we start there are none of either input nor output. */
     out_num = in_num = elem_entries = 0;
Signature · 1 line
MST
#61 lore raw

[PULL 50/90] hw/scsi-disk: Fix accounting for IGNORE, ret > 0

In reply to Michael S. Tsirkin

From: Hanna Czenczek <[email protected]>

When encountering SCSI error status (ret > 0), accounting is left to scsi_handle_rw_error(), but the BLOCK_ERROR_ACTION_IGNORE path in turn leaves accounting (block_acct_done()) to the caller, so neither side does it. Fix this by unconditionally calling block_acct_done() in the IGNORE path. Yes, this will often result in it being called twice, but that is a no-op, as block_acct_done() resets the cookie type to BLOCK_ACCT_NONE, and will only do accounting if the type is not BLOCK_ACCT_NONE.

(And given that the conditions on who does what accounting are quite confusing in scsi-disk, for me at least, I prefer this unconditional call rather than guard it with a condition that has no obvious reason.)

Message-ID: <[email protected]>

---
 hw/scsi/scsi-disk.c | 7 +++++++
 1 file changed, 7 insertions(+)
hw/scsi/scsi-disk.c +7 -0
index a42f7d8e77..deb33ac1dd 100644
@@ -318,6 +318,13 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
         return true;
 
     case BLOCK_ERROR_ACTION_IGNORE:
+        /*
+         * The caller may have already finalized the accounting cookie
+         * (e.g. scsi_dma_complete() for ret < 0), but calling
+         * block_acct_done() afterwards is fine (just a no-op).  Just
+         * make sure all cookies are indeed accounted at some point.
+         */
+        block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
         return false;
 
     case BLOCK_ERROR_ACTION_STOP:
Signature · 1 line
MST
#62 lore raw

[PULL 05/90] vhost-vsock: block CPR migration modes

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

CPR migration with a vhost-vsock device currently crashes the target QEMU. The device ownership is not handed over, so while the source QEMU still holds the guest CID hashed in the kernel, the target's freshly opened vhost-vsock device fails to set the same CID in realize():

qemu-system-x86_64: -device vhost-vsock-pci,id=vsock0,guest-cid=3:
vhost-vsock: unable to set guest cid: Address already in use

Add an unconditional migration blocker for the CPR modes, so that such a migration fails early and gracefully instead. The following patches implement the actual vhost-vsock CPR support, and the blocker is lifted once it's fully working.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost-vsock.h |  1 +
 hw/virtio/vhost-vsock.c         | 27 +++++++++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)
include/hw/virtio/vhost-vsock.h +1 -0
index 84f4e727c7..a964d57e1b 100644
@@ -29,6 +29,7 @@ struct VHostVSock {
     /*< private >*/
     VHostVSockCommon parent;
     VHostVSockConf conf;
+    Error *migration_blocker;   /* CPR migration is not supported */
 
     /*< public >*/
 };
hw/virtio/vhost-vsock.c +23 -4
index da244eb165..503d248a61 100644
@@ -20,6 +20,8 @@
 #include "hw/core/qdev-properties.h"
 #include "hw/virtio/vhost-vsock.h"
 #include "monitor/monitor.h"
+#include "migration/blocker.h"
+#include "migration/misc.h"
 
 static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config)
 {
@@ -140,25 +142,38 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    /*
+     * CPR migration of a vhost-vsock device is not supported yet: the
+     * device ownership is not handed over, so the target fails to set
+     * up its device.  Fail the migration early and gracefully instead.
+     */
+    error_setg(&vsock->migration_blocker,
+               "vhost-vsock: CPR migration is not supported");
+    if (migrate_add_blocker_modes(&vsock->migration_blocker,
+                                  BIT(MIG_MODE_CPR_TRANSFER) |
+                                  BIT(MIG_MODE_CPR_EXEC), errp) < 0) {
+        return;
+    }
+
     if (vsock->conf.vhostfd) {
         vhostfd = monitor_fd_param(monitor_cur(), vsock->conf.vhostfd, errp);
         if (vhostfd == -1) {
             error_prepend(errp, "vhost-vsock: unable to parse vhostfd: ");
-            return;
+            goto err_blocker;
         }
 
         if (!qemu_set_blocking(vhostfd, false, errp)) {
-            return;
+            goto err_blocker;
         }
     } else {
         vhostfd = open("/dev/vhost-vsock", O_RDWR);
         if (vhostfd < 0) {
             error_setg_file_open(errp, errno, "/dev/vhost-vsock");
-            return;
+            goto err_blocker;
         }
 
         if (!qemu_set_blocking(vhostfd, false, errp)) {
-            return;
+            goto err_blocker;
         }
     }
 
@@ -187,16 +202,20 @@ err_vhost_dev:
     vhost_dev_cleanup(&vvc->vhost_dev);
 err_virtio:
     vhost_vsock_common_unrealize(vdev);
+err_blocker:
+    migrate_del_blocker(&vsock->migration_blocker);
 }
 
 static void vhost_vsock_device_unrealize(DeviceState *dev)
 {
     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostVSock *vsock = VHOST_VSOCK(dev);
 
     /* This will stop vhost backend if appropriate. */
     vhost_vsock_set_status(vdev, 0);
 
+    migrate_del_blocker(&vsock->migration_blocker);
     vhost_dev_cleanup(&vvc->vhost_dev);
     vhost_vsock_common_unrealize(vdev);
 }
Signature · 1 line
MST
#63 lore raw

[PULL 61/90] amd_iommu: acpi-build: update PA, GVA and VA size macros

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

Current implementation supports up to 64 bit IOVA and up to 52 bit PA. Modify related macros so that guest can see right size.

Also, use these macros to build the IVINFO field in the IVRS.

Message-ID: <[email protected]>

---
 hw/i386/amd_iommu.h  | 11 ++++++++---
 hw/i386/acpi-build.c |  4 +++-
 hw/i386/amd_iommu.c  |  2 +-
 3 files changed, 12 insertions(+), 5 deletions(-)
hw/i386/amd_iommu.h +8 -3
index 687691ec1c..d01f9b41df 100644
@@ -243,9 +243,14 @@
 #define AMDVI_PAGE_SHIFT_4K 12
 #define AMDVI_PAGE_MASK_4K      GENMASK64(63, 12)
 
-#define AMDVI_MAX_GVA_ADDR      (2UL << 5)
-#define AMDVI_MAX_PH_ADDR       (40UL << 8)
-#define AMDVI_MAX_VA_ADDR       (48UL << 15)
+/*
+ * IOMMU Capability Offset 10h: Miscellaneous Information Register 0.
+ * VAsize[21:15], PAsize[14:8], and GVAsize[7:5].
+ * These fields use the same layout in the IVRS IVinfo Field.
+ */
+#define AMDVI_VA_SIZE_64        (64UL << 15)
+#define AMDVI_PA_SIZE_52        (52UL << 8)
+#define AMDVI_GVA_SIZE_48       (2UL << 5)
 
 /* Completion Wait data size */
 #define AMDVI_COMPLETION_DATA_SIZE    8
hw/i386/acpi-build.c +3 -1
index 1696821048..05b68d05a8 100644
@@ -1858,7 +1858,9 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
      */
     build_append_int_noprefix(table_data,
                              (1UL << 0) | /* EFRSup */
-                             (40UL << 8), /* PASize */
+                             AMDVI_GVA_SIZE_48 | /* GVASize:     010b = 48 bits */
+                             AMDVI_PA_SIZE_52 |  /* PASize: 011_0100b = 52 bits */
+                             AMDVI_VA_SIZE_64,   /* VASize: 100_0000b = 64 bits */
                              4);
     /* reserved */
     build_append_int_noprefix(table_data, 0, 8);
hw/i386/amd_iommu.c +1 -1
index 578c27ccbe..56e7815412 100644
@@ -2595,7 +2595,7 @@ static void amdvi_pci_realize(PCIDevice *pdev, Error **errp)
                  0xff000000);
     pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_MISC, 0);
     pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_MISC,
-            AMDVI_MAX_PH_ADDR | AMDVI_MAX_GVA_ADDR | AMDVI_MAX_VA_ADDR);
+            AMDVI_PA_SIZE_52 | AMDVI_GVA_SIZE_48 | AMDVI_VA_SIZE_64);
 }
 
 static void amdvi_sysbus_reset(DeviceState *dev)
Signature · 1 line
MST
#64 lore raw

[PULL 89/90] vhost-user-blk: use GET_VRING_BASE_SKIP_DRAIN when inflight-migration is on

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

Currently during live migration vhost-user-blk sends GET_VRING_BASE to stop vrings, which causes the back-end to drain all in-flight I/O before returning. This blocks the migration source until all I/O completes, adding significant downtime proportional to the I/O load.

When inflight-migration is enabled, send GET_VRING_BASE_SKIP_DRAIN instead. This instructs the back-end to immediately suspend in-flight I/O and record it in the shared inflight region, which is then migrated to the destination host along with the rest of the device state.

Since inflight-migration can only be toggled while the VM is running, i2ts value at stop time reliably reflects the intent set on a live VM. There is no need to check migration runstate to decide whether to skip draining. Using GET_VRING_BASE_SKIP_DRAIN on a regular VM stop is safe - the back-end records any in-flight requests in the shared inflight region, and they will be resubmitted when the VM starts again via SET_INFLIGHT_FD.

If the back-end does not support VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN,
migration is aborted with an error in pre_save rather than hitting an assert at runtime.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost-user.h |  1 -
 hw/block/vhost-user-blk.c      | 29 +++++++++++++++++++++++------
 hw/virtio/vhost-user.c         |  3 +--
 3 files changed, 24 insertions(+), 9 deletions(-)
include/hw/virtio/vhost-user.h +0 -1
index 47c13f8677..78b4fba27f 100644
@@ -73,7 +73,6 @@ typedef struct VhostUserState {
     GPtrArray *notifiers;
     int memory_slots;
     bool supports_config;
-    bool supports_inflight_migration;
 } VhostUserState;
 
 /**
hw/block/vhost-user-blk.c +23 -6
index 3eaaa19719..3dade143c9 100644
@@ -141,10 +141,7 @@ static bool vhost_user_blk_inflight_needed(void *opaque)
 {
     struct VHostUserBlk *s = opaque;
 
-    bool inflight_migration = virtio_has_feature(s->dev.protocol_features,
-                               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
-
-    return inflight_migration;
+    return s->inflight_migration;
 }
 
 
@@ -245,11 +242,13 @@ static int vhost_user_blk_stop(VirtIODevice *vdev)
         return 0;
     }
 
+    bool skip_drain = vhost_user_blk_inflight_needed(s);
+
     force_stop = s->skip_get_vring_base_on_force_shutdown &&
                  qemu_force_shutdown_requested();
 
     ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) :
-                       vhost_dev_stop(&s->dev, vdev, true, false);
+                       vhost_dev_stop(&s->dev, vdev, true, skip_drain);
 
     err = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
     if (err < 0) {
@@ -381,7 +380,6 @@ static int vhost_user_blk_connect(DeviceState *dev, Error **errp)
     vhost_dev_set_config_notifier(&s->dev, &blk_ops);
 
     s->vhost_user.supports_config = true;
-    s->vhost_user.supports_inflight_migration = s->inflight_migration;
     ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0,
                          errp);
     if (ret < 0) {
@@ -608,10 +606,29 @@ static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev)
     return &s->dev;
 }
 
+static bool vhost_user_blk_pre_save(void *opaque, Error **errp)
+{
+    VHostUserBlk *s = VHOST_USER_BLK(opaque);
+
+    bool inflight_migration_enabled = vhost_user_has_protocol_feature(&s->dev,
+                               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN);
+
+    if (vhost_user_blk_inflight_needed(s) && !inflight_migration_enabled) {
+        error_setg(errp, "can't migrate vhost-user-blk device: "
+                         "backend doesn't support "
+                         "VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN "
+                         "protocol feature");
+        return false;
+    }
+
+    return true;
+}
+
 static const VMStateDescription vmstate_vhost_user_blk_inflight = {
     .name = "vhost-user-blk/inflight",
     .version_id = 1,
     .needed = vhost_user_blk_inflight_needed,
+    .pre_save_errp = vhost_user_blk_pre_save,
     .fields = (const VMStateField[]) {
         VMSTATE_VHOST_INFLIGHT_REGION(inflight, VHostUserBlk),
         VMSTATE_END_OF_LIST()
hw/virtio/vhost-user.c +1 -2
index faf9c8aedd..047058833b 100644
@@ -2598,8 +2598,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
             }
         }
 
-        if (!u->user->supports_inflight_migration ||
-            !virtio_has_feature(protocol_features,
+        if (!virtio_has_feature(protocol_features,
                                 VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) {
             protocol_features &= ~(1ULL <<
                                VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
Signature · 1 line
MST
#65 lore raw

[PULL 27/90] qapi: add local migration parameter

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

We are going to implement local-migration feature: some devices will be able to transfer open file descriptors through migration stream (which must UNIX domain socket for that purpose). This allows to transfer the whole backend state without reconnecting and restarting the backend service. For example, virtio-net will migrate its attached TAP netdev, together with its connected file descriptors.

In this commit we introduce a migration parameter, which enables the feature for devices that support it (none at the moment).

We can't simply auto-detect local migration by checking whether the migration channel is a UNIX domain socket: the UNIX socket may be only the first part of the transfer channel to a remote target. Hence an explicit parameter is needed. Moreover, "local" migration parameter may be useful in cpr-exec mode, when FDs are passed through exec instead of UNIX socket.

Message-ID: <[email protected]>

---
 qapi/migration.json      | 21 +++++++++++++++++----
 include/migration/misc.h |  2 ++
 migration/options.c      | 18 +++++++++++++++++-
 3 files changed, 36 insertions(+), 5 deletions(-)
qapi/migration.json +17 -4
index b1eaf7b054..f7628b55e9 100644
@@ -830,7 +830,8 @@
            'zero-page-detection',
            'direct-io',
            { 'name': 'x-rdma-chunk-size', 'features': [ 'unstable' ] },
-           'cpr-exec-command'] }
+           'cpr-exec-command',
+           'local'] }
 
 ##
 # @migrate-set-parameters:
@@ -1012,10 +1013,20 @@
 #     Must be set to the same value on both source and destination
 #     before migration starts.  (Since 11.1)
 #
+# @local: Permit the use of optimizations for local migration.  This
+#     must only be set when either both the source and destination
+#     QEMU processes are directly connected with a UNIX domain socket
+#     as the migration channel (to enable use of file descriptor
+#     passing) or cpr-exec migration mode is enabled (this way file
+#     descriptors are inherited by new process).  Individual device
+#     backends may need additional configuration flags set to enable
+#     local migration optimizations.  This will be documented against
+#     the device backends where it applies.  (Since 11.2)
+#
 # Features:
 #
-# @unstable: Members @x-checkpoint-delay, @x-rdma-chunk-size, and
-#     @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @local, @x-checkpoint-delay, @x-rdma-chunk-size,
+#     and @x-vcpu-dirty-limit-period are experimental.
 #
 # Since: 2.4
 ##
@@ -1053,7 +1064,9 @@
             '*direct-io': 'bool',
             '*x-rdma-chunk-size': { 'type': 'uint64',
                                     'features': [ 'unstable' ] },
-            '*cpr-exec-command': [ 'str' ]} }
+            '*cpr-exec-command': [ 'str' ],
+            '*local': { 'type': 'bool',
+                        'features': [ 'unstable' ] } } }
 
 ##
 # @query-migrate-parameters:
include/migration/misc.h +2 -0
index 2b2fbb59a4..019717f4cd 100644
@@ -161,4 +161,6 @@ bool multifd_join_device_state_save_threads(void);
 
 void migration_request_switchover_ack_legacy(const char *requester);
 
+bool migrate_local(void);
+
 #endif
migration/options.c +17 -1
index d2575edb6c..05b026f4bf 100644
@@ -14,6 +14,7 @@
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
 #include "qemu/units.h"
+#include "qapi/util.h"
 #include "exec/target_page.h"
 #include "qapi/clone-visitor.h"
 #include "qapi/error.h"
@@ -25,6 +26,7 @@
 #include "migration/colo.h"
 #include "migration/cpr.h"
 #include "migration/misc.h"
+#include "migration/options.h"
 #include "migration.h"
 #include "migration-stats.h"
 #include "qemu-file.h"
@@ -350,6 +352,12 @@ bool migrate_mapped_ram(void)
     return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
 }
 
+bool migrate_local(void)
+{
+    MigrationState *s = migrate_get_current();
+    return s->parameters.local;
+}
+
 bool migrate_ignore_shared(void)
 {
     MigrationState *s = migrate_get_current();
@@ -1101,7 +1109,7 @@ static void migrate_mark_all_params_present(MigrationParameters *p)
         &p->has_announce_step, &p->has_block_bitmap_mapping,
         &p->has_x_vcpu_dirty_limit_period, &p->has_vcpu_dirty_limit,
         &p->has_mode, &p->has_zero_page_detection, &p->has_direct_io,
-        &p->has_x_rdma_chunk_size, &p->has_cpr_exec_command,
+        &p->has_x_rdma_chunk_size, &p->has_cpr_exec_command, &p->has_local,
     };
 
     len = ARRAY_SIZE(has_fields);
@@ -1449,6 +1457,10 @@ static void migrate_params_test_apply(MigrationParameters *params,
         qapi_free_strList(dest->cpr_exec_command);
         dest->cpr_exec_command = QAPI_CLONE(strList, params->cpr_exec_command);
     }
+
+    if (params->has_local) {
+        dest->local = params->local;
+    }
 }
 
 static void migrate_params_apply(MigrationParameters *params)
@@ -1581,6 +1593,10 @@ static void migrate_params_apply(MigrationParameters *params)
         s->parameters.cpr_exec_command =
             QAPI_CLONE(strList, params->cpr_exec_command);
     }
+
+    if (params->has_local) {
+        s->parameters.local = params->local;
+    }
 }
 
 void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
Signature · 1 line
MST
#66 lore raw

[PULL 73/90] intel_iommu: Only set dirty bit when PTE exposes write permission

In reply to Michael S. Tsirkin

From: Clément MATHIEU--DRIF <[email protected]>

Setting the dirty bit without the write bit in vIOMMU creates a spoofed shadow stack PTE that misleads the guest OS. This results in infinite PRI requests from the device, as no actual write permission is ever granted - the guest OS treats the PTE as a legitimate shadow stack entry and considers the permissions already correct.

Fixes 65c4f0999991 ("intel_iommu: Set accessed and dirty bits during stage-1 translation")

Message-ID: <[email protected]>

---
 hw/i386/intel_iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/i386/intel_iommu.c +1 -1
index 7c442a86ca..eccb16346c 100644
@@ -2039,7 +2039,7 @@ static int vtd_iova_to_fspte(IntelIOMMUState *s, VTDContextEntry *ce,
             return -VTD_FR_FS_PAGING_ENTRY_RSVD;
         }
 
-        if (vtd_is_last_pte(fspte, *fspte_level) && is_write) {
+        if (vtd_is_last_pte(fspte, *fspte_level) && *writes && is_write) {
             flag_ad |= VTD_FS_D;
         }
 
Signature · 1 line
MST
#67 lore raw

[PULL 15/90] linux-headers: add VIRTIO_ID_MEDIA

In reply to Michael S. Tsirkin

From: Albert Esteve <[email protected]>

The ID was added in Linux commit 2187be212179 ("virtio: Add ID for virtio media") and is included in v7.3-rc1.

Message-ID: <[email protected]>

---
 include/standard-headers/linux/virtio_ids.h | 1 +
 1 file changed, 1 insertion(+)
include/standard-headers/linux/virtio_ids.h +1 -0
index 6c12db16fa..f9056af0c6 100644
@@ -69,6 +69,7 @@
 #define VIRTIO_ID_BT			40 /* virtio bluetooth */
 #define VIRTIO_ID_GPIO			41 /* virtio gpio */
 #define VIRTIO_ID_SPI			45 /* virtio spi */
+#define VIRTIO_ID_MEDIA			48 /* virtio media */
 
 /*
  * Virtio Transitional IDs
Signature · 1 line
MST
#68 lore raw

[PULL 12/90] vhost: add vhost_dev_set_owner() / vhost_dev_reset_owner() helpers

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

Wrap the set_owner/reset_owner backend ops in dev-level helpers, matching other vhost_dev_* wrappers, so device code can take or release ownership without reaching into vhost_ops directly. vhost_dev_init() now uses vhost_dev_set_owner(). Both return -ENOSYS if the backend has no such op.

No functional change. These are used by the following vhost-vsock patch to hand a device between owners during CPR.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost.h | 13 +++++++++++++
 hw/virtio/vhost.c         | 20 +++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)
include/hw/virtio/vhost.h +13 -0
index 9b98d34dd0..44e65968d9 100644
@@ -178,6 +178,19 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
 int vhost_dev_init_backend(struct vhost_dev *hdev, void *opaque,
                            VhostBackendType backend_type, Error **errp);
 
+/**
+ * vhost_dev_set_owner() / vhost_dev_reset_owner() - take / release ownership
+ * @hdev: the common vhost_dev structure
+ *
+ * Take (VHOST_SET_OWNER) or release (VHOST_RESET_OWNER) ownership of a
+ * device that has already been set up.  Used to hand a device over during
+ * CPR.  Returns -ENOSYS if the backend has no such op.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int vhost_dev_set_owner(struct vhost_dev *hdev);
+int vhost_dev_reset_owner(struct vhost_dev *hdev);
+
 /**
  * vhost_dev_cleanup() - tear down and cleanup vhost interface
  * @hdev: the common vhost_dev structure
hw/virtio/vhost.c +19 -1
index 2bb9a23fee..ea17bf0108 100644
@@ -1690,6 +1690,24 @@ int vhost_dev_init_backend(struct vhost_dev *hdev, void *opaque,
     return 0;
 }
 
+int vhost_dev_set_owner(struct vhost_dev *hdev)
+{
+    assert(hdev->vhost_ops);
+    if (!hdev->vhost_ops->vhost_set_owner) {
+        return -ENOSYS;
+    }
+    return hdev->vhost_ops->vhost_set_owner(hdev);
+}
+
+int vhost_dev_reset_owner(struct vhost_dev *hdev)
+{
+    assert(hdev->vhost_ops);
+    if (!hdev->vhost_ops->vhost_reset_owner) {
+        return -ENOSYS;
+    }
+    return hdev->vhost_ops->vhost_reset_owner(hdev);
+}
+
 int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
                    VhostBackendType backend_type, uint32_t busyloop_timeout,
                    Error **errp)
@@ -1707,7 +1725,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
         goto fail;
     }
 
-    r = hdev->vhost_ops->vhost_set_owner(hdev);
+    r = vhost_dev_set_owner(hdev);
     if (r < 0) {
         error_setg_errno(errp, -r, "vhost_set_owner failed");
         goto fail;
Signature · 1 line
MST
#69 lore raw

[PULL 81/90] net/tap-solaris: Fix resource leaks on error paths

In reply to Michael S. Tsirkin
---
 net/tap-solaris.c | 69 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 21 deletions(-)
net/tap-solaris.c +48 -21
index 8704b1084b..2c6c7af15e 100644
@@ -60,8 +60,6 @@ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
  */
 static int tap_alloc(char *dev, size_t dev_size, Error **errp)
 {
-    /* FIXME leaks like a sieve on error paths */
-    /* FIXME suspicious: many errors are reported, then ignored */
     int tap_fd, if_fd, ppa = -1;
     static int ip_fd = 0;
     char *ptr;
@@ -102,45 +100,61 @@ static int tap_alloc(char *dev, size_t dev_size, Error **errp)
     strioc_ppa.ic_timout = 0;
     strioc_ppa.ic_len = sizeof(ppa);
     strioc_ppa.ic_dp = (char *)&ppa;
-    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) {
         error_report("Can't assign new interface");
+        goto fail_tap_fd;
+    }
 
     if_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0));
     if (if_fd < 0) {
         error_setg_file_open(errp, errno, "/dev/tap");
-        return -1;
+        goto fail_tap_fd;
     }
     if(ioctl(if_fd, I_PUSH, "ip") < 0){
         error_setg(errp, "Can't push IP module");
-        return -1;
+        goto fail_if_fd;
     }
 
-    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
         error_report("Can't get flags");
+        goto fail_if_fd;
+    }
 
-    snprintf (actual_name, 32, "tap%d", ppa);
+    snprintf(actual_name, 32, "tap%d", ppa);
     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
 
     ifr.lifr_ppa = ppa;
-    /* Assign ppa according to the unit number returned by tun device */
-
-    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+    if (ioctl(if_fd, SIOCSLIFNAME, &ifr) < 0) {
         error_report("Can't set PPA %d", ppa);
-    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+        goto fail_if_fd;
+    }
+
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
         error_report("Can't get flags");
+        goto fail_if_fd;
+    }
+
     /* Push arp module to if_fd */
-    if (ioctl (if_fd, I_PUSH, "arp") < 0)
+    if (ioctl(if_fd, I_PUSH, "arp") < 0) {
         error_report("Can't push ARP module (2)");
+        goto fail_if_fd;
+    }
 
     /* Push arp module to ip_fd */
-    if (ioctl (ip_fd, I_POP, NULL) < 0)
+    if (ioctl(ip_fd, I_POP, NULL) < 0) {
         error_report("I_POP failed");
-    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+        goto fail_if_fd;
+    }
+    if (ioctl(ip_fd, I_PUSH, "arp") < 0) {
         error_report("Can't push ARP module (3)");
+        goto fail_if_fd;
+    }
     /* Open arp_fd */
     arp_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0));
-    if (arp_fd < 0)
+    if (arp_fd < 0) {
         error_report("Can't open %s", "/dev/tap");
+        goto fail_if_fd;
+    }
 
     /* Set ifname to arp */
     strioc_if.ic_cmd = SIOCSLIFNAME;
@@ -149,32 +163,45 @@ static int tap_alloc(char *dev, size_t dev_size, Error **errp)
     strioc_if.ic_dp = (char *)&ifr;
     if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
         error_report("Can't set ifname to arp");
+        goto fail_arp_fd;
     }
 
     if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
         error_setg(errp, "Can't link TAP device to IP");
-        return -1;
+        goto fail_arp_fd;
     }
 
-    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+    if ((arp_muxid = ioctl(ip_fd, link_type, arp_fd)) < 0) {
         error_report("Can't link TAP device to ARP");
+        goto fail_ip_muxid;
+    }
 
-    close (if_fd);
+    close(if_fd);
 
     memset(&ifr, 0x0, sizeof(ifr));
     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
     ifr.lifr_ip_muxid  = ip_muxid;
     ifr.lifr_arp_muxid = arp_muxid;
 
-    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+    if (ioctl(ip_fd, SIOCSLIFMUXID, &ifr) < 0)
     {
-      ioctl (ip_fd, I_PUNLINK , arp_muxid);
-      ioctl (ip_fd, I_PUNLINK, ip_muxid);
+      ioctl(ip_fd, I_PUNLINK, arp_muxid);
+      ioctl(ip_fd, I_PUNLINK, ip_muxid);
       error_report("Can't set multiplexor id");
     }
 
     snprintf(dev, dev_size, "tap%d", ppa);
     return tap_fd;
+
+fail_ip_muxid:
+    ioctl(ip_fd, I_PUNLINK, ip_muxid);
+fail_arp_fd:
+    close(arp_fd);
+fail_if_fd:
+    close(if_fd);
+fail_tap_fd:
+    close(tap_fd);
+    return -1;
 }
 
 int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
Signature · 1 line
MST
#70 lore raw

[PULL 14/90] vhost-vsock: hand off device ownership across CPR

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

The previous patches reuse the source vhost FD on the destination, however both source and target still call vhost_dev_init() (VHOST_SET_OWNER) in realize(). For cpr-transfer the destination realizes while the source still owns the shared FD, so its SET_OWNER would fail - ownership has to be handed over explicitly.

Do this through the device's CPR vmstate hooks. Namely, release device ownership in pre_save, reclaim in post_load, re-acquire on failure:

- .pre_save() releases ownership on the source (VHOST_RESET_OWNER) once the VM is stopped, for the FD-preserving CPR modes (cpr-transfer and cpr-exec).

- .realize(), for an incoming CPR, only sets up the virtio device and queries the backend features by calling vhost_dev_init_backend(). It doesn't take device ownership and doesn't touch the VQs which still-running source might use. The full init is deferred to .post_load().

- .post_load() reclaims it on the destination: the full vhost_dev_init() (VHOST_SET_OWNER) on the preserved FD, plus sets the guest cid, before the device is started at vm_start.

- A MIG_EVENT_FAILED notifier re-acquires ownership if the migration fails after pre_save released it and the source VM is resumed.

- .set_status() refuses to start a device whose handoff hasn't
completed: not fully initialized yet, or left ownerless after a failed CPR.

With the handoff in place, lift the CPR blocker: only ID-less devices, which can't preserve their FDs, remain blocked.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost-vsock.h |   5 +-
 hw/virtio/vhost-vsock.c         | 165 ++++++++++++++++++++++++++++----
 2 files changed, 152 insertions(+), 18 deletions(-)
include/hw/virtio/vhost-vsock.h +4 -1
index a964d57e1b..6d0cff4fb9 100644
@@ -15,6 +15,7 @@
 #define QEMU_VHOST_VSOCK_H
 
 #include "hw/virtio/vhost-vsock-common.h"
+#include "qemu/notify.h"
 #include "qom/object.h"
 
 #define TYPE_VHOST_VSOCK "vhost-vsock-device"
@@ -29,7 +30,9 @@ struct VHostVSock {
     /*< private >*/
     VHostVSockCommon parent;
     VHostVSockConf conf;
-    Error *migration_blocker;   /* CPR migration is not supported */
+    Error *migration_blocker;   /* set when the device has no ID */
+    bool owner_reset;           /* CPR released ownership; needs re-acquire */
+    NotifierWithReturn cpr_notifier;   /* re-acquires ownership if CPR fails */
 
     /*< public >*/
 };
hw/virtio/vhost-vsock.c +148 -17

229 lines not on this page · raw message

Signature · 1 line
MST
#71 lore raw

[PULL 37/90] vhost-user-gpu: Add shared memory region support

In reply to Michael S. Tsirkin

From: Matej Hrica <[email protected]>

Add a 'hostmem' property to the vhost-user-gpu which enables the shared memory in the parent object.

Register a container MR in the shmem_list for SHMEM_MAP/UNMAP operations. A container MR is used so that SHMEM_MAP FD-backed subregions each get their own KVM memory slot with the correct backing fd.

Message-ID: <[email protected]>

---
 hw/display/vhost-user-gpu.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
hw/display/vhost-user-gpu.c +11 -0
index cd684d6363..80ab6b773e 100644
@@ -687,6 +687,16 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
     }
 
     g->vhost_gpu_fd = -1;
+
+    /*
+     * If shared memory is enabled, register the hostmem region for
+     * SHMEM_MAP/UNMAP operations.
+     */
+    if (virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
+        VirtioSharedMemory *shmem = virtio_new_shmem_region(
+            vdev, VIRTIO_GPU_SHM_ID_HOST_VISIBLE, g->parent_obj.conf.hostmem);
+        memory_region_add_subregion(&g->parent_obj.hostmem, 0, &shmem->mr);
+    }
 }
 
 static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
@@ -697,6 +707,7 @@ static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
 
 static const Property vhost_user_gpu_properties[] = {
     VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf),
+    DEFINE_PROP_SIZE("hostmem", VhostUserGPU, parent_obj.conf.hostmem, 0),
 };
 
 static void
Signature · 1 line
MST
#72 lore raw

[PULL 74/90] intel_iommu: Always write all the flags passed to vtd_set_flag_in_pte

In reply to Michael S. Tsirkin

From: Clément MATHIEU--DRIF <[email protected]>

This function was initially designed to write a single flag in a pte. The current implementation expects it to set several flags.

Fixes 65c4f0999991 ("intel_iommu: Set accessed and dirty bits during stage-1 translation")

Message-ID: <[email protected]>

---
 hw/i386/intel_iommu.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
hw/i386/intel_iommu.c +5 -5
index eccb16346c..91ab549dbf 100644
@@ -1964,13 +1964,13 @@ static bool vtd_iova_fs_check_canonical(IntelIOMMUState *s, uint64_t iova,
     }
 }
 
-static MemTxResult vtd_set_flag_in_pte(dma_addr_t base_addr, uint32_t index,
-                                       uint64_t pte, uint64_t flag)
+static MemTxResult vtd_set_flags_in_pte(dma_addr_t base_addr, uint32_t index,
+                                       uint64_t pte, uint64_t flags)
 {
-    if (pte & flag) {
+    if ((pte & flags) == flags) {
         return MEMTX_OK;
     }
-    pte |= flag;
+    pte |= flags;
     pte = cpu_to_le64(pte);
     return dma_memory_write(&address_space_memory,
                             base_addr + index * sizeof(pte),
@@ -2043,7 +2043,7 @@ static int vtd_iova_to_fspte(IntelIOMMUState *s, VTDContextEntry *ce,
             flag_ad |= VTD_FS_D;
         }
 
-        if (vtd_set_flag_in_pte(addr, offset, fspte, flag_ad) != MEMTX_OK) {
+        if (vtd_set_flags_in_pte(addr, offset, fspte, flag_ad) != MEMTX_OK) {
             return -VTD_FR_FS_BIT_UPDATE_FAILED;
         }
 
Signature · 1 line
MST
#73 lore raw

[PULL 22/90] net/tap: move vhost-net open() calls to tap_parse_vhost_fds()

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

1. Simplify code path: get vhostfds for all cases in one function.

2. Prepare for further tap-fd-migraton feature, when we'll need to postpone vhost initialization up to post-load stage.

Based-on: <[email protected]>

Message-ID: <[email protected]>

---
 net/tap.c | 39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)
net/tap.c +22 -17
index f4051e8d4b..bec2cd48fd 100644
@@ -756,8 +756,7 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
         }
     }
 
-    if (tap->has_vhost ? tap->vhost :
-        (vhostfd != -1) || (tap->has_vhostforce && tap->vhostforce)) {
+    if (vhostfd != -1) {
         VhostNetOptions options;
 
         options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
@@ -767,17 +766,6 @@ static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
         } else {
             options.busyloop_timeout = 0;
         }
-
-        if (vhostfd == -1) {
-            vhostfd = open("/dev/vhost-net", O_RDWR);
-            if (vhostfd < 0) {
-                error_setg_file_open(errp, errno, "/dev/vhost-net");
-                goto failed;
-            }
-            if (!qemu_set_blocking(vhostfd, false, errp)) {
-                goto failed;
-            }
-        }
         options.opaque = (void *)(uintptr_t)vhostfd;
         options.nvqs = 2;
         options.feature_bits = kernel_feature_bits;
@@ -863,14 +851,31 @@ static int tap_parse_fds_and_queues(const NetdevTapOptions *tap, int **fds,
 static bool tap_parse_vhost_fds(const NetdevTapOptions *tap, int **vhost_fds,
                                 int queues, Error **errp)
 {
-    if (!(tap->vhostfd || tap->vhostfds)) {
+    bool need_vhost = tap->has_vhost ? tap->vhost :
+        ((tap->vhostfd || tap->vhostfds) ||
+         (tap->has_vhostforce && tap->vhostforce));
+
+    if (!need_vhost) {
         *vhost_fds = NULL;
         return true;
     }
 
-    if (net_parse_fds(tap->vhostfd ?: tap->vhostfds,
-                      vhost_fds, queues, errp) < 0) {
-        return false;
+    if (tap->vhostfd || tap->vhostfds) {
+        if (net_parse_fds(tap->vhostfd ?: tap->vhostfds,
+                          vhost_fds, queues, errp) < 0) {
+            return false;
+        }
+    } else {
+        *vhost_fds = g_new(int, queues);
+        for (int i = 0; i < queues; i++) {
+            int vhostfd = open("/dev/vhost-net", O_RDWR);
+            if (vhostfd < 0) {
+                error_setg_file_open(errp, errno, "/dev/vhost-net");
+                net_free_fds(*vhost_fds, i);
+                return false;
+            }
+            (*vhost_fds)[i] = vhostfd;
+        }
     }
 
     if (!unblock_fds(*vhost_fds, queues, errp)) {
Signature · 1 line
MST
#74 lore raw

[PULL 08/90] vhost-vsock: fix FD leak in realize()

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

In vhost_vsock_device_realize(), after unsuccessful call to qemu_set_blocking(vhostfd, false), vhostfd gets leaked. Let's close it explicitly in this case. CPR-saved FDs don't get automatically closed, thus it is safe both for vhostfd obtained from cpr_find_fd() and from open(/dev/vhost-vsock).

Message-ID: <[email protected]>

---
 hw/virtio/vhost-vsock.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)
hw/virtio/vhost-vsock.c +4 -7
index c582ac9fcc..3ec20d8760 100644
@@ -176,20 +176,17 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
             error_prepend(errp, "vhost-vsock: unable to parse vhostfd: ");
             goto err_blocker;
         }
-
-        if (!qemu_set_blocking(vhostfd, false, errp)) {
-            goto err_blocker;
-        }
     } else {
         vhostfd = open("/dev/vhost-vsock", O_RDWR);
         if (vhostfd < 0) {
             error_setg_file_open(errp, errno, "/dev/vhost-vsock");
             goto err_blocker;
         }
+    }
 
-        if (!qemu_set_blocking(vhostfd, false, errp)) {
-            goto err_blocker;
-        }
+    if (!qemu_set_blocking(vhostfd, false, errp)) {
+        close(vhostfd);
+        goto err_blocker;
     }
 
     vhost_vsock_common_realize(vdev);
Signature · 1 line
MST
#75 lore raw

[PULL 88/90] vhost-user-blk: move inflight_needed higher

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

Move vhost_user_blk_inflight_needed() earlier in the file so it can be called from vhost_user_blk_stop(), which is defined before the VMState section. No functional change.

Message-ID: <[email protected]>

---
 hw/block/vhost-user-blk.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)
hw/block/vhost-user-blk.c +11 -8
index 501de30796..3eaaa19719 100644
@@ -137,6 +137,17 @@ const VhostDevConfigOps blk_ops = {
     .vhost_dev_config_notifier = vhost_user_blk_handle_config_change,
 };
 
+static bool vhost_user_blk_inflight_needed(void *opaque)
+{
+    struct VHostUserBlk *s = opaque;
+
+    bool inflight_migration = virtio_has_feature(s->dev.protocol_features,
+                               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
+
+    return inflight_migration;
+}
+
+
 static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp)
 {
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
@@ -597,14 +608,6 @@ static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev)
     return &s->dev;
 }
 
-static bool vhost_user_blk_inflight_needed(void *opaque)
-{
-    struct VHostUserBlk *s = opaque;
-
-    return vhost_user_has_protocol_feature(
-        &s->dev, VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT);
-}
-
 static const VMStateDescription vmstate_vhost_user_blk_inflight = {
     .name = "vhost-user-blk/inflight",
     .version_id = 1,
Signature · 1 line
MST
#76 lore raw

[PULL 40/90] hw/cxl: Drop Back-Invalidate from default CFMW window restrictions

In reply to Michael S. Tsirkin

From: Davidlohr Bueso <[email protected]>

The default CXL Fixed Memory Window restrictions advertised host-only coherent together with Back-Invalidate. A window advertising both simultaneously is undefined behavior per CXL r4.0 9.18.1.3.

Drop Back-Invalidate from the default, leaving device-coherent + host-only + volatile + persistent.

Message-ID: <[email protected]>

---
 hw/acpi/cxl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/acpi/cxl.c +1 -1
index f92f7fa3d5..75edb2c0a6 100644
@@ -172,7 +172,7 @@ static void cedt_build_cfmws(CXLFixedWindow *fw, Aml *cedt)
     build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
 
     /* Window Restrictions */
-    build_append_int_noprefix(table_data, 0x2f, 2);
+    build_append_int_noprefix(table_data, 0x0f, 2);
 
     /* QTG ID */
     build_append_int_noprefix(table_data, 0, 2);
Signature · 1 line
MST
#77 lore raw

[PULL 02/90] virtio: fix config_len DoS in migration restore path

In reply to Michael S. Tsirkin

virtio_load() reads config_len from the migration stream into a local int32_t variable and then, if the incoming length exceeds the device's own config size, skips the surplus one byte at a time in a loop. Two defects in this loop allow a malicious or truncated migration stream to cause a prolonged CPU spin on the destination QEMU.

First, the local variable is int32_t while vdev->config_len is size_t. The C standard converts the signed operand to the unsigned type for the comparison, so any value with the high bit set becomes a very large size_t that exceeds the device config length. The loop then counts the signed counter down through all negative values and back around, effectively running for up to 2^32 iterations.

Second, once the file stream reaches EOF, qemu_get_byte() returns 0 without advancing the read position. Without a check for file errors, the loop spins until the counter reaches the device config length. An attacker who sends a large config_len and then closes the stream can hold the destination QEMU busy for attacker-controlled time.

Change the local config_len to uint32_t so that the comparison with size_t is unsigned and values with the high bit set are treated as large-but-finite skip counts. In addition, check qemu_file_get_error() after each byte read and return failure immediately when the stream signals EOF or an I/O error.

Fixes 2f5732e964 ("Allow mismatched virtio config-len")
Cc Dr. David Alan Gilbert <[email protected]>

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3891

---
 hw/virtio/virtio.c | 3 +++
 1 file changed, 3 insertions(+)
hw/virtio/virtio.c +3 -0
index 34f1df260b..848fe8539e 100644
@@ -3584,6 +3584,9 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
             return -1;
         }
         qemu_get_byte(f);
+        if (qemu_file_get_error(f)) {
+            return -1;
+        }
         config_len--;
     }
 
Signature · 1 line
MST
#78 lore raw

[PULL 31/90] virtio-net: support local migration of backend

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Next commit will introduce live-migration (with fd-passing) for TAP net backend. So, now we prepare virtio-net for it
Add virtio-net option local-migration, which is true by default, but false for older machine types, which doesn't support the feature.

We introduce interface for live-migrating backends:

1. ->is_wait_incoming() handler, so that virtio-net knows, that backend is not fully intialized, as it waits for incoming migration stream.

2. MIG_PRI_BACKEND priority: backends should migrate with higher priority than virtio-net, so that we can do final preparations here in post-load handlers and be sure, that backends are already prepared.

Message-ID: <[email protected]>

---
 include/hw/virtio/virtio-net.h |  1 +
 include/migration/vmstate.h    |  2 +
 include/net/net.h              |  2 +
 hw/net/virtio-net.c            | 89 +++++++++++++++++++++++++++++++++-
 4 files changed, 93 insertions(+), 1 deletion(-)
include/hw/virtio/virtio-net.h +1 -0
index 371e376428..8c967760c2 100644
@@ -230,6 +230,7 @@ struct VirtIONet {
     struct EBPFRSSContext ebpf_rss;
     uint32_t nr_ebpf_rss_fds;
     char **ebpf_rss_fds;
+    bool peers_wait_incoming;
 };
 
 size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
include/migration/vmstate.h +2 -0
index e72c3fae9a..7d2b786382 100644
@@ -169,6 +169,8 @@ typedef enum {
 
     MIG_PRI_LOW,                /* Must happen after default */
     MIG_PRI_DEFAULT,
+    MIG_PRI_BACKEND,            /* Must happen before emulated devices, */
+                                /* e.g. virtio-net */
     MIG_PRI_IOMMU,              /* Must happen before PCI devices */
     MIG_PRI_PCI_BUS,            /* Must happen before IOMMU */
     MIG_PRI_VIRTIO_MEM,         /* Must happen before IOMMU */
include/net/net.h +2 -0
index ea07760b56..fdf6a2ddd4 100644
@@ -82,6 +82,7 @@ typedef void (SocketReadStateFinalize)(SocketReadState *rs);
 typedef void (NetAnnounce)(NetClientState *);
 typedef bool (SetSteeringEBPF)(NetClientState *, int);
 typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
+typedef bool (IsWaitIncoming)(NetClientState *);
 typedef struct vhost_net *(GetVHostNet)(NetClientState *nc);
 
 typedef struct NetClientInfo {
@@ -110,6 +111,7 @@ typedef struct NetClientInfo {
     NetAnnounce *announce;
     SetSteeringEBPF *set_steering_ebpf;
     NetCheckPeerType *check_peer_type;
+    IsWaitIncoming *is_wait_incoming;
     GetVHostNet *get_vhost_net;
 } NetClientInfo;
 
hw/net/virtio-net.c +88 -1

137 lines not on this page · raw message

Signature · 1 line
MST
#79 lore raw

[PULL 06/90] vhost: add vhost_reset_owner op

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

Add a VhostOps callback issuing VHOST_RESET_OWNER, wired up for the kernel backend. The CPR (checkpoint-restore) path uses it to release device ownership on the source so the destination can reclaim it later with VHOST_SET_OWNER.

Message-ID: <[email protected]>

---
 include/hw/virtio/vhost-backend.h | 1 +
 hw/virtio/vhost-kernel.c          | 6 ++++++
 2 files changed, 7 insertions(+)
include/hw/virtio/vhost-backend.h +1 -0
index d878d7b733..6c949e6a38 100644
@@ -204,6 +204,7 @@ typedef struct VhostOps {
     vhost_get_features_op vhost_get_features;
     vhost_set_backend_cap_op vhost_set_backend_cap;
     vhost_set_owner_op vhost_set_owner;
+    vhost_set_owner_op vhost_reset_owner;
     vhost_reset_device_op vhost_reset_device;
     vhost_get_vq_index_op vhost_get_vq_index;
     vhost_set_vring_enable_op vhost_set_vring_enable;
hw/virtio/vhost-kernel.c +6 -0
index 3390b48c6f..55d316b88e 100644
@@ -261,6 +261,11 @@ static int vhost_kernel_set_owner(struct vhost_dev *dev)
     return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
 }
 
+static int vhost_kernel_reset_owner(struct vhost_dev *dev)
+{
+    return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
+}
+
 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
 {
     assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
@@ -385,6 +390,7 @@ const VhostOps kernel_ops = {
         .vhost_get_features_ex = vhost_kernel_get_features,
         .vhost_set_backend_cap = vhost_kernel_set_backend_cap,
         .vhost_set_owner = vhost_kernel_set_owner,
+        .vhost_reset_owner = vhost_kernel_reset_owner,
         .vhost_get_vq_index = vhost_kernel_get_vq_index,
         .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
         .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
Signature · 1 line
MST
#80 lore raw

[PULL 87/90] vhost-user-blk: make inflight-migration prop mutable on running vm

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

The inflight-migration property currently can only be set before the device is realized. This makes it impossible to disable inflight migration at runtime without restarting the VM.

Make the property mutable, but only while the VM is running. Blocking changes when the VM is not running ensures that the value at stop time reliably reflects the intent set on a live VM, which allows vhost_user_blk_stop() to use skip_drain unconditionally based on the property value without inspecting migration runstate.

Message-ID: <[email protected]>

---
 hw/block/vhost-user-blk.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)
hw/block/vhost-user-blk.c +26 -2
index c3e3c37f8c..501de30796 100644
@@ -629,6 +629,8 @@ static const VMStateDescription vmstate_vhost_user_blk = {
     }
 };
 
+static PropertyInfo vhost_user_blk_inflight_migration_prop;
+
 static const Property vhost_user_blk_properties[] = {
     DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev),
     DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues,
@@ -644,8 +646,9 @@ static const Property vhost_user_blk_properties[] = {
                       VIRTIO_BLK_F_WRITE_ZEROES, true),
     DEFINE_PROP_BOOL("skip-get-vring-base-on-force-shutdown", VHostUserBlk,
                      skip_get_vring_base_on_force_shutdown, false),
-    DEFINE_PROP_BOOL("inflight-migration", VHostUserBlk,
-                     inflight_migration, false),
+    DEFINE_PROP("inflight-migration", VHostUserBlk, inflight_migration,
+                vhost_user_blk_inflight_migration_prop, bool,
+                .set_default = true, .defval.u = false),
 };
 
 static void vhost_user_blk_class_init(ObjectClass *klass, const void *data)
@@ -675,8 +678,29 @@ static const TypeInfo vhost_user_blk_info = {
     .class_init = vhost_user_blk_class_init,
 };
 
+static void vhost_user_blk_set_inflight_migration(Object *obj, Visitor *v,
+                                                  const char *name,
+                                                  void *opaque, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+
+    if (dev->realized && !runstate_is_running()) {
+        error_setg(errp, "Property '%s' cannot be changed "
+                         "while VM is not running", name);
+        return;
+    }
+
+    qdev_prop_bool.set(obj, v, name, opaque, errp);
+}
+
+
 static void virtio_register_types(void)
 {
+    vhost_user_blk_inflight_migration_prop = qdev_prop_bool;
+    vhost_user_blk_inflight_migration_prop.realized_set_allowed = true;
+    vhost_user_blk_inflight_migration_prop.set =
+        vhost_user_blk_set_inflight_migration;
+
     type_register_static(&vhost_user_blk_info);
 }
 
Signature · 1 line
MST
#81 lore raw

[PULL 85/90] vhost-user: add GET_VRING_BASE_SKIP_DRAIN message

In reply to Michael S. Tsirkin

From: Alexandr Moshkov <[email protected]>

VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT was introduced to allow the back-end to suspend in-flight I/O during GET_VRING_BASE instead of draining it, enabling live migration of in-flight requests. However, this behaviour is tied to the protocol feature itself - once negotiated, there is no way for the front-end to tell the back-end to fall back to the normal drain behaviour on a per-stop basis.

Introduce a separate message VHOST_USER_GET_VRING_BASE_SKIP_DRAIN (id=45) guarded by a new protocol feature VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN. The message is identical to GET_VRING_BASE except that the back-end must immediately suspend all in-flight I/O and record it in the inflight region. This way the front-end has explicit per-call control: send GET_VRING_BASE for normal drain, send GET_VRING_BASE_SKIP_DRAIN when immediate suspend is needed.

The new feature requires both VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT
and VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD to be negotiated.

Message-ID: <[email protected]>

---
 docs/interop/vhost-user.rst       | 42 ++++++++++++++++++++---------
 include/hw/virtio/vhost-backend.h |  1 +
 include/hw/virtio/vhost-user.h    |  1 +
 hw/virtio/vhost-user.c            | 44 +++++++++++++++++++++++++++----
 hw/virtio/vhost.c                 |  2 +-
 5 files changed, 72 insertions(+), 18 deletions(-)
docs/interop/vhost-user.rst +30 -12
index fbfb9d01c6..c1e02ff7e9 100644
@@ -457,6 +457,7 @@ replies, except for the following requests:
 * ``VHOST_USER_GET_FEATURES``
 * ``VHOST_USER_GET_PROTOCOL_FEATURES``
 * ``VHOST_USER_GET_VRING_BASE``
+* ``VHOST_USER_GET_VRING_BASE_SKIP_DRAIN``
 * ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``)
 * ``VHOST_USER_GET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``)
 
@@ -533,7 +534,7 @@ Rings have two independent states: started/stopped, and enabled/disabled.
 Each ring is initialized in a stopped and disabled state.  Rings are started
 with ``VHOST_USER_SET_VRING_KICK`` (or ``VHOST_USER_VRING_KICK`` if
 ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` is negotiated) and stopped with
-``VHOST_USER_GET_VRING_BASE``.  A stopped ring enters the started state again
+``VHOST_USER_GET_VRING_BASE`` or ``VHOST_USER_GET_VRING_BASE_SKIP_DRAIN``.  A stopped ring enters the started state again
 with ``VHOST_USER_SET_VRING_KICK`` (or ``VHOST_USER_VRING_KICK`` if
 ``VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS`` is negotiated) and the back-end
 resumes processing requests.
@@ -1159,6 +1160,7 @@ Protocol features
   #define VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT 20
   #define VHOST_USER_PROTOCOL_F_GPA_ADDRESSES           21
   #define VHOST_USER_PROTOCOL_F_SHMEM                   22
+  #define VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN 23
 
 Front-end message types
 -----------------------
@@ -1355,17 +1357,11 @@ Front-end message types
   set to 0.
 
   By default, the back-end must complete all inflight I/O requests for the
-  specified vring before stopping it.
-
-  If the ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT`` protocol
-  feature has been negotiated, the back-end may suspend in-flight I/O
-  requests and record them as described in :ref:`Inflight I/O tracking
-  <inflight_io_tracking>` instead of completing them before stopping the vring.
-  How to suspend an in-flight request depends on the implementation of the back-end
-  but it typically can be done by aborting or cancelling the underlying I/O
-  request. The ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT``
-  protocol feature must only be negotiated if
-  ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` is also negotiated.
+  specified vring before stopping it. If the
+  ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN`` protocol feature has
+  been negotiated, the front-end may instead use
+  ``VHOST_USER_GET_VRING_BASE_SKIP_DRAIN`` to request the back-end to
+  suspend in-flight I/O immediately.
 
 ``VHOST_USER_SET_VRING_KICK``
   :id: 12
@@ -1868,6 +1864,28 @@ Front-end message types
 
   * The size may be 0 if the region is unused.
 
+``VHOST_USER_GET_VRING_BASE_SKIP_DRAIN``
+  :id: 45
+  :equivalent ioctl: N/A
+  :request payload: vring state description
+  :reply payload: vring descriptor index/indices
+
+  This message requires the ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN``
+  protocol feature to be negotiated.
+
+  Identical to ``VHOST_USER_GET_VRING_BASE`` except that the back-end
+  must not wait for inflight I/O requests to complete before stopping
+  the vring.  Instead, the back-end must immediately suspend all
+  in-flight I/O requests and record them as described in
+  :ref:`Inflight I/O tracking <inflight_io_tracking>`. How to suspend
+  an in-flight request depends on the implementation of the back-end,
+  but it typically can be done by aborting or cancelling the underlying
+  I/O request.
+
+  The ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN`` protocol feature
+  must only be negotiated if both ``VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT``
+  and ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` are also negotiated.
+
 Back-end message types
 ----------------------
 
include/hw/virtio/vhost-backend.h +1 -0
index 6c949e6a38..2333fddacd 100644
@@ -190,6 +190,7 @@ typedef struct VhostOps {
     vhost_set_vring_num_op vhost_set_vring_num;
     vhost_set_vring_base_op vhost_set_vring_base;
     vhost_get_vring_base_op vhost_get_vring_base;
+    vhost_get_vring_base_op vhost_get_vring_base_skip_drain;
     vhost_set_vring_kick_op vhost_set_vring_kick;
     vhost_set_vring_call_op vhost_set_vring_call;
     vhost_set_vring_err_op vhost_set_vring_err;
include/hw/virtio/vhost-user.h +1 -0
index 06c360af18..47c13f8677 100644
@@ -36,6 +36,7 @@ enum VhostUserProtocolFeature {
     VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT = 20,
     VHOST_USER_PROTOCOL_F_GPA_ADDRESSES = 21,
     VHOST_USER_PROTOCOL_F_SHMEM = 22,
+    VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN = 23,
     VHOST_USER_PROTOCOL_F_MAX
 };
 
hw/virtio/vhost-user.c +39 -5

90 lines not on this page · raw message

hw/virtio/vhost.c +1 -1
index 17b36366dc..27c78ffabf 100644
@@ -1515,7 +1515,7 @@ static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
 {
     if (skip_drain) {
         assert(vhost_user_has_protocol_feature(dev,
-               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT));
+               VHOST_USER_PROTOCOL_F_GET_VRING_BASE_SKIP_DRAIN));
     }
     int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
     struct vhost_vring_state state = {
Signature · 1 line
MST
#82 lore raw

[PULL 19/90] net/tap: rework tap_parse_script

In reply to Michael S. Tsirkin

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Factor out tap_is_explicit_no_script() helper, to simplify further changes.

Avoid extra copying by simpler code flow: first check for NULL / empty / "no" cases, then get default or do copying respectively.

Message-ID: <[email protected]>

---
 net/tap.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)
net/tap.c +23 -7
index 57ffb09885..2076f5b780 100644
@@ -92,19 +92,35 @@ static void launch_script(const char *setup_script, const char *ifname,
 static void tap_send(void *opaque);
 static void tap_writable(void *opaque);
 
-static char *tap_parse_script(const char *script_arg, const char *default_path)
+static bool tap_is_explicit_no_script(const char *script_arg_value)
 {
-    g_autofree char *res = g_strdup(script_arg);
-
-    if (!res) {
-        res = get_relocated_path(default_path);
+    if (!script_arg_value) {
+        return false;
     }
 
-    if (res[0] == '\0' || strcmp(res, "no") == 0) {
+    if (script_arg_value[0] == '\0') {
+        return true;
+    }
+
+    if (strcmp(script_arg_value, "no") == 0) {
+        return true;
+    }
+
+    return false;
+}
+
+static char *tap_parse_script(const char *script_arg_value,
+                              const char *default_path)
+{
+    if (tap_is_explicit_no_script(script_arg_value)) {
         return NULL;
     }
 
-    return g_steal_pointer(&res);
+    if (!script_arg_value) {
+        return get_relocated_path(default_path);
+    }
+
+    return g_strdup(script_arg_value);
 }
 
 static void tap_update_fd_handler(TAPState *s)
Signature · 1 line
MST
#83 lore raw

[PULL 01/90] virtio: fix exit(1) on DMA mapping failure during migration restore

In reply to Michael S. Tsirkin

When QEMU restores pending virtio requests from a migration stream, it calls qemu_get_virtqueue_element(), which calls virtqueue_map() and virtqueue_map_iovec() to re-map the saved DMA fragment addresses into the destination address space. If the addresses in the migration stream are corrupted, and as a result dma_memory_map() returns NULL or a shorter-than-expected length, virtqueue_map_iovec() calls exit(1), terminating the destination QEMU process instead of failing the migration cleanly.

Convert virtqueue_map_iovec() and virtqueue_map() from void to bool. On failure, virtqueue_map_iovec() unmaps any entries it has already mapped and returns false; virtqueue_map() similarly cleans up the in_sg entries if out_sg mapping fails. qemu_get_virtqueue_element() now checks the return value, frees the element and returns NULL on failure, allowing the migration restore path to propagate a clean error. The callers in virtio-blk, virtio-serial-bus and virtio-scsi that invoke qemu_get_virtqueue_element() during load are updated to check for NULL and return an error code.

Fixes 3b3b062821 ("virtio: slim down allocation of VirtQueueElements")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3888

---
 include/hw/virtio/virtio.h  |  2 +-
 hw/block/virtio-blk.c       |  4 +++
 hw/char/virtio-serial-bus.c |  4 +++
 hw/scsi/virtio-scsi.c       |  4 +++
 hw/virtio/virtio.c          | 49 +++++++++++++++++++++++++++----------
 5 files changed, 49 insertions(+), 14 deletions(-)
include/hw/virtio/virtio.h +1 -1
index c99cb19d88..27c5fe3a6b 100644
@@ -320,7 +320,7 @@ bool virtqueue_rewind(VirtQueue *vq, unsigned int num);
 void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
                     unsigned int len, unsigned int idx);
 
-void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem);
+bool virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem);
 void *virtqueue_pop(VirtQueue *vq, size_t sz);
 unsigned int virtqueue_drop_all(VirtQueue *vq);
 void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz);
hw/block/virtio-blk.c +4 -0
index 6b92066aff..cb6a276a82 100644
@@ -1384,6 +1384,10 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
         }
 
         req = qemu_get_virtqueue_element(vdev, f, sizeof(VirtIOBlockReq));
+        if (!req) {
+            error_report("Failed to restore virtio-blk request");
+            return -EINVAL;
+        }
         virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req);
 
         WITH_QEMU_LOCK_GUARD(&s->rq_lock) {
hw/char/virtio-serial-bus.c +4 -0
index 83a033ce85..81db0bdc91 100644
@@ -764,6 +764,10 @@ static int fetch_active_ports_list(QEMUFile *f,
 
             port->elem =
                 qemu_get_virtqueue_element(vdev, f, sizeof(VirtQueueElement));
+            if (!port->elem) {
+                error_report("Failed to restore virtio-serial element");
+                return -EINVAL;
+            }
 
             /*
              *  Port was throttled on source machine.  Let's
hw/scsi/virtio-scsi.c +4 -0
index bf64d1231a..132f833226 100644
@@ -274,6 +274,10 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
     assert(n < vs->conf.num_queues);
     req = qemu_get_virtqueue_element(vdev, f,
                                      sizeof(VirtIOSCSIReq) + vs->cdb_size);
+    if (!req) {
+        error_report("Failed to restore virtio-scsi request");
+        return NULL;
+    }
     virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
 
     if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
hw/virtio/virtio.c +36 -13

79 lines not on this page · raw message

Signature · 1 line
MST
#84 lore raw

[PULL 55/90] virtio-balloon: fix free-page BH teardown on unrealize

In reply to Michael S. Tsirkin

When a guest triggers PCIe hot-unplug while the free-page-hint BH is running on an IOThread, the BH will keep accessing vq->used_elems array when running it. Note that qemu_bh_delete merely prevents new BHs from running, it does not wait for already running ones to finish.

We need to wait for it to finish - do it like virtio scsi and run a dummy oneshot AIO in the same context, and wait for it.

But there's a twist: BH could be blocked in qemu_cond_wait, then AIO won't run.

Add a special reporting state FREE_PAGE_HINT_S_UNREALIZE to make BH exit immediately.

Cc: David Hildenbrand <[email protected]>
Fixes: CVE-2026-66899
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4079

Message-ID: <0967d574d9ffe469edf5fc16da86237e54a69c34.1785327742.git.mst@redhat.com>

---
 include/hw/virtio/virtio-balloon.h |  1 +
 hw/virtio/virtio-balloon.c         | 19 ++++++++++++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)
include/hw/virtio/virtio-balloon.h +1 -0
index abbf339718..53bbaa4c9a 100644
@@ -39,6 +39,7 @@ enum virtio_balloon_free_page_hint_status {
     FREE_PAGE_HINT_S_REQUESTED = 1,
     FREE_PAGE_HINT_S_START = 2,
     FREE_PAGE_HINT_S_DONE = 3,
+    FREE_PAGE_HINT_S_UNREALIZE = 4,
 };
 
 struct VirtIOBalloon {
hw/virtio/virtio-balloon.c +18 -1
index 4c5f486ba2..07d519cf6d 100644
@@ -35,6 +35,7 @@
 #include "system/reset.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/virtio-access.h"
+#include "qemu/aio-wait.h"
 
 #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
 
@@ -519,6 +520,9 @@ static bool get_free_page_hints(VirtIOBalloon *dev)
     int i;
 
     while (dev->block_iothread) {
+        if (dev->free_page_hint_status == FREE_PAGE_HINT_S_UNREALIZE) {
+            return false;
+        }
         qemu_cond_wait(&dev->free_page_cond, &dev->free_page_lock);
     }
 
@@ -912,6 +916,11 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
     qemu_register_resettable(OBJECT(dev));
 }
 
+static void dummy_bh(void *opaque)
+{
+    /* Do nothing */
+}
+
 static void virtio_balloon_device_unrealize(DeviceState *dev)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -919,9 +928,17 @@ static void virtio_balloon_device_unrealize(DeviceState *dev)
 
     qemu_unregister_resettable(OBJECT(dev));
     if (s->free_page_bh) {
+        AioContext *ctx = iothread_get_aio_context(s->iothread);
+
         qemu_bh_delete(s->free_page_bh);
+
+        qemu_mutex_lock(&s->free_page_lock);
+        s->free_page_hint_status = FREE_PAGE_HINT_S_UNREALIZE;
+        qemu_cond_signal(&s->free_page_cond);
+        qemu_mutex_unlock(&s->free_page_lock);
+        aio_wait_bh_oneshot(ctx, dummy_bh, NULL);
+
         object_unref(OBJECT(s->iothread));
-        virtio_balloon_free_page_stop(s);
         precopy_remove_notifier(&s->free_page_hint_notify);
     }
     balloon_stats_destroy_timer(s);
Signature · 1 line
MST
#85 lore raw

[PULL 60/90] tests/acpi: x86: Allow IVRS acpi table changes

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

Message-ID: <[email protected]>

---
 tests/qtest/bios-tables-test-allowed-diff.h | 1 +
 1 file changed, 1 insertion(+)
tests/qtest/bios-tables-test-allowed-diff.h +1 -0
index dfb8523c8b..33e9981655 100644
@@ -1 +1,2 @@
 /* List of comma-separated changed AML files to ignore */
+tests/data/acpi/x86/q35/IVRS.ivrs
Signature · 1 line
MST
#86 lore raw

[PULL 07/90] vhost-vsock: don't reset connections during CPR

In reply to Michael S. Tsirkin

From: Andrey Drobyshev <[email protected]>

Migration target with a vhost-vsock device in the .post_load() hook issues VIRTIO_VSOCK_EVENT_TRANSPORT_RESET event to the guest. This results into the guest tearing down all its vsock connections. That reset exists because after a normal migration the cid may change.

However it's not true for CPR-style migration. In this case cid remains the same, and we want the connections to persist. Thus, let's customize the .post_load() hook to skip the common transport reset part in this case.

Message-ID: <[email protected]>

---
 hw/virtio/vhost-vsock.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
hw/virtio/vhost-vsock.c +16 -1
index 503d248a61..c582ac9fcc 100644
@@ -20,6 +20,7 @@
 #include "hw/core/qdev-properties.h"
 #include "hw/virtio/vhost-vsock.h"
 #include "monitor/monitor.h"
+#include "migration/cpr.h"
 #include "migration/blocker.h"
 #include "migration/misc.h"
 
@@ -110,6 +111,20 @@ static uint64_t vhost_vsock_get_features(VirtIODevice *vdev,
     return vhost_vsock_common_get_features(vdev, requested_features, errp);
 }
 
+static int vhost_vsock_post_load(void *opaque, int version_id)
+{
+    /*
+     * Only reset vsock connections for non-CPR migration.  For CPR the
+     * guest cid is unchanged, and the cid-change reset would otherwise
+     * tear the vsock connections down.
+     */
+    if (!cpr_is_incoming()) {
+        return vhost_vsock_common_post_load(opaque, version_id);
+    }
+
+    return 0;
+}
+
 static const VMStateDescription vmstate_virtio_vhost_vsock = {
     .name = "virtio-vhost_vsock",
     .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION,
@@ -119,7 +134,7 @@ static const VMStateDescription vmstate_virtio_vhost_vsock = {
         VMSTATE_END_OF_LIST()
     },
     .pre_save = vhost_vsock_common_pre_save,
-    .post_load = vhost_vsock_common_post_load,
+    .post_load = vhost_vsock_post_load,
 };
 
 static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
Signature · 1 line
MST
#87 lore raw

[PULL 03/90] virtio-pci: reject Q_ENABLE write on already-enabled queue

In reply to Michael S. Tsirkin

When the guest writes 1 to the VIRTIO_PCI_COMMON_Q_ENABLE field of a queue that is already enabled, QEMU re-applies the ring geometry stored in the PCI proxy shadow registers by calling virtio_queue_set_num() and virtio_queue_set_rings(). Those functions update the vring descriptor, available, and used addresses and the region cache, but they do not touch the host-side progress fields - last_avail_idx, shadow_avail_idx, used_idx, inuse, and the packed-ring wrap counters - which are only zeroed by __virtio_queue_reset().

Because the progress indices are stale while the ring layout is new, the host can treat the new ring as though there are up to 65535 pending descriptors already waiting, causing virtqueue_pop() to iterate far beyond what the guest actually posted. On virtio-iommu this translates into a stream of ATTACH/DETACH/MAP/UNMAP commands, driving the QEMU process toward OOM from guest-controlled BAR writes.

The virtio specification requires the driver to complete a full queue reset cycle before re-enabling a queue. Fix this by checking the proxy's per-queue enabled flag before processing the write. If the queue is already enabled, log the violation as a guest error and ignore the write.

Fixes d1060e3dc5 ("virtio-pci: support queue enable")
Cc Kangjie Xu <[email protected]>
---
 hw/virtio/virtio-pci.c | 7 +++++++
 1 file changed, 7 insertions(+)
hw/virtio/virtio-pci.c +7 -0
index 6f5db5fc42..c73f1f546c 100644
@@ -1692,6 +1692,13 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr,
         break;
     case VIRTIO_PCI_COMMON_Q_ENABLE:
         if (val == 1) {
+            if (proxy->vqs[vdev->queue_sel].enabled) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "%s: queue %d already enabled - "
+                              "reset queue before re-enabling\n",
+                              __func__, vdev->queue_sel);
+                break;
+            }
             virtio_queue_set_num(vdev, vdev->queue_sel,
                                  proxy->vqs[vdev->queue_sel].num);
             virtio_queue_set_rings(vdev, vdev->queue_sel,
Signature · 1 line
MST
#88 lore raw

[PULL 59/90] amd_iommu: Return empty efr for stub call

In reply to Michael S. Tsirkin

From: Sairaj Kodilkar <[email protected]>

The stub call should not return normal EFR as it is used as place holder when actual AMD IOMMU calls are not available. Hence return 0.

Message-ID: <[email protected]>

---
 hw/i386/amd_iommu-stub.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/i386/amd_iommu-stub.c +1 -1
index d62a3732e6..fb36dee903 100644
@@ -22,5 +22,5 @@
 
 uint64_t amdvi_extended_feature_register(AMDVIState *s)
 {
-    return AMDVI_DEFAULT_EXT_FEATURES;
+    return 0;
 }
Signature · 1 line
MST
#89 lore raw

[PULL 35/90] vhost-user-gpu: validate command buffer size in submit_3d

In reply to Michael S. Tsirkin

From: Marc-André Lureau <[email protected]>

virgl_cmd_submit_3d() passes the guest-controlled cs.size directly to g_malloc() without any bounds check. A malicious guest can set this field to an arbitrarily large value (up to 4GB), causing an OOM abort that crashes the vhost-user-gpu daemon.

Validate cs.size against the actual descriptor payload size before allocating, rejecting values that exceed what the virtqueue entry can carry.

Fixes d52c454aadc ("contrib: add vhost-user-gpu")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3776

Message-ID: <[email protected]>

---
 contrib/vhost-user-gpu/virgl.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
contrib/vhost-user-gpu/virgl.c +8 -4
index 20bae57d0f..c95c4afc5c 100644
@@ -197,20 +197,24 @@ virgl_cmd_submit_3d(VuGpu *g,
                     struct virtio_gpu_ctrl_command *cmd)
 {
     struct virtio_gpu_cmd_submit cs;
+    size_t iov_len;
     void *buf;
     size_t s;
 
     VUGPU_FILL_CMD(cs);
 
-    if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
-        g_critical("%s: command buffer too large (%u)",
-                   __func__, cs.size);
+    iov_len = iov_size(cmd->elem.out_sg, cmd->elem.out_num);
+    if (cs.size == 0 || iov_len < sizeof(cs) ||
+        cs.size > iov_len - sizeof(cs) ||
+        cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
+        g_critical("%s: size out of range (%u/%zu)",
+                   __func__, cs.size, iov_len);
         cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
         return;
     }
 
     buf = g_try_malloc(cs.size);
-    if (!buf && cs.size) {
+    if (!buf) {
         cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
         return;
     }
Signature · 1 line
MST
#90 lore raw

Re: [PULL 35/90] vhost-user-gpu: validate command buffer size in submit_3d

Thanks Michael for the review. Merci Marc-André!
Let me know if I can support in any ways shape or form in other such work. Best,
Martin Brodeur

Quoted 59 lines · Michael S. Tsirkin

From: Marc-André Lureau <[email protected]>

virgl_cmd_submit_3d() passes the guest-controlled cs.size directly to g_malloc() without any bounds check. A malicious guest can set this field to an arbitrarily large value (up to 4GB), causing an OOM abort that crashes the vhost-user-gpu daemon.

Validate cs.size against the actual descriptor payload size before allocating, rejecting values that exceed what the virtqueue entry can carry.

Fixes d52c454aadc ("contrib: add vhost-user-gpu")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3776

Message-ID: <[email protected]>

---
 contrib/vhost-user-gpu/virgl.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
contrib/vhost-user-gpu/virgl.c +8 -5
index 20bae57d0f..c95c4afc5c 100644
@@ -197,20 +197,24 @@ virgl_cmd_submit_3d(VuGpu *g,
                     struct virtio_gpu_ctrl_command *cmd)
 {
     struct virtio_gpu_cmd_submit cs;
+    size_t iov_len;
     void *buf;
     size_t s;
 
     VUGPU_FILL_CMD(cs);
 
-    if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
-        g_critical("%s: command buffer too large (%u)",
-                   __func__, cs.size);
+    iov_len = iov_size(cmd->elem.out_sg, cmd->elem.out_num);
+    if (cs.size == 0 || iov_len < sizeof(cs) ||
+        cs.size > iov_len - sizeof(cs) ||
+        cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
+        g_critical("%s: size out of range (%u/%zu)",
+                   __func__, cs.size, iov_len);
         cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
         return;
     }
 
     buf = g_try_malloc(cs.size);
-    if (!buf && cs.size) {
+    if (!buf) {
         cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
         return;
     }
--

MST

#91 lore raw

Re: [PULL 35/90] vhost-user-gpu: validate command buffer size in submit_3d

Quoted 4 lines · admin

Thanks Michael for the review. Merci Marc-André!
Let me know if I can support in any ways shape or form in other such work. Best,
Martin Brodeur

Sorry I dropped this for now, I think Marc-André is better suited to merge them.

Quoted 64 lines · Michael S. Tsirkin
Quoted 60 lines

From: Marc-André Lureau <[email protected]>

virgl_cmd_submit_3d() passes the guest-controlled cs.size directly to g_malloc() without any bounds check. A malicious guest can set this field to an arbitrarily large value (up to 4GB), causing an OOM abort that crashes the vhost-user-gpu daemon.

Validate cs.size against the actual descriptor payload size before allocating, rejecting values that exceed what the virtqueue entry can carry.

Fixes d52c454aadc ("contrib: add vhost-user-gpu")

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3776

Message-ID: <[email protected]>

---
 contrib/vhost-user-gpu/virgl.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
contrib/vhost-user-gpu/virgl.c +8 -5
index 20bae57d0f..c95c4afc5c 100644
@@ -197,20 +197,24 @@ virgl_cmd_submit_3d(VuGpu *g,
                     struct virtio_gpu_ctrl_command *cmd)
 {
     struct virtio_gpu_cmd_submit cs;
+    size_t iov_len;
     void *buf;
     size_t s;
 
     VUGPU_FILL_CMD(cs);
 
-    if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
-        g_critical("%s: command buffer too large (%u)",
-                   __func__, cs.size);
+    iov_len = iov_size(cmd->elem.out_sg, cmd->elem.out_num);
+    if (cs.size == 0 || iov_len < sizeof(cs) ||
+        cs.size > iov_len - sizeof(cs) ||
+        cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
+        g_critical("%s: size out of range (%u/%zu)",
+                   __func__, cs.size, iov_len);
         cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
         return;
     }
 
     buf = g_try_malloc(cs.size);
-    if (!buf && cs.size) {
+    if (!buf) {
         cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
         return;
     }
--

MST

#92 lore raw

[PULL 39/90] tests/bios-tables-test: Exclude CEDT.cxl for the CFMW restriction change

In reply to Michael S. Tsirkin

From: Davidlohr Bueso <[email protected]>

The next patch changes the default CXL Fixed Memory Window restrictions, dropping Back-Invalidate. Add CEDT.cxl to the allowed-diff list so the comparison passes until the expected blob is regenerated.

Message-ID: <[email protected]>

---
 tests/qtest/bios-tables-test-allowed-diff.h | 1 +
 1 file changed, 1 insertion(+)
tests/qtest/bios-tables-test-allowed-diff.h +1 -0
index dfb8523c8b..b4646b5b31 100644
@@ -1 +1,2 @@
 /* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/x86/q35/CEDT.cxl",
Signature · 1 line
MST
#93 lore raw
In reply to Michael S. Tsirkin

Hi Michael,

CCing Andrey

Quoted 9 lines · Michael S. Tsirkin

The following changes since commit 1df256f5968e9f7c3c4533a1383b071c044a36d6:

Merge tag 'qom-qapi-pr-pr-v1' of https://gitlab.com/marcandre.lureau/qemu into staging (2026-09-08 18:35:31 +0100)

are available in the Git repository at:

https://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream

Quoted 8 lines

for you to fetch changes up to 99c75c61d61251d98e0b93dd199edbb10a990205:

MAINTAINERS: add Junjie Cao as CXL reviewer (2026-09-10 10:55:03 -0400)

----------------------------------------------------------------
pci, vhost, virtio, iommu, apci: features, fixes

migration/cpr now supports vhost-vsock devices

In the last review we found several issues and Andrey is going to fix them in v5, so IMO is better to remove that series from the pull request.

See
https://lore.kernel.org/qemu-devel/[email protected]/
mainly in patch 5 and 10 IIRC.

Thanks,
Stefano

#94 lore raw
Quoted 18 lines · Stefano Garzarella

Hi Michael,

CCing Andrey

Quoted 13 lines · Michael S. Tsirkin

The following changes since commit 1df256f5968e9f7c3c4533a1383b071c044a36d6:

Merge tag 'qom-qapi-pr-pr-v1' of https://gitlab.com/marcandre.lureau/qemu into staging (2026-09-08 18:35:31 +0100)

are available in the Git repository at:

https://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream

for you to fetch changes up to 99c75c61d61251d98e0b93dd199edbb10a990205:

MAINTAINERS: add Junjie Cao as CXL reviewer (2026-09-10 10:55:03 -0400)

Quoted 8 lines
Quoted 4 lines

----------------------------------------------------------------
pci, vhost, virtio, iommu, apci: features, fixes

migration/cpr now supports vhost-vsock devices

In the last review we found several issues and Andrey is going to fix them in v5, so IMO is better to remove that series from the pull request.

Thanks, will do now.

Quoted 6 lines

See
https://lore.kernel.org/qemu-devel/[email protected]/
mainly in patch 5 and 10 IIRC.

Thanks,
Stefano