From 274a73a7a6425ecb5eabef8d9e6cc0a195cf963b Mon Sep 17 00:00:00 2001 From: Jiabo Feng Date: Tue, 28 Nov 2023 15:57:41 +0800 Subject: [PATCH] QEMU update to version 6.2.0-84(master) - hw/arm/fsl-imx: Do not ignore Error argument - hw/net/cadence_gem.c: spelling fixes: Octects - tests/qtest: check the return value - libvhost-user: Fix VHOST_USER_GET_MAX_MEM_SLOTS reply mainline inclusion commit 69a5daec06f423843ce1bb9be5fb049314996f78 category: bugfix - io_uring: fix short read slow path mainline inclusion commit c06fc7ce147e57ab493bad9263f1601b8298484b category: bugfix - libvhost-user: Fix VHOST_USER_ADD_MEM_REG reply mainline inclusion commit 7f27d20ded2f480f3e66d03f90ea71507b834276 category: bugfix - qsd: Unlink absolute PID file path mainline inclusion commit 9d8f8233b9fa525a7e37350fbc18877051128c5d category: bugfix - net: Fix a misleading error message - vdpa: stop all svq on device deletion - vhost: release virtqueue objects in error path - vhost: fix the fd leak - virtio: i2c: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX - hw/virtio: fix typo in VIRTIO_CONFIG_IRQ_IDX comments - virtio-net: clear guest_announce feature if no cvq backend - vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check - vdpa: do not block migration if device has cvq and x-svq=on - vdpa net: block migration if the device has CVQ - vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mq() - vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mac() - vdpa: fix not using CVQ buffer in case of error - vdpa: Fix possible use-after-free for VirtQueueElement - hw/virtio: fix vhost_user_read tracepoint - vhost: Fix false positive out-of-bounds - vhost: fix possible wrap in SVQ descriptor ring - vhost: move iova_tree set to vhost_svq_start - vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd - virtio-crypto: verify src&dst buffer length for sym request - vdpa: commit all host notifier MRs in a single MR transaction - vdpa: harden the error path if get_iova_range failed - vdpa-dev: get iova range explicitly - virtio-pci: add support for configure interrupt - virtio-mmio: add support for configure interrupt - virtio-net: add support for configure interrupt - vhost: add support for configure interrupt - virtio: add support for configure interrupt - vhost-vdpa: add support for config interrupt - vhost: introduce new VhostOps vhost_set_config_call - virtio-pci: decouple the single vector from the interrupt process - virtio-pci: decouple notifier from interrupt process - virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX - vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa - vdpa: handle VIRTIO_NET_CTRL_ANNOUNCE in vhost_vdpa_net_handle_ctrl_avail - vhost: fix vq dirty bitmap syncing when vIOMMU is enabled - hw/virtio: gracefully handle unset vhost_dev vdev - hw/virtio/vhost: Fix typo in comment. - vdpa: always start CVQ in SVQ mode if possible - vdpa: add shadow_data to vhost_vdpa - vdpa: store x-svq parameter in VhostVDPAState - vdpa: add asid parameter to vhost_vdpa_dma_map/unmap - vdpa: allocate SVQ array unconditionally - vdpa: move SVQ vring features check to net/ - vdpa: request iova_range only once - vdpa: add vhost_vdpa_net_valid_svq_features - vhost: allocate SVQ device file descriptors at device start - vhost: set SVQ device call handler at SVQ start - vdpa: use v->shadow_vqs_enabled in vhost_vdpa_svqs_start & stop - vhost: enable vrings in vhost_dev_start() for vhost-user devices - vhost-vdpa: fix assert !virtio_net_get_subqueue(nc)->async_tx.elem in virtio_net_reset - net/vhost-vdpa.c: Fix clang compilation failure - vhost-vdpa: allow passing opened vhostfd to vhost-vdpa - vdpa: Remove shadow CVQ command check - vdpa: Delete duplicated vdpa_feature_bits entry - hw/virtio: add some vhost-user trace events - vdpa: Allow MQ feature in SVQ - virtio-net: Update virtio-net curr_queue_pairs in vdpa backends - vdpa: validate MQ CVQ commands - vdpa: Add vhost_vdpa_net_load_mq - vdpa: extract vhost_vdpa_net_load_mac from vhost_vdpa_net_load - vdpa: Make VhostVDPAState cvq_cmd_in_buffer control ack type - vdpa: Delete CVQ migration blocker - vdpa: Add virtio-net mac address via CVQ at start - vhost_net: add NetClientState->load() callback - vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail - vdpa: Move command buffers map to start of net device - vdpa: add net_vhost_vdpa_cvq_info NetClientInfo - vhost_net: Add NetClientInfo stop callback - vhost_net: Add NetClientInfo start callback - vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring - vdpa: Make SVQ vring unmapping return void - vdpa: Remove SVQ vring from iova_tree at shutdown - util: accept iova_tree_remove_parameter by value - vdpa: do not save failed dma maps in SVQ iova tree - vdpa: Skip the maps not in the iova tree - vdpa: Fix file descriptor leak on get features error - vdpa: Fix memory listener deletions of iova tree - vhost: Get vring base from vq, not svq - vdpa: Add x-svq to NetdevVhostVDPAOptions - vdpa: Add device migration blocker - vdpa: Extract get features part from vhost_vdpa_get_max_queue_pairs - vdpa: Buffer CVQ support on shadow virtqueue - vdpa: manual forward CVQ buffers - vdpa: Export vhost_vdpa_dma_map and unmap calls - vhost: Add svq avail_handler callback - vhost: add vhost_svq_poll - vhost: Expose vhost_svq_add - vhost: add vhost_svq_push_elem - vhost: Track number of descs in SVQDescState - vhost: Add SVQDescState - vhost: Decouple vhost_svq_add from VirtQueueElement - vhost: Check for queue full at vhost_svq_add - vhost: Move vhost_svq_kick call to vhost_svq_add - vhost: Reorder vhost_svq_kick - vdpa: Avoid compiler to squash reads to used idx - virtio-net: Expose ctrl virtqueue logic - virtio-net: Expose MAC_TABLE_ENTRIES - vhost: move descriptor translation to vhost_svq_vring_write_descs - util: Return void on iova_tree_remove - virtio-net: don't handle mq request in userspace handler for vhost-vdpa - vhost-vdpa: change name and polarity for vhost_vdpa_one_time_request() - vhost-vdpa: backend feature should set only once - vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa - virtio-net: align ctrl_vq index for non-mq guest for vhost_vdpa - virtio: add vhost support for virtio devices - include/hw: start documenting the vhost API - hw/virtio: add vhost_user_[read|write] trace points - vhost: Fix element in vhost_svq_add failure - vdpa: Fix index calculus at vhost_vdpa_svqs_start - vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base - vhost: Fix device's used descriptor dequeue - vhost: Track descriptor chain in private at SVQ - vdpa: Add missing tracing to batch mapping functions - vhost-vdpa: fix typo in a comment - virtio: fix --enable-vhost-user build on non-Linux - vdpa: Expose VHOST_F_LOG_ALL on SVQ - vdpa: Never set log_base addr if SVQ is enabled - vdpa: Adapt vhost_vdpa_get_vring_base to SVQ - vdpa: Add custom IOTLB translations to SVQ - vhost: Add VhostIOVATree - util: add iova_tree_find_iova - util: Add iova_tree_alloc_map - vhost: Shadow virtqueue buffers forwarding - vdpa: adapt vhost_ops callbacks to svq - virtio: Add vhost_svq_get_vring_addr - vhost: Add vhost_svq_valid_features to shadow vq - vhost: Add Shadow VirtQueue call forwarding capabilities - vhost: Add Shadow VirtQueue kick forwarding capabilities - vhost: Add VhostShadowVirtqueue - vdpa: Make ncs autofree - Revert "virtio: introduce macro IRTIO_CONFIG_IRQ_IDX" - Revert "virtio-pci: decouple notifier from interrupt process" - Revert "virtio-pci: decouple the single vector from the interrupt process" - Revert "vhost-vdpa: add support for config interrupt" - Revert "virtio: add support for configure interrupt" - Revert "vhost: add support for configure interrupt" - Revert "virtio-net: add support for configure interrupt" - Revert "virtio-mmio: add support for configure interrupt" - Revert "virtio-pci: add support for configure interrupt" - Revert "vhost: introduce new VhostOps vhost_set_config_call" - virtio: signal after wrapping packed used_idx - target/i386: Adjust feature level according to FEAT_7_1_EDX - target/i386: Add new CPU model GraniteRapids - target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration - target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration - target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration - target/i386: Add support for AVX-IFMA in CPUID enumeration - target/i386: Add support for AMX-FP16 in CPUID enumeration - target/i386: Add support for CMPCCXADD in CPUID enumeration - tracetool: avoid invalid escape in Python string - hw/pvrdma: Protect against buggy or malicious guest driver - vga: avoid crash if no default vga card mainline inclusion commit 6985d8ede92494f3b791de01e8ee9306eb6d5e4a category: bugfix - qom/object: Remove circular include dependency mainline inclusion commit 5bba9bcfbb42e7c016626420e148a1bf1b080835 category: bugfix - artist: set memory region owners for buffers to the artist device mainline inclusion commit 39fbaeca096a9bf6cbe2af88572c1cb2aa62aa8c category: bugfix - virtio-iommu: Fix the partial copy of probe request mainline inclusion commit 45461aace83d961e933b27519b81d17b4c690514 category: bugfix - e1000: set RX descriptor status in a separate operation mainline inclusion commit 034d00d4858161e1d4cff82d8d230bce874a04d3 category: bugfix - vhost: introduce new VhostOps vhost_set_config_call - vhost: stick to -errno error return convention - vhost-user: stick to -errno error return convention - vhost-vdpa: stick to -errno error return convention - virtio-pci: add support for configure interrupt - virtio-mmio: add support for configure interrupt - virtio-net: add support for configure interrupt - vhost: add support for configure interrupt - virtio: add support for configure interrupt - vhost-vdpa: add support for config interrupt - virtio-pci: decouple the single vector from the interrupt process - virtio-pci: decouple notifier from interrupt process - virtio: introduce macro IRTIO_CONFIG_IRQ_IDX - pci: Fix the update of interrupt disable bit in PCI_COMMAND register - hw/timer/npcm7xx_timer: Prevent timer from counting down past zero - tpm_crb: mark command buffer as dirty on request completion mainline inclusion commit e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 category: bugfix - pci: fix overflow in snprintf string formatting mainline inclusion commit 36f18c6989a3d1ff1d7a0e50b0868ef3958299b4 category: bugfix - hw/usb/hcd-ehci: fix writeback order mainline inclusion commit f471e8b060798f26a7fc339c6152f82f22a7b33d category: bugfix - qemu-timer: Skip empty timer lists before locking in qemu_clock_deadline_ns_all mainline inclusion commit 3f42906c9ab2c777a895b48b87b8107167e4a275 category: bugfix - semihosting/config: Merge --semihosting-config option groups mainline inclusion commit 90c072e063737e9e8f431489bbd334452f89056e category: bugfix - semihosting: fix memleak at semihosting_arg_fallback - target/i386: Export GDS_NO bit to guests Signed-off-by: Jiabo Feng (cherry picked from commit 946c69b8875ed50024bc4bab1bed8c4c0cac2ac3) --- ...-add-support-for-configure-interrupt.patch | 163 +++ ...roduce-new-VhostOps-vhost_set_config.patch | 36 + ...dpa-add-support-for-config-interrupt.patch | 56 + ...-add-support-for-configure-interrupt.patch | 101 ++ ...introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch | 161 +++ ...io-add-support-for-configure-interru.patch | 64 + ...t-add-support-for-configure-interrup.patch | 52 + ...i-add-support-for-configure-interrup.patch | 215 ++++ ...i-decouple-notifier-from-interrupt-p.patch | 255 ++++ ...i-decouple-the-single-vector-from-th.patch | 192 +++ ...y-region-owners-for-buffers-to-the-a.patch | 37 + ...criptor-status-in-a-separate-operati.patch | 89 ++ ...fsl-imx-Do-not-ignore-Error-argument.patch | 62 + ...cadence_gem.c-spelling-fixes-Octects.patch | 39 + ...inst-buggy-or-malicious-guest-driver.patch | 65 + ..._timer-Prevent-timer-from-counting-d.patch | 38 + hw-usb-hcd-ehci-fix-writeback-order.patch | 64 + ...tio-add-some-vhost-user-trace-events.patch | 70 ++ ...-vhost_user_-read-write-trace-points.patch | 62 + ...po-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch | 135 ++ ...irtio-fix-vhost_user_read-tracepoint.patch | 48 + ...acefully-handle-unset-vhost_dev-vdev.patch | 52 + hw-virtio-vhost-Fix-typo-in-comment.patch | 34 + ...e-hw-start-documenting-the-vhost-API.patch | 192 +++ io_uring-fix-short-read-slow-path.patch | 55 + ...ser-Fix-VHOST_USER_ADD_MEM_REG-reply.patch | 48 + ...x-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch | 53 + net-Fix-a-misleading-error-message.patch | 50 + ...vdpa.c-Fix-clang-compilation-failure.patch | 62 + ...te-of-interrupt-disable-bit-in-PCI_C.patch | 53 + ...erflow-in-snprintf-string-formatting.patch | 106 ++ ...empty-timer-lists-before-locking-in-.patch | 39 + qemu.spec | 376 +++++- ...t-Remove-circular-include-dependency.patch | 41 + qsd-Unlink-absolute-PID-file-path.patch | 81 ++ ...ig-Merge-semihosting-config-option-g.patch | 54 + ...-memleak-at-semihosting_arg_fallback.patch | 47 + ...i386-Add-new-CPU-model-GraniteRapids.patch | 183 +++ ...support-for-AMX-FP16-in-CPUID-enumer.patch | 62 + ...support-for-AVX-IFMA-in-CPUID-enumer.patch | 60 + ...support-for-AVX-NE-CONVERT-in-CPUID-.patch | 62 + ...support-for-AVX-VNNI-INT8-in-CPUID-e.patch | 110 ++ ...support-for-CMPCCXADD-in-CPUID-enume.patch | 61 + ...support-for-PREFETCHIT0-1-in-CPUID-e.patch | 61 + ...st-feature-level-according-to-FEAT_7.patch | 46 + target-i386-Export-GDS_NO-bit-to-guests.patch | 46 + tests-qtest-check-the-return-value.patch | 62 + ...mand-buffer-as-dirty-on-request-comp.patch | 43 + ...void-invalid-escape-in-Python-string.patch | 38 + util-Add-iova_tree_alloc_map.patch | 219 ++++ util-Return-void-on-iova_tree_remove.patch | 61 + ...-iova_tree_remove_parameter-by-value.patch | 173 +++ util-add-iova_tree_find_iova.patch | 116 ++ ...apt-vhost_vdpa_get_vring_base-to-SVQ.patch | 59 + ...Add-custom-IOTLB-translations-to-SVQ.patch | 415 +++++++ vdpa-Add-device-migration-blocker.patch | 87 ++ ...g-tracing-to-batch-mapping-functions.patch | 58 + vdpa-Add-vhost_vdpa_net_load_mq.patch | 65 + ...tio-net-mac-address-via-CVQ-at-start.patch | 78 ++ ...-Add-x-svq-to-NetdevVhostVDPAOptions.patch | 208 ++++ vdpa-Allow-MQ-feature-in-SVQ.patch | 32 + ...compiler-to-squash-reads-to-used-idx.patch | 46 + ...ffer-CVQ-support-on-shadow-virtqueue.patch | 305 +++++ vdpa-Delete-CVQ-migration-blocker.patch | 89 ++ ...e-duplicated-vdpa_feature_bits-entry.patch | 34 + ...t-vhost_vdpa_dma_map-and-unmap-calls.patch | 65 + vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch | 120 ++ ...-features-part-from-vhost_vdpa_get_m.patch | 89 ++ ...ex-calculus-at-vhost_vdpa_get_vring_.patch | 41 + ...escriptor-leak-on-get-features-error.patch | 50 + ...ex-calculus-at-vhost_vdpa_svqs_start.patch | 37 + ...mory-listener-deletions-of-iova-tree.patch | 53 + ...e-use-after-free-for-VirtQueueElemen.patch | 63 + ...Make-SVQ-vring-unmapping-return-void.patch | 124 ++ ...DPAState-cvq_cmd_in_buffer-control-a.patch | 103 ++ vdpa-Make-ncs-autofree.patch | 54 + ...d-buffers-map-to-start-of-net-device.patch | 242 ++++ ...-set-log_base-addr-if-SVQ-is-enabled.patch | 36 + ...SVQ-vring-from-iova_tree-at-shutdown.patch | 40 + vdpa-Remove-shadow-CVQ-command-check.patch | 94 ++ ...evice-ack-is-VIRTIO_NET_ERR-in-_-new.patch | 63 + ...if-device-ack-is-VIRTIO_NET_ERR-in-_.patch | 62 + vdpa-Skip-the-maps-not-in-the-iova-tree.patch | 39 + ...-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch | 70 ++ vdpa-adapt-vhost_ops-callbacks-to-svq.patch | 104 ++ ...arameter-to-vhost_vdpa_dma_map-unmap.patch | 227 ++++ ...et_vhost_vdpa_cvq_info-NetClientInfo.patch | 53 + vdpa-add-shadow_data-to-vhost_vdpa.patch | 86 ++ ...dd-vhost_vdpa_net_valid_svq_features.patch | 68 + vdpa-allocate-SVQ-array-unconditionally.patch | 42 + ...ys-start-CVQ-in-SVQ-mode-if-possible.patch | 224 ++++ ...host-notifier-MRs-in-a-single-MR-tra.patch | 79 ++ vdpa-dev-get-iova-range-explicitly.patch | 104 ++ ...k-migration-if-device-has-cvq-and-x-.patch | 52 + ...le-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch | 35 + ...ave-failed-dma-maps-in-SVQ-iova-tree.patch | 74 ++ ...st_vdpa_net_cvq_add-from-vhost_vdpa_.patch | 144 +++ ...st_vdpa_net_load_mac-from-vhost_vdpa.patch | 106 ++ ...HOST_BACKEND_F_IOTLB_ASID-flag-check.patch | 38 + ...ot-using-CVQ-buffer-in-case-of-error.patch | 39 + ...IO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch | 51 + ...-error-path-if-get_iova_range-failed.patch | 39 + vdpa-manual-forward-CVQ-buffers.patch | 146 +++ ...move-SVQ-vring-features-check-to-net.patch | 110 ++ ...lock-migration-if-the-device-has-CVQ.patch | 70 ++ vdpa-request-iova_range-only-once.patch | 137 ++ vdpa-stop-all-svq-on-device-deletion.patch | 73 ++ ...re-x-svq-parameter-in-VhostVDPAState.patch | 54 + ...w_vqs_enabled-in-vhost_vdpa_svqs_sta.patch | 50 + vdpa-validate-MQ-CVQ-commands.patch | 41 + vga-avoid-crash-if-no-default-vga-card.patch | 41 + vhost-Add-SVQDescState.patch | 116 ++ ...-VirtQueue-call-forwarding-capabilit.patch | 168 +++ ...-VirtQueue-kick-forwarding-capabilit.patch | 395 ++++++ vhost-Add-VhostIOVATree.patch | 200 +++ vhost-Add-VhostShadowVirtqueue.patch | 147 +++ vhost-Add-svq-avail_handler-callback.patch | 145 +++ ...host_svq_valid_features-to-shadow-vq.patch | 133 ++ ...re-new-kick-fd-on-vhost_svq_set_svq_.patch | 57 + ...heck-for-queue-full-at-vhost_svq_add.patch | 115 ++ ...-vhost_svq_add-from-VirtQueueElement.patch | 119 ++ vhost-Expose-vhost_svq_add.patch | 54 + ...Fix-device-s-used-descriptor-dequeue.patch | 64 + ...Fix-element-in-vhost_svq_add-failure.patch | 49 + vhost-Fix-false-positive-out-of-bounds.patch | 49 + vhost-Get-vring-base-from-vq-not-svq.patch | 78 ++ ...vhost_svq_kick-call-to-vhost_svq_add.patch | 42 + vhost-Reorder-vhost_svq_kick.patch | 69 ++ ...-Shadow-virtqueue-buffers-forwarding.patch | 684 ++++++++++ ...k-descriptor-chain-in-private-at-SVQ.patch | 104 ++ ...rack-number-of-descs-in-SVQDescState.patch | 62 + ...-support-for-configure-interrupt-new.patch | 172 +++ ...-add-support-for-configure-interrupt.patch | 170 +++ vhost-add-vhost_svq_poll.patch | 73 ++ vhost-add-vhost_svq_push_elem.patch | 64 + ...VQ-device-file-descriptors-at-device.patch | 162 +++ ...ngs-in-vhost_dev_start-for-vhost-use.patch | 453 +++++++ ...possible-wrap-in-SVQ-descriptor-ring.patch | 108 ++ vhost-fix-the-fd-leak.patch | 37 + ...ty-bitmap-syncing-when-vIOMMU-is-ena.patch | 143 +++ ...w-VhostOps-vhost_set_config_call-new.patch | 42 + ...e-new-VhostOps-vhost_set_config_call.patch | 41 + ...iptor-translation-to-vhost_svq_vring.patch | 101 ++ ...ove-iova_tree-set-to-vhost_svq_start.patch | 114 ++ ...ease-virtqueue-objects-in-error-path.patch | 39 + ...SVQ-device-call-handler-at-SVQ-start.patch | 65 + ...ick-to-errno-error-return-convention.patch | 349 ++++++ ...ick-to-errno-error-return-convention.patch | 1100 +++++++++++++++++ ...add-support-for-config-interrupt-new.patch | 62 + ...dpa-add-support-for-config-interrupt.patch | 59 + ...-passing-opened-vhostfd-to-vhost-vdp.patch | 114 ++ ...backend-feature-should-set-only-once.patch | 49 + ...e-name-and-polarity-for-vhost_vdpa_o.patch | 111 ++ ...ssert-virtio_net_get_subqueue-nc-asy.patch | 75 ++ ...mproper-cleanup-in-net_init_vhost_vd.patch | 36 + vhost-vdpa-fix-typo-in-a-comment.patch | 35 + ...ick-to-errno-error-return-convention.patch | 107 ++ ...net-Add-NetClientInfo-start-callback.patch | 64 + ..._net-Add-NetClientInfo-stop-callback.patch | 59 + ...net-add-NetClientState-load-callback.patch | 64 + virtio-Add-vhost_svq_get_vring_addr.patch | 96 ++ ...-support-for-configure-interrupt-new.patch | 102 ++ ...-add-support-for-configure-interrupt.patch | 106 ++ ...add-vhost-support-for-virtio-devices.patch | 336 +++++ ...rc-dst-buffer-length-for-sym-request.patch | 46 + ...enable-vhost-user-build-on-non-Linux.patch | 39 + ...-notifier-helpers-for-VIRTIO_CONFIG_.patch | 55 + ...introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch | 166 +++ ...ntroduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch | 227 ++++ ...ix-the-partial-copy-of-probe-request.patch | 60 + ...-support-for-configure-interrupt-new.patch | 67 + ...-add-support-for-configure-interrupt.patch | 66 + virtio-net-Expose-MAC_TABLE_ENTRIES.patch | 50 + virtio-net-Expose-ctrl-virtqueue-logic.patch | 149 +++ ...e-virtio-net-curr_queue_pairs-in-vdp.patch | 53 + ...-support-for-configure-interrupt-new.patch | 102 ++ ...-add-support-for-configure-interrupt.patch | 56 + ...-ctrl_vq-index-for-non-mq-guest-for-.patch | 131 ++ ...-guest_announce-feature-if-no-cvq-ba.patch | 67 + ...-handle-mq-request-in-userspace-hand.patch | 97 ++ ...-support-for-configure-interrupt-new.patch | 261 ++++ ...-add-support-for-configure-interrupt.patch | 218 ++++ ...-notifier-from-interrupt-process-new.patch | 259 ++++ ...uple-notifier-from-interrupt-process.patch | 259 ++++ ...the-single-vector-from-the-inter-new.patch | 198 +++ ...ple-the-single-vector-from-the-inter.patch | 196 +++ ...ignal-after-wrapping-packed-used_idx.patch | 51 + 187 files changed, 20388 insertions(+), 1 deletion(-) create mode 100644 Revert-vhost-add-support-for-configure-interrupt.patch create mode 100644 Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch create mode 100644 Revert-vhost-vdpa-add-support-for-config-interrupt.patch create mode 100644 Revert-virtio-add-support-for-configure-interrupt.patch create mode 100644 Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch create mode 100644 Revert-virtio-mmio-add-support-for-configure-interru.patch create mode 100644 Revert-virtio-net-add-support-for-configure-interrup.patch create mode 100644 Revert-virtio-pci-add-support-for-configure-interrup.patch create mode 100644 Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch create mode 100644 Revert-virtio-pci-decouple-the-single-vector-from-th.patch create mode 100644 artist-set-memory-region-owners-for-buffers-to-the-a.patch create mode 100644 e1000-set-RX-descriptor-status-in-a-separate-operati.patch create mode 100644 hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch create mode 100644 hw-net-cadence_gem.c-spelling-fixes-Octects.patch create mode 100644 hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch create mode 100644 hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch create mode 100644 hw-usb-hcd-ehci-fix-writeback-order.patch create mode 100644 hw-virtio-add-some-vhost-user-trace-events.patch create mode 100644 hw-virtio-add-vhost_user_-read-write-trace-points.patch create mode 100644 hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch create mode 100644 hw-virtio-fix-vhost_user_read-tracepoint.patch create mode 100644 hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch create mode 100644 hw-virtio-vhost-Fix-typo-in-comment.patch create mode 100644 include-hw-start-documenting-the-vhost-API.patch create mode 100644 io_uring-fix-short-read-slow-path.patch create mode 100644 libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch create mode 100644 libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch create mode 100644 net-Fix-a-misleading-error-message.patch create mode 100644 net-vhost-vdpa.c-Fix-clang-compilation-failure.patch create mode 100644 pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch create mode 100644 pci-fix-overflow-in-snprintf-string-formatting.patch create mode 100644 qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch create mode 100644 qom-object-Remove-circular-include-dependency.patch create mode 100644 qsd-Unlink-absolute-PID-file-path.patch create mode 100644 semihosting-config-Merge-semihosting-config-option-g.patch create mode 100644 semihosting-fix-memleak-at-semihosting_arg_fallback.patch create mode 100644 target-i386-Add-new-CPU-model-GraniteRapids.patch create mode 100644 target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch create mode 100644 target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch create mode 100644 target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch create mode 100644 target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch create mode 100644 target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch create mode 100644 target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch create mode 100644 target-i386-Adjust-feature-level-according-to-FEAT_7.patch create mode 100644 target-i386-Export-GDS_NO-bit-to-guests.patch create mode 100644 tests-qtest-check-the-return-value.patch create mode 100644 tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch create mode 100644 tracetool-avoid-invalid-escape-in-Python-string.patch create mode 100644 util-Add-iova_tree_alloc_map.patch create mode 100644 util-Return-void-on-iova_tree_remove.patch create mode 100644 util-accept-iova_tree_remove_parameter-by-value.patch create mode 100644 util-add-iova_tree_find_iova.patch create mode 100644 vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch create mode 100644 vdpa-Add-custom-IOTLB-translations-to-SVQ.patch create mode 100644 vdpa-Add-device-migration-blocker.patch create mode 100644 vdpa-Add-missing-tracing-to-batch-mapping-functions.patch create mode 100644 vdpa-Add-vhost_vdpa_net_load_mq.patch create mode 100644 vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch create mode 100644 vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch create mode 100644 vdpa-Allow-MQ-feature-in-SVQ.patch create mode 100644 vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch create mode 100644 vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch create mode 100644 vdpa-Delete-CVQ-migration-blocker.patch create mode 100644 vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch create mode 100644 vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch create mode 100644 vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch create mode 100644 vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch create mode 100644 vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch create mode 100644 vdpa-Fix-file-descriptor-leak-on-get-features-error.patch create mode 100644 vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch create mode 100644 vdpa-Fix-memory-listener-deletions-of-iova-tree.patch create mode 100644 vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch create mode 100644 vdpa-Make-SVQ-vring-unmapping-return-void.patch create mode 100644 vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch create mode 100644 vdpa-Make-ncs-autofree.patch create mode 100644 vdpa-Move-command-buffers-map-to-start-of-net-device.patch create mode 100644 vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch create mode 100644 vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch create mode 100644 vdpa-Remove-shadow-CVQ-command-check.patch create mode 100644 vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch create mode 100644 vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch create mode 100644 vdpa-Skip-the-maps-not-in-the-iova-tree.patch create mode 100644 vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch create mode 100644 vdpa-adapt-vhost_ops-callbacks-to-svq.patch create mode 100644 vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch create mode 100644 vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch create mode 100644 vdpa-add-shadow_data-to-vhost_vdpa.patch create mode 100644 vdpa-add-vhost_vdpa_net_valid_svq_features.patch create mode 100644 vdpa-allocate-SVQ-array-unconditionally.patch create mode 100644 vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch create mode 100644 vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch create mode 100644 vdpa-dev-get-iova-range-explicitly.patch create mode 100644 vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch create mode 100644 vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch create mode 100644 vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch create mode 100644 vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch create mode 100644 vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch create mode 100644 vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch create mode 100644 vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch create mode 100644 vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch create mode 100644 vdpa-harden-the-error-path-if-get_iova_range-failed.patch create mode 100644 vdpa-manual-forward-CVQ-buffers.patch create mode 100644 vdpa-move-SVQ-vring-features-check-to-net.patch create mode 100644 vdpa-net-block-migration-if-the-device-has-CVQ.patch create mode 100644 vdpa-request-iova_range-only-once.patch create mode 100644 vdpa-stop-all-svq-on-device-deletion.patch create mode 100644 vdpa-store-x-svq-parameter-in-VhostVDPAState.patch create mode 100644 vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch create mode 100644 vdpa-validate-MQ-CVQ-commands.patch create mode 100644 vga-avoid-crash-if-no-default-vga-card.patch create mode 100644 vhost-Add-SVQDescState.patch create mode 100644 vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch create mode 100644 vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch create mode 100644 vhost-Add-VhostIOVATree.patch create mode 100644 vhost-Add-VhostShadowVirtqueue.patch create mode 100644 vhost-Add-svq-avail_handler-callback.patch create mode 100644 vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch create mode 100644 vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch create mode 100644 vhost-Check-for-queue-full-at-vhost_svq_add.patch create mode 100644 vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch create mode 100644 vhost-Expose-vhost_svq_add.patch create mode 100644 vhost-Fix-device-s-used-descriptor-dequeue.patch create mode 100644 vhost-Fix-element-in-vhost_svq_add-failure.patch create mode 100644 vhost-Fix-false-positive-out-of-bounds.patch create mode 100644 vhost-Get-vring-base-from-vq-not-svq.patch create mode 100644 vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch create mode 100644 vhost-Reorder-vhost_svq_kick.patch create mode 100644 vhost-Shadow-virtqueue-buffers-forwarding.patch create mode 100644 vhost-Track-descriptor-chain-in-private-at-SVQ.patch create mode 100644 vhost-Track-number-of-descs-in-SVQDescState.patch create mode 100644 vhost-add-support-for-configure-interrupt-new.patch create mode 100644 vhost-add-support-for-configure-interrupt.patch create mode 100644 vhost-add-vhost_svq_poll.patch create mode 100644 vhost-add-vhost_svq_push_elem.patch create mode 100644 vhost-allocate-SVQ-device-file-descriptors-at-device.patch create mode 100644 vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch create mode 100644 vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch create mode 100644 vhost-fix-the-fd-leak.patch create mode 100644 vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch create mode 100644 vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch create mode 100644 vhost-introduce-new-VhostOps-vhost_set_config_call.patch create mode 100644 vhost-move-descriptor-translation-to-vhost_svq_vring.patch create mode 100644 vhost-move-iova_tree-set-to-vhost_svq_start.patch create mode 100644 vhost-release-virtqueue-objects-in-error-path.patch create mode 100644 vhost-set-SVQ-device-call-handler-at-SVQ-start.patch create mode 100644 vhost-stick-to-errno-error-return-convention.patch create mode 100644 vhost-user-stick-to-errno-error-return-convention.patch create mode 100644 vhost-vdpa-add-support-for-config-interrupt-new.patch create mode 100644 vhost-vdpa-add-support-for-config-interrupt.patch create mode 100644 vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch create mode 100644 vhost-vdpa-backend-feature-should-set-only-once.patch create mode 100644 vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch create mode 100644 vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch create mode 100644 vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch create mode 100644 vhost-vdpa-fix-typo-in-a-comment.patch create mode 100644 vhost-vdpa-stick-to-errno-error-return-convention.patch create mode 100644 vhost_net-Add-NetClientInfo-start-callback.patch create mode 100644 vhost_net-Add-NetClientInfo-stop-callback.patch create mode 100644 vhost_net-add-NetClientState-load-callback.patch create mode 100644 virtio-Add-vhost_svq_get_vring_addr.patch create mode 100644 virtio-add-support-for-configure-interrupt-new.patch create mode 100644 virtio-add-support-for-configure-interrupt.patch create mode 100644 virtio-add-vhost-support-for-virtio-devices.patch create mode 100644 virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch create mode 100644 virtio-fix-enable-vhost-user-build-on-non-Linux.patch create mode 100644 virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch create mode 100644 virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch create mode 100644 virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch create mode 100644 virtio-iommu-Fix-the-partial-copy-of-probe-request.patch create mode 100644 virtio-mmio-add-support-for-configure-interrupt-new.patch create mode 100644 virtio-mmio-add-support-for-configure-interrupt.patch create mode 100644 virtio-net-Expose-MAC_TABLE_ENTRIES.patch create mode 100644 virtio-net-Expose-ctrl-virtqueue-logic.patch create mode 100644 virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch create mode 100644 virtio-net-add-support-for-configure-interrupt-new.patch create mode 100644 virtio-net-add-support-for-configure-interrupt.patch create mode 100644 virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch create mode 100644 virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch create mode 100644 virtio-net-don-t-handle-mq-request-in-userspace-hand.patch create mode 100644 virtio-pci-add-support-for-configure-interrupt-new.patch create mode 100644 virtio-pci-add-support-for-configure-interrupt.patch create mode 100644 virtio-pci-decouple-notifier-from-interrupt-process-new.patch create mode 100644 virtio-pci-decouple-notifier-from-interrupt-process.patch create mode 100644 virtio-pci-decouple-the-single-vector-from-the-inter-new.patch create mode 100644 virtio-pci-decouple-the-single-vector-from-the-inter.patch create mode 100644 virtio-signal-after-wrapping-packed-used_idx.patch diff --git a/Revert-vhost-add-support-for-configure-interrupt.patch b/Revert-vhost-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..e330692 --- /dev/null +++ b/Revert-vhost-add-support-for-configure-interrupt.patch @@ -0,0 +1,163 @@ +From 529074fd45a543a9259441e02652c3ac60673d07 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:53:34 +0800 +Subject: [PATCH] Revert "vhost: add support for configure interrupt" + +This reverts commit f7220a7ce21604a4bc6260ccca4dc9068c1f27f2. + +Fixes: f7220a7ce2 ("vhost: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 76 --------------------------------------- + include/hw/virtio/vhost.h | 4 --- + 2 files changed, 80 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index caa53443ab..2f9bb96d63 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1581,67 +1581,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + } + } + +-bool vhost_config_pending(struct vhost_dev *hdev) +-{ +- assert(hdev->vhost_ops); +- if ((hdev->started == false) || +- (hdev->vhost_ops->vhost_set_config_call == NULL)) { +- return false; +- } +- +- EventNotifier *notifier = +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; +- return event_notifier_test_and_clear(notifier); +-} +- +-void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) +-{ +- int fd; +- int r; +- EventNotifier *notifier = +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; +- EventNotifier *config_notifier = &vdev->config_notifier; +- assert(hdev->vhost_ops); +- +- if ((hdev->started == false) || +- (hdev->vhost_ops->vhost_set_config_call == NULL)) { +- return; +- } +- if (mask) { +- assert(vdev->use_guest_notifier_mask); +- fd = event_notifier_get_fd(notifier); +- } else { +- fd = event_notifier_get_fd(config_notifier); +- } +- r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); +- if (r < 0) { +- VHOST_OPS_DEBUG(r, "vhost_set_config_call failed"); +- } +-} +- +-static void vhost_stop_config_intr(struct vhost_dev *dev) +-{ +- int fd = -1; +- assert(dev->vhost_ops); +- if (dev->vhost_ops->vhost_set_config_call) { +- dev->vhost_ops->vhost_set_config_call(dev, fd); +- } +-} +- +-static void vhost_start_config_intr(struct vhost_dev *dev) +-{ +- int r; +- +- assert(dev->vhost_ops); +- int fd = event_notifier_get_fd(&dev->vdev->config_notifier); +- if (dev->vhost_ops->vhost_set_config_call) { +- r = dev->vhost_ops->vhost_set_config_call(dev, fd); +- if (!r) { +- event_notifier_set(&dev->vdev->config_notifier); +- } +- } +-} +- + uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features) + { +@@ -1854,16 +1793,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + +- r = event_notifier_init( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); +- if (r < 0) { +- return r; +- } +- event_notifier_test_and_clear( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +- if (!vdev->use_guest_notifier_mask) { +- vhost_config_mask(hdev, vdev, true); +- } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1896,7 +1825,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } +- vhost_start_config_intr(hdev); + return 0; + fail_log: + vhost_log_put(hdev, false); +@@ -1922,9 +1850,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); +- event_notifier_test_and_clear( +- &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +- event_notifier_test_and_clear(&vdev->config_notifier); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); +@@ -1942,7 +1867,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + memory_listener_unregister(&hdev->iommu_listener); + } +- vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + hdev->vdev = NULL; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 2ae5c3bfd8..86f36f0106 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -29,7 +29,6 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; +- EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -38,7 +37,6 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) +-#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -118,8 +116,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +-bool vhost_config_pending(struct vhost_dev *hdev); +-void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. +-- +2.27.0 + diff --git a/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch b/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch new file mode 100644 index 0000000..7a33b47 --- /dev/null +++ b/Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch @@ -0,0 +1,36 @@ +From 0ad1ce1ff54a4d654c00e4a3b95361b519f4fd37 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:43:37 +0800 +Subject: [PATCH] Revert "vhost: introduce new VhostOps vhost_set_config_call" + +This reverts commit af8377d0e9437401ad30d80a27ab1fcf8252fad1. + +Signed-off-by: fangyi +--- + include/hw/virtio/vhost-backend.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index bd1c7dfe4f..a64708f456 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,8 +125,6 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); +-typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, +- int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -175,7 +173,6 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; +- vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/Revert-vhost-vdpa-add-support-for-config-interrupt.patch b/Revert-vhost-vdpa-add-support-for-config-interrupt.patch new file mode 100644 index 0000000..725ea3b --- /dev/null +++ b/Revert-vhost-vdpa-add-support-for-config-interrupt.patch @@ -0,0 +1,56 @@ +From 92df45517567838512512f093f418067c857e8dc Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:58:20 +0800 +Subject: [PATCH] Revert "vhost-vdpa: add support for config interrupt" + +This reverts commit 634f7c89fbd78f57d00d5d6b39c0ade9df1fe27f. + +Fixes: 634f7c89fb ("vhost-vdpa: add support for config interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 - + hw/virtio/vhost-vdpa.c | 7 ------- + 2 files changed, 8 deletions(-) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 39c36ff7a6..650e521e35 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -53,7 +53,6 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 +-vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d8fba0b714..25a2f570a2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -737,12 +737,6 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } +-static int vhost_vdpa_set_config_call(struct vhost_dev *dev, +- int fd) +-{ +- trace_vhost_vdpa_set_config_call(dev, fd); +- return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); +-} + + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) +@@ -823,7 +817,6 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, +- .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/Revert-virtio-add-support-for-configure-interrupt.patch b/Revert-virtio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..41dfe16 --- /dev/null +++ b/Revert-virtio-add-support-for-configure-interrupt.patch @@ -0,0 +1,101 @@ +From 3ee9abc7cdd10ccb7057a523326fec21fb01a7bb Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:55:19 +0800 +Subject: [PATCH] Revert "virtio: add support for configure interrupt" + +This reverts commit 081f864f56307551f59c5e934e3f30a7290d0faa. + +Fixes: 081f864f56 ("virtio: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 ----------------------------- + include/hw/virtio/virtio.h | 4 ---- + 2 files changed, 33 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 05409b84d1..c1497f59aa 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3547,14 +3547,7 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } +-static void virtio_config_guest_notifier_read(EventNotifier *n) +-{ +- VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + +- if (event_notifier_test_and_clear(n)) { +- virtio_notify_config(vdev); +- } +-} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3571,23 +3564,6 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + +-void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, +- bool assign, bool with_irqfd) +-{ +- EventNotifier *n; +- n = &vdev->config_notifier; +- if (assign && !with_irqfd) { +- event_notifier_set_handler(n, virtio_config_guest_notifier_read); +- } else { +- event_notifier_set_handler(n, NULL); +- } +- if (!assign) { +- /* Test and clear notifier before closing it,*/ +- /* in case poll callback didn't have time to run. */ +- virtio_config_guest_notifier_read(n); +- } +-} +- + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3661,11 +3637,6 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + +-EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) +-{ +- return &vdev->config_notifier; +-} +- + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 8788ccd1f3..c113a5b864 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -112,7 +112,6 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; +- EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -316,14 +315,11 @@ uint16_t virtio_get_queue_index(VirtQueue *vq); + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd); +-void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, +- bool assign, bool with_irqfd); + int virtio_device_start_ioeventfd(VirtIODevice *vdev); + int virtio_device_grab_ioeventfd(VirtIODevice *vdev); + void virtio_device_release_ioeventfd(VirtIODevice *vdev); + bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); + EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); +-EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); + void virtio_queue_host_notifier_read(EventNotifier *n); + void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, +-- +2.27.0 + diff --git a/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch b/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000..b87ac13 --- /dev/null +++ b/Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,161 @@ +From 01e4e3aa5f2e2e44b72e81e76a74821edf2debd3 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:05:16 +0800 +Subject: [PATCH] Revert "virtio: introduce macro IRTIO_CONFIG_IRQ_IDX" + +This reverts commit bf1d85c166c19af95dbd27b1faba1d2909732323. + +Fixes: bf1d85c166 ("virtio: introduce macro IRTIO_CONFIG_IRQ_IDX") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 6 ------ + hw/net/virtio-net.c | 10 ++-------- + hw/virtio/vhost-user-fs.c | 6 ------ + hw/virtio/vhost-vsock-common.c | 6 ------ + hw/virtio/virtio-crypto.c | 6 ------ + include/hw/virtio/virtio.h | 3 --- + 6 files changed, 2 insertions(+), 35 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 73ad3d84c9..49df56cd14 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,9 +485,6 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -496,9 +493,6 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 7537f44d10..3bd786cc22 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3195,9 +3195,6 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3207,11 +3204,8 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } +- +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), ++ vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 90c2bc9c5d..fc7dcc96ef 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,9 +161,6 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -171,9 +168,6 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index b1f0d46209..ed706681ac 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,9 +125,6 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -136,9 +133,6 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 52ba34ef1e..274c7b4dea 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,9 +953,6 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return; +- } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -966,9 +963,6 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + +- if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; +- } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index c113a5b864..7472145821 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -68,9 +68,6 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + +-/* special index value used internally for config irqs */ +-#define VIRTIO_CONFIG_IRQ_IDX -1 +- + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/Revert-virtio-mmio-add-support-for-configure-interru.patch b/Revert-virtio-mmio-add-support-for-configure-interru.patch new file mode 100644 index 0000000..b87a979 --- /dev/null +++ b/Revert-virtio-mmio-add-support-for-configure-interru.patch @@ -0,0 +1,64 @@ +From 9633634fe4395000e88c8ab829ec756c7132d3bf Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:48:17 +0800 +Subject: [PATCH] Revert "virtio-mmio: add support for configure interrupt" + +This reverts commit d48185f1a40d4e4ed2fa2873a42b2a5eb8748256. + +Fixes: d48185f1a4 ("virtio-mmio: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 --------------------------- + 1 file changed, 27 deletions(-) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 809132018b..72da12fea5 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,30 +673,7 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } +-static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign) +-{ +- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- bool with_irqfd = false; +- EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); +- int r = 0; + +- if (assign) { +- r = event_notifier_init(notifier, 0); +- if (r < 0) { +- return r; +- } +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- } else { +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- event_notifier_cleanup(notifier); +- } +- if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { +- vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); +- } +- return r; +-} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -718,10 +695,6 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } +- r = virtio_mmio_set_config_guest_notifier(d, assign); +- if (r < 0) { +- goto assign_error; +- } + + return 0; + +-- +2.27.0 + diff --git a/Revert-virtio-net-add-support-for-configure-interrup.patch b/Revert-virtio-net-add-support-for-configure-interrup.patch new file mode 100644 index 0000000..845af47 --- /dev/null +++ b/Revert-virtio-net-add-support-for-configure-interrup.patch @@ -0,0 +1,52 @@ +From 4f6f9e62214a008523b054c82d663d14d82a2c86 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:50:43 +0800 +Subject: [PATCH] Revert "virtio-net: add support for configure interrupt" + +This reverts commit 497679d51087090d5a22fd265d1b96cf92d49d9d. + +Fixes: 497679d510 ("virtio-net: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 9 --------- + include/net/vhost_net.h | 2 -- + 2 files changed, 11 deletions(-) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index d5a92144bb..bea053a742 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -524,15 +524,6 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + +-bool vhost_net_config_pending(VHostNetState *net) +-{ +- return vhost_config_pending(&net->dev); +-} +- +-void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) +-{ +- vhost_config_mask(&net->dev, dev, mask); +-} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 1844f0ed46..7bdbf484e4 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,8 +39,6 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); +-bool vhost_net_config_pending(VHostNetState *net); +-void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/Revert-virtio-pci-add-support-for-configure-interrup.patch b/Revert-virtio-pci-add-support-for-configure-interrup.patch new file mode 100644 index 0000000..0ce8a4b --- /dev/null +++ b/Revert-virtio-pci-add-support-for-configure-interrup.patch @@ -0,0 +1,215 @@ +From b97597030e537248f3986589cfc4a32a3e7eb8f5 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 09:46:06 +0800 +Subject: [PATCH] Revert "virtio-pci: add support for configure interrupt" + +This reverts commit d5d24d859c3957ea1674d0e102f96439cdbfe93a. + +Fixes: d5d24d859c ("virtio-pci: add support for configure interrupt") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 92 ++++++------------------------------------ + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 13 insertions(+), 83 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 90237f523e..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,8 +812,7 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- *n = virtio_config_get_guest_notifier(vdev); +- *vector = vdev->config_vector; ++ return -1; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -888,10 +887,6 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + +-static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) +-{ +- return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +-} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -929,11 +924,6 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + +-static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) +-{ +- kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); +-} +- + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1015,17 +1005,9 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- /* unmask config intr */ +- n = virtio_config_get_guest_notifier(vdev); +- ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, +- msg, n); +- if (ret < 0) { +- goto undo_config; +- } ++ + return 0; +-undo_config: +- n = virtio_config_get_guest_notifier(vdev); +- virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); ++ + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1059,8 +1041,6 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } +- n = virtio_config_get_guest_notifier(vdev); +- virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1092,34 +1072,6 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } +- /* poll the config intr */ +- ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, +- &vector); +- if (ret < 0) { +- return; +- } +- if (vector < vector_start || vector >= vector_end || +- !msix_is_masked(dev, vector)) { +- return; +- } +- if (k->guest_notifier_pending) { +- if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { +- msix_set_pending(dev, vector); +- } +- } else if (event_notifier_test_and_clear(notifier)) { +- msix_set_pending(dev, vector); +- } +-} +- +-void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, +- int n, bool assign, +- bool with_irqfd) +-{ +- if (n == VIRTIO_CONFIG_IRQ_IDX) { +- virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); +- } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); +- } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1128,25 +1080,17 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = NULL; +- EventNotifier *notifier = NULL; +- +- if (n == VIRTIO_CONFIG_IRQ_IDX) { +- notifier = virtio_config_get_guest_notifier(vdev); +- } else { +- vq = virtio_get_queue(vdev, n); +- notifier = virtio_queue_get_guest_notifier(vq); +- } ++ VirtQueue *vq = virtio_get_queue(vdev, n); ++ EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); ++ virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); + } else { +- virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, +- with_irqfd); ++ virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1188,7 +1132,6 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { + kvm_virtio_pci_vector_release(proxy, nvqs); +- kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1204,11 +1147,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, +- with_irqfd); +- if (r < 0) { +- goto config_assign_error; +- } ++ + /* Must set vector notifier after guest notifier has been assigned */ + if ((with_irqfd || k->guest_notifier_mask) && assign) { + if (with_irqfd) { +@@ -1217,14 +1156,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_nr_vectors_allocated(&proxy->pci_dev)); + r = kvm_virtio_pci_vector_use(proxy, nvqs); + if (r < 0) { +- goto config_assign_error; ++ goto assign_error; + } + } +- r = kvm_virtio_pci_vector_config_use(proxy); +- if (r < 0) { +- goto config_error; +- } +- r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, ++ r = msix_set_vector_notifiers(&proxy->pci_dev, ++ virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1239,11 +1175,7 @@ notifiers_error: + assert(assign); + kvm_virtio_pci_vector_release(proxy, nvqs); + } +-config_error: +- kvm_virtio_pci_vector_config_release(proxy); +-config_assign_error: +- virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, +- with_irqfd); ++ + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index 6d8e071d8d..d95b1a13a5 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,7 +256,5 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +-void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, +- int n, bool assign, +- bool with_irqfd); ++ + #endif +-- +2.27.0 + diff --git a/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch b/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch new file mode 100644 index 0000000..deda743 --- /dev/null +++ b/Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch @@ -0,0 +1,255 @@ +From 38c0a07985c6616c43ee98caf7054ddd49dcd34e Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:02:59 +0800 +Subject: [PATCH] Revert "virtio-pci: decouple notifier from interrupt process" + +This reverts commit e3480ef81f6fb61cc9c04e3b5be8b7e84484fc05. + +Fixes: e3480ef81f ("virtio-pci: decouple notifier from interrupt process") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++--------------------------- + 1 file changed, 31 insertions(+), 57 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..21c0ec3b1b 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,41 +789,29 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- EventNotifier *n, ++ unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- EventNotifier *n , ++ unsigned int queue_no, + unsigned int vector) + { ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } +-static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, +- EventNotifier **n, unsigned int *vector) +-{ +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq; +- +- if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; +- } else { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- return -1; +- } +- *vector = virtio_queue_vector(vdev, queue_no); +- vq = virtio_get_queue(vdev, queue_no); +- *n = virtio_queue_get_guest_notifier(vq); +- } +- return 0; +-} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -832,15 +820,12 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- EventNotifier *n; ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -852,7 +837,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -868,11 +853,7 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -886,16 +867,12 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- EventNotifier *n; +- int ret ; ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -903,20 +880,21 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg, +- EventNotifier *n) ++ MSIMessage msg) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ VirtQueue *vq = virtio_get_queue(vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -943,15 +921,14 @@ static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + } + return ret; + } + +-static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector, +- EventNotifier *n) ++ unsigned int vector) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -962,7 +939,7 @@ static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); + } + } + +@@ -972,7 +949,6 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); +- EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -981,8 +957,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- n = virtio_queue_get_guest_notifier(vq); +- ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); ++ ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); + if (ret < 0) { + goto undo; + } +@@ -998,8 +973,7 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- n = virtio_queue_get_guest_notifier(vq); +- virtio_pci_one_vector_mask(proxy, index, vector, n); ++ virtio_pci_vq_vector_mask(proxy, index, vector); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -1012,17 +986,15 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); +- EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); +- n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_one_vector_mask(proxy, index, vector, n); ++ virtio_pci_vq_vector_mask(proxy, index, vector); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1038,17 +1010,19 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- int ret; ++ VirtQueue *vq; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); +- if (ret < 0) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } ++ vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } ++ vq = virtio_get_queue(vdev, queue_no); ++ notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/Revert-virtio-pci-decouple-the-single-vector-from-th.patch b/Revert-virtio-pci-decouple-the-single-vector-from-th.patch new file mode 100644 index 0000000..45fa977 --- /dev/null +++ b/Revert-virtio-pci-decouple-the-single-vector-from-th.patch @@ -0,0 +1,192 @@ +From 074043d5d6c2610a320d2bc7d8649b7eff9c806e Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Wed, 22 Nov 2023 10:01:17 +0800 +Subject: [PATCH] Revert "virtio-pci: decouple the single vector from the + interrupt process" + +This reverts commit 316011b8a74e777eb3ba03171cd701a291c28867. + +Fixes: 316011b8a7 ("virtio-pci: decouple the single vector from the interrupt process") +Cc: "Cindy Lu" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 ++++++++++++++++++----------------------- + 1 file changed, 58 insertions(+), 73 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,6 +762,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, ++ unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -824,103 +825,87 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +- unsigned int vector; +- int ret; +- EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return ret; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return 0; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, vector); +- if (ret < 0) { +- goto undo; +- } +- /* +- * If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ unsigned int vector; ++ int ret, queue_no; ++ EventNotifier *n; ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ break; ++ } ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); + if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } ++ /* If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); ++ if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++ goto undo; ++ } ++ } + } +- + return 0; +-undo: + +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return ret; +- } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return ret; ++undo: ++ while (--queue_no >= 0) { ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; + } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- return ret; +-} +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) +-{ +- int queue_no; +- int ret = 0; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- return -1; ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } +- ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + } + return ret; + } + +- +-static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, +- int queue_no) ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + { ++ PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- EventNotifier *n; +- int ret; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- PCIDevice *dev = &proxy->pci_dev; +- +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- return; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- return; +- } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); +-} +- +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) +-{ + int queue_no; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- kvm_virtio_pci_vector_release_one(proxy, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ continue; ++ } ++ /* If guest supports masking, clean up irqfd now. ++ * Otherwise, it was cleaned when masked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-- +2.27.0 + diff --git a/artist-set-memory-region-owners-for-buffers-to-the-a.patch b/artist-set-memory-region-owners-for-buffers-to-the-a.patch new file mode 100644 index 0000000..4513e1e --- /dev/null +++ b/artist-set-memory-region-owners-for-buffers-to-the-a.patch @@ -0,0 +1,37 @@ +From db2e1d340763e23180e4709e4ddf33390f2e49ea Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:00:01 +0000 +Subject: [PATCH] artist: set memory region owners for buffers to the artist + device mainline inclusion commit 39fbaeca096a9bf6cbe2af88572c1cb2aa62aa8c + category: bugfix + +--------------------------------------------------------------- + +This fixes the output of "info qom-tree" so that the buffers appear as children +of the artist device, rather than underneath the "unattached" container. + +Signed-off-by: Mark Cave-Ayland +Message-Id: <20220624160839.886649-1-mark.cave-ayland@ilande.co.uk> +Reviewed-by: Helge Deller + +Signed-off-by: tangbinzy +--- + hw/display/artist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/display/artist.c b/hw/display/artist.c +index 21b7fd1b44..1767203477 100644 +--- a/hw/display/artist.c ++++ b/hw/display/artist.c +@@ -1359,7 +1359,7 @@ static void artist_create_buffer(ARTISTState *s, const char *name, + { + struct vram_buffer *buf = s->vram_buffer + idx; + +- memory_region_init_ram(&buf->mr, NULL, name, width * height, ++ memory_region_init_ram(&buf->mr, OBJECT(s), name, width * height, + &error_fatal); + memory_region_add_subregion_overlap(&s->mem_as_root, *offset, &buf->mr, 0); + +-- +2.27.0 + diff --git a/e1000-set-RX-descriptor-status-in-a-separate-operati.patch b/e1000-set-RX-descriptor-status-in-a-separate-operati.patch new file mode 100644 index 0000000..ffa0f96 --- /dev/null +++ b/e1000-set-RX-descriptor-status-in-a-separate-operati.patch @@ -0,0 +1,89 @@ +From dcebeb0f7acf549620faff1badf73baba04b2068 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 10:15:09 +0000 +Subject: [PATCH] e1000: set RX descriptor status in a separate operation + mainline inclusion commit 034d00d4858161e1d4cff82d8d230bce874a04d3 category: + bugfix + +--------------------------------------------------------------- + +The code of setting RX descriptor status field maybe work fine in +previously, however with the update of glibc version, it shows two +issues when guest using dpdk receive packets: + + 1. The dpdk has a certain probability getting wrong buffer_addr + + this impact may be not obvious, such as lost a packet once in + a while + + 2. The dpdk may consume a packet twice when scan the RX desc queue + over again + + this impact will lead a infinite wait in Qemu, since the RDT + (tail pointer) be inscreased to equal to RDH by unexpected, + which regard as the RX desc queue is full + +Write a whole of RX desc with DD flag on is not quite correct, because +when the underlying implementation of memcpy using XMM registers to +copy e1000_rx_desc (when AVX or something else CPU feature is usable), +the bytes order of desc writing to memory is indeterminacy + +We can use full-scale test case to reproduce the issue-2 by +https://github.com/BASM/qemu_dpdk_e1000_test (thanks to Leonid Myravjev) + +I also write a POC test case at https://github.com/cdkey/e1000_poc +which can reproduce both of them, and easy to verify the patch effect. + +The hw watchpoint also shows that, when Qemu using XMM related instructions +writing 16 bytes e1000_rx_desc, concurrent with DPDK using movb +writing 1 byte status, the final result of writing to memory will be one +of them, if it made by Qemu which DD flag is on, DPDK will consume it +again. + +Setting DD status in a separate operation, can prevent the impact of +disorder memory writing by memcpy, also avoid unexpected data when +concurrent writing status by qemu and guest dpdk. + +Links: https://lore.kernel.org/qemu-devel/20200102110504.GG121208@stefanha-x1.localdomain/T/ + +Reported-by: Leonid Myravjev +Cc: Stefan Hajnoczi +Cc: Paolo Bonzini +Cc: Michael S. Tsirkin +Cc: qemu-stable@nongnu.org +Tested-by: Jing Zhang +Reviewed-by: Frank Lee +Signed-off-by: Ding Hui +Signed-off-by: Jason Wang + +Signed-off-by: tangbinzy +--- + hw/net/e1000.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index f5bc81296d..e26e0a64c1 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -979,7 +979,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) + base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; + pci_dma_read(d, base, &desc, sizeof(desc)); + desc.special = vlan_special; +- desc.status |= (vlan_status | E1000_RXD_STAT_DD); ++ desc.status &= ~E1000_RXD_STAT_DD; + if (desc.buffer_addr) { + if (desc_offset < size) { + size_t iov_copy; +@@ -1013,6 +1013,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) + DBGOUT(RX, "Null RX descriptor!!\n"); + } + pci_dma_write(d, base, &desc, sizeof(desc)); ++ desc.status |= (vlan_status | E1000_RXD_STAT_DD); ++ pci_dma_write(d, base + offsetof(struct e1000_rx_desc, status), ++ &desc.status, sizeof(desc.status)); + + if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) + s->mac_reg[RDH] = 0; +-- +2.27.0 + diff --git a/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch b/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch new file mode 100644 index 0000000..8cc3789 --- /dev/null +++ b/hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch @@ -0,0 +1,62 @@ +From 81c2b665d9ea6670677f35aa1ab2ad68d6e73aa4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= +Date: Mon, 20 Nov 2023 12:51:15 +0100 +Subject: [PATCH] hw/arm/fsl-imx: Do not ignore Error argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mainline inclusion +commit 0cbb56c236a4a28f5149eed227d74bb737321cfc +category: bugfix + +-------------------------------------------------------- + +Both i.MX25 and i.MX6 SoC models ignore the Error argument when +setting the PHY number. Pick &error_abort which is the error +used by the i.MX7 SoC (see commit 1f7197deb0 "ability to change +the FEC PHY on i.MX7 processor"). + +Fixes: 74c1330582 ("ability to change the FEC PHY on i.MX25 processor") +Fixes: a9c167a3c4 ("ability to change the FEC PHY on i.MX6 processor") +Signed-off-by: Philippe Mathieu-Daudé +Message-id: 20231120115116.76858-1-philmd@linaro.org +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: zhujun2 +--- + hw/arm/fsl-imx25.c | 3 ++- + hw/arm/fsl-imx6.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c +index 24c4374590..9aabbf7f58 100644 +--- a/hw/arm/fsl-imx25.c ++++ b/hw/arm/fsl-imx25.c +@@ -169,7 +169,8 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) + epit_table[i].irq)); + } + +- object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, &err); ++ object_property_set_uint(OBJECT(&s->fec), "phy-num", s->phy_num, ++ &error_abort); + qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->fec), errp)) { +diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c +index 00dafe3f62..c4b95dc7a7 100644 +--- a/hw/arm/fsl-imx6.c ++++ b/hw/arm/fsl-imx6.c +@@ -377,7 +377,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) + spi_table[i].irq)); + } + +- object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &err); ++ object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, ++ &error_abort); + qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->eth), errp)) { + return; +-- +2.27.0 + diff --git a/hw-net-cadence_gem.c-spelling-fixes-Octects.patch b/hw-net-cadence_gem.c-spelling-fixes-Octects.patch new file mode 100644 index 0000000..31ebc99 --- /dev/null +++ b/hw-net-cadence_gem.c-spelling-fixes-Octects.patch @@ -0,0 +1,39 @@ +From 2e37d6ac7713c9962cb006900d18e83df54e8e0f Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Fri, 24 Nov 2023 00:21:31 -0800 +Subject: [PATCH] hw/net/cadence_gem.c: spelling fixes: Octects + +Signed-off-by: zhujun2 +--- + hw/net/cadence_gem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index 24b3a0ff66..21e1bd091f 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -81,8 +81,8 @@ + #define GEM_IPGSTRETCH (0x000000BC / 4) /* IPG Stretch reg */ + #define GEM_SVLAN (0x000000C0 / 4) /* Stacked VLAN reg */ + #define GEM_MODID (0x000000FC / 4) /* Module ID reg */ +-#define GEM_OCTTXLO (0x00000100 / 4) /* Octects transmitted Low reg */ +-#define GEM_OCTTXHI (0x00000104 / 4) /* Octects transmitted High reg */ ++#define GEM_OCTTXLO (0x00000100 / 4) /* Octets transmitted Low reg */ ++#define GEM_OCTTXHI (0x00000104 / 4) /* Octets transmitted High reg */ + #define GEM_TXCNT (0x00000108 / 4) /* Error-free Frames transmitted */ + #define GEM_TXBCNT (0x0000010C / 4) /* Error-free Broadcast Frames */ + #define GEM_TXMCNT (0x00000110 / 4) /* Error-free Multicast Frame */ +@@ -101,8 +101,8 @@ + #define GEM_LATECOLLCNT (0x00000144 / 4) /* Late Collision Frames */ + #define GEM_DEFERTXCNT (0x00000148 / 4) /* Deferred Transmission Frames */ + #define GEM_CSENSECNT (0x0000014C / 4) /* Carrier Sense Error Counter */ +-#define GEM_OCTRXLO (0x00000150 / 4) /* Octects Received register Low */ +-#define GEM_OCTRXHI (0x00000154 / 4) /* Octects Received register High */ ++#define GEM_OCTRXLO (0x00000150 / 4) /* Octets Received register Low */ ++#define GEM_OCTRXHI (0x00000154 / 4) /* Octets Received register High */ + #define GEM_RXCNT (0x00000158 / 4) /* Error-free Frames Received */ + #define GEM_RXBROADCNT (0x0000015C / 4) /* Error-free Broadcast Frames RX */ + #define GEM_RXMULTICNT (0x00000160 / 4) /* Error-free Multicast Frames RX */ +-- +2.27.0 + diff --git a/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch new file mode 100644 index 0000000..edc0d62 --- /dev/null +++ b/hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch @@ -0,0 +1,65 @@ +From 6532f02449e7a001bc74ea43690d6e1a87a7e3fc Mon Sep 17 00:00:00 2001 +From: Yuval Shaia +Date: Wed, 1 Mar 2023 16:29:26 +0200 +Subject: [PATCH] hw/pvrdma: Protect against buggy or malicious guest driver + +Guest driver allocates and initialize page tables to be used as a ring +of descriptors for CQ and async events. +The page table that represents the ring, along with the number of pages +in the page table is passed to the device. +Currently our device supports only one page table for a ring. + +Let's make sure that the number of page table entries the driver +reports, do not exceeds the one page table size. + +Reported-by: Soul Chen +Signed-off-by: Yuval Shaia +Fixes: CVE-2023-1544 +Message-ID: <20230301142926.18686-1-yuval.shaia.ml@gmail.com> +Signed-off-by: Thomas Huth +--- + hw/rdma/vmw/pvrdma_main.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c +index 91206dbb8e..f99b12a592 100644 +--- a/hw/rdma/vmw/pvrdma_main.c ++++ b/hw/rdma/vmw/pvrdma_main.c +@@ -91,19 +91,33 @@ static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state, + dma_addr_t dir_addr, uint32_t num_pages) + { + uint64_t *dir, *tbl; +- int rc = 0; ++ int max_pages, rc = 0; + + if (!num_pages) { + rdma_error_report("Ring pages count must be strictly positive"); + return -EINVAL; + } + ++ /* ++ * Make sure we can satisfy the requested number of pages in a single ++ * TARGET_PAGE_SIZE sized page table (taking into account that first entry ++ * is reserved for ring-state) ++ */ ++ max_pages = TARGET_PAGE_SIZE / sizeof(dma_addr_t) - 1; ++ if (num_pages > max_pages) { ++ rdma_error_report("Maximum pages on a single directory must not exceed %d\n", ++ max_pages); ++ return -EINVAL; ++ } ++ + dir = rdma_pci_dma_map(pci_dev, dir_addr, TARGET_PAGE_SIZE); + if (!dir) { + rdma_error_report("Failed to map to page directory (ring %s)", name); + rc = -ENOMEM; + goto out; + } ++ ++ /* We support only one page table for a ring */ + tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE); + if (!tbl) { + rdma_error_report("Failed to map to page table (ring %s)", name); +-- +2.27.0 + diff --git a/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch b/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch new file mode 100644 index 0000000..c554bb4 --- /dev/null +++ b/hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch @@ -0,0 +1,38 @@ +From 7f5cf2958ee5d178d058470031b96a82d3002a5c Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 1 Nov 2023 19:00:34 +0800 +Subject: [PATCH] hw/timer/npcm7xx_timer: Prevent timer from counting down past + zero + +cheery-pick from 9ef2629712680e70cbf39d8b6cb1ec0e0e2e72fa + +The counter register is only 24-bits and counts down. If the timer is +running but the qtimer to reset it hasn't fired off yet, there is a chance +the regster read can return an invalid result. + +Signed-off-by: Chris Rauer +Message-id: 20230922181411.2697135-1-crauer@google.com +Reviewed-by: Peter Maydell +Signed-off-by: Peter Maydell +Signed-off-by: qihao_yewu +--- + hw/timer/npcm7xx_timer.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c +index 32f5e021f8..a8bd93aeb2 100644 +--- a/hw/timer/npcm7xx_timer.c ++++ b/hw/timer/npcm7xx_timer.c +@@ -138,6 +138,9 @@ static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count) + /* Convert a time interval in nanoseconds to a timer cycle count. */ + static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns) + { ++ if (ns < 0) { ++ return 0; ++ } + return clock_ns_to_ticks(t->ctrl->clock, ns) / + npcm7xx_tcsr_prescaler(t->tcsr); + } +-- +2.27.0 + diff --git a/hw-usb-hcd-ehci-fix-writeback-order.patch b/hw-usb-hcd-ehci-fix-writeback-order.patch new file mode 100644 index 0000000..8d0d611 --- /dev/null +++ b/hw-usb-hcd-ehci-fix-writeback-order.patch @@ -0,0 +1,64 @@ +From fc52088f7aa8a1be3b3c7d135a2aebd28ba4c673 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:57:46 +0000 +Subject: [PATCH] hw/usb/hcd-ehci: fix writeback order mainline inclusion + commit f471e8b060798f26a7fc339c6152f82f22a7b33d category: bugfix + +--------------------------------------------------------------- + +The 'active' bit passes control over a qTD between the guest and the +controller: set to 1 by guest to enable execution by the controller, +and the controller sets it to '0' to hand back control to the guest. + +ehci_state_writeback write two dwords to main memory using DMA: +the third dword of the qTD (containing dt, total bytes to transfer, +cpage, cerr and status) and the fourth dword of the qTD (containing +the offset). + +This commit makes sure the fourth dword is written before the third, +avoiding a race condition where a new offset written into the qTD +by the guest after it observed the status going to go to '0' gets +overwritten by a 'late' DMA writeback of the previous offset. + +This race condition could lead to 'cpage out of range (5)' errors, +and reproduced by: + +./qemu-system-x86_64 -enable-kvm -bios $SEABIOS/bios.bin -m 4096 -device usb-ehci -blockdev driver=file,read-only=on,filename=/home/aengelen/Downloads/openSUSE-Tumbleweed-DVD-i586-Snapshot20220428-Media.iso,node-name=iso -device usb-storage,drive=iso,bootindex=0 -chardev pipe,id=shell,path=/tmp/pipe -device virtio-serial -device virtconsole,chardev=shell -device virtio-rng-pci -serial mon:stdio -nographic + +(press a key, select 'Installation' (2), and accept the default +values. On my machine the 'cpage out of range' is reproduced while +loading the Linux Kernel about once per 7 attempts. With the fix in +this commit it no longer fails) + +This problem was previously reported as a seabios problem in +https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/OUTHT5ISSQJGXPNTUPY3O5E5EPZJCHM3/ +and as a nixos CI build failure in +https://github.com/NixOS/nixpkgs/issues/170803 + +Signed-off-by: Arnout Engelen +Signed-off-by: Gerd Hoffmann + +Signed-off-by: tangbinzy +--- + hw/usb/hcd-ehci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 0289b3696d..f9aa567f5d 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2013,7 +2013,10 @@ static int ehci_state_writeback(EHCIQueue *q) + ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd); + qtd = (uint32_t *) &q->qh.next_qtd; + addr = NLPTR_GET(p->qtdaddr); +- put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2); ++ /* First write back the offset */ ++ put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qtd + 3, 1); ++ /* Then write back the token, clearing the 'active' bit */ ++ put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 1); + ehci_free_packet(p); + + /* +-- +2.27.0 + diff --git a/hw-virtio-add-some-vhost-user-trace-events.patch b/hw-virtio-add-some-vhost-user-trace-events.patch new file mode 100644 index 0000000..5979d62 --- /dev/null +++ b/hw-virtio-add-some-vhost-user-trace-events.patch @@ -0,0 +1,70 @@ +From f5b5cba0b86caacdea334725bedcdfb689504b3a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Tue, 2 Aug 2022 10:49:57 +0100 +Subject: [PATCH] hw/virtio: add some vhost-user trace events +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are useful for tracing the lifetime of vhost-user connections. + +Signed-off-by: Alex Bennée +Message-Id: <20220802095010.3330793-10-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 4 ++++ + hw/virtio/vhost.c | 6 ++++++ + 2 files changed, 10 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 63c7668e5b..b8a33b2a83 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -8,6 +8,10 @@ vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size, + vhost_section(const char *name) "%s" + vhost_reject_section(const char *name, int d) "%s:%d" + vhost_iotlb_miss(void *dev, int step) "%p step %d" ++vhost_dev_cleanup(void *dev) "%p" ++vhost_dev_start(void *dev, const char *name) "%p:%s" ++vhost_dev_stop(void *dev, const char *name) "%p:%s" ++ + + # vhost-user.c + vhost_user_postcopy_end_entry(void) "" +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index c1f5cb5b91..86c727d2ab 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1460,6 +1460,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) + { + int i; + ++ trace_vhost_dev_cleanup(hdev); ++ + for (i = 0; i < hdev->nvqs; ++i) { + vhost_virtqueue_cleanup(hdev->vqs + i); + } +@@ -1766,6 +1768,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ trace_vhost_dev_start(hdev, vdev->name); ++ + vdev->vhost_started = true; + hdev->started = true; + hdev->vdev = vdev; +@@ -1852,6 +1856,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ trace_vhost_dev_stop(hdev, vdev->name); ++ + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } +-- +2.27.0 + diff --git a/hw-virtio-add-vhost_user_-read-write-trace-points.patch b/hw-virtio-add-vhost_user_-read-write-trace-points.patch new file mode 100644 index 0000000..ca9de06 --- /dev/null +++ b/hw-virtio-add-vhost_user_-read-write-trace-points.patch @@ -0,0 +1,62 @@ +From 57451ee8e278827ef0ab592d565c14076dd62fd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 21 Mar 2022 15:30:27 +0000 +Subject: [PATCH] hw/virtio: add vhost_user_[read|write] trace points +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are useful when trying to debug the initial vhost-user +negotiation, especially when it hard to get logging from the low level +library on the other side. + +Signed-off-by: Alex Bennée + +Message-Id: <20220321153037.3622127-4-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 2 ++ + hw/virtio/vhost-user.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 37c1555330..63c7668e5b 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -21,6 +21,8 @@ vhost_user_set_mem_table_withfd(int index, const char *name, uint64_t memory_siz + vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 + vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64 + vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64 ++vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" ++vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + + # vhost-vdpa.c + vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 358dc82010..ea6d40eb5f 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -491,6 +491,8 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, + return ret < 0 ? -saved_errno : -EIO; + } + ++ trace_vhost_user_write(msg->hdr.request, msg->hdr.flags); ++ + return 0; + } + +@@ -544,6 +546,8 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + } + } + ++ trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); ++ + return 0; + } + +-- +2.27.0 + diff --git a/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch b/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch new file mode 100644 index 0000000..76a7d1c --- /dev/null +++ b/hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch @@ -0,0 +1,135 @@ +From 6cbac9f34c67e2a2e28109152957f5eca35b6e73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 10 Jul 2023 16:35:05 +0100 +Subject: [PATCH] hw/virtio: fix typo in VIRTIO_CONFIG_IRQ_IDX comments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 544f0278af (virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX) +Signed-off-by: Alex Bennée +Message-Id: <20230710153522.3469097-4-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 4 ++-- + hw/net/virtio-net.c | 4 ++-- + hw/virtio/vhost-user-fs.c | 4 ++-- + hw/virtio/vhost-vsock-common.c | 4 ++-- + hw/virtio/virtio-crypto.c | 4 ++-- + 5 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 1c78272a83..4363e34db1 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -487,7 +487,7 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -504,7 +504,7 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index ae37b3461b..3e1fa6adf3 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3249,7 +3249,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + } + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return false + */ + +@@ -3281,7 +3281,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + } + /* + *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 0c6ecd3b4f..5ac5dcce49 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -163,7 +163,7 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -179,7 +179,7 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index e4a8d90f4c..b9cf5f3f29 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -127,7 +127,7 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -144,7 +144,7 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 9f7dcc88ba..61b421aab3 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -960,7 +960,7 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +@@ -979,7 +979,7 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + /* + * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 +- * as the Marco of configure interrupt's IDX, If this driver does not ++ * as the macro of configure interrupt's IDX, If this driver does not + * support, the function will return + */ + +-- +2.27.0 + diff --git a/hw-virtio-fix-vhost_user_read-tracepoint.patch b/hw-virtio-fix-vhost_user_read-tracepoint.patch new file mode 100644 index 0000000..6185ae4 --- /dev/null +++ b/hw-virtio-fix-vhost_user_read-tracepoint.patch @@ -0,0 +1,48 @@ +From 09081b494d4aad3137fd375f5f18edc63c7e5d10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Thu, 28 Jul 2022 14:55:03 +0100 +Subject: [PATCH] hw/virtio: fix vhost_user_read tracepoint +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As reads happen in the callback we were never seeing them. We only +really care about the header so move the tracepoint to when the header +is complete. + +Fixes: 6ca6d8ee9d (hw/virtio: add vhost_user_[read|write] trace points) +Signed-off-by: Alex Bennée +Acked-by: Jason Wang +Message-Id: <20220728135503.1060062-5-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index ea6d40eb5f..937b3021e9 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -297,6 +297,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + return -EPROTO; + } + ++ trace_vhost_user_read(msg->hdr.request, msg->hdr.flags); ++ + return 0; + } + +@@ -546,8 +548,6 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + } + } + +- trace_vhost_user_read(msg.hdr.request, msg.hdr.flags); +- + return 0; + } + +-- +2.27.0 + diff --git a/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch b/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch new file mode 100644 index 0000000..b2dea4b --- /dev/null +++ b/hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch @@ -0,0 +1,52 @@ +From edbbc82bdf7cdb21604bb1c8b4a222691b3c3665 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Thu, 28 Jul 2022 14:55:01 +0100 +Subject: [PATCH] hw/virtio: gracefully handle unset vhost_dev vdev +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I've noticed asserts firing because we query the status of vdev after +a vhost connection is closed down. Rather than faulting on the NULL +indirect just quietly reply false. + +Signed-off-by: Alex Bennée +Message-Id: <20220728135503.1060062-3-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2f0ddd35d6..8e8657fb0d 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -310,7 +310,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + dev->log_size = size; + } + +-static int vhost_dev_has_iommu(struct vhost_dev *dev) ++static bool vhost_dev_has_iommu(struct vhost_dev *dev) + { + VirtIODevice *vdev = dev->vdev; + +@@ -320,8 +320,12 @@ static int vhost_dev_has_iommu(struct vhost_dev *dev) + * does not have IOMMU, there's no need to enable this feature + * which may cause unnecessary IOTLB miss/update transactions. + */ +- return virtio_bus_device_iommu_enabled(vdev) && +- virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ if (vdev) { ++ return virtio_bus_device_iommu_enabled(vdev) && ++ virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ } else { ++ return false; ++ } + } + + static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, +-- +2.27.0 + diff --git a/hw-virtio-vhost-Fix-typo-in-comment.patch b/hw-virtio-vhost-Fix-typo-in-comment.patch new file mode 100644 index 0000000..e3da1d0 --- /dev/null +++ b/hw-virtio-vhost-Fix-typo-in-comment.patch @@ -0,0 +1,34 @@ +From 7c0b752e2bfd9c6e12570d7a9229a6f733d9ca59 Mon Sep 17 00:00:00 2001 +From: Leonardo Garcia +Date: Tue, 23 Nov 2021 08:48:31 -0300 +Subject: [PATCH] hw/virtio/vhost: Fix typo in comment. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Leonardo Garcia +Reviewed-by: Laurent Vivier +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 22ec9e1ef7..2f0ddd35d6 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -318,7 +318,7 @@ static int vhost_dev_has_iommu(struct vhost_dev *dev) + * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support + * incremental memory mapping API via IOTLB API. For platform that + * does not have IOMMU, there's no need to enable this feature +- * which may cause unnecessary IOTLB miss/update trnasactions. ++ * which may cause unnecessary IOTLB miss/update transactions. + */ + return virtio_bus_device_iommu_enabled(vdev) && + virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); +-- +2.27.0 + diff --git a/include-hw-start-documenting-the-vhost-API.patch b/include-hw-start-documenting-the-vhost-API.patch new file mode 100644 index 0000000..f53f07c --- /dev/null +++ b/include-hw-start-documenting-the-vhost-API.patch @@ -0,0 +1,192 @@ +From 6e43246f43753030a247c23cd6082792a588817b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Benn=C3=A9e?= +Date: Mon, 21 Mar 2022 15:30:34 +0000 +Subject: [PATCH] include/hw: start documenting the vhost API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While trying to get my head around the nest of interactions for vhost +devices I though I could start by documenting the key API functions. +This patch documents the main API hooks for creating and starting a +vhost device as well as how the configuration changes are handled. + +Signed-off-by: Alex Bennée +Cc: Michael S. Tsirkin +Cc: Stefan Hajnoczi +Cc: Marc-André Lureau +Message-Id: <20220321153037.3622127-11-alex.bennee@linaro.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + include/hw/virtio/vhost.h | 132 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 122 insertions(+), 10 deletions(-) + +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 86f36f0106..d7ab2579ff 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -61,6 +61,12 @@ typedef struct VhostDevConfigOps { + } VhostDevConfigOps; + + struct vhost_memory; ++ ++/** ++ * struct vhost_dev - common vhost_dev structure ++ * @vhost_ops: backend specific ops ++ * @config_ops: ops for config changes (see @vhost_dev_set_config_notifier) ++ */ + struct vhost_dev { + VirtIODevice *vdev; + MemoryListener memory_listener; +@@ -108,15 +114,129 @@ struct vhost_net { + NetClientState *nc; + }; + ++/** ++ * vhost_dev_init() - initialise the vhost interface ++ * @hdev: the common vhost_dev structure ++ * @opaque: opaque ptr passed to backend (vhost/vhost-user/vdpa) ++ * @backend_type: type of backend ++ * @busyloop_timeout: timeout for polling virtqueue ++ * @errp: error handle ++ * ++ * The initialisation of the vhost device will trigger the ++ * initialisation of the backend and potentially capability ++ * negotiation of backend interface. Configuration of the VirtIO ++ * itself won't happen until the interface is started. ++ * ++ * Return: 0 on success, non-zero on error while setting errp. ++ */ + int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + VhostBackendType backend_type, + uint32_t busyloop_timeout, Error **errp); ++ ++/** ++ * vhost_dev_cleanup() - tear down and cleanup vhost interface ++ * @hdev: the common vhost_dev structure ++ */ + void vhost_dev_cleanup(struct vhost_dev *hdev); +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_enable_notifiers() - enable event notifiers ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Enable notifications directly to the vhost device rather than being ++ * triggered by QEMU itself. Notifications should be enabled before ++ * the vhost device is started via @vhost_dev_start. ++ * ++ * Return: 0 on success, < 0 on error. ++ */ + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_disable_notifiers - disable event notifications ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Disable direct notifications to vhost device. ++ */ + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + ++/** ++ * vhost_dev_start() - start the vhost device ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Starts the vhost device. From this point VirtIO feature negotiation ++ * can start and the device can start processing VirtIO transactions. ++ * ++ * Return: 0 on success, < 0 on error. ++ */ ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * vhost_dev_stop() - stop the vhost device ++ * @hdev: common vhost_dev structure ++ * @vdev: the VirtIODevice structure ++ * ++ * Stop the vhost device. After the device is stopped the notifiers ++ * can be disabled (@vhost_dev_disable_notifiers) and the device can ++ * be torn down (@vhost_dev_cleanup). ++ */ ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++ ++/** ++ * DOC: vhost device configuration handling ++ * ++ * The VirtIO device configuration space is used for rarely changing ++ * or initialisation time parameters. The configuration can be updated ++ * by either the guest driver or the device itself. If the device can ++ * change the configuration over time the vhost handler should ++ * register a @VhostDevConfigOps structure with ++ * @vhost_dev_set_config_notifier so the guest can be notified. Some ++ * devices register a handler anyway and will signal an error if an ++ * unexpected config change happens. ++ */ ++ ++/** ++ * vhost_dev_get_config() - fetch device configuration ++ * @hdev: common vhost_dev_structure ++ * @config: pointer to device appropriate config structure ++ * @config_len: size of device appropriate config structure ++ * ++ * Return: 0 on success, < 0 on error while setting errp ++ */ ++int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, ++ uint32_t config_len, Error **errp); ++ ++/** ++ * vhost_dev_set_config() - set device configuration ++ * @hdev: common vhost_dev_structure ++ * @data: pointer to data to set ++ * @offset: offset into configuration space ++ * @size: length of set ++ * @flags: @VhostSetConfigType flags ++ * ++ * By use of @offset/@size a subset of the configuration space can be ++ * written to. The @flags are used to indicate if it is a normal ++ * transaction or related to migration. ++ * ++ * Return: 0 on success, non-zero on error ++ */ ++int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, ++ uint32_t offset, uint32_t size, uint32_t flags); ++ ++/** ++ * vhost_dev_set_config_notifier() - register VhostDevConfigOps ++ * @hdev: common vhost_dev_structure ++ * @ops: notifier ops ++ * ++ * If the device is expected to change configuration a notifier can be ++ * setup to handle the case. ++ */ ++void vhost_dev_set_config_notifier(struct vhost_dev *dev, ++ const VhostDevConfigOps *ops); ++ ++ + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. + */ +@@ -136,14 +256,6 @@ int vhost_net_set_backend(struct vhost_dev *hdev, + struct vhost_vring_file *file); + + int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write); +-int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, +- uint32_t config_len, Error **errp); +-int vhost_dev_set_config(struct vhost_dev *dev, const uint8_t *data, +- uint32_t offset, uint32_t size, uint32_t flags); +-/* notifier callback in case vhost device config space changed +- */ +-void vhost_dev_set_config_notifier(struct vhost_dev *dev, +- const VhostDevConfigOps *ops); + + void vhost_dev_reset_inflight(struct vhost_inflight *inflight); + void vhost_dev_free_inflight(struct vhost_inflight *inflight); +-- +2.27.0 + diff --git a/io_uring-fix-short-read-slow-path.patch b/io_uring-fix-short-read-slow-path.patch new file mode 100644 index 0000000..9a0722b --- /dev/null +++ b/io_uring-fix-short-read-slow-path.patch @@ -0,0 +1,55 @@ +From 78cb2c9c218155d048e566c5ac6d59961703b5d3 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:14:40 +0000 +Subject: [PATCH] io_uring: fix short read slow path mainline inclusion commit + c06fc7ce147e57ab493bad9263f1601b8298484b category: bugfix + +--------------------------------------------------------------- + +sqeq.off here is the offset to read within the disk image, so obviously +not 'nread' (the amount we just read), but as the author meant to write +its current value incremented by the amount we just read. + +Normally recent versions of linux will not issue short reads, +but it can happen so we should fix this. + +This lead to weird image corruptions when short read happened + +Fixes: 6663a0a33764 ("block/io_uring: implements interfaces for io_uring") +Link: https://lkml.kernel.org/r/YrrFGO4A1jS0GI0G@atmark-techno.com +Signed-off-by: Dominique Martinet +Message-Id: <20220630010137.2518851-1-dominique.martinet@atmark-techno.com> +Reviewed-by: Hanna Reitz +Reviewed-by: Stefano Garzarella +Signed-off-by: Stefan Hajnoczi + +Signed-off-by: tangbinzy +--- + block/io_uring.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/io_uring.c b/block/io_uring.c +index dfa475cc87..e88d75d462 100644 +--- a/block/io_uring.c ++++ b/block/io_uring.c +@@ -89,7 +89,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, + trace_luring_resubmit_short_read(s, luringcb, nread); + + /* Update read position */ +- luringcb->total_read = nread; ++ luringcb->total_read += nread; + remaining = luringcb->qiov->size - luringcb->total_read; + + /* Shorten qiov */ +@@ -103,7 +103,7 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, + remaining); + + /* Update sqe */ +- luringcb->sqeq.off = nread; ++ luringcb->sqeq.off += nread; + luringcb->sqeq.addr = (__u64)(uintptr_t)luringcb->resubmit_qiov.iov; + luringcb->sqeq.len = luringcb->resubmit_qiov.niov; + +-- +2.27.0 + diff --git a/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch b/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch new file mode 100644 index 0000000..23cde54 --- /dev/null +++ b/libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch @@ -0,0 +1,48 @@ +From c2353941d94a5aeb8364dc5204c29a4fbb09437f Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:47:43 +0000 +Subject: [PATCH] libvhost-user: Fix VHOST_USER_ADD_MEM_REG reply mainline + inclusion commit 7f27d20ded2f480f3e66d03f90ea71507b834276 category: bugfix + +--------------------------------------------------------------- + +With REPLY_NEEDED, libvhost-user sends both the acutal result and an +additional ACK reply for VHOST_USER_ADD_MEM_REG. This is incorrect, the +spec mandates that it behave the same with and without REPLY_NEEDED +because it always sends a reply. + +Fixes: ec94c8e621de96c50c2d381c8c9ec94f5beec7c1 +Signed-off-by: Kevin Wolf +Message-Id: <20220627134500.94842-4-kwolf@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + subprojects/libvhost-user/libvhost-user.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c +index 787f4d2d4f..8ab20138f4 100644 +--- a/subprojects/libvhost-user/libvhost-user.c ++++ b/subprojects/libvhost-user/libvhost-user.c +@@ -756,15 +756,9 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { + + /* Send the message back to qemu with the addresses filled in. */ + vmsg->fd_num = 0; +- if (!vu_send_reply(dev, dev->sock, vmsg)) { +- vu_panic(dev, "failed to respond to add-mem-region for postcopy"); +- return false; +- } +- + DPRINT("Successfully added new region in postcopy\n"); + dev->nregions++; +- return false; +- ++ return true; + } else { + for (i = 0; i < dev->max_queues; i++) { + if (dev->vq[i].vring.desc) { +-- +2.27.0 + diff --git a/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch b/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch new file mode 100644 index 0000000..fac4191 --- /dev/null +++ b/libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch @@ -0,0 +1,53 @@ +From 3e2df0133efdf3e3aea63f413b42e37bc6c87112 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 06:36:05 +0000 +Subject: [PATCH] libvhost-user: Fix VHOST_USER_GET_MAX_MEM_SLOTS reply + mainline inclusion commit 69a5daec06f423843ce1bb9be5fb049314996f78 category: + bugfix + +--------------------------------------------------------------- + +With REPLY_NEEDED, libvhost-user sends both the acutal result and an +additional ACK reply for VHOST_USER_GET_MAX_MEM_SLOTS. This is +incorrect, the spec mandates that it behave the same with and without +REPLY_NEEDED because it always sends a reply. + +Fixes: 6fb2e173d20c9bbb5466183d33a3ad7dcd0375fa +Signed-off-by: Kevin Wolf +Message-Id: <20220627134500.94842-3-kwolf@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +Signed-off-by: tangbinzy +--- + subprojects/libvhost-user/libvhost-user.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c +index 787f4d2d4f..27e7799262 100644 +--- a/subprojects/libvhost-user/libvhost-user.c ++++ b/subprojects/libvhost-user/libvhost-user.c +@@ -1788,18 +1788,11 @@ vu_handle_vring_kick(VuDev *dev, VhostUserMsg *vmsg) + + static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg) + { +- vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION; +- vmsg->size = sizeof(vmsg->payload.u64); +- vmsg->payload.u64 = VHOST_USER_MAX_RAM_SLOTS; +- vmsg->fd_num = 0; +- +- if (!vu_message_write(dev, dev->sock, vmsg)) { +- vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno)); +- } ++ vmsg_set_reply_u64(vmsg, VHOST_USER_MAX_RAM_SLOTS); + + DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_USER_MAX_RAM_SLOTS); + +- return false; ++ return true; + } + + static bool +-- +2.27.0 + diff --git a/net-Fix-a-misleading-error-message.patch b/net-Fix-a-misleading-error-message.patch new file mode 100644 index 0000000..75a49b1 --- /dev/null +++ b/net-Fix-a-misleading-error-message.patch @@ -0,0 +1,50 @@ +From 1cc7783df04674ff375905cc9a8ec23f71617408 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Tue, 21 Nov 2023 20:40:24 +0800 +Subject: [PATCH] net: Fix a misleading error message + +cheery-pick from 0a4a1512e01228fc59b00d68e86f7099b6439773 + +The error message + + $ qemu-system-x86_64 -netdev user,id=net0,ipv6-net=fec0::0/ + qemu-system-x86_64: -netdev user,id=net0,ipv6-net=fec0::0/: Parameter 'ipv6-prefixlen' expects a number + +points to ipv6-prefixlen instead of ipv6-net. Fix: + + qemu-system-x86_64: -netdev user,id=net0,ipv6-net=fec0::0/: parameter 'ipv6-net' expects a number after '/' + +Signed-off-by: Markus Armbruster +Message-ID: <20231031111059.3407803-6-armbru@redhat.com> +Signed-off-by: qihao_yewu +--- + net/net.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/net.c b/net/net.c +index ed4b1c1740..daad8784ec 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -1122,7 +1122,7 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) + int ret = -1; + Visitor *v = opts_visitor_new(opts); + +- /* Parse convenience option format ip6-net=fec0::0[/64] */ ++ /* Parse convenience option format ipv6-net=fec0::0[/64] */ + const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); + + if (ip6_net) { +@@ -1142,8 +1142,8 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) + if (substrings[1] && + qemu_strtoul(substrings[1], NULL, 10, &prefix_len)) + { +- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, +- "ipv6-prefixlen", "a number"); ++ error_setg(errp, ++ "parameter 'ipv6-net' expects a number after '/'"); + goto out; + } + +-- +2.27.0 + diff --git a/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch b/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch new file mode 100644 index 0000000..47ea2c8 --- /dev/null +++ b/net-vhost-vdpa.c-Fix-clang-compilation-failure.patch @@ -0,0 +1,62 @@ +From 02c67ab8c1f1e29bf8274d9b460dc2f07b8e195b Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Mon, 31 Oct 2022 13:29:01 +0000 +Subject: [PATCH] net/vhost-vdpa.c: Fix clang compilation failure + +Commit 8801ccd0500437 introduced a compilation failure with clang +version 10.0.0-4ubuntu1: + +../../net/vhost-vdpa.c:654:16: error: variable 'vdpa_device_fd' is +used uninitialized whenever 'if' condition is false +[-Werror,-Wsometimes-uninitialized] + } else if (opts->has_vhostfd) { + ^~~~~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:662:33: note: uninitialized use occurs here + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); + ^~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:654:12: note: remove the 'if' if its condition +is always true + } else if (opts->has_vhostfd) { + ^~~~~~~~~~~~~~~~~~~~~~~ +../../net/vhost-vdpa.c:629:23: note: initialize the variable +'vdpa_device_fd' to silence this warning + int vdpa_device_fd; + ^ + = 0 +1 error generated. + +It's a false positive -- the compiler doesn't manage to figure out +that the error checks further up mean that there's no code path where +vdpa_device_fd isn't initialized. Put another way, the problem is +that we check "if (opts->has_vhostfd)" when in fact that condition +must always be true. A cleverer static analyser would probably warn +that we were checking an always-true condition. + +Fix the compilation failure by removing the unnecessary if(). + +Fixes: 8801ccd0500437 ("vhost-vdpa: allow passing opened vhostfd to vhost-vdpa") +Signed-off-by: Peter Maydell +Message-Id: <20221031132901.1277150-1-peter.maydell@linaro.org> +Signed-off-by: Stefan Hajnoczi +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 58225649f9..c89f9d1243 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -659,7 +659,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (vdpa_device_fd == -1) { + return -errno; + } +- } else if (opts->has_vhostfd) { ++ } else { ++ /* has_vhostfd */ + vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp); + if (vdpa_device_fd == -1) { + error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: "); +-- +2.27.0 + diff --git a/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch b/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch new file mode 100644 index 0000000..e2b162c --- /dev/null +++ b/pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch @@ -0,0 +1,53 @@ +From d81bf8c86e2b024f85d90e199181ae048134d4ee Mon Sep 17 00:00:00 2001 +From: Guoyi Tu +Date: Fri, 11 Aug 2023 22:46:51 +0800 +Subject: [PATCH] pci: Fix the update of interrupt disable bit in PCI_COMMAND + register + +The PCI_COMMAND register is located at offset 4 within +the PCI configuration space and occupies 2 bytes. The +interrupt disable bit is at the 10th bit, which corresponds +to the byte at offset 5 in the PCI configuration space. + +In our testing environment, the guest driver may directly +updates the byte at offset 5 in the PCI configuration space. +The backtrace looks like as following: + at hw/pci/pci.c:1442 + at hw/virtio/virtio-pci.c:605 + val=5, len=1) at hw/pci/pci_host.c:81 + +In this situation, the range_covers_byte function called +by the pci_default_write_config function will return false, +resulting in the inability to handle the interrupt disable +update event. + +To fix this issue, we can use the ranges_overlap function +instead of range_covers_byte to determine whether the interrupt +bit has been updated. + +Signed-off-by: Guoyi Tu +Signed-off-by: yuanminghao +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Fixes: b6981cb57be5 ("pci: interrupt disable bit support") +--- + hw/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 3e6805d54a..3a4619e2a5 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -1471,7 +1471,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int + range_covers_byte(addr, l, PCI_COMMAND)) + pci_update_mappings(d); + +- if (range_covers_byte(addr, l, PCI_COMMAND)) { ++ if (ranges_overlap(addr, l, PCI_COMMAND, 2)) { + pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + (pci_get_word(d->config + PCI_COMMAND) +-- +2.27.0 + diff --git a/pci-fix-overflow-in-snprintf-string-formatting.patch b/pci-fix-overflow-in-snprintf-string-formatting.patch new file mode 100644 index 0000000..e1e2e1b --- /dev/null +++ b/pci-fix-overflow-in-snprintf-string-formatting.patch @@ -0,0 +1,106 @@ +From b2d665abb4dbd3c91c0ceceebe537cf411f6c650 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:35:28 +0000 +Subject: [PATCH] pci: fix overflow in snprintf string formatting mainline + inclusion commit 36f18c6989a3d1ff1d7a0e50b0868ef3958299b4 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +the code in pcibus_get_fw_dev_path contained the potential for a +stack buffer overflow of 1 byte, potentially writing to the stack an +extra NUL byte. + +This overflow could happen if the PCI slot is >= 0x10000000, +and the PCI function is >= 0x10000000, due to the size parameter +of snprintf being incorrectly calculated in the call: + + if (PCI_FUNC(d->devfn)) + snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); + +since the off obtained from a previous call to snprintf is added +instead of subtracted from the total available size of the buffer. + +Without the accurate size guard from snprintf, we end up writing in the +worst case: + +name (32) + "@" (1) + SLOT (8) + "," (1) + FUNC (8) + term NUL (1) = 51 bytes + +In order to provide something more robust, replace all of the code in +pcibus_get_fw_dev_path with a single call to g_strdup_printf, +so there is no need to rely on manual calculations. + +Found by compiling QEMU with FORTIFY_SOURCE=3 as the error: + +*** buffer overflow detected ***: terminated + +Thread 1 "qemu-system-x86" received signal SIGABRT, Aborted. +[Switching to Thread 0x7ffff642c380 (LWP 121307)] +0x00007ffff71ff55c in __pthread_kill_implementation () from /lib64/libc.so.6 +(gdb) bt + #0 0x00007ffff71ff55c in __pthread_kill_implementation () at /lib64/libc.so.6 + #1 0x00007ffff71ac6f6 in raise () at /lib64/libc.so.6 + #2 0x00007ffff7195814 in abort () at /lib64/libc.so.6 + #3 0x00007ffff71f279e in __libc_message () at /lib64/libc.so.6 + #4 0x00007ffff729767a in __fortify_fail () at /lib64/libc.so.6 + #5 0x00007ffff7295c36 in () at /lib64/libc.so.6 + #6 0x00007ffff72957f5 in __snprintf_chk () at /lib64/libc.so.6 + #7 0x0000555555b1c1fd in pcibus_get_fw_dev_path () + #8 0x0000555555f2bde4 in qdev_get_fw_dev_path_helper.constprop () + #9 0x0000555555f2bd86 in qdev_get_fw_dev_path_helper.constprop () + #10 0x00005555559a6e5d in get_boot_device_path () + #11 0x00005555559a712c in get_boot_devices_list () + #12 0x0000555555b1a3d0 in fw_cfg_machine_reset () + #13 0x0000555555bf4c2d in pc_machine_reset () + #14 0x0000555555c66988 in qemu_system_reset () + #15 0x0000555555a6dff6 in qdev_machine_creation_done () + #16 0x0000555555c79186 in qmp_x_exit_preconfig.part () + #17 0x0000555555c7b459 in qemu_init () + #18 0x0000555555960a29 in main () + +Found-by: Dario Faggioli +Found-by: Martin LiÅ¡ka +Cc: qemu-stable@nongnu.org +Signed-off-by: Claudio Fontana +Message-Id: <20220531114707.18830-1-cfontana@suse.de> +Reviewed-by: Ani Sinha + +Signed-off-by: tangbinzy +--- + hw/pci/pci.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/hw/pci/pci.c b/hw/pci/pci.c +index 3e6805d54a..6a5e8a3654 100644 +--- a/hw/pci/pci.c ++++ b/hw/pci/pci.c +@@ -2588,15 +2588,15 @@ static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len) + static char *pcibus_get_fw_dev_path(DeviceState *dev) + { + PCIDevice *d = (PCIDevice *)dev; +- char path[50], name[33]; +- int off; +- +- off = snprintf(path, sizeof(path), "%s@%x", +- pci_dev_fw_name(dev, name, sizeof name), +- PCI_SLOT(d->devfn)); +- if (PCI_FUNC(d->devfn)) +- snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); +- return g_strdup(path); ++ char name[33]; ++ int has_func = !!PCI_FUNC(d->devfn); ++ ++ return g_strdup_printf("%s@%x%s%.*x", ++ pci_dev_fw_name(dev, name, sizeof(name)), ++ PCI_SLOT(d->devfn), ++ has_func ? "," : "", ++ has_func, ++ PCI_FUNC(d->devfn)); + } + + static char *pcibus_get_dev_path(DeviceState *dev) +-- +2.27.0 + diff --git a/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch b/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch new file mode 100644 index 0000000..2578891 --- /dev/null +++ b/qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch @@ -0,0 +1,39 @@ +From 274dd10230eef97714a2a283ecd8a8ce2ecbf687 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 07:28:31 +0000 +Subject: [PATCH] qemu-timer: Skip empty timer lists before locking in + qemu_clock_deadline_ns_all mainline inclusion commit + 3f42906c9ab2c777a895b48b87b8107167e4a275 category: bugfix + +--------------------------------------------------------------- + +This decreases qemu_clock_deadline_ns_all's share from 23.2% to 13% in a +profile of icount-enabled aarch64-softmmu. + +Signed-off-by: Idan Horowitz +Reviewed-by: Richard Henderson +Message-Id: <20220114004358.299534-2-idan.horowitz@gmail.com> +Signed-off-by: Richard Henderson + +Signed-off-by: tangbinzy +--- + util/qemu-timer.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/util/qemu-timer.c b/util/qemu-timer.c +index 40e8c83722..c5b6dc987c 100644 +--- a/util/qemu-timer.c ++++ b/util/qemu-timer.c +@@ -330,6 +330,9 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask) + } + + QLIST_FOREACH(timer_list, &clock->timerlists, list) { ++ if (!qatomic_read(&timer_list->active_timers)) { ++ continue; ++ } + qemu_mutex_lock(&timer_list->active_timers_lock); + ts = timer_list->active_timers; + /* Skip all external timers */ +-- +2.27.0 + diff --git a/qemu.spec b/qemu.spec index 7e42c71..be32300 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 6.2.0 -Release: 83 +Release: 84 Epoch: 10 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -599,6 +599,192 @@ Patch0584: disas-riscv-Fix-the-typo-of-inverted-order-of-pmpadd.patch Patch0585: softmmu-dirtylimit-Add-parameter-check-for-hmp-set_v.patch Patch0586: tests-Fix-printf-format-string-in-acpi-utils.c.patch Patch0587: hw-virtio-virtio-pmem-Replace-impossible-check-by-as.patch +Patch0588: target-i386-Export-GDS_NO-bit-to-guests.patch +Patch0589: semihosting-fix-memleak-at-semihosting_arg_fallback.patch +Patch0590: semihosting-config-Merge-semihosting-config-option-g.patch +Patch0591: qemu-timer-Skip-empty-timer-lists-before-locking-in-.patch +Patch0592: hw-usb-hcd-ehci-fix-writeback-order.patch +Patch0593: pci-fix-overflow-in-snprintf-string-formatting.patch +Patch0594: tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch +Patch0595: hw-timer-npcm7xx_timer-Prevent-timer-from-counting-d.patch +Patch0596: pci-Fix-the-update-of-interrupt-disable-bit-in-PCI_C.patch +Patch0597: virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch +Patch0598: virtio-pci-decouple-notifier-from-interrupt-process.patch +Patch0599: virtio-pci-decouple-the-single-vector-from-the-inter.patch +Patch0600: vhost-vdpa-add-support-for-config-interrupt.patch +Patch0601: virtio-add-support-for-configure-interrupt.patch +Patch0602: vhost-add-support-for-configure-interrupt.patch +Patch0603: virtio-net-add-support-for-configure-interrupt.patch +Patch0604: virtio-mmio-add-support-for-configure-interrupt.patch +Patch0605: virtio-pci-add-support-for-configure-interrupt.patch +Patch0606: vhost-vdpa-stick-to-errno-error-return-convention.patch +Patch0607: vhost-user-stick-to-errno-error-return-convention.patch +Patch0608: vhost-stick-to-errno-error-return-convention.patch +Patch0609: vhost-introduce-new-VhostOps-vhost_set_config_call.patch +Patch0610: e1000-set-RX-descriptor-status-in-a-separate-operati.patch +Patch0611: virtio-iommu-Fix-the-partial-copy-of-probe-request.patch +Patch0612: artist-set-memory-region-owners-for-buffers-to-the-a.patch +Patch0613: qom-object-Remove-circular-include-dependency.patch +Patch0614: vga-avoid-crash-if-no-default-vga-card.patch +Patch0615: hw-pvrdma-Protect-against-buggy-or-malicious-guest-driver.patch +Patch0616: tracetool-avoid-invalid-escape-in-Python-string.patch +Patch0617: target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch +Patch0618: target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch +Patch0619: target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch +Patch0620: target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch +Patch0621: target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch +Patch0622: target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch +Patch0623: target-i386-Add-new-CPU-model-GraniteRapids.patch +Patch0624: target-i386-Adjust-feature-level-according-to-FEAT_7.patch +Patch0625: virtio-signal-after-wrapping-packed-used_idx.patch +Patch0626: Revert-vhost-introduce-new-VhostOps-vhost_set_config.patch +Patch0627: Revert-virtio-pci-add-support-for-configure-interrup.patch +Patch0628: Revert-virtio-mmio-add-support-for-configure-interru.patch +Patch0629: Revert-virtio-net-add-support-for-configure-interrup.patch +Patch0630: Revert-vhost-add-support-for-configure-interrupt.patch +Patch0631: Revert-virtio-add-support-for-configure-interrupt.patch +Patch0632: Revert-vhost-vdpa-add-support-for-config-interrupt.patch +Patch0633: Revert-virtio-pci-decouple-the-single-vector-from-th.patch +Patch0634: Revert-virtio-pci-decouple-notifier-from-interrupt-p.patch +Patch0635: Revert-virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch +Patch0636: vdpa-Make-ncs-autofree.patch +Patch0637: vhost-Add-VhostShadowVirtqueue.patch +Patch0638: vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch +Patch0639: vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch +Patch0640: vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch +Patch0641: virtio-Add-vhost_svq_get_vring_addr.patch +Patch0642: vdpa-adapt-vhost_ops-callbacks-to-svq.patch +Patch0643: vhost-Shadow-virtqueue-buffers-forwarding.patch +Patch0644: util-Add-iova_tree_alloc_map.patch +Patch0645: util-add-iova_tree_find_iova.patch +Patch0646: vhost-Add-VhostIOVATree.patch +Patch0647: vdpa-Add-custom-IOTLB-translations-to-SVQ.patch +Patch0648: vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch +Patch0649: vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch +Patch0650: vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch +Patch0651: virtio-fix-enable-vhost-user-build-on-non-Linux.patch +Patch0652: vhost-vdpa-fix-typo-in-a-comment.patch +Patch0653: vdpa-Add-missing-tracing-to-batch-mapping-functions.patch +Patch0654: vhost-Track-descriptor-chain-in-private-at-SVQ.patch +Patch0655: vhost-Fix-device-s-used-descriptor-dequeue.patch +Patch0656: vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch +Patch0657: vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch +Patch0658: vhost-Fix-element-in-vhost_svq_add-failure.patch +Patch0659: hw-virtio-add-vhost_user_-read-write-trace-points.patch +Patch0660: include-hw-start-documenting-the-vhost-API.patch +Patch0661: virtio-add-vhost-support-for-virtio-devices.patch +Patch0662: virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch +Patch0663: vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch +Patch0664: vhost-vdpa-backend-feature-should-set-only-once.patch +Patch0665: vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch +Patch0666: virtio-net-don-t-handle-mq-request-in-userspace-hand.patch +Patch0667: util-Return-void-on-iova_tree_remove.patch +Patch0668: vhost-move-descriptor-translation-to-vhost_svq_vring.patch +Patch0669: virtio-net-Expose-MAC_TABLE_ENTRIES.patch +Patch0670: virtio-net-Expose-ctrl-virtqueue-logic.patch +Patch0671: vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch +Patch0672: vhost-Reorder-vhost_svq_kick.patch +Patch0673: vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch +Patch0674: vhost-Check-for-queue-full-at-vhost_svq_add.patch +Patch0675: vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch +Patch0676: vhost-Add-SVQDescState.patch +Patch0677: vhost-Track-number-of-descs-in-SVQDescState.patch +Patch0678: vhost-add-vhost_svq_push_elem.patch +Patch0679: vhost-Expose-vhost_svq_add.patch +Patch0680: vhost-add-vhost_svq_poll.patch +Patch0681: vhost-Add-svq-avail_handler-callback.patch +Patch0682: vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch +Patch0683: vdpa-manual-forward-CVQ-buffers.patch +Patch0684: vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch +Patch0685: vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch +Patch0686: vdpa-Add-device-migration-blocker.patch +Patch0687: vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch +Patch0688: vhost-Get-vring-base-from-vq-not-svq.patch +Patch0689: vdpa-Fix-memory-listener-deletions-of-iova-tree.patch +Patch0690: vdpa-Fix-file-descriptor-leak-on-get-features-error.patch +Patch0691: vdpa-Skip-the-maps-not-in-the-iova-tree.patch +Patch0692: vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch +Patch0693: util-accept-iova_tree_remove_parameter-by-value.patch +Patch0694: vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch +Patch0695: vdpa-Make-SVQ-vring-unmapping-return-void.patch +Patch0696: vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch +Patch0697: vhost_net-Add-NetClientInfo-start-callback.patch +Patch0698: vhost_net-Add-NetClientInfo-stop-callback.patch +Patch0699: vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch +Patch0700: vdpa-Move-command-buffers-map-to-start-of-net-device.patch +Patch0701: vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch +Patch0702: vhost_net-add-NetClientState-load-callback.patch +Patch0703: vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch +Patch0704: vdpa-Delete-CVQ-migration-blocker.patch +Patch0705: vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch +Patch0706: vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch +Patch0707: vdpa-Add-vhost_vdpa_net_load_mq.patch +Patch0708: vdpa-validate-MQ-CVQ-commands.patch +Patch0709: virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch +Patch0710: vdpa-Allow-MQ-feature-in-SVQ.patch +Patch0711: hw-virtio-add-some-vhost-user-trace-events.patch +Patch0712: vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch +Patch0713: vdpa-Remove-shadow-CVQ-command-check.patch +Patch0714: vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch +Patch0715: net-vhost-vdpa.c-Fix-clang-compilation-failure.patch +Patch0716: vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch +Patch0717: vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch +Patch0718: vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch +Patch0719: vhost-set-SVQ-device-call-handler-at-SVQ-start.patch +Patch0720: vhost-allocate-SVQ-device-file-descriptors-at-device.patch +Patch0721: vdpa-add-vhost_vdpa_net_valid_svq_features.patch +Patch0722: vdpa-request-iova_range-only-once.patch +Patch0723: vdpa-move-SVQ-vring-features-check-to-net.patch +Patch0724: vdpa-allocate-SVQ-array-unconditionally.patch +Patch0725: vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch +Patch0726: vdpa-store-x-svq-parameter-in-VhostVDPAState.patch +Patch0727: vdpa-add-shadow_data-to-vhost_vdpa.patch +Patch0728: vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch +Patch0729: hw-virtio-vhost-Fix-typo-in-comment.patch +Patch0730: hw-virtio-gracefully-handle-unset-vhost_dev-vdev.patch +Patch0731: vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch +Patch0732: vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch +Patch0733: vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch +Patch0734: virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch +Patch0735: virtio-pci-decouple-notifier-from-interrupt-process-new.patch +Patch0736: virtio-pci-decouple-the-single-vector-from-the-inter-new.patch +Patch0737: vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch +Patch0738: vhost-vdpa-add-support-for-config-interrupt-new.patch +Patch0739: virtio-add-support-for-configure-interrupt-new.patch +Patch0740: vhost-add-support-for-configure-interrupt-new.patch +Patch0741: virtio-net-add-support-for-configure-interrupt-new.patch +Patch0742: virtio-mmio-add-support-for-configure-interrupt-new.patch +Patch0743: virtio-pci-add-support-for-configure-interrupt-new.patch +Patch0744: vdpa-dev-get-iova-range-explicitly.patch +Patch0745: vdpa-harden-the-error-path-if-get_iova_range-failed.patch +Patch0746: vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch +Patch0747: virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch +Patch0748: vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch +Patch0749: vhost-move-iova_tree-set-to-vhost_svq_start.patch +Patch0750: vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch +Patch0751: vhost-Fix-false-positive-out-of-bounds.patch +Patch0752: hw-virtio-fix-vhost_user_read-tracepoint.patch +Patch0753: vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch +Patch0754: vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch +Patch0755: vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch +Patch0756: vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch +Patch0757: vdpa-net-block-migration-if-the-device-has-CVQ.patch +Patch0758: vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch +Patch0759: vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch +Patch0760: virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch +Patch0761: hw-virtio-fix-typo-in-VIRTIO_CONFIG_IRQ_IDX-comments.patch +Patch0762: virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch +Patch0763: vhost-fix-the-fd-leak.patch +Patch0764: vhost-release-virtqueue-objects-in-error-path.patch +Patch0765: vdpa-stop-all-svq-on-device-deletion.patch +Patch0766: net-Fix-a-misleading-error-message.patch +Patch0767: qsd-Unlink-absolute-PID-file-path.patch +Patch0768: libvhost-user-Fix-VHOST_USER_ADD_MEM_REG-reply.patch +Patch0769: io_uring-fix-short-read-slow-path.patch +Patch0770: libvhost-user-Fix-VHOST_USER_GET_MAX_MEM_SLOTS-reply.patch +Patch0771: tests-qtest-check-the-return-value.patch +Patch0772: hw-net-cadence_gem.c-spelling-fixes-Octects.patch +Patch0773: hw-arm-fsl-imx-Do-not-ignore-Error-argument.patch BuildRequires: flex BuildRequires: gcc @@ -1172,6 +1358,194 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Tue Nov 28 2023 - 10:6.2.0-84 +- hw/arm/fsl-imx: Do not ignore Error argument +- hw/net/cadence_gem.c: spelling fixes: Octects +- tests/qtest: check the return value +- libvhost-user: Fix VHOST_USER_GET_MAX_MEM_SLOTS reply mainline inclusion commit 69a5daec06f423843ce1bb9be5fb049314996f78 category: bugfix +- io_uring: fix short read slow path mainline inclusion commit c06fc7ce147e57ab493bad9263f1601b8298484b category: bugfix +- libvhost-user: Fix VHOST_USER_ADD_MEM_REG reply mainline inclusion commit 7f27d20ded2f480f3e66d03f90ea71507b834276 category: bugfix +- qsd: Unlink absolute PID file path mainline inclusion commit 9d8f8233b9fa525a7e37350fbc18877051128c5d category: bugfix +- net: Fix a misleading error message +- vdpa: stop all svq on device deletion +- vhost: release virtqueue objects in error path +- vhost: fix the fd leak +- virtio: i2c: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX +- hw/virtio: fix typo in VIRTIO_CONFIG_IRQ_IDX comments +- virtio-net: clear guest_announce feature if no cvq backend +- vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check +- vdpa: do not block migration if device has cvq and x-svq=on +- vdpa net: block migration if the device has CVQ +- vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mq() +- vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in _load_mac() +- vdpa: fix not using CVQ buffer in case of error +- vdpa: Fix possible use-after-free for VirtQueueElement +- hw/virtio: fix vhost_user_read tracepoint +- vhost: Fix false positive out-of-bounds +- vhost: fix possible wrap in SVQ descriptor ring +- vhost: move iova_tree set to vhost_svq_start +- vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd +- virtio-crypto: verify src&dst buffer length for sym request +- vdpa: commit all host notifier MRs in a single MR transaction +- vdpa: harden the error path if get_iova_range failed +- vdpa-dev: get iova range explicitly +- virtio-pci: add support for configure interrupt +- virtio-mmio: add support for configure interrupt +- virtio-net: add support for configure interrupt +- vhost: add support for configure interrupt +- virtio: add support for configure interrupt +- vhost-vdpa: add support for config interrupt +- vhost: introduce new VhostOps vhost_set_config_call +- virtio-pci: decouple the single vector from the interrupt process +- virtio-pci: decouple notifier from interrupt process +- virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX +- vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa +- vdpa: handle VIRTIO_NET_CTRL_ANNOUNCE in vhost_vdpa_net_handle_ctrl_avail +- vhost: fix vq dirty bitmap syncing when vIOMMU is enabled +- hw/virtio: gracefully handle unset vhost_dev vdev +- hw/virtio/vhost: Fix typo in comment. +- vdpa: always start CVQ in SVQ mode if possible +- vdpa: add shadow_data to vhost_vdpa +- vdpa: store x-svq parameter in VhostVDPAState +- vdpa: add asid parameter to vhost_vdpa_dma_map/unmap +- vdpa: allocate SVQ array unconditionally +- vdpa: move SVQ vring features check to net/ +- vdpa: request iova_range only once +- vdpa: add vhost_vdpa_net_valid_svq_features +- vhost: allocate SVQ device file descriptors at device start +- vhost: set SVQ device call handler at SVQ start +- vdpa: use v->shadow_vqs_enabled in vhost_vdpa_svqs_start & stop +- vhost: enable vrings in vhost_dev_start() for vhost-user devices +- vhost-vdpa: fix assert !virtio_net_get_subqueue(nc)->async_tx.elem in virtio_net_reset +- net/vhost-vdpa.c: Fix clang compilation failure +- vhost-vdpa: allow passing opened vhostfd to vhost-vdpa +- vdpa: Remove shadow CVQ command check +- vdpa: Delete duplicated vdpa_feature_bits entry +- hw/virtio: add some vhost-user trace events +- vdpa: Allow MQ feature in SVQ +- virtio-net: Update virtio-net curr_queue_pairs in vdpa backends +- vdpa: validate MQ CVQ commands +- vdpa: Add vhost_vdpa_net_load_mq +- vdpa: extract vhost_vdpa_net_load_mac from vhost_vdpa_net_load +- vdpa: Make VhostVDPAState cvq_cmd_in_buffer control ack type +- vdpa: Delete CVQ migration blocker +- vdpa: Add virtio-net mac address via CVQ at start +- vhost_net: add NetClientState->load() callback +- vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail +- vdpa: Move command buffers map to start of net device +- vdpa: add net_vhost_vdpa_cvq_info NetClientInfo +- vhost_net: Add NetClientInfo stop callback +- vhost_net: Add NetClientInfo start callback +- vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring +- vdpa: Make SVQ vring unmapping return void +- vdpa: Remove SVQ vring from iova_tree at shutdown +- util: accept iova_tree_remove_parameter by value +- vdpa: do not save failed dma maps in SVQ iova tree +- vdpa: Skip the maps not in the iova tree +- vdpa: Fix file descriptor leak on get features error +- vdpa: Fix memory listener deletions of iova tree +- vhost: Get vring base from vq, not svq +- vdpa: Add x-svq to NetdevVhostVDPAOptions +- vdpa: Add device migration blocker +- vdpa: Extract get features part from vhost_vdpa_get_max_queue_pairs +- vdpa: Buffer CVQ support on shadow virtqueue +- vdpa: manual forward CVQ buffers +- vdpa: Export vhost_vdpa_dma_map and unmap calls +- vhost: Add svq avail_handler callback +- vhost: add vhost_svq_poll +- vhost: Expose vhost_svq_add +- vhost: add vhost_svq_push_elem +- vhost: Track number of descs in SVQDescState +- vhost: Add SVQDescState +- vhost: Decouple vhost_svq_add from VirtQueueElement +- vhost: Check for queue full at vhost_svq_add +- vhost: Move vhost_svq_kick call to vhost_svq_add +- vhost: Reorder vhost_svq_kick +- vdpa: Avoid compiler to squash reads to used idx +- virtio-net: Expose ctrl virtqueue logic +- virtio-net: Expose MAC_TABLE_ENTRIES +- vhost: move descriptor translation to vhost_svq_vring_write_descs +- util: Return void on iova_tree_remove +- virtio-net: don't handle mq request in userspace handler for vhost-vdpa +- vhost-vdpa: change name and polarity for vhost_vdpa_one_time_request() +- vhost-vdpa: backend feature should set only once +- vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa +- virtio-net: align ctrl_vq index for non-mq guest for vhost_vdpa +- virtio: add vhost support for virtio devices +- include/hw: start documenting the vhost API +- hw/virtio: add vhost_user_[read|write] trace points +- vhost: Fix element in vhost_svq_add failure +- vdpa: Fix index calculus at vhost_vdpa_svqs_start +- vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base +- vhost: Fix device's used descriptor dequeue +- vhost: Track descriptor chain in private at SVQ +- vdpa: Add missing tracing to batch mapping functions +- vhost-vdpa: fix typo in a comment +- virtio: fix --enable-vhost-user build on non-Linux +- vdpa: Expose VHOST_F_LOG_ALL on SVQ +- vdpa: Never set log_base addr if SVQ is enabled +- vdpa: Adapt vhost_vdpa_get_vring_base to SVQ +- vdpa: Add custom IOTLB translations to SVQ +- vhost: Add VhostIOVATree +- util: add iova_tree_find_iova +- util: Add iova_tree_alloc_map +- vhost: Shadow virtqueue buffers forwarding +- vdpa: adapt vhost_ops callbacks to svq +- virtio: Add vhost_svq_get_vring_addr +- vhost: Add vhost_svq_valid_features to shadow vq +- vhost: Add Shadow VirtQueue call forwarding capabilities +- vhost: Add Shadow VirtQueue kick forwarding capabilities +- vhost: Add VhostShadowVirtqueue +- vdpa: Make ncs autofree +- Revert "virtio: introduce macro IRTIO_CONFIG_IRQ_IDX" +- Revert "virtio-pci: decouple notifier from interrupt process" +- Revert "virtio-pci: decouple the single vector from the interrupt process" +- Revert "vhost-vdpa: add support for config interrupt" +- Revert "virtio: add support for configure interrupt" +- Revert "vhost: add support for configure interrupt" +- Revert "virtio-net: add support for configure interrupt" +- Revert "virtio-mmio: add support for configure interrupt" +- Revert "virtio-pci: add support for configure interrupt" +- Revert "vhost: introduce new VhostOps vhost_set_config_call" +- virtio: signal after wrapping packed used_idx +- target/i386: Adjust feature level according to FEAT_7_1_EDX +- target/i386: Add new CPU model GraniteRapids +- target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration +- target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration +- target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration +- target/i386: Add support for AVX-IFMA in CPUID enumeration +- target/i386: Add support for AMX-FP16 in CPUID enumeration +- target/i386: Add support for CMPCCXADD in CPUID enumeration +- tracetool: avoid invalid escape in Python string +- hw/pvrdma: Protect against buggy or malicious guest driver +- vga: avoid crash if no default vga card mainline inclusion commit 6985d8ede92494f3b791de01e8ee9306eb6d5e4a category: bugfix +- qom/object: Remove circular include dependency mainline inclusion commit 5bba9bcfbb42e7c016626420e148a1bf1b080835 category: bugfix +- artist: set memory region owners for buffers to the artist device mainline inclusion commit 39fbaeca096a9bf6cbe2af88572c1cb2aa62aa8c category: bugfix +- virtio-iommu: Fix the partial copy of probe request mainline inclusion commit 45461aace83d961e933b27519b81d17b4c690514 category: bugfix +- e1000: set RX descriptor status in a separate operation mainline inclusion commit 034d00d4858161e1d4cff82d8d230bce874a04d3 category: bugfix +- vhost: introduce new VhostOps vhost_set_config_call +- vhost: stick to -errno error return convention +- vhost-user: stick to -errno error return convention +- vhost-vdpa: stick to -errno error return convention +- virtio-pci: add support for configure interrupt +- virtio-mmio: add support for configure interrupt +- virtio-net: add support for configure interrupt +- vhost: add support for configure interrupt +- virtio: add support for configure interrupt +- vhost-vdpa: add support for config interrupt +- virtio-pci: decouple the single vector from the interrupt process +- virtio-pci: decouple notifier from interrupt process +- virtio: introduce macro IRTIO_CONFIG_IRQ_IDX +- pci: Fix the update of interrupt disable bit in PCI_COMMAND register +- hw/timer/npcm7xx_timer: Prevent timer from counting down past zero +- tpm_crb: mark command buffer as dirty on request completion mainline inclusion commit e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 category: bugfix +- pci: fix overflow in snprintf string formatting mainline inclusion commit 36f18c6989a3d1ff1d7a0e50b0868ef3958299b4 category: bugfix +- hw/usb/hcd-ehci: fix writeback order mainline inclusion commit f471e8b060798f26a7fc339c6152f82f22a7b33d category: bugfix +- qemu-timer: Skip empty timer lists before locking in qemu_clock_deadline_ns_all mainline inclusion commit 3f42906c9ab2c777a895b48b87b8107167e4a275 category: bugfix +- semihosting/config: Merge --semihosting-config option groups mainline inclusion commit 90c072e063737e9e8f431489bbd334452f89056e category: bugfix +- semihosting: fix memleak at semihosting_arg_fallback +- target/i386: Export GDS_NO bit to guests + * Mon Oct 30 2023 - 10:6.2.0-83 - hw/virtio/virtio-pmem: Replace impossible check by assertion - tests: Fix printf format string in acpi-utils.c diff --git a/qom-object-Remove-circular-include-dependency.patch b/qom-object-Remove-circular-include-dependency.patch new file mode 100644 index 0000000..f527a3b --- /dev/null +++ b/qom-object-Remove-circular-include-dependency.patch @@ -0,0 +1,41 @@ +From e4393667e45bdcf04150ada3840a6d87e3188d36 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:13:07 +0000 +Subject: [PATCH] qom/object: Remove circular include dependency mainline + inclusion commit 5bba9bcfbb42e7c016626420e148a1bf1b080835 category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +"qom/object.h" doesn't need to include itself. + +Fixes: db1015e92e04 ("Move QOM typedefs and add missing includes") +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Damien Hedde +Reviewed-by: Peter Maydell +Reviewed-by: Markus Armbruster +Message-Id: <20220509084659.52076-1-philippe.mathieu.daude@gmail.com> +Signed-off-by: Laurent Vivier + +Signed-off-by: tangbinzy +--- + include/qom/object.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/include/qom/object.h b/include/qom/object.h +index fae096f51c..f658e1e0a0 100644 +--- a/include/qom/object.h ++++ b/include/qom/object.h +@@ -16,7 +16,6 @@ + + #include "qapi/qapi-builtin-types.h" + #include "qemu/module.h" +-#include "qom/object.h" + + struct TypeImpl; + typedef struct TypeImpl *Type; +-- +2.27.0 + diff --git a/qsd-Unlink-absolute-PID-file-path.patch b/qsd-Unlink-absolute-PID-file-path.patch new file mode 100644 index 0000000..7c5138a --- /dev/null +++ b/qsd-Unlink-absolute-PID-file-path.patch @@ -0,0 +1,81 @@ +From 43668bdb7ebaa64536277d4b5b47875e58a3452a Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Tue, 21 Nov 2023 07:00:39 +0000 +Subject: [PATCH] qsd: Unlink absolute PID file path mainline inclusion commit + 9d8f8233b9fa525a7e37350fbc18877051128c5d category: bugfix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--------------------------------------------------------------- + +After writing the PID file, we register an atexit() handler to unlink it +when the process terminates. However, if the process has changed its +working directory in the meantime (e.g. in os_setup_post() when +daemonizing), this will not work when the PID file path was relative. +Therefore, pass the absolute path (created with realpath()) to the +unlink() call in the atexit() handler. + +(realpath() needs a path pointing to an existing file, so we cannot use +it before qemu_write_pidfile().) + +Reproducer: +$ cd /tmp +$ qemu-storage-daemon --daemonize --pidfile qsd.pid +$ file qsd.pid +qsd.pid: ASCII text +$ kill $(cat qsd.pid) +$ file qsd.pid +qsd.pid: ASCII text + +(qsd.pid should be gone after the process has terminated.) + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2092322 +Signed-off-by: Hanna Reitz +Message-Id: <20220609122701.17172-2-hreitz@redhat.com> +Reviewed-by: Daniel P. Berrangé + +Signed-off-by: tangbinzy +--- + storage-daemon/qemu-storage-daemon.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c +index 52cf17e8ac..f3d8c4ca11 100644 +--- a/storage-daemon/qemu-storage-daemon.c ++++ b/storage-daemon/qemu-storage-daemon.c +@@ -60,6 +60,7 @@ + #include "trace/control.h" + + static const char *pid_file; ++static char *pid_file_realpath; + static volatile bool exit_requested = false; + + void qemu_system_killed(int signal, pid_t pid) +@@ -292,7 +293,7 @@ static void process_options(int argc, char *argv[]) + + static void pid_file_cleanup(void) + { +- unlink(pid_file); ++ unlink(pid_file_realpath); + } + + static void pid_file_init(void) +@@ -308,6 +309,14 @@ static void pid_file_init(void) + exit(EXIT_FAILURE); + } + ++ pid_file_realpath = g_malloc(PATH_MAX); ++ if (!realpath(pid_file, pid_file_realpath)) { ++ error_report("cannot resolve PID file path: %s: %s", ++ pid_file, strerror(errno)); ++ unlink(pid_file); ++ exit(EXIT_FAILURE); ++ } ++ + atexit(pid_file_cleanup); + } + +-- +2.27.0 + diff --git a/semihosting-config-Merge-semihosting-config-option-g.patch b/semihosting-config-Merge-semihosting-config-option-g.patch new file mode 100644 index 0000000..c7c9e59 --- /dev/null +++ b/semihosting-config-Merge-semihosting-config-option-g.patch @@ -0,0 +1,54 @@ +From ff7918646e3c696d13732fb22f032d7d78c34fe1 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 08:15:13 +0000 +Subject: [PATCH] semihosting/config: Merge --semihosting-config option groups + mainline inclusion commit 90c072e063737e9e8f431489bbd334452f89056e category: + bugfix + +--------------------------------------------------------------- + +Currently we mishandle the --semihosting-config option if the +user specifies it on the command line more than once. For +example with: + --semihosting-config target=gdb --semihosting-config arg=foo,arg=bar + +the function qemu_semihosting_config_options() is called twice, once +for each argument. But that function expects to be called only once, +and it always unconditionally sets the semihosting.enabled, +semihost_chardev and semihosting.target variables. This means that +if any of those options were set anywhere except the last +--semihosting-config option on the command line, those settings are +ignored. In the example above, 'target=gdb' in the first option is +overridden by an implied default 'target=auto' in the second. + +The QemuOptsList machinery has a flag for handling this kind of +"option group is setting global state": by setting + .merge_lists = true; +we make the machinery merge all the --semihosting-config arguments +the user passes into a single set of options and call our +qemu_semihosting_config_options() just once. + +Signed-off-by: Peter Maydell +Reviewed-by: Luc Michel +Message-id: 20220526190053.521505-3-peter.maydell@linaro.org + +Signed-off-by: tangbinzy +--- + semihosting/config.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/semihosting/config.c b/semihosting/config.c +index 137171b717..ba3e310a61 100644 +--- a/semihosting/config.c ++++ b/semihosting/config.c +@@ -27,6 +27,7 @@ + + QemuOptsList qemu_semihosting_config_opts = { + .name = "semihosting-config", ++ .merge_lists = true, + .implied_opt_name = "enable", + .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head), + .desc = { +-- +2.27.0 + diff --git a/semihosting-fix-memleak-at-semihosting_arg_fallback.patch b/semihosting-fix-memleak-at-semihosting_arg_fallback.patch new file mode 100644 index 0000000..ccee1a5 --- /dev/null +++ b/semihosting-fix-memleak-at-semihosting_arg_fallback.patch @@ -0,0 +1,47 @@ +From 47a24e233e335025ed37ab0ba4a4e728719a2ad3 Mon Sep 17 00:00:00 2001 +From: qihao +Date: Mon, 6 Nov 2023 18:14:06 +0800 +Subject: [PATCH] semihosting: fix memleak at semihosting_arg_fallback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 2eb71a0c20a6a77be128a76c1ef8fb5dc7028a8b + +We duplicate "cmd" as strtok may modify its argument, but we forgot +to free it later. Furthermore, add_semihosting_arg doesn't take +responsibility for this memory either (it strdup's the argument). + +Signed-off-by: Matheus Tavares Bernardino +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <03d81c56bfc3d08224e4106efca5949d8894cfa5.1697801632.git.quic_mathbern@quicinc.com> +Reviewed-by: Richard Henderson +Signed-off-by: Alex Bennée +Message-Id: <20231029145033.592566-18-alex.bennee@linaro.org> +Signed-off-by: qihao_yewu +--- + semihosting/config.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/semihosting/config.c b/semihosting/config.c +index 137171b717..303338f647 100644 +--- a/semihosting/config.c ++++ b/semihosting/config.c +@@ -109,12 +109,13 @@ static int add_semihosting_arg(void *opaque, + void semihosting_arg_fallback(const char *file, const char *cmd) + { + char *cmd_token; ++ g_autofree char *cmd_dup = g_strdup(cmd); + + /* argv[0] */ + add_semihosting_arg(&semihosting, "arg", file, NULL); + + /* split -append and initialize argv[1..n] */ +- cmd_token = strtok(g_strdup(cmd), " "); ++ cmd_token = strtok(cmd_dup, " "); + while (cmd_token) { + add_semihosting_arg(&semihosting, "arg", cmd_token, NULL); + cmd_token = strtok(NULL, " "); +-- +2.27.0 + diff --git a/target-i386-Add-new-CPU-model-GraniteRapids.patch b/target-i386-Add-new-CPU-model-GraniteRapids.patch new file mode 100644 index 0000000..24672e9 --- /dev/null +++ b/target-i386-Add-new-CPU-model-GraniteRapids.patch @@ -0,0 +1,183 @@ +From 7ebcbfb9ac1d53ea46bfd86fa7f0a90a4012412e Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:49 +0800 +Subject: [PATCH] target/i386: Add new CPU model GraniteRapids + +commit 6d5e9694ef374159072984c0958c3eaab6dd1d52 upstream. + +The GraniteRapids CPU model mainly adds the following new features +based on SapphireRapids: +- PREFETCHITI CPUID.(EAX=7,ECX=1):EDX[bit 14] +- AMX-FP16 CPUID.(EAX=7,ECX=1):EAX[bit 21] + +And adds the following security fix for corresponding vulnerabilities: +- MCDT_NO CPUID.(EAX=7,ECX=2):EDX[bit 5] +- SBDR_SSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 13] +- FBSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 14] +- PSDP_NO MSR_IA32_ARCH_CAPABILITIES[bit 15] +- PBRSB_NO MSR_IA32_ARCH_CAPABILITIES[bit 24] + +Intel-SIG: commit 6d5e9694ef37 target/i386: Add new CPU model GraniteRapids. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Tao Su +Tested-by: Xuelian Guo +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-7-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 136 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ee243693e3..efe0c2b46c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3707,6 +3707,142 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .name = "GraniteRapids", ++ .level = 0x20, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 173, ++ .stepping = 0, ++ /* ++ * please keep the ascending order so that we can have a clear view of ++ * bit position of each feature. ++ */ ++ .features[FEAT_1_EDX] = ++ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | ++ CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | ++ CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | ++ CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | CPUID_FXSR | ++ CPUID_SSE | CPUID_SSE2, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | ++ CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | ++ CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | ++ CPUID_EXT_POPCNT | CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_AES | ++ CPUID_EXT_XSAVE | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_WBNOINVD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_HLE | ++ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | ++ CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RTM | ++ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | ++ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | ++ CPUID_7_0_EBX_AVX512IFMA | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | ++ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | ++ CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | ++ CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_BUS_LOCK_DETECT, ++ .features[FEAT_7_0_EDX] = ++ CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_SERIALIZE | ++ CPUID_7_0_EDX_TSX_LDTRK | CPUID_7_0_EDX_AMX_BF16 | ++ CPUID_7_0_EDX_AVX512_FP16 | CPUID_7_0_EDX_AMX_TILE | ++ CPUID_7_0_EDX_AMX_INT8 | CPUID_7_0_EDX_SPEC_CTRL | ++ CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_SPEC_CTRL_SSBD, ++ .features[FEAT_ARCH_CAPABILITIES] = ++ MSR_ARCH_CAP_RDCL_NO | MSR_ARCH_CAP_IBRS_ALL | ++ MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | ++ MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO | ++ MSR_ARCH_CAP_SBDR_SSDP_NO | MSR_ARCH_CAP_FBSDP_NO | ++ MSR_ARCH_CAP_PSDP_NO | MSR_ARCH_CAP_PBRSB_NO, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES | CPUID_D_1_EAX_XFD, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16 | ++ CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | CPUID_7_1_EAX_FSRC | ++ CPUID_7_1_EAX_AMX_FP16, ++ .features[FEAT_7_1_EDX] = ++ CPUID_7_1_EDX_PREFETCHITI, ++ .features[FEAT_7_2_EDX] = ++ CPUID_7_2_EDX_MCDT_NO, ++ .features[FEAT_VMX_BASIC] = ++ MSR_VMX_BASIC_INS_OUTS | MSR_VMX_BASIC_TRUE_CTLS, ++ .features[FEAT_VMX_ENTRY_CTLS] = ++ VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS | VMX_VM_ENTRY_IA32E_MODE | ++ VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_ENTRY_LOAD_IA32_PAT | VMX_VM_ENTRY_LOAD_IA32_EFER, ++ .features[FEAT_VMX_EPT_VPID_CAPS] = ++ MSR_VMX_EPT_EXECONLY | ++ MSR_VMX_EPT_PAGE_WALK_LENGTH_4 | MSR_VMX_EPT_PAGE_WALK_LENGTH_5 | ++ MSR_VMX_EPT_WB | MSR_VMX_EPT_2MB | MSR_VMX_EPT_1GB | ++ MSR_VMX_EPT_INVEPT | MSR_VMX_EPT_AD_BITS | ++ MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT | MSR_VMX_EPT_INVEPT_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID | MSR_VMX_EPT_INVVPID_SINGLE_ADDR | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT | ++ MSR_VMX_EPT_INVVPID_ALL_CONTEXT | ++ MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS, ++ .features[FEAT_VMX_EXIT_CTLS] = ++ VMX_VM_EXIT_SAVE_DEBUG_CONTROLS | ++ VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | ++ VMX_VM_EXIT_ACK_INTR_ON_EXIT | VMX_VM_EXIT_SAVE_IA32_PAT | ++ VMX_VM_EXIT_LOAD_IA32_PAT | VMX_VM_EXIT_SAVE_IA32_EFER | ++ VMX_VM_EXIT_LOAD_IA32_EFER | VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER, ++ .features[FEAT_VMX_MISC] = ++ MSR_VMX_MISC_STORE_LMA | MSR_VMX_MISC_ACTIVITY_HLT | ++ MSR_VMX_MISC_VMWRITE_VMEXIT, ++ .features[FEAT_VMX_PINBASED_CTLS] = ++ VMX_PIN_BASED_EXT_INTR_MASK | VMX_PIN_BASED_NMI_EXITING | ++ VMX_PIN_BASED_VIRTUAL_NMIS | VMX_PIN_BASED_VMX_PREEMPTION_TIMER | ++ VMX_PIN_BASED_POSTED_INTR, ++ .features[FEAT_VMX_PROCBASED_CTLS] = ++ VMX_CPU_BASED_VIRTUAL_INTR_PENDING | ++ VMX_CPU_BASED_USE_TSC_OFFSETING | VMX_CPU_BASED_HLT_EXITING | ++ VMX_CPU_BASED_INVLPG_EXITING | VMX_CPU_BASED_MWAIT_EXITING | ++ VMX_CPU_BASED_RDPMC_EXITING | VMX_CPU_BASED_RDTSC_EXITING | ++ VMX_CPU_BASED_CR3_LOAD_EXITING | VMX_CPU_BASED_CR3_STORE_EXITING | ++ VMX_CPU_BASED_CR8_LOAD_EXITING | VMX_CPU_BASED_CR8_STORE_EXITING | ++ VMX_CPU_BASED_TPR_SHADOW | VMX_CPU_BASED_VIRTUAL_NMI_PENDING | ++ VMX_CPU_BASED_MOV_DR_EXITING | VMX_CPU_BASED_UNCOND_IO_EXITING | ++ VMX_CPU_BASED_USE_IO_BITMAPS | VMX_CPU_BASED_MONITOR_TRAP_FLAG | ++ VMX_CPU_BASED_USE_MSR_BITMAPS | VMX_CPU_BASED_MONITOR_EXITING | ++ VMX_CPU_BASED_PAUSE_EXITING | ++ VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS, ++ .features[FEAT_VMX_SECONDARY_CTLS] = ++ VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | ++ VMX_SECONDARY_EXEC_ENABLE_EPT | VMX_SECONDARY_EXEC_DESC | ++ VMX_SECONDARY_EXEC_RDTSCP | ++ VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | ++ VMX_SECONDARY_EXEC_ENABLE_VPID | VMX_SECONDARY_EXEC_WBINVD_EXITING | ++ VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST | ++ VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT | ++ VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | ++ VMX_SECONDARY_EXEC_RDRAND_EXITING | ++ VMX_SECONDARY_EXEC_ENABLE_INVPCID | ++ VMX_SECONDARY_EXEC_ENABLE_VMFUNC | VMX_SECONDARY_EXEC_SHADOW_VMCS | ++ VMX_SECONDARY_EXEC_RDSEED_EXITING | VMX_SECONDARY_EXEC_ENABLE_PML | ++ VMX_SECONDARY_EXEC_XSAVES, ++ .features[FEAT_VMX_VMFUNC] = ++ MSR_VMX_VMFUNC_EPT_SWITCHING, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Xeon Processor (GraniteRapids)", ++ .versions = (X86CPUVersionDefinition[]) { ++ { .version = 1 }, ++ { /* end of list */ }, ++ }, ++ }, + { + .name = "Denverton", + .level = 21, +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch b/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch new file mode 100644 index 0000000..27cdfaf --- /dev/null +++ b/target-i386-Add-support-for-AMX-FP16-in-CPUID-enumer.patch @@ -0,0 +1,62 @@ +From c362956eb88558991bee59e43d7db52c8bc7e5f5 Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:09 +0800 +Subject: [PATCH] target/i386: Add support for AMX-FP16 in CPUID enumeration + +commit 99ed8445ea27742a4df40f51a3a5fbd6f8e76fa5 upstream. + +Latest Intel platform Granite Rapids has introduced a new instruction - +AMX-FP16, which performs dot-products of two FP16 tiles and accumulates +the results into a packed single precision tile. AMX-FP16 adds FP16 +capability and allows a FP16 GPU trained model to run faster without +loss of accuracy or added SW overhead. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 21] + +Add CPUID definition for AMX-FP16. + +Intel-SIG: commit 99ed8445ea27 target/i386: Add support for AMX-FP16 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-3-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 47c2d9da80..3fc3b8041a 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "amx-fp16", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 4a7362ee07..c747e68a7a 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -891,6 +891,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_FSRS (1U << 11) + /* Fast Short REP CMPS/SCAS */ + #define CPUID_7_1_EAX_FSRC (1U << 12) ++/* Support Tile Computational Operations on FP16 Numbers */ ++#define CPUID_7_1_EAX_AMX_FP16 (1U << 21) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch b/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch new file mode 100644 index 0000000..8b99815 --- /dev/null +++ b/target-i386-Add-support-for-AVX-IFMA-in-CPUID-enumer.patch @@ -0,0 +1,60 @@ +From 8fe9899c39d86f9e0baf832744a7cfe19642a3fd Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:10 +0800 +Subject: [PATCH] target/i386: Add support for AVX-IFMA in CPUID enumeration + +commit a957a88416ecbec51e147cba9fe89b93f6646b3b upstream. + +AVX-IFMA is a new instruction in the latest Intel platform Sierra +Forest. This instruction packed multiplies unsigned 52-bit integers and +adds the low/high 52-bit products to Qword Accumulators. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 23] + +Add CPUID definition for AVX-IFMA. + +Intel-SIG: commit a957a88416ec target/i386: Add support for AVX-IFMA in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-4-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3fc3b8041a..b19fb0cf87 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -876,7 +876,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, "amx-fp16", NULL, NULL, ++ NULL, "amx-fp16", NULL, "avx-ifma", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index c747e68a7a..2bcc127fac 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -893,6 +893,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_FSRC (1U << 12) + /* Support Tile Computational Operations on FP16 Numbers */ + #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) ++/* Support for VPMADD52[H,L]UQ */ ++#define CPUID_7_1_EAX_AVX_IFMA (1U << 23) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch b/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch new file mode 100644 index 0000000..0eb1635 --- /dev/null +++ b/target-i386-Add-support-for-AVX-NE-CONVERT-in-CPUID-.patch @@ -0,0 +1,62 @@ +From 165d587b52f7c8459d9a9deca389610f9165b33a Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:44:56 +0800 +Subject: [PATCH] target/i386: Add support for AVX-NE-CONVERT in CPUID + enumeration + +commit ecd2e6ca037d7bf3673c5478590d686d5cd6135a upstream. + +AVX-NE-CONVERT is a new set of instructions which can convert low +precision floating point like BF16/FP16 to high precision floating point +FP32, as well as convert FP32 elements to BF16. This instruction allows +the platform to have improved AI capabilities and better compatibility. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 5] + +Add CPUID definition for AVX-NE-CONVERT. + +Intel-SIG: commit ecd2e6ca037d target/i386: Add support for AVX-NE-CONVERT in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-6-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a14284a81b..d36174d689 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -911,7 +911,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, +- "avx-vnni-int8", NULL, NULL, NULL, ++ "avx-vnni-int8", "avx-ne-convert", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index b81d77084c..93c8bd6a13 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -898,6 +898,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) + /* Support for VPDPB[SU,UU,SS]D[,S] */ + #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) ++/* AVX NE CONVERT Instructions */ ++#define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch b/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch new file mode 100644 index 0000000..b6fc1d0 --- /dev/null +++ b/target-i386-Add-support-for-AVX-VNNI-INT8-in-CPUID-e.patch @@ -0,0 +1,110 @@ +From 71b820dc04fbe04342d5a05be3d774c704b682ec Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:43:11 +0800 +Subject: [PATCH] target/i386: Add support for AVX-VNNI-INT8 in CPUID + enumeration + +commit eaaa197d5b112ea2758b54df58881a2626de3af5 upstream. + +AVX-VNNI-INT8 is a new set of instructions in the latest Intel platform +Sierra Forest, aims for the platform to have superior AI capabilities. +This instruction multiplies the individual bytes of two unsigned or +unsigned source operands, then adds and accumulates the results into the +destination dword element size operand. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 4] + +AVX-VNNI-INT8 is on a new feature bits leaf. Add a CPUID feature word +FEAT_7_1_EDX for this leaf. + +Add CPUID definition for AVX-VNNI-INT8. + +Intel-SIG: commit eaaa197d5b11 target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-5-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 22 +++++++++++++++++++++- + target/i386/cpu.h | 3 +++ + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b19fb0cf87..a14284a81b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -663,6 +663,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM + #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ + CPUID_7_1_EAX_FSRC) ++#define TCG_7_1_EDX_FEATURES 0 + #define TCG_7_2_EDX_FEATURES 0 + #define TCG_APM_FEATURES 0 + #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT +@@ -906,6 +907,25 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + }, + .tcg_features = TCG_7_2_EDX_FEATURES, + }, ++ [FEAT_7_1_EDX] = { ++ .type = CPUID_FEATURE_WORD, ++ .feat_names = { ++ NULL, NULL, NULL, NULL, ++ "avx-vnni-int8", NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ }, ++ .cpuid = { ++ .eax = 7, ++ .needs_ecx = true, .ecx = 1, ++ .reg = R_EDX, ++ }, ++ .tcg_features = TCG_7_1_EDX_FEATURES, ++ }, + [FEAT_8000_0007_EDX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { +@@ -5557,9 +5577,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } else if (count == 1) { + *eax = env->features[FEAT_7_1_EAX]; ++ *edx = env->features[FEAT_7_1_EDX]; + *ebx = 0; + *ecx = 0; +- *edx = 0; + } else if (count == 2) { + *edx = env->features[FEAT_7_2_EDX]; + *eax = 0; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 2bcc127fac..b81d77084c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -601,6 +601,7 @@ typedef enum FeatureWord { + FEAT_SGX_12_0_EAX, /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */ + FEAT_SGX_12_0_EBX, /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */ + FEAT_SGX_12_1_EAX, /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */ ++ FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ + FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ + FEATURE_WORDS, + } FeatureWord; +@@ -895,6 +896,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AMX_FP16 (1U << 21) + /* Support for VPMADD52[H,L]UQ */ + #define CPUID_7_1_EAX_AVX_IFMA (1U << 23) ++/* Support for VPDPB[SU,UU,SS]D[,S] */ ++#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch b/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch new file mode 100644 index 0000000..d163312 --- /dev/null +++ b/target-i386-Add-support-for-CMPCCXADD-in-CPUID-enume.patch @@ -0,0 +1,61 @@ +From 25d08629eab566f5a47bf915a86e20318ee1cf08 Mon Sep 17 00:00:00 2001 +From: Jiaxi Chen +Date: Fri, 3 Mar 2023 14:59:08 +0800 +Subject: [PATCH] target/i386: Add support for CMPCCXADD in CPUID enumeration + +commit a9ce107fd0f2017af84255a9cf6542fa3eb3e214 upstream. + +CMPccXADD is a new set of instructions in the latest Intel platform +Sierra Forest. This new instruction set includes a semaphore operation +that can compare and add the operands if condition is met, which can +improve database performance. + +The bit definition: +CPUID.(EAX=7,ECX=1):EAX[bit 7] + +Add CPUID definition for CMPCCXADD. + +Intel-SIG: commit a9ce107fd0f2 target/i386: Add support for CMPCCXADD in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-2-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 58124071da..47c2d9da80 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -872,7 +872,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, +- "avx-vnni", "avx512-bf16", NULL, NULL, ++ "avx-vnni", "avx512-bf16", NULL, "cmpccxadd", + NULL, NULL, "fzrm", "fsrs", + "fsrc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 37c687d4d8..4a7362ee07 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -883,6 +883,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) + /* AVX512 BFloat16 Instruction */ + #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) ++/* CMPCCXADD Instructions */ ++#define CPUID_7_1_EAX_CMPCCXADD (1U << 7) + /* Fast Zero REP MOVS */ + #define CPUID_7_1_EAX_FZRM (1U << 10) + /* Fast Short REP STOS */ +-- +2.27.0 + diff --git a/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch b/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch new file mode 100644 index 0000000..59053fd --- /dev/null +++ b/target-i386-Add-support-for-PREFETCHIT0-1-in-CPUID-e.patch @@ -0,0 +1,61 @@ +From 9a56c714caaf3bf31430a769befdf92e79388dda Mon Sep 17 00:00:00 2001 +From: Quanxian Wang +Date: Wed, 8 Nov 2023 12:46:00 +0800 +Subject: [PATCH] target/i386: Add support for PREFETCHIT0/1 in CPUID + enumeration + +commit d1a1111514333e46a98b136235f71eef90d610fa upstream. + +Latest Intel platform Granite Rapids has introduced a new instruction - +PREFETCHIT0/1, which moves code to memory (cache) closer to the +processor depending on specific hints. + +The bit definition: +CPUID.(EAX=7,ECX=1):EDX[bit 14] + +Add CPUID definition for PREFETCHIT0/1. + +Intel-SIG: commit d1a111151433 target/i386: Add support for PREFETCHIT0/1 in CPUID enumeration. +Backport GNR and SRF ISA into QEMU-6.2 + +Signed-off-by: Jiaxi Chen +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-Id: <20230303065913.1246327-7-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d36174d689..ee243693e3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -913,7 +913,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, NULL, NULL, + "avx-vnni-int8", "avx-ne-convert", NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, "prefetchiti", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 93c8bd6a13..32ecec5fa7 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -900,6 +900,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + #define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4) + /* AVX NE CONVERT Instructions */ + #define CPUID_7_1_EDX_AVX_NE_CONVERT (1U << 5) ++/* PREFETCHIT0/1 Instructions */ ++#define CPUID_7_1_EDX_PREFETCHITI (1U << 14) + + /* Do not exhibit MXCSR Configuration Dependent Timing (MCDT) behavior */ + #define CPUID_7_2_EDX_MCDT_NO (1U << 5) +-- +2.27.0 + diff --git a/target-i386-Adjust-feature-level-according-to-FEAT_7.patch b/target-i386-Adjust-feature-level-according-to-FEAT_7.patch new file mode 100644 index 0000000..3c238c6 --- /dev/null +++ b/target-i386-Adjust-feature-level-according-to-FEAT_7.patch @@ -0,0 +1,46 @@ +From 52d000a4043f3000f880bb5c75a298f57b8e0fe0 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 6 Jul 2023 13:49:44 +0800 +Subject: [PATCH] target/i386: Adjust feature level according to FEAT_7_1_EDX + +commit 8731336e90dea3dd04948127e775c9f087f97a4c upstream. + +If FEAT_7_1_EAX is 0 and FEAT_7_1_EDX is non-zero, as is the case +with a Granite Rapids host and +'-cpu host,-avx-vnni,-avx512-bf16,-fzrm,-fsrs,-fsrc,-amx-fp16', we can't +get CPUID_7_1 leaf even though CPUID_7_1_EDX has non-zero value. + +Update cpuid_level_func7 according to CPUID_7_1_EDX, otherwise +guest may report wrong maximum number sub-leaves in leaf 07H. + +Fixes: eaaa197d5b11 ("target/i386: Add support for AVX-VNNI-INT8 in CPUID enumeration") + +Intel-SIG: commit 8731336e90de target/i386: Adjust feature level according to FEAT_7_1_EDX. +Backport GNR and SRF ISA into QEMU-6.2 + +Cc: qemu-stable@nongnu.org +Signed-off-by: Tao Su +Reviewed-by: Xiaoyao Li +Message-ID: <20230706054949.66556-2-tao1.su@linux.intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index efe0c2b46c..6aaa730a0d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6551,6 +6551,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EAX); ++ x86_cpu_adjust_feat_level(cpu, FEAT_7_1_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_2_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); +-- +2.27.0 + diff --git a/target-i386-Export-GDS_NO-bit-to-guests.patch b/target-i386-Export-GDS_NO-bit-to-guests.patch new file mode 100644 index 0000000..5b6e5f1 --- /dev/null +++ b/target-i386-Export-GDS_NO-bit-to-guests.patch @@ -0,0 +1,46 @@ +From 3cea2c36571b39a6fa956abe66507c04283ad614 Mon Sep 17 00:00:00 2001 +From: Pawan Gupta +Date: Mon, 14 Aug 2023 21:54:27 -0700 +Subject: [PATCH] target/i386: Export GDS_NO bit to guests + +commit 3a2a1f97ea349745094e789e6b0768dbd92d0dcd upstream. + +Gather Data Sampling (GDS) is a side-channel attack using Gather +instructions. Some Intel processors will set ARCH_CAP_GDS_NO bit in +MSR IA32_ARCH_CAPABILITIES to report that they are not vulnerable to +GDS. + +Make this bit available to guests. + +Intel-SIG: commit 3a2a1f97ea34 ("target/i386: Export GDS_NO bit to guests") +Backport to export GDS_NO bit to guests(CVE-2022-40982). + +Closes: https://lore.kernel.org/qemu-devel/CAMGffEmG6TNq0n3+4OJAgXc8J0OevY60KHZekXCBs3LoK9vehA@mail.gmail.com/ +Reported-by: Jack Wang +Signed-off-by: Pawan Gupta +Tested-by: Jack Wang +Tested-by: Daniel Sneddon +Message-ID: +Signed-off-by: Paolo Bonzini +[ Aichun Shi: amend commit log ] +Signed-off-by: Aichun Shi +--- + target/i386/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index eb911b12fa..58124071da 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1004,7 +1004,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, "sbdr-ssdp-no", "fbsdp-no", "psdp-no", + NULL, "fb-clear", NULL, NULL, + NULL, NULL, NULL, NULL, +- "pbrsb-no", NULL, NULL, NULL, ++ "pbrsb-no", NULL, "gds-no", NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { +-- +2.27.0 + diff --git a/tests-qtest-check-the-return-value.patch b/tests-qtest-check-the-return-value.patch new file mode 100644 index 0000000..ada8e4a --- /dev/null +++ b/tests-qtest-check-the-return-value.patch @@ -0,0 +1,62 @@ +From 53e0242318e838013504688307af44e80ab36c70 Mon Sep 17 00:00:00 2001 +From: zhujun2 +Date: Tue, 21 Nov 2023 18:03:25 -0800 +Subject: [PATCH] tests/qtest: check the return value + +These variables "ret" are never referenced in the code, thus +add check logic for the "ret" + +Signed-off-by: zhujun2 +--- + tests/qtest/test-filter-mirror.c | 1 + + tests/qtest/test-filter-redirector.c | 2 ++ + tests/qtest/virtio-net-test.c | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/tests/qtest/test-filter-mirror.c b/tests/qtest/test-filter-mirror.c +index bc0dee64dd..40f736734a 100644 +--- a/tests/qtest/test-filter-mirror.c ++++ b/tests/qtest/test-filter-mirror.c +@@ -71,6 +71,7 @@ static void test_mirror(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock[0], recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); +diff --git a/tests/qtest/test-filter-redirector.c b/tests/qtest/test-filter-redirector.c +index 4269b2cdd9..f802c94f54 100644 +--- a/tests/qtest/test-filter-redirector.c ++++ b/tests/qtest/test-filter-redirector.c +@@ -133,6 +133,7 @@ static void test_redirector_tx(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock, recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); +@@ -201,6 +202,7 @@ static void test_redirector_rx(void) + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(backend_sock[0], recv_buf, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(recv_buf, ==, send_buf); + + close(send_sock); +diff --git a/tests/qtest/virtio-net-test.c b/tests/qtest/virtio-net-test.c +index 8bf74e516c..aab4480fb0 100644 +--- a/tests/qtest/virtio-net-test.c ++++ b/tests/qtest/virtio-net-test.c +@@ -92,6 +92,7 @@ static void tx_test(QVirtioDevice *dev, + len = ntohl(len); + + ret = qemu_recv(socket, buffer, len, 0); ++ g_assert_cmpint(ret, ==, len); + g_assert_cmpstr(buffer, ==, "TEST"); + } + +-- +2.27.0 + diff --git a/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch b/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch new file mode 100644 index 0000000..c989e26 --- /dev/null +++ b/tpm_crb-mark-command-buffer-as-dirty-on-request-comp.patch @@ -0,0 +1,43 @@ +From 1e32685272ff1932b9ca022db8717720fc901d0e Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Mon, 6 Nov 2023 06:17:47 +0000 +Subject: [PATCH] tpm_crb: mark command buffer as dirty on request completion + mainline inclusion commit e37a0ef4605e5d2041785ff3fc89ca6021faf7a0 category: + bugfix + +--------------------------------------------------------------- + +At the moment, there doesn't seems to be any way to know that QEMU +made modification to the command buffer. This is potentially an issue +on Xen while migrating a guest, as modification to the buffer after +the migration as started could be ignored and not transfered to the +destination. + +Mark the memory region of the command buffer as dirty once a request +is completed. + +Signed-off-by: Anthony PERARD +Reviewed-by: Stefan Berger +Signed-off-by: Stefan Berger +Message-id: 20220411144749.47185-1-anthony.perard@citrix.com + +Signed-off-by: tangbinzy +--- + hw/tpm/tpm_crb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c +index 58ebd1469c..c05972736a 100644 +--- a/hw/tpm/tpm_crb.c ++++ b/hw/tpm/tpm_crb.c +@@ -196,6 +196,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret) + ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, + tpmSts, 1); /* fatal error */ + } ++ memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE); + } + + static enum TPMVersion tpm_crb_get_version(TPMIf *ti) +-- +2.27.0 + diff --git a/tracetool-avoid-invalid-escape-in-Python-string.patch b/tracetool-avoid-invalid-escape-in-Python-string.patch new file mode 100644 index 0000000..ffd30a2 --- /dev/null +++ b/tracetool-avoid-invalid-escape-in-Python-string.patch @@ -0,0 +1,38 @@ +From cb5e4e55c489462a2ff11143a5768b5c096bf1ad Mon Sep 17 00:00:00 2001 +From: qihao +Date: Wed, 15 Nov 2023 14:49:44 +0800 +Subject: [PATCH] tracetool: avoid invalid escape in Python string +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 4d96307c5b4fac40c6ca25f38318b4b65d315de0 + +This is an error in Python 3.12; fix it by using a raw string literal. + +Cc: +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Stefan Hajnoczi +Message-ID: <20231108105649.60453-1-marcandre.lureau@redhat.com> +Signed-off-by: qihao_yewu +--- + scripts/tracetool/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py +index 5bc94d95cf..630e85a5d6 100644 +--- a/scripts/tracetool/__init__.py ++++ b/scripts/tracetool/__init__.py +@@ -94,7 +94,7 @@ def out(*lines, **kwargs): + def validate_type(name): + bits = name.split(" ") + for bit in bits: +- bit = re.sub("\*", "", bit) ++ bit = re.sub(r"\*", "", bit) + if bit == "": + continue + if bit == "const": +-- +2.27.0 + diff --git a/util-Add-iova_tree_alloc_map.patch b/util-Add-iova_tree_alloc_map.patch new file mode 100644 index 0000000..c1ab3f7 --- /dev/null +++ b/util-Add-iova_tree_alloc_map.patch @@ -0,0 +1,219 @@ +From 6dac473fb3f4f98ef67c63a38b00465299519132 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:48 +0100 +Subject: [PATCH] util: Add iova_tree_alloc_map +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This iova tree function allows it to look for a hole in allocated +regions and return a totally new translation for a given translated +address. + +It's usage is mainly to allow devices to access qemu address space, +remapping guest's one into a new iova space where qemu can add chunks of +addresses. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Peter Xu +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 18 ++++++ + util/iova-tree.c | 136 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 154 insertions(+) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index 8249edd764..d066400f09 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -29,6 +29,7 @@ + #define IOVA_OK (0) + #define IOVA_ERR_INVALID (-1) /* Invalid parameters */ + #define IOVA_ERR_OVERLAP (-2) /* IOVA range overlapped */ ++#define IOVA_ERR_NOMEM (-3) /* Cannot allocate */ + + typedef struct IOVATree IOVATree; + typedef struct DMAMap { +@@ -119,6 +120,23 @@ const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova); + */ + void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator); + ++/** ++ * iova_tree_alloc_map: ++ * ++ * @tree: the iova tree to allocate from ++ * @map: the new map (as translated addr & size) to allocate in the iova region ++ * @iova_begin: the minimum address of the allocation ++ * @iova_end: the maximum addressable direction of the allocation ++ * ++ * Allocates a new region of a given size, between iova_min and iova_max. ++ * ++ * Return: Same as iova_tree_insert, but cannot overlap and can return error if ++ * iova tree is out of free contiguous range. The caller gets the assigned iova ++ * in map->iova. ++ */ ++int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin, ++ hwaddr iova_end); ++ + /** + * iova_tree_destroy: + * +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 23ea35b7a4..139626b46f 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -16,6 +16,40 @@ struct IOVATree { + GTree *tree; + }; + ++/* Args to pass to iova_tree_alloc foreach function. */ ++struct IOVATreeAllocArgs { ++ /* Size of the desired allocation */ ++ size_t new_size; ++ ++ /* The minimum address allowed in the allocation */ ++ hwaddr iova_begin; ++ ++ /* Map at the left of the hole, can be NULL if "this" is first one */ ++ const DMAMap *prev; ++ ++ /* Map at the right of the hole, can be NULL if "prev" is the last one */ ++ const DMAMap *this; ++ ++ /* If found, we fill in the IOVA here */ ++ hwaddr iova_result; ++ ++ /* Whether have we found a valid IOVA */ ++ bool iova_found; ++}; ++ ++/** ++ * Iterate args to the next hole ++ * ++ * @args: The alloc arguments ++ * @next: The next mapping in the tree. Can be NULL to signal the last one ++ */ ++static void iova_tree_alloc_args_iterate(struct IOVATreeAllocArgs *args, ++ const DMAMap *next) ++{ ++ args->prev = args->this; ++ args->this = next; ++} ++ + static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data) + { + const DMAMap *m1 = a, *m2 = b; +@@ -107,6 +141,108 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map) + return IOVA_OK; + } + ++/** ++ * Try to find an unallocated IOVA range between prev and this elements. ++ * ++ * @args: Arguments to allocation ++ * ++ * Cases: ++ * ++ * (1) !prev, !this: No entries allocated, always succeed ++ * ++ * (2) !prev, this: We're iterating at the 1st element. ++ * ++ * (3) prev, !this: We're iterating at the last element. ++ * ++ * (4) prev, this: this is the most common case, we'll try to find a hole ++ * between "prev" and "this" mapping. ++ * ++ * Note that this function assumes the last valid iova is HWADDR_MAX, but it ++ * searches linearly so it's easy to discard the result if it's not the case. ++ */ ++static void iova_tree_alloc_map_in_hole(struct IOVATreeAllocArgs *args) ++{ ++ const DMAMap *prev = args->prev, *this = args->this; ++ uint64_t hole_start, hole_last; ++ ++ if (this && this->iova + this->size < args->iova_begin) { ++ return; ++ } ++ ++ hole_start = MAX(prev ? prev->iova + prev->size + 1 : 0, args->iova_begin); ++ hole_last = this ? this->iova : HWADDR_MAX; ++ ++ if (hole_last - hole_start > args->new_size) { ++ args->iova_result = hole_start; ++ args->iova_found = true; ++ } ++} ++ ++/** ++ * Foreach dma node in the tree, compare if there is a hole with its previous ++ * node (or minimum iova address allowed) and the node. ++ * ++ * @key: Node iterating ++ * @value: Node iterating ++ * @pargs: Struct to communicate with the outside world ++ * ++ * Return: false to keep iterating, true if needs break. ++ */ ++static gboolean iova_tree_alloc_traverse(gpointer key, gpointer value, ++ gpointer pargs) ++{ ++ struct IOVATreeAllocArgs *args = pargs; ++ DMAMap *node = value; ++ ++ assert(key == value); ++ ++ iova_tree_alloc_args_iterate(args, node); ++ iova_tree_alloc_map_in_hole(args); ++ return args->iova_found; ++} ++ ++int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin, ++ hwaddr iova_last) ++{ ++ struct IOVATreeAllocArgs args = { ++ .new_size = map->size, ++ .iova_begin = iova_begin, ++ }; ++ ++ if (unlikely(iova_last < iova_begin)) { ++ return IOVA_ERR_INVALID; ++ } ++ ++ /* ++ * Find a valid hole for the mapping ++ * ++ * Assuming low iova_begin, so no need to do a binary search to ++ * locate the first node. ++ * ++ * TODO: Replace all this with g_tree_node_first/next/last when available ++ * (from glib since 2.68). To do it with g_tree_foreach complicates the ++ * code a lot. ++ * ++ */ ++ g_tree_foreach(tree->tree, iova_tree_alloc_traverse, &args); ++ if (!args.iova_found) { ++ /* ++ * Either tree is empty or the last hole is still not checked. ++ * g_tree_foreach does not compare (last, iova_last] range, so we check ++ * it here. ++ */ ++ iova_tree_alloc_args_iterate(&args, NULL); ++ iova_tree_alloc_map_in_hole(&args); ++ } ++ ++ if (!args.iova_found || args.iova_result + map->size > iova_last) { ++ return IOVA_ERR_NOMEM; ++ } ++ ++ map->iova = args.iova_result; ++ return iova_tree_insert(tree, map); ++} ++ + void iova_tree_destroy(IOVATree *tree) + { + g_tree_destroy(tree->tree); +-- +2.27.0 + diff --git a/util-Return-void-on-iova_tree_remove.patch b/util-Return-void-on-iova_tree_remove.patch new file mode 100644 index 0000000..a38c7c3 --- /dev/null +++ b/util-Return-void-on-iova_tree_remove.patch @@ -0,0 +1,61 @@ +From b4c0eb3ad95c5c9a32cf87d30647d63ec9c193a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 27 Apr 2022 17:49:31 +0200 +Subject: [PATCH] util: Return void on iova_tree_remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It always returns IOVA_OK so nobody uses it. + +Acked-by: Jason Wang +Reviewed-by: Peter Xu +Signed-off-by: Eugenio Pérez +Message-Id: <20220427154931.3166388-1-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 4 +--- + util/iova-tree.c | 4 +--- + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index c938fb0793..16bbfdf5f8 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -72,10 +72,8 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); + * provided. The range does not need to be exactly what has inserted, + * all the mappings that are included in the provided range will be + * removed from the tree. Here map->translated_addr is meaningless. +- * +- * Return: 0 if succeeded, or <0 if error. + */ +-int iova_tree_remove(IOVATree *tree, const DMAMap *map); ++void iova_tree_remove(IOVATree *tree, const DMAMap *map); + + /** + * iova_tree_find: +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 6dff29c1f6..fee530a579 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -164,15 +164,13 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) + g_tree_foreach(tree->tree, iova_tree_traverse, iterator); + } + +-int iova_tree_remove(IOVATree *tree, const DMAMap *map) ++void iova_tree_remove(IOVATree *tree, const DMAMap *map) + { + const DMAMap *overlap; + + while ((overlap = iova_tree_find(tree, map))) { + g_tree_remove(tree->tree, overlap); + } +- +- return IOVA_OK; + } + + /** +-- +2.27.0 + diff --git a/util-accept-iova_tree_remove_parameter-by-value.patch b/util-accept-iova_tree_remove_parameter-by-value.patch new file mode 100644 index 0000000..6ee1059 --- /dev/null +++ b/util-accept-iova_tree_remove_parameter-by-value.patch @@ -0,0 +1,173 @@ +From 4ac2c0c847ffee0fb6aa92a9735be9448c62c107 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:04 +0200 +Subject: [PATCH] util: accept iova_tree_remove_parameter by value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's convenient to call iova_tree_remove from a map returned from +iova_tree_find or iova_tree_find_iova. With the current code this is not +possible, since we will free it, and then we will try to search for it +again. + +Fix it making accepting the map by value, forcing a copy of the +argument. Not applying a fixes tag, since there is no use like that at +the moment. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/i386/intel_iommu.c | 6 +++--- + hw/virtio/vhost-iova-tree.c | 2 +- + hw/virtio/vhost-iova-tree.h | 2 +- + hw/virtio/vhost-vdpa.c | 6 +++--- + include/qemu/iova-tree.h | 2 +- + net/vhost-vdpa.c | 4 ++-- + util/iova-tree.c | 4 ++-- + 7 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 5b865ac08c..2d5ad84149 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1157,7 +1157,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) + return ret; + } + /* Drop any existing mapping */ +- iova_tree_remove(as->iova_tree, &target); ++ iova_tree_remove(as->iova_tree, target); + /* Recover the correct type */ + event->type = IOMMU_NOTIFIER_MAP; + entry->perm = cache_perm; +@@ -1170,7 +1170,7 @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info) + trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); + return 0; + } +- iova_tree_remove(as->iova_tree, &target); ++ iova_tree_remove(as->iova_tree, target); + } + + trace_vtd_page_walk_one(info->domain_id, entry->iova, +@@ -3516,7 +3516,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + + map.iova = n->start; + map.size = size; +- iova_tree_remove(as->iova_tree, &map); ++ iova_tree_remove(as->iova_tree, map); + } + + static void vtd_address_space_unmap_all(IntelIOMMUState *s) +diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c +index 55fed1fefb..1339a4de8b 100644 +--- a/hw/virtio/vhost-iova-tree.c ++++ b/hw/virtio/vhost-iova-tree.c +@@ -104,7 +104,7 @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) + * @iova_tree: The vhost iova tree + * @map: The map to remove + */ +-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map) ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map) + { + iova_tree_remove(iova_tree->iova_taddr_map, map); + } +diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h +index 6a4f24e0f9..4adfd79ff0 100644 +--- a/hw/virtio/vhost-iova-tree.h ++++ b/hw/virtio/vhost-iova-tree.h +@@ -22,6 +22,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete); + const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree, + const DMAMap *map); + int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map); +-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map); ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map); + + #endif +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 02dab41c42..0f640f670b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -242,7 +242,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + + fail_map: + if (v->shadow_vqs_enabled) { +- vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ vhost_iova_tree_remove(v->iova_tree, mem_region); + } + + fail: +@@ -302,7 +302,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + return; + } + iova = result->iova; +- vhost_iova_tree_remove(v->iova_tree, result); ++ vhost_iova_tree_remove(v->iova_tree, *result); + } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); +@@ -946,7 +946,7 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, + needle->perm == IOMMU_RO); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Cannot map region to device"); +- vhost_iova_tree_remove(v->iova_tree, needle); ++ vhost_iova_tree_remove(v->iova_tree, *needle); + } + + return r == 0; +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index 16bbfdf5f8..8528e5c98f 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -73,7 +73,7 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map); + * all the mappings that are included in the provided range will be + * removed from the tree. Here map->translated_addr is meaningless. + */ +-void iova_tree_remove(IOVATree *tree, const DMAMap *map); ++void iova_tree_remove(IOVATree *tree, DMAMap map); + + /** + * iova_tree_find: +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 0f75aa6080..8cfd086639 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -252,7 +252,7 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); + } + +- vhost_iova_tree_remove(tree, map); ++ vhost_iova_tree_remove(tree, *map); + } + + static size_t vhost_vdpa_net_cvq_cmd_len(void) +@@ -305,7 +305,7 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, + return true; + + dma_map_err: +- vhost_iova_tree_remove(v->iova_tree, &map); ++ vhost_iova_tree_remove(v->iova_tree, map); + return false; + } + +diff --git a/util/iova-tree.c b/util/iova-tree.c +index fee530a579..536789797e 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -164,11 +164,11 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) + g_tree_foreach(tree->tree, iova_tree_traverse, iterator); + } + +-void iova_tree_remove(IOVATree *tree, const DMAMap *map) ++void iova_tree_remove(IOVATree *tree, DMAMap map) + { + const DMAMap *overlap; + +- while ((overlap = iova_tree_find(tree, map))) { ++ while ((overlap = iova_tree_find(tree, &map))) { + g_tree_remove(tree->tree, overlap); + } + } +-- +2.27.0 + diff --git a/util-add-iova_tree_find_iova.patch b/util-add-iova_tree_find_iova.patch new file mode 100644 index 0000000..fd935fe --- /dev/null +++ b/util-add-iova_tree_find_iova.patch @@ -0,0 +1,116 @@ +From 087ef4f1cfef58eadcb157585b70cf716c567305 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:49 +0100 +Subject: [PATCH] util: add iova_tree_find_iova +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function does the reverse operation of iova_tree_find: To look for +a mapping that match a translated address so we can do the reverse. + +This have linear complexity instead of logarithmic, but it supports +overlapping HVA. Future developments could reduce it. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + include/qemu/iova-tree.h | 20 +++++++++++++++++++- + util/iova-tree.c | 34 ++++++++++++++++++++++++++++++++++ + 2 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +index d066400f09..c938fb0793 100644 +--- a/include/qemu/iova-tree.h ++++ b/include/qemu/iova-tree.h +@@ -83,7 +83,7 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map); + * @tree: the iova tree to search from + * @map: the mapping to search + * +- * Search for a mapping in the iova tree that overlaps with the ++ * Search for a mapping in the iova tree that iova overlaps with the + * mapping range specified. Only the first found mapping will be + * returned. + * +@@ -95,6 +95,24 @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map); + */ + const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map); + ++/** ++ * iova_tree_find_iova: ++ * ++ * @tree: the iova tree to search from ++ * @map: the mapping to search ++ * ++ * Search for a mapping in the iova tree that translated_addr overlaps with the ++ * mapping range specified. Only the first found mapping will be ++ * returned. ++ * ++ * Return: DMAMap pointer if found, or NULL if not found. Note that ++ * the returned DMAMap pointer is maintained internally. User should ++ * only read the content but never modify or free the content. Also, ++ * user is responsible to make sure the pointer is valid (say, no ++ * concurrent deletion in progress). ++ */ ++const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map); ++ + /** + * iova_tree_find_address: + * +diff --git a/util/iova-tree.c b/util/iova-tree.c +index 139626b46f..6dff29c1f6 100644 +--- a/util/iova-tree.c ++++ b/util/iova-tree.c +@@ -37,6 +37,11 @@ struct IOVATreeAllocArgs { + bool iova_found; + }; + ++typedef struct IOVATreeFindIOVAArgs { ++ const DMAMap *needle; ++ const DMAMap *result; ++} IOVATreeFindIOVAArgs; ++ + /** + * Iterate args to the next hole + * +@@ -81,6 +86,35 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map) + return g_tree_lookup(tree->tree, map); + } + ++static gboolean iova_tree_find_address_iterator(gpointer key, gpointer value, ++ gpointer data) ++{ ++ const DMAMap *map = key; ++ IOVATreeFindIOVAArgs *args = data; ++ const DMAMap *needle; ++ ++ g_assert(key == value); ++ ++ needle = args->needle; ++ if (map->translated_addr + map->size < needle->translated_addr || ++ needle->translated_addr + needle->size < map->translated_addr) { ++ return false; ++ } ++ ++ args->result = map; ++ return true; ++} ++ ++const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map) ++{ ++ IOVATreeFindIOVAArgs args = { ++ .needle = map, ++ }; ++ ++ g_tree_foreach(tree->tree, iova_tree_find_address_iterator, &args); ++ return args.result; ++} ++ + const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova) + { + const DMAMap map = { .iova = iova, .size = 0 }; +-- +2.27.0 + diff --git a/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch b/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch new file mode 100644 index 0000000..cd93861 --- /dev/null +++ b/vdpa-Adapt-vhost_vdpa_get_vring_base-to-SVQ.patch @@ -0,0 +1,59 @@ +From d42fea8a40c4a5d8909103910d86da8e674d1fb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:52 +0100 +Subject: [PATCH] vdpa: Adapt vhost_vdpa_get_vring_base to SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed to achieve migration, so the destination can restore its +index. + +Setting base as last used idx, so destination will see as available all +the entries that the device did not use, including the in-flight +processing ones. + +This is ok for networking, but other kinds of devices might have +problems with these retransmissions. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8245345bcd..428137f654 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1143,8 +1143,25 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + ++ if (v->shadow_vqs_enabled) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, ++ ring->index); ++ ++ /* ++ * Setting base as last used idx, so destination will see as available ++ * all the entries that the device did not use, including the in-flight ++ * processing ones. ++ * ++ * TODO: This is ok for networking, but other kinds of devices might ++ * have problems with these retransmissions. ++ */ ++ ring->num = svq->last_used_idx; ++ return 0; ++ } ++ + ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring); + trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num); + return ret; +-- +2.27.0 + diff --git a/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch b/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch new file mode 100644 index 0000000..4f6c127 --- /dev/null +++ b/vdpa-Add-custom-IOTLB-translations-to-SVQ.patch @@ -0,0 +1,415 @@ +From 649e277b6ec0d2cd798f6d43776ea38b00450db9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:51 +0100 +Subject: [PATCH] vdpa: Add custom IOTLB translations to SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use translations added in VhostIOVATree in SVQ. + +Only introduce usage here, not allocation and deallocation. As with +previous patches, we use the dead code paths of shadow_vqs_enabled to +avoid commiting too many changes at once. These are impossible to take +at the moment. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 86 +++++++++++++++++--- + hw/virtio/vhost-shadow-virtqueue.h | 6 +- + hw/virtio/vhost-vdpa.c | 122 ++++++++++++++++++++++++----- + include/hw/virtio/vhost-vdpa.h | 3 + + 4 files changed, 187 insertions(+), 30 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 46e94f0861..c38b6b6ab5 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -69,7 +69,59 @@ static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) + return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); + } + +-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, ++/** ++ * Translate addresses between the qemu's virtual address and the SVQ IOVA ++ * ++ * @svq: Shadow VirtQueue ++ * @vaddr: Translated IOVA addresses ++ * @iovec: Source qemu's VA addresses ++ * @num: Length of iovec and minimum length of vaddr ++ */ ++static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, ++ hwaddr *addrs, const struct iovec *iovec, ++ size_t num) ++{ ++ if (num == 0) { ++ return true; ++ } ++ ++ for (size_t i = 0; i < num; ++i) { ++ DMAMap needle = { ++ .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base, ++ .size = iovec[i].iov_len, ++ }; ++ Int128 needle_last, map_last; ++ size_t off; ++ ++ const DMAMap *map = vhost_iova_tree_find_iova(svq->iova_tree, &needle); ++ /* ++ * Map cannot be NULL since iova map contains all guest space and ++ * qemu already has a physical address mapped ++ */ ++ if (unlikely(!map)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Invalid address 0x%"HWADDR_PRIx" given by guest", ++ needle.translated_addr); ++ return false; ++ } ++ ++ off = needle.translated_addr - map->translated_addr; ++ addrs[i] = map->iova + off; ++ ++ needle_last = int128_add(int128_make64(needle.translated_addr), ++ int128_make64(iovec[i].iov_len)); ++ map_last = int128_make64(map->translated_addr + map->size); ++ if (unlikely(int128_gt(needle_last, map_last))) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Guest buffer expands over iova range"); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + const struct iovec *iovec, size_t num, + bool more_descs, bool write) + { +@@ -88,7 +140,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, + } else { + descs[i].flags = flags; + } +- descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base); ++ descs[i].addr = cpu_to_le64(sg[n]); + descs[i].len = cpu_to_le32(iovec[n].iov_len); + + last = i; +@@ -103,6 +155,8 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + { + unsigned avail_idx; + vring_avail_t *avail = svq->vring.avail; ++ bool ok; ++ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num)); + + *head = svq->free_head; + +@@ -113,9 +167,20 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return false; + } + +- vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0, +- false); +- vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true); ++ ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, ++ elem->in_num > 0, false); ++ ++ ++ ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true); + + /* + * Put the entry in the available array (but don't update avail->idx until +@@ -394,9 +459,9 @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) + void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, + struct vhost_vring_addr *addr) + { +- addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc; +- addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail; +- addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used; ++ addr->desc_user_addr = (uint64_t)(uintptr_t)svq->vring.desc; ++ addr->avail_user_addr = (uint64_t)(uintptr_t)svq->vring.avail; ++ addr->used_user_addr = (uint64_t)(uintptr_t)svq->vring.used; + } + + size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq) +@@ -517,11 +582,13 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * Creates vhost shadow virtqueue, and instructs the vhost device to use the + * shadow methods and file descriptors. + * ++ * @iova_tree: Tree to perform descriptors translations ++ * + * Returns the new virtqueue or NULL. + * + * In case of error, reason is reported through error_report. + */ +-VhostShadowVirtqueue *vhost_svq_new(void) ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) + { + g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + int r; +@@ -542,6 +609,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); ++ svq->iova_tree = iova_tree; + return g_steal_pointer(&svq); + + err_init_hdev_call: +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 38b3b91ca7..e5e24c536d 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -13,6 +13,7 @@ + #include "qemu/event_notifier.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" ++#include "hw/virtio/vhost-iova-tree.h" + + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { +@@ -43,6 +44,9 @@ typedef struct VhostShadowVirtqueue { + /* Virtio device */ + VirtIODevice *vdev; + ++ /* IOVA mapping */ ++ VhostIOVATree *iova_tree; ++ + /* Map for use the guest's descriptors */ + VirtQueueElement **ring_id_maps; + +@@ -75,7 +79,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(void); ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree); + + void vhost_svq_free(gpointer vq); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index db34f26246..8245345bcd 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -211,6 +211,21 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + + llsize = int128_sub(llend, int128_make64(iova)); ++ if (v->shadow_vqs_enabled) { ++ DMAMap mem_region = { ++ .translated_addr = (hwaddr)(uintptr_t)vaddr, ++ .size = int128_get64(llsize) - 1, ++ .perm = IOMMU_ACCESS_FLAG(true, section->readonly), ++ }; ++ ++ int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); ++ if (unlikely(r != IOVA_OK)) { ++ error_report("Can't allocate a mapping (%d)", r); ++ goto fail; ++ } ++ ++ iova = mem_region.iova; ++ } + + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), +@@ -263,6 +278,20 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + ++ if (v->shadow_vqs_enabled) { ++ const DMAMap *result; ++ const void *vaddr = memory_region_get_ram_ptr(section->mr) + ++ section->offset_within_region + ++ (iova - section->offset_within_address_space); ++ DMAMap mem_region = { ++ .translated_addr = (hwaddr)(uintptr_t)vaddr, ++ .size = int128_get64(llsize) - 1, ++ }; ++ ++ result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); ++ iova = result->iova; ++ vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); + if (ret) { +@@ -372,7 +401,7 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); ++ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree); + + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); +@@ -809,33 +838,70 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova, +- hwaddr size) ++static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, ++ const DMAMap *needle) + { ++ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); ++ hwaddr size; + int r; + +- size = ROUND_UP(size, qemu_real_host_page_size); +- r = vhost_vdpa_dma_unmap(v, iova, size); ++ if (unlikely(!result)) { ++ error_report("Unable to find SVQ address to unmap"); ++ return false; ++ } ++ ++ size = ROUND_UP(result->size, qemu_real_host_page_size); ++ r = vhost_vdpa_dma_unmap(v, result->iova, size); + return r == 0; + } + + static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { ++ DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; +- size_t device_size = vhost_svq_device_area_size(svq); +- size_t driver_size = vhost_svq_driver_area_size(svq); + bool ok; + + vhost_svq_get_vring_addr(svq, &svq_addr); + +- ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size); ++ needle.translated_addr = svq_addr.desc_user_addr; ++ ok = vhost_vdpa_svq_unmap_ring(v, &needle); + if (unlikely(!ok)) { + return false; + } + +- return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size); ++ needle.translated_addr = svq_addr.used_user_addr; ++ return vhost_vdpa_svq_unmap_ring(v, &needle); ++} ++ ++/** ++ * Map the SVQ area in the device ++ * ++ * @v: Vhost-vdpa device ++ * @needle: The area to search iova ++ * @errorp: Error pointer ++ */ ++static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, ++ Error **errp) ++{ ++ int r; ++ ++ r = vhost_iova_tree_map_alloc(v->iova_tree, needle); ++ if (unlikely(r != IOVA_OK)) { ++ error_setg(errp, "Cannot allocate iova (%d)", r); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1, ++ (void *)(uintptr_t)needle->translated_addr, ++ needle->perm == IOMMU_RO); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot map region to device"); ++ vhost_iova_tree_remove(v->iova_tree, needle); ++ } ++ ++ return r == 0; + } + + /** +@@ -851,28 +917,44 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, + struct vhost_vring_addr *addr, + Error **errp) + { ++ DMAMap device_region, driver_region; ++ struct vhost_vring_addr svq_addr; + struct vhost_vdpa *v = dev->opaque; + size_t device_size = vhost_svq_device_area_size(svq); + size_t driver_size = vhost_svq_driver_area_size(svq); +- int r; ++ size_t avail_offset; ++ bool ok; + + ERRP_GUARD(); +- vhost_svq_get_vring_addr(svq, addr); ++ vhost_svq_get_vring_addr(svq, &svq_addr); + +- r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size, +- (void *)(uintptr_t)addr->desc_user_addr, true); +- if (unlikely(r != 0)) { +- error_setg_errno(errp, -r, "Cannot create vq driver region: "); ++ driver_region = (DMAMap) { ++ .translated_addr = svq_addr.desc_user_addr, ++ .size = driver_size - 1, ++ .perm = IOMMU_RO, ++ }; ++ ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp); ++ if (unlikely(!ok)) { ++ error_prepend(errp, "Cannot create vq driver region: "); + return false; + } ++ addr->desc_user_addr = driver_region.iova; ++ avail_offset = svq_addr.avail_user_addr - svq_addr.desc_user_addr; ++ addr->avail_user_addr = driver_region.iova + avail_offset; + +- r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size, +- (void *)(intptr_t)addr->used_user_addr, false); +- if (unlikely(r != 0)) { +- error_setg_errno(errp, -r, "Cannot create vq device region: "); ++ device_region = (DMAMap) { ++ .translated_addr = svq_addr.used_user_addr, ++ .size = device_size - 1, ++ .perm = IOMMU_RW, ++ }; ++ ok = vhost_vdpa_svq_map_ring(v, &device_region, errp); ++ if (unlikely(!ok)) { ++ error_prepend(errp, "Cannot create vq device region: "); ++ vhost_vdpa_svq_unmap_ring(v, &driver_region); + } ++ addr->used_user_addr = device_region.iova; + +- return r == 0; ++ return ok; + } + + static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 009a9f3b6b..ee8e939ad0 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -14,6 +14,7 @@ + + #include + ++#include "hw/virtio/vhost-iova-tree.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -30,6 +31,8 @@ typedef struct vhost_vdpa { + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; + bool shadow_vqs_enabled; ++ /* IOVA mapping used by the Shadow Virtqueue */ ++ VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; +-- +2.27.0 + diff --git a/vdpa-Add-device-migration-blocker.patch b/vdpa-Add-device-migration-blocker.patch new file mode 100644 index 0000000..85644d9 --- /dev/null +++ b/vdpa-Add-device-migration-blocker.patch @@ -0,0 +1,87 @@ +From 3f0eafe9e86bac9cf99176bf65a22d2dab154617 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:45 +0200 +Subject: [PATCH] vdpa: Add device migration blocker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since the vhost-vdpa device is exposing _F_LOG, adding a migration blocker if +it uses CVQ. + +However, qemu is able to migrate simple devices with no CVQ as long as +they use SVQ. To allow it, add a placeholder error to vhost_vdpa, and +only add to vhost_dev when used. vhost_dev machinery place the migration +blocker if needed. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 +++++++++++++++ + include/hw/virtio/vhost-vdpa.h | 1 + + 2 files changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 31b58aec59..5956ff4660 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -20,6 +20,7 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/vhost-vdpa.h" + #include "exec/address-spaces.h" ++#include "migration/blocker.h" + #include "qemu/main-loop.h" + #include "cpu.h" + #include "trace.h" +@@ -1024,6 +1025,13 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + return true; + } + ++ if (v->migration_blocker) { ++ int r = migrate_add_blocker(v->migration_blocker, &err); ++ if (unlikely(r < 0)) { ++ return false; ++ } ++ } ++ + for (i = 0; i < v->shadow_vqs->len; ++i) { + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +@@ -1066,6 +1074,10 @@ err: + vhost_svq_stop(svq); + } + ++ if (v->migration_blocker) { ++ migrate_del_blocker(v->migration_blocker); ++ } ++ + return false; + } + +@@ -1085,6 +1097,9 @@ static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) + } + } + ++ if (v->migration_blocker) { ++ migrate_del_blocker(v->migration_blocker); ++ } + return true; + } + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 1111d85643..d10a89303e 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -35,6 +35,7 @@ typedef struct vhost_vdpa { + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; ++ Error *migration_blocker; + GPtrArray *shadow_vqs; + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; +-- +2.27.0 + diff --git a/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch b/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch new file mode 100644 index 0000000..b305d76 --- /dev/null +++ b/vdpa-Add-missing-tracing-to-batch-mapping-functions.patch @@ -0,0 +1,58 @@ +From d3aa8e2f948c0b3cd2cd723364fe968fd6befca9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 5 Apr 2022 08:36:28 +0200 +Subject: [PATCH] vdpa: Add missing tracing to batch mapping functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These functions were not traced properly. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Laurent Vivier +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Message-Id: <20220405063628.853745-1-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 2 ++ + hw/virtio/vhost-vdpa.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 650e521e35..37c1555330 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -25,6 +25,8 @@ vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%" + # vhost-vdpa.c + vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 + vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 ++vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 ++vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" + vhost_vdpa_listener_region_del(void *vdpa, uint64_t iova, uint64_t llend) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64 + vhost_vdpa_add_status(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8 +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index b66697da6e..022d70aefb 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -131,6 +131,7 @@ static void vhost_vdpa_listener_begin_batch(struct vhost_vdpa *v) + .iotlb.type = VHOST_IOTLB_BATCH_BEGIN, + }; + ++ trace_vhost_vdpa_listener_begin_batch(v, fd, msg.type, msg.iotlb.type); + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); +@@ -165,6 +166,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) + msg.type = v->msg_type; + msg.iotlb.type = VHOST_IOTLB_BATCH_END; + ++ trace_vhost_vdpa_listener_commit(v, fd, msg.type, msg.iotlb.type); + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", + fd, errno, strerror(errno)); +-- +2.27.0 + diff --git a/vdpa-Add-vhost_vdpa_net_load_mq.patch b/vdpa-Add-vhost_vdpa_net_load_mq.patch new file mode 100644 index 0000000..2b06bfd --- /dev/null +++ b/vdpa-Add-vhost_vdpa_net_load_mq.patch @@ -0,0 +1,65 @@ +From 6dc398327ebe7fcfe78b3df4fe9c1386bafef552 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:16 +0200 +Subject: [PATCH] vdpa: Add vhost_vdpa_net_load_mq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Same way as with the MAC, restore the expected number of queues at +device's start. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 15cd38b52e..b32fe5e68a 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -408,6 +408,28 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) + return 0; + } + ++static int vhost_vdpa_net_load_mq(VhostVDPAState *s, ++ const VirtIONet *n) ++{ ++ struct virtio_net_ctrl_mq mq; ++ uint64_t features = n->parent_obj.guest_features; ++ ssize_t dev_written; ++ ++ if (!(features & BIT_ULL(VIRTIO_NET_F_MQ))) { ++ return 0; ++ } ++ ++ mq.virtqueue_pairs = cpu_to_le16(n->curr_queue_pairs); ++ dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MQ, ++ VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &mq, ++ sizeof(mq)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *s->status != VIRTIO_NET_OK; ++} ++ + static int vhost_vdpa_net_load(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -426,6 +448,10 @@ static int vhost_vdpa_net_load(NetClientState *nc) + if (unlikely(r < 0)) { + return r; + } ++ r = vhost_vdpa_net_load_mq(s, n); ++ if (unlikely(r)) { ++ return r; ++ } + + return 0; + } +-- +2.27.0 + diff --git a/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch b/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch new file mode 100644 index 0000000..ad2ab28 --- /dev/null +++ b/vdpa-Add-virtio-net-mac-address-via-CVQ-at-start.patch @@ -0,0 +1,78 @@ +From 8df992cbd90fb742e14ea1a90211cf535f20fbaa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:36 +0200 +Subject: [PATCH] vdpa: Add virtio-net mac address via CVQ at start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is needed so the destination vdpa device see the same state a the +guest set in the source. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b24e0919d0..561e43fa92 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -371,11 +371,51 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + return vhost_svq_poll(svq); + } + ++static int vhost_vdpa_net_load(NetClientState *nc) ++{ ++ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ const struct vhost_vdpa *v = &s->vhost_vdpa; ++ const VirtIONet *n; ++ uint64_t features; ++ ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ if (!v->shadow_vqs_enabled) { ++ return 0; ++ } ++ ++ n = VIRTIO_NET(v->dev->vdev); ++ features = n->parent_obj.guest_features; ++ if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { ++ const struct virtio_net_ctrl_hdr ctrl = { ++ .class = VIRTIO_NET_CTRL_MAC, ++ .cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET, ++ }; ++ char *cursor = s->cvq_cmd_out_buffer; ++ ssize_t dev_written; ++ ++ memcpy(cursor, &ctrl, sizeof(ctrl)); ++ cursor += sizeof(ctrl); ++ memcpy(cursor, n->mac, sizeof(n->mac)); ++ ++ dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac), ++ sizeof(virtio_net_ctrl_ack)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK; ++ } ++ ++ return 0; ++} ++ + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .receive = vhost_vdpa_receive, + .start = vhost_vdpa_net_cvq_start, ++ .load = vhost_vdpa_net_load, + .stop = vhost_vdpa_net_cvq_stop, + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, +-- +2.27.0 + diff --git a/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch b/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch new file mode 100644 index 0000000..b97319d --- /dev/null +++ b/vdpa-Add-x-svq-to-NetdevVhostVDPAOptions.patch @@ -0,0 +1,208 @@ +From 3f278509424df64a731f69f4599460eda9a8d133 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:46 +0200 +Subject: [PATCH] vdpa: Add x-svq to NetdevVhostVDPAOptions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Finally offering the possibility to enable SVQ from the command line. + +Signed-off-by: Eugenio Pérez +Acked-by: Markus Armbruster +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-- + qapi/net.json | 9 +++++- + 2 files changed, 77 insertions(+), 4 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 6a0fcab443..460f9674d7 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -74,6 +74,28 @@ const int vdpa_feature_bits[] = { + VHOST_INVALID_FEATURE_BIT + }; + ++/** Supported device specific feature bits with SVQ */ ++static const uint64_t vdpa_svq_device_features = ++ BIT_ULL(VIRTIO_NET_F_CSUM) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | ++ BIT_ULL(VIRTIO_NET_F_MTU) | ++ BIT_ULL(VIRTIO_NET_F_MAC) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_TSO6) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_ECN) | ++ BIT_ULL(VIRTIO_NET_F_GUEST_UFO) | ++ BIT_ULL(VIRTIO_NET_F_HOST_TSO4) | ++ BIT_ULL(VIRTIO_NET_F_HOST_TSO6) | ++ BIT_ULL(VIRTIO_NET_F_HOST_ECN) | ++ BIT_ULL(VIRTIO_NET_F_HOST_UFO) | ++ BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | ++ BIT_ULL(VIRTIO_NET_F_STATUS) | ++ BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | ++ BIT_ULL(VIRTIO_F_ANY_LAYOUT) | ++ BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | ++ BIT_ULL(VIRTIO_NET_F_RSC_EXT) | ++ BIT_ULL(VIRTIO_NET_F_STANDBY); ++ + VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -132,6 +154,7 @@ err_init: + static void vhost_vdpa_cleanup(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ struct vhost_dev *dev = &s->vhost_net->dev; + + /* + * If a peer NIC is attached, do not cleanup anything. +@@ -144,6 +167,9 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + + qemu_vfree(s->cvq_cmd_out_buffer); + qemu_vfree(s->cvq_cmd_in_buffer); ++ if (dev->vq_index + dev->nvqs == dev->vq_index_end) { ++ g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); ++ } + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); +@@ -445,7 +471,9 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + int vdpa_device_fd, + int queue_pair_index, + int nvqs, +- bool is_datapath) ++ bool is_datapath, ++ bool svq, ++ VhostIOVATree *iova_tree) + { + NetClientState *nc = NULL; + VhostVDPAState *s; +@@ -463,6 +491,8 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ s->vhost_vdpa.shadow_vqs_enabled = svq; ++ s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, + vhost_vdpa_net_cvq_cmd_page_len()); +@@ -473,6 +503,8 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "Migration disabled: vhost-vdpa uses CVQ."); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +@@ -482,6 +514,14 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + ++static int vhost_vdpa_get_iova_range(int fd, ++ struct vhost_vdpa_iova_range *iova_range) ++{ ++ int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); ++ ++ return ret < 0 ? -errno : 0; ++} ++ + static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) + { + int ret = ioctl(fd, VHOST_GET_FEATURES, features); +@@ -532,6 +572,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + uint64_t features; + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; ++ g_autoptr(VhostIOVATree) iova_tree = NULL; + NetClientState *nc; + int queue_pairs, r, i, has_cvq = 0; + +@@ -559,22 +600,45 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + ++ if (opts->x_svq) { ++ struct vhost_vdpa_iova_range iova_range; ++ ++ uint64_t invalid_dev_features = ++ features & ~vdpa_svq_device_features & ++ /* Transport are all accepted at this point */ ++ ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, ++ VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); ++ ++ if (invalid_dev_features) { ++ error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, ++ invalid_dev_features); ++ goto err_svq; ++ } ++ ++ vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last); ++ } ++ + ncs = g_malloc0(sizeof(*ncs) * queue_pairs); + + for (i = 0; i < queue_pairs; i++) { + ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, +- vdpa_device_fd, i, 2, true); ++ vdpa_device_fd, i, 2, true, opts->x_svq, ++ iova_tree); + if (!ncs[i]) + goto err; + } + + if (has_cvq) { + nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, +- vdpa_device_fd, i, 1, false); ++ vdpa_device_fd, i, 1, false, ++ opts->x_svq, iova_tree); + if (!nc) + goto err; + } + ++ /* iova_tree ownership belongs to last NetClientState */ ++ g_steal_pointer(&iova_tree); + return 0; + + err: +@@ -583,6 +647,8 @@ err: + qemu_del_net_client(ncs[i]); + } + } ++ ++err_svq: + qemu_close(vdpa_device_fd); + + return -1; +diff --git a/qapi/net.json b/qapi/net.json +index 7fab2e7cd8..6a5460ce56 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -445,12 +445,19 @@ + # @queues: number of queues to be created for multiqueue vhost-vdpa + # (default: 1) + # ++# @x-svq: Start device with (experimental) shadow virtqueue. (Since 7.1) ++# (default: false) ++# ++# Features: ++# @unstable: Member @x-svq is experimental. ++# + # Since: 5.1 + ## + { 'struct': 'NetdevVhostVDPAOptions', + 'data': { + '*vhostdev': 'str', +- '*queues': 'int' } } ++ '*queues': 'int', ++ '*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } } + + ## + # @NetClientDriver: +-- +2.27.0 + diff --git a/vdpa-Allow-MQ-feature-in-SVQ.patch b/vdpa-Allow-MQ-feature-in-SVQ.patch new file mode 100644 index 0000000..7ebfa15 --- /dev/null +++ b/vdpa-Allow-MQ-feature-in-SVQ.patch @@ -0,0 +1,32 @@ +From 275135fcfb7e7c22ec84a79297ffc9c96fb82639 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:19 +0200 +Subject: [PATCH] vdpa: Allow MQ feature in SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Finally enable SVQ with MQ feature. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 831709a270..479abf97a7 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -93,6 +93,7 @@ static const uint64_t vdpa_svq_device_features = + BIT_ULL(VIRTIO_NET_F_MRG_RXBUF) | + BIT_ULL(VIRTIO_NET_F_STATUS) | + BIT_ULL(VIRTIO_NET_F_CTRL_VQ) | ++ BIT_ULL(VIRTIO_NET_F_MQ) | + BIT_ULL(VIRTIO_F_ANY_LAYOUT) | + BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) | + BIT_ULL(VIRTIO_NET_F_RSC_EXT) | +-- +2.27.0 + diff --git a/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch b/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch new file mode 100644 index 0000000..64e5871 --- /dev/null +++ b/vdpa-Avoid-compiler-to-squash-reads-to-used-idx.patch @@ -0,0 +1,46 @@ +From 853f14a29c9a31ca132647770f7d6886103b2b77 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:29 +0200 +Subject: [PATCH] vdpa: Avoid compiler to squash reads to used idx +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the next patch we will allow busypolling of this value. The compiler +have a running path where shadow_used_idx, last_used_idx, and vring used +idx are not modified within the same thread busypolling. + +This was not an issue before since we always cleared device event +notifier before checking it, and that could act as memory barrier. +However, the busypoll needs something similar to kernel READ_ONCE. + +Let's add it here, sepparated from the polling. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index da1e1ce3c7..acf50a9a0b 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -326,11 +326,12 @@ static void vhost_handle_guest_kick_notifier(EventNotifier *n) + + static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) + { ++ uint16_t *used_idx = &svq->vring.used->idx; + if (svq->last_used_idx != svq->shadow_used_idx) { + return true; + } + +- svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx); ++ svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx); + + return svq->last_used_idx != svq->shadow_used_idx; + } +-- +2.27.0 + diff --git a/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch b/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch new file mode 100644 index 0000000..fdbcc5d --- /dev/null +++ b/vdpa-Buffer-CVQ-support-on-shadow-virtqueue.patch @@ -0,0 +1,305 @@ +From 31bf37b3097c1ece48b915137167bbd4bd7340aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:43 +0200 +Subject: [PATCH] vdpa: Buffer CVQ support on shadow virtqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce the control virtqueue support for vDPA shadow virtqueue. This +is needed for advanced networking features like rx filtering. + +Virtio-net control VQ copies the descriptors to qemu's VA, so we avoid +TOCTOU with the guest's or device's memory every time there is a device +model change. Otherwise, the guest could change the memory content in +the time between qemu and the device read it. + +To demonstrate command handling, VIRTIO_NET_F_CTRL_MACADDR is +implemented. If the virtio-net driver changes MAC the virtio-net device +model will be updated with the new one, and a rx filtering change event +will be raised. + +More cvq commands could be added here straightforwardly but they have +not been tested. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 214 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 206 insertions(+), 8 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 53a14bc756..2d928feefb 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -32,6 +32,9 @@ typedef struct VhostVDPAState { + NetClientState nc; + struct vhost_vdpa vhost_vdpa; + VHostNetState *vhost_net; ++ ++ /* Control commands shadow buffers */ ++ void *cvq_cmd_out_buffer, *cvq_cmd_in_buffer; + bool started; + } VhostVDPAState; + +@@ -138,6 +141,9 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { + return; + } ++ ++ qemu_vfree(s->cvq_cmd_out_buffer); ++ qemu_vfree(s->cvq_cmd_in_buffer); + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); +@@ -197,24 +203,191 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) ++{ ++ VhostIOVATree *tree = v->iova_tree; ++ DMAMap needle = { ++ /* ++ * No need to specify size or to look for more translations since ++ * this contiguous chunk was allocated by us. ++ */ ++ .translated_addr = (hwaddr)(uintptr_t)addr, ++ }; ++ const DMAMap *map = vhost_iova_tree_find_iova(tree, &needle); ++ int r; ++ ++ if (unlikely(!map)) { ++ error_report("Cannot locate expected map"); ++ return; ++ } ++ ++ r = vhost_vdpa_dma_unmap(v, map->iova, map->size + 1); ++ if (unlikely(r != 0)) { ++ error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); ++ } ++ ++ vhost_iova_tree_remove(tree, map); ++} ++ ++static size_t vhost_vdpa_net_cvq_cmd_len(void) ++{ ++ /* ++ * MAC_TABLE_SET is the ctrl command that produces the longer out buffer. ++ * In buffer is always 1 byte, so it should fit here ++ */ ++ return sizeof(struct virtio_net_ctrl_hdr) + ++ 2 * sizeof(struct virtio_net_ctrl_mac) + ++ MAC_TABLE_ENTRIES * ETH_ALEN; ++} ++ ++static size_t vhost_vdpa_net_cvq_cmd_page_len(void) ++{ ++ return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size); ++} ++ ++/** Copy and map a guest buffer. */ ++static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, ++ const struct iovec *out_data, ++ size_t out_num, size_t data_len, void *buf, ++ size_t *written, bool write) ++{ ++ DMAMap map = {}; ++ int r; ++ ++ if (unlikely(!data_len)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n", ++ __func__, write ? "in" : "out"); ++ return false; ++ } ++ ++ *written = iov_to_buf(out_data, out_num, 0, buf, data_len); ++ map.translated_addr = (hwaddr)(uintptr_t)buf; ++ map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1; ++ map.perm = write ? IOMMU_RW : IOMMU_RO, ++ r = vhost_iova_tree_map_alloc(v->iova_tree, &map); ++ if (unlikely(r != IOVA_OK)) { ++ error_report("Cannot map injected element"); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, ++ !write); ++ if (unlikely(r < 0)) { ++ goto dma_map_err; ++ } ++ ++ return true; ++ ++dma_map_err: ++ vhost_iova_tree_remove(v->iova_tree, &map); ++ return false; ++} ++ + /** +- * Forward buffer for the moment. ++ * Copy the guest element into a dedicated buffer suitable to be sent to NIC ++ * ++ * @iov: [0] is the out buffer, [1] is the in one ++ */ ++static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, ++ VirtQueueElement *elem, ++ struct iovec *iov) ++{ ++ size_t in_copied; ++ bool ok; ++ ++ iov[0].iov_base = s->cvq_cmd_out_buffer; ++ ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num, ++ vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base, ++ &iov[0].iov_len, false); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ iov[1].iov_base = s->cvq_cmd_in_buffer; ++ ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0, ++ sizeof(virtio_net_ctrl_ack), iov[1].iov_base, ++ &in_copied, true); ++ if (unlikely(!ok)) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); ++ return false; ++ } ++ ++ iov[1].iov_len = sizeof(virtio_net_ctrl_ack); ++ return true; ++} ++ ++/** ++ * Do not forward commands not supported by SVQ. Otherwise, the device could ++ * accept it and qemu would not know how to update the device model. ++ */ ++static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, ++ size_t out_num) ++{ ++ struct virtio_net_ctrl_hdr ctrl; ++ size_t n; ++ ++ n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl)); ++ if (unlikely(n < sizeof(ctrl))) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: invalid legnth of out buffer %zu\n", __func__, n); ++ return false; ++ } ++ ++ switch (ctrl.class) { ++ case VIRTIO_NET_CTRL_MAC: ++ switch (ctrl.cmd) { ++ case VIRTIO_NET_CTRL_MAC_ADDR_SET: ++ return true; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mac cmd %u\n", ++ __func__, ctrl.cmd); ++ }; ++ break; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", ++ __func__, ctrl.class); ++ }; ++ ++ return false; ++} ++ ++/** ++ * Validate and copy control virtqueue commands. ++ * ++ * Following QEMU guidelines, we offer a copy of the buffers to the device to ++ * prevent TOCTOU bugs. + */ + static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + VirtQueueElement *elem, + void *opaque) + { +- unsigned int n = elem->out_num + elem->in_num; +- g_autofree struct iovec *dev_buffers = g_new(struct iovec, n); ++ VhostVDPAState *s = opaque; + size_t in_len, dev_written; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- int r; ++ /* out and in buffers sent to the device */ ++ struct iovec dev_buffers[2] = { ++ { .iov_base = s->cvq_cmd_out_buffer }, ++ { .iov_base = s->cvq_cmd_in_buffer }, ++ }; ++ /* in buffer used for device model */ ++ const struct iovec in = { ++ .iov_base = &status, ++ .iov_len = sizeof(status), ++ }; ++ int r = -EINVAL; ++ bool ok; ++ ++ ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers); ++ if (unlikely(!ok)) { ++ goto out; ++ } + +- memcpy(dev_buffers, elem->out_sg, elem->out_num); +- memcpy(dev_buffers + elem->out_num, elem->in_sg, elem->in_num); ++ ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1); ++ if (unlikely(!ok)) { ++ goto out; ++ } + +- r = vhost_svq_add(svq, &dev_buffers[0], elem->out_num, &dev_buffers[1], +- elem->in_num, elem); ++ r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem); + if (unlikely(r != 0)) { + if (unlikely(r == -ENOSPC)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +@@ -231,6 +404,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + dev_written = vhost_svq_poll(svq); + if (unlikely(dev_written < sizeof(status))) { + error_report("Insufficient written data (%zu)", dev_written); ++ goto out; ++ } ++ ++ memcpy(&status, dev_buffers[1].iov_base, sizeof(status)); ++ if (status != VIRTIO_NET_OK) { ++ goto out; ++ } ++ ++ status = VIRTIO_NET_ERR; ++ virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1); ++ if (status != VIRTIO_NET_OK) { ++ error_report("Bad CVQ processing in model"); + } + + out: +@@ -241,6 +426,12 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); ++ if (dev_buffers[0].iov_base) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base); ++ } ++ if (dev_buffers[1].iov_base) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base); ++ } + return r; + } + +@@ -273,6 +464,13 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; + if (!is_datapath) { ++ s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ s->cvq_cmd_in_buffer = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->cvq_cmd_in_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; + } +-- +2.27.0 + diff --git a/vdpa-Delete-CVQ-migration-blocker.patch b/vdpa-Delete-CVQ-migration-blocker.patch new file mode 100644 index 0000000..568fb20 --- /dev/null +++ b/vdpa-Delete-CVQ-migration-blocker.patch @@ -0,0 +1,89 @@ +From cdc1b97f133a2b79318cc10aa6d1a9b69abac78f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:37 +0200 +Subject: [PATCH] vdpa: Delete CVQ migration blocker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can restore the device state in the destination via CVQ now. Remove +the migration blocker. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 --------------- + include/hw/virtio/vhost-vdpa.h | 1 - + net/vhost-vdpa.c | 2 -- + 3 files changed, 18 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d7bdc0f37c..0f07c85b91 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1035,13 +1035,6 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + return true; + } + +- if (v->migration_blocker) { +- int r = migrate_add_blocker(v->migration_blocker, &err); +- if (unlikely(r < 0)) { +- return false; +- } +- } +- + for (i = 0; i < v->shadow_vqs->len; ++i) { + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +@@ -1084,10 +1077,6 @@ err: + vhost_svq_stop(svq); + } + +- if (v->migration_blocker) { +- migrate_del_blocker(v->migration_blocker); +- } +- + return false; + } + +@@ -1103,10 +1092,6 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + vhost_vdpa_svq_unmap_rings(dev, svq); + } +- +- if (v->migration_blocker) { +- migrate_del_blocker(v->migration_blocker); +- } + } + + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index d10a89303e..1111d85643 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -35,7 +35,6 @@ typedef struct vhost_vdpa { + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; +- Error *migration_blocker; + GPtrArray *shadow_vqs; + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 561e43fa92..b10a18aeb4 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -563,8 +563,6 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; +- error_setg(&s->vhost_vdpa.migration_blocker, +- "Migration disabled: vhost-vdpa uses CVQ."); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch b/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch new file mode 100644 index 0000000..8a0b365 --- /dev/null +++ b/vdpa-Delete-duplicated-vdpa_feature_bits-entry.patch @@ -0,0 +1,34 @@ +From e316083c41f99c424879622c6e79452a6878b32f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 20 Oct 2022 10:00:58 +0200 +Subject: [PATCH] vdpa: Delete duplicated vdpa_feature_bits entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This entry was duplicated on referenced commit. Removing it. + +Fixes: 402378407dbd ("vhost-vdpa: multiqueue support") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 479abf97a7..f4f6b8587f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -62,7 +62,6 @@ const int vdpa_feature_bits[] = { + VIRTIO_NET_F_CTRL_RX, + VIRTIO_NET_F_CTRL_RX_EXTRA, + VIRTIO_NET_F_CTRL_VLAN, +- VIRTIO_NET_F_GUEST_ANNOUNCE, + VIRTIO_NET_F_CTRL_MAC_ADDR, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_MQ, +-- +2.27.0 + diff --git a/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch b/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch new file mode 100644 index 0000000..6fade98 --- /dev/null +++ b/vdpa-Export-vhost_vdpa_dma_map-and-unmap-calls.patch @@ -0,0 +1,65 @@ +From 4054b1e42fde8f22703d5fc9bc84a9179ee8f9f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:40 +0200 +Subject: [PATCH] vdpa: Export vhost_vdpa_dma_map and unmap calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Shadow CVQ will copy buffers on qemu VA, so we avoid TOCTOU attacks from +the guest that could set a different state in qemu device model and vdpa +device. + +To do so, it needs to be able to map these new buffers to the device. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 7 +++---- + include/hw/virtio/vhost-vdpa.h | 4 ++++ + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index a8d42655f0..8e962f511d 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -73,8 +73,8 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, + return false; + } + +-static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly) ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, ++ void *vaddr, bool readonly) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; +@@ -99,8 +99,7 @@ static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, + return ret; + } + +-static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, +- hwaddr size) ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index a29dbb3f53..7214eb47dc 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -39,4 +39,8 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, ++ void *vaddr, bool readonly); ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size); ++ + #endif +-- +2.27.0 + diff --git a/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch b/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch new file mode 100644 index 0000000..610d418 --- /dev/null +++ b/vdpa-Expose-VHOST_F_LOG_ALL-on-SVQ.patch @@ -0,0 +1,120 @@ +From a531a56bddf997f559f67fe9d3dc6d4258c82eb1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:54 +0100 +Subject: [PATCH] vdpa: Expose VHOST_F_LOG_ALL on SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SVQ is able to log the dirty bits by itself, so let's use it to not +block migration. + +Also, ignore set and clear of VHOST_F_LOG_ALL on set_features if SVQ is +enabled. Even if the device supports it, the reports would be nonsense +because SVQ memory is in the qemu region. + +The log region is still allocated. Future changes might skip that, but +this series is already long enough. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 39 ++++++++++++++++++++++++++++++---- + include/hw/virtio/vhost-vdpa.h | 1 + + 2 files changed, 36 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 840141321a..3b5456cc0e 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -375,6 +375,16 @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) + return v->index != 0; + } + ++static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, ++ uint64_t *features) ++{ ++ int ret; ++ ++ ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); ++ trace_vhost_vdpa_get_features(dev, *features); ++ return ret; ++} ++ + static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + Error **errp) + { +@@ -387,7 +397,7 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + return 0; + } + +- r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features); ++ r = vhost_vdpa_get_dev_features(hdev, &dev_features); + if (r != 0) { + error_setg_errno(errp, -r, "Can't get vdpa device features"); + return r; +@@ -612,12 +622,29 @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + static int vhost_vdpa_set_features(struct vhost_dev *dev, + uint64_t features) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + + if (vhost_vdpa_one_time_request(dev)) { + return 0; + } + ++ if (v->shadow_vqs_enabled) { ++ if ((v->acked_features ^ features) == BIT_ULL(VHOST_F_LOG_ALL)) { ++ /* ++ * QEMU is just trying to enable or disable logging. SVQ handles ++ * this sepparately, so no need to forward this. ++ */ ++ v->acked_features = features; ++ return 0; ++ } ++ ++ v->acked_features = features; ++ ++ /* We must not ack _F_LOG if SVQ is enabled */ ++ features &= ~BIT_ULL(VHOST_F_LOG_ALL); ++ } ++ + trace_vhost_vdpa_set_features(dev, features); + ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); + if (ret) { +@@ -1202,10 +1229,14 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) + { +- int ret; ++ struct vhost_vdpa *v = dev->opaque; ++ int ret = vhost_vdpa_get_dev_features(dev, features); ++ ++ if (ret == 0 && v->shadow_vqs_enabled) { ++ /* Add SVQ logging capabilities */ ++ *features |= BIT_ULL(VHOST_F_LOG_ALL); ++ } + +- ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features); +- trace_vhost_vdpa_get_features(dev, *features); + return ret; + } + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index ee8e939ad0..a29dbb3f53 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -30,6 +30,7 @@ typedef struct vhost_vdpa { + bool iotlb_batch_begin_sent; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; ++ uint64_t acked_features; + bool shadow_vqs_enabled; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; +-- +2.27.0 + diff --git a/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch b/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch new file mode 100644 index 0000000..9a2f337 --- /dev/null +++ b/vdpa-Extract-get-features-part-from-vhost_vdpa_get_m.patch @@ -0,0 +1,89 @@ +From 29048bdf8848d527b39a383c7f0c4f8c60870f71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:44 +0200 +Subject: [PATCH] vdpa: Extract get features part from + vhost_vdpa_get_max_queue_pairs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To know the device features is needed for CVQ SVQ, so SVQ knows if it +can handle all commands or not. Extract from +vhost_vdpa_get_max_queue_pairs so we can reuse it. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 2d928feefb..6a0fcab443 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -482,20 +482,24 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + +-static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp) ++static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) ++{ ++ int ret = ioctl(fd, VHOST_GET_FEATURES, features); ++ if (unlikely(ret < 0)) { ++ error_setg_errno(errp, errno, ++ "Fail to query features from vhost-vDPA device"); ++ } ++ return ret; ++} ++ ++static int vhost_vdpa_get_max_queue_pairs(int fd, uint64_t features, ++ int *has_cvq, Error **errp) + { + unsigned long config_size = offsetof(struct vhost_vdpa_config, buf); + g_autofree struct vhost_vdpa_config *config = NULL; + __virtio16 *max_queue_pairs; +- uint64_t features; + int ret; + +- ret = ioctl(fd, VHOST_GET_FEATURES, &features); +- if (ret) { +- error_setg(errp, "Fail to query features from vhost-vDPA device"); +- return ret; +- } +- + if (features & (1 << VIRTIO_NET_F_CTRL_VQ)) { + *has_cvq = 1; + } else { +@@ -525,10 +529,11 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) + { + const NetdevVhostVDPAOptions *opts; ++ uint64_t features; + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; + NetClientState *nc; +- int queue_pairs, i, has_cvq = 0; ++ int queue_pairs, r, i, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +@@ -542,7 +547,12 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return -errno; + } + +- queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, ++ r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, + &has_cvq, errp); + if (queue_pairs < 0) { + qemu_close(vdpa_device_fd); +-- +2.27.0 + diff --git a/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch b/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch new file mode 100644 index 0000000..a156e6c --- /dev/null +++ b/vdpa-Fix-bad-index-calculus-at-vhost_vdpa_get_vring_.patch @@ -0,0 +1,41 @@ +From b37494d53478957b9e126e97f03d9501888a4d83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:44 +0200 +Subject: [PATCH] vdpa: Fix bad index calculus at vhost_vdpa_get_vring_base +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 6d0b222666 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") + +Acked-by: Jason Wang +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 022d70aefb..3b67c9fd12 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1174,11 +1174,11 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; ++ int vdpa_idx = ring->index - dev->vq_index; + int ret; + + if (v->shadow_vqs_enabled) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, +- ring->index); ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); + + /* + * Setting base as last used idx, so destination will see as available +-- +2.27.0 + diff --git a/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch b/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch new file mode 100644 index 0000000..6436bab --- /dev/null +++ b/vdpa-Fix-file-descriptor-leak-on-get-features-error.patch @@ -0,0 +1,50 @@ +From 4077ce7f2d21dc67d18dc444165859b8496a185e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 2 Aug 2022 13:24:46 +0200 +Subject: [PATCH] vdpa: Fix file descriptor leak on get features error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +File descriptor vdpa_device_fd is not free in the case of returning +error from vhost_vdpa_get_features. Fixing it by making all errors go to +the same error path. + +Resolves: Coverity CID 1490785 +Fixes: 8170ab3f43 ("vdpa: Extract get features part from vhost_vdpa_get_max_queue_pairs") + +Signed-off-by: Eugenio Pérez +Reviewed-by: Laurent Vivier +Reviewed-by: Michael S. Tsirkin +Message-Id: <20220802112447.249436-2-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 460f9674d7..0f75aa6080 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -574,7 +574,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + g_autofree NetClientState **ncs = NULL; + g_autoptr(VhostIOVATree) iova_tree = NULL; + NetClientState *nc; +- int queue_pairs, r, i, has_cvq = 0; ++ int queue_pairs, r, i = 0, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +@@ -590,7 +590,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); + if (unlikely(r < 0)) { +- return r; ++ goto err; + } + + queue_pairs = vhost_vdpa_get_max_queue_pairs(vdpa_device_fd, features, +-- +2.27.0 + diff --git a/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch b/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch new file mode 100644 index 0000000..69f1496 --- /dev/null +++ b/vdpa-Fix-index-calculus-at-vhost_vdpa_svqs_start.patch @@ -0,0 +1,37 @@ +From 2f19a3fd1fbaca215906199ab7da7cd961b68d65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:45 +0200 +Subject: [PATCH] vdpa: Fix index calculus at vhost_vdpa_svqs_start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the introduction of MQ the index of the vq needs to be calculated +with the device model vq_index. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20220512175747.142058-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3b67c9fd12..1360f2eaf7 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1020,7 +1020,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + struct vhost_vring_addr addr = { +- .index = i, ++ .index = dev->vq_index + i, + }; + int r; + bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); +-- +2.27.0 + diff --git a/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch b/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch new file mode 100644 index 0000000..bba1ee0 --- /dev/null +++ b/vdpa-Fix-memory-listener-deletions-of-iova-tree.patch @@ -0,0 +1,53 @@ +From de9a72905ad70e256a73608c92f50c3862b8eb8e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 22 Jul 2022 10:26:30 +0200 +Subject: [PATCH] vdpa: Fix memory listener deletions of iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +vhost_vdpa_listener_region_del is always deleting the first iova entry +of the tree, since it's using the needle iova instead of the result's +one. + +This was detected using a vga virtual device in the VM using vdpa SVQ. +It makes some extra memory adding and deleting, so the wrong one was +mapped / unmapped. This was undetected before since all the memory was +mappend and unmapped totally without that device, but other conditions +could trigger it too: + +* mem_region was with .iova = 0, .translated_addr = (correct GPA). +* iova_tree_find_iova returned right result, but does not update + mem_region. +* iova_tree_remove always removed region with .iova = 0. Right iova were + sent to the device. +* Next map will fill the first region with .iova = 0, causing a mapping + with the same iova and device complains, if the next action is a map. +* Next unmap will cause to try to unmap again iova = 0, causing the + device to complain that no region was mapped at iova = 0. + +Fixes: 34e3c94edaef ("vdpa: Add custom IOTLB translations to SVQ") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 6304f174c2..d0cf7a0745 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -292,7 +292,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); + iova = result->iova; +- vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ vhost_iova_tree_remove(v->iova_tree, result); + } + vhost_vdpa_iotlb_batch_begin_once(v); + ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); +-- +2.27.0 + diff --git a/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch b/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch new file mode 100644 index 0000000..925cb9e --- /dev/null +++ b/vdpa-Fix-possible-use-after-free-for-VirtQueueElemen.patch @@ -0,0 +1,63 @@ +From c8d132a62f026e51c2fb1f87dbf40aad8080fa9a Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Sat, 8 Jul 2023 00:44:42 +0800 +Subject: [PATCH] vdpa: Fix possible use-after-free for VirtQueueElement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU uses vhost_handle_guest_kick() to forward guest's available +buffers to the vdpa device in SVQ avail ring. + +In vhost_handle_guest_kick(), a `g_autofree` `elem` is used to +iterate through the available VirtQueueElements. This `elem` is +then passed to `svq->ops->avail_handler`, specifically to the +vhost_vdpa_net_handle_ctrl_avail(). If this handler fails to +process the CVQ command, vhost_handle_guest_kick() regains +ownership of the `elem`, and either frees it or requeues it. + +Yet the problem is that, vhost_vdpa_net_handle_ctrl_avail() +mistakenly frees the `elem`, even if it fails to forward the +CVQ command to vdpa device. This can result in a use-after-free +for the `elem` in vhost_handle_guest_kick(). + +This patch solves this problem by refactoring +vhost_vdpa_net_handle_ctrl_avail() to only freeing the `elem` if +it owns it. + +Fixes: bd907ae4b0 ("vdpa: manual forward CVQ buffers") +Signed-off-by: Hawkins Jiawei +Message-Id: +Reviewed-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index fd5dc8c6aa..94f74b54ae 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -658,7 +658,16 @@ out: + error_report("Bad device CVQ written length"); + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); +- g_free(elem); ++ /* ++ * `elem` belongs to vhost_vdpa_net_handle_ctrl_avail() only when ++ * the function successfully forwards the CVQ command, indicated ++ * by a non-negative value of `dev_written`. Otherwise, it still ++ * belongs to SVQ. ++ * This function should only free the `elem` when it owns. ++ */ ++ if (dev_written >= 0) { ++ g_free(elem); ++ } + return dev_written < 0 ? dev_written : 0; + } + +-- +2.27.0 + diff --git a/vdpa-Make-SVQ-vring-unmapping-return-void.patch b/vdpa-Make-SVQ-vring-unmapping-return-void.patch new file mode 100644 index 0000000..589898b --- /dev/null +++ b/vdpa-Make-SVQ-vring-unmapping-return-void.patch @@ -0,0 +1,124 @@ +From 39de24fc2b1cd16e8810b9e26cd23bb3896982a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:06 +0200 +Subject: [PATCH] vdpa: Make SVQ vring unmapping return void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Nothing actually reads the return value, but an error in cleaning some +entries could cause device stop to abort, making a restart impossible. +Better ignore explicitely the return value. + +Reported-by: Lei Yang +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 32 ++++++++++---------------------- + 1 file changed, 10 insertions(+), 22 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3be6988e9c..31c1b71498 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -886,7 +886,7 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, ++static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + const DMAMap *needle) + { + const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); +@@ -895,38 +895,33 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + + if (unlikely(!result)) { + error_report("Unable to find SVQ address to unmap"); +- return false; ++ return; + } + + size = ROUND_UP(result->size, qemu_real_host_page_size); + r = vhost_vdpa_dma_unmap(v, result->iova, size); + if (unlikely(r < 0)) { + error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); +- return false; ++ return; + } + + vhost_iova_tree_remove(v->iova_tree, *result); +- return r == 0; + } + +-static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, ++static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { + DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; +- bool ok; + + vhost_svq_get_vring_addr(svq, &svq_addr); + + needle.translated_addr = svq_addr.desc_user_addr; +- ok = vhost_vdpa_svq_unmap_ring(v, &needle); +- if (unlikely(!ok)) { +- return false; +- } ++ vhost_vdpa_svq_unmap_ring(v, &needle); + + needle.translated_addr = svq_addr.used_user_addr; +- return vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, &needle); + } + + /** +@@ -1097,26 +1092,22 @@ err: + return false; + } + +-static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) ++static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + + if (!v->shadow_vqs) { +- return true; ++ return; + } + + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +- bool ok = vhost_vdpa_svq_unmap_rings(dev, svq); +- if (unlikely(!ok)) { +- return false; +- } ++ vhost_vdpa_svq_unmap_rings(dev, svq); + } + + if (v->migration_blocker) { + migrate_del_blocker(v->migration_blocker); + } +- return true; + } + + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) +@@ -1133,10 +1124,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + vhost_vdpa_set_vring_ready(dev); + } else { +- ok = vhost_vdpa_svqs_stop(dev); +- if (unlikely(!ok)) { +- return -1; +- } ++ vhost_vdpa_svqs_stop(dev); + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + } + +-- +2.27.0 + diff --git a/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch b/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch new file mode 100644 index 0000000..d9efa49 --- /dev/null +++ b/vdpa-Make-VhostVDPAState-cvq_cmd_in_buffer-control-a.patch @@ -0,0 +1,103 @@ +From fdb55acf1833e6a35171b4e7e1c357f4b133e26f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:14 +0200 +Subject: [PATCH] vdpa: Make VhostVDPAState cvq_cmd_in_buffer control ack type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows to simplify the code. Rename to status while we're at it. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b10a18aeb4..2700ef656f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -34,7 +34,9 @@ typedef struct VhostVDPAState { + VHostNetState *vhost_net; + + /* Control commands shadow buffers */ +- void *cvq_cmd_out_buffer, *cvq_cmd_in_buffer; ++ void *cvq_cmd_out_buffer; ++ virtio_net_ctrl_ack *status; ++ + bool started; + } VhostVDPAState; + +@@ -166,7 +168,7 @@ static void vhost_vdpa_cleanup(NetClientState *nc) + } + + qemu_vfree(s->cvq_cmd_out_buffer); +- qemu_vfree(s->cvq_cmd_in_buffer); ++ qemu_vfree(s->status); + if (dev->vq_index + dev->nvqs == dev->vq_index_end) { + g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); + } +@@ -318,7 +320,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) + return r; + } + +- r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer, ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->status, + vhost_vdpa_net_cvq_cmd_page_len(), true); + if (unlikely(r < 0)) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +@@ -335,7 +337,7 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + + if (s->vhost_vdpa.shadow_vqs_enabled) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer); ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status); + } + } + +@@ -348,7 +350,7 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + .iov_len = out_len, + }; + const struct iovec in = { +- .iov_base = s->cvq_cmd_in_buffer, ++ .iov_base = s->status, + .iov_len = sizeof(virtio_net_ctrl_ack), + }; + VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); +@@ -404,7 +406,7 @@ static int vhost_vdpa_net_load(NetClientState *nc) + return dev_written; + } + +- return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK; ++ return *s->status != VIRTIO_NET_OK; + } + + return 0; +@@ -499,8 +501,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); +- if (status != VIRTIO_NET_OK) { ++ if (*s->status != VIRTIO_NET_OK) { + return VIRTIO_NET_ERR; + } + +@@ -557,9 +558,9 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, + vhost_vdpa_net_cvq_cmd_page_len()); + memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); +- s->cvq_cmd_in_buffer = qemu_memalign(qemu_real_host_page_size, +- vhost_vdpa_net_cvq_cmd_page_len()); +- memset(s->cvq_cmd_in_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); ++ s->status = qemu_memalign(qemu_real_host_page_size, ++ vhost_vdpa_net_cvq_cmd_page_len()); ++ memset(s->status, 0, vhost_vdpa_net_cvq_cmd_page_len()); + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; +-- +2.27.0 + diff --git a/vdpa-Make-ncs-autofree.patch b/vdpa-Make-ncs-autofree.patch new file mode 100644 index 0000000..e2b8775 --- /dev/null +++ b/vdpa-Make-ncs-autofree.patch @@ -0,0 +1,54 @@ +From 1f1c2f74668cd1250cbd00b397dd59be92121314 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Feb 2022 20:34:15 +0100 +Subject: [PATCH] vdpa: Make ncs autofree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Simplifying memory management. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Stefano Garzarella +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220214193415.1606752-2-eperezma@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 60b715aef1..9ba0f7bfca 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -271,7 +271,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + { + const NetdevVhostVDPAOptions *opts; + int vdpa_device_fd; +- NetClientState **ncs, *nc; ++ g_autofree NetClientState **ncs = NULL; ++ NetClientState *nc; + int queue_pairs, i, has_cvq = 0; + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); +@@ -309,7 +310,6 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + goto err; + } + +- g_free(ncs); + return 0; + + err: +@@ -317,7 +317,6 @@ err: + qemu_del_net_client(ncs[0]); + } + qemu_close(vdpa_device_fd); +- g_free(ncs); + + return -1; + } +-- +2.27.0 + diff --git a/vdpa-Move-command-buffers-map-to-start-of-net-device.patch b/vdpa-Move-command-buffers-map-to-start-of-net-device.patch new file mode 100644 index 0000000..5b943d2 --- /dev/null +++ b/vdpa-Move-command-buffers-map-to-start-of-net-device.patch @@ -0,0 +1,242 @@ +From 811a2e0b40724cc505141d4caf322030b83f86a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:33 +0200 +Subject: [PATCH] vdpa: Move command buffers map to start of net device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As this series will reuse them to restore the device state at the end of +a migration (or a device start), let's allocate only once at the device +start so we don't duplicate their map and unmap. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 123 ++++++++++++++++++++++------------------------- + 1 file changed, 58 insertions(+), 65 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 04cb08d418..882f5ee89c 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -271,29 +271,20 @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void) + return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size); + } + +-/** Copy and map a guest buffer. */ +-static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, +- const struct iovec *out_data, +- size_t out_num, size_t data_len, void *buf, +- size_t *written, bool write) ++/** Map CVQ buffer. */ ++static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, ++ bool write) + { + DMAMap map = {}; + int r; + +- if (unlikely(!data_len)) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n", +- __func__, write ? "in" : "out"); +- return false; +- } +- +- *written = iov_to_buf(out_data, out_num, 0, buf, data_len); + map.translated_addr = (hwaddr)(uintptr_t)buf; +- map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1; ++ map.size = size - 1; + map.perm = write ? IOMMU_RW : IOMMU_RO, + r = vhost_iova_tree_map_alloc(v->iova_tree, &map); + if (unlikely(r != IOVA_OK)) { + error_report("Cannot map injected element"); +- return false; ++ return r; + } + + r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, +@@ -302,50 +293,58 @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, + goto dma_map_err; + } + +- return true; ++ return 0; + + dma_map_err: + vhost_iova_tree_remove(v->iova_tree, map); +- return false; ++ return r; + } + +-/** +- * Copy the guest element into a dedicated buffer suitable to be sent to NIC +- * +- * @iov: [0] is the out buffer, [1] is the in one +- */ +-static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, +- VirtQueueElement *elem, +- struct iovec *iov) ++static int vhost_vdpa_net_cvq_start(NetClientState *nc) + { +- size_t in_copied; +- bool ok; ++ VhostVDPAState *s; ++ int r; + +- iov[0].iov_base = s->cvq_cmd_out_buffer; +- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num, +- vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base, +- &iov[0].iov_len, false); +- if (unlikely(!ok)) { +- return false; ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ s = DO_UPCAST(VhostVDPAState, nc, nc); ++ if (!s->vhost_vdpa.shadow_vqs_enabled) { ++ return 0; + } + +- iov[1].iov_base = s->cvq_cmd_in_buffer; +- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0, +- sizeof(virtio_net_ctrl_ack), iov[1].iov_base, +- &in_copied, true); +- if (unlikely(!ok)) { ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer, ++ vhost_vdpa_net_cvq_cmd_page_len(), false); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer, ++ vhost_vdpa_net_cvq_cmd_page_len(), true); ++ if (unlikely(r < 0)) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); +- return false; + } + +- iov[1].iov_len = sizeof(virtio_net_ctrl_ack); +- return true; ++ return r; ++} ++ ++static void vhost_vdpa_net_cvq_stop(NetClientState *nc) ++{ ++ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); ++ ++ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); ++ ++ if (s->vhost_vdpa.shadow_vqs_enabled) { ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); ++ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer); ++ } + } + + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), + .receive = vhost_vdpa_receive, ++ .start = vhost_vdpa_net_cvq_start, ++ .stop = vhost_vdpa_net_cvq_stop, + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .has_ufo = vhost_vdpa_has_ufo, +@@ -356,19 +355,17 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { + * Do not forward commands not supported by SVQ. Otherwise, the device could + * accept it and qemu would not know how to update the device model. + */ +-static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out, +- size_t out_num) ++static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) + { + struct virtio_net_ctrl_hdr ctrl; +- size_t n; + +- n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl)); +- if (unlikely(n < sizeof(ctrl))) { ++ if (unlikely(len < sizeof(ctrl))) { + qemu_log_mask(LOG_GUEST_ERROR, +- "%s: invalid legnth of out buffer %zu\n", __func__, n); ++ "%s: invalid legnth of out buffer %zu\n", __func__, len); + return false; + } + ++ memcpy(&ctrl, out_buf, sizeof(ctrl)); + switch (ctrl.class) { + case VIRTIO_NET_CTRL_MAC: + switch (ctrl.cmd) { +@@ -400,10 +397,14 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + VhostVDPAState *s = opaque; + size_t in_len, dev_written; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- /* out and in buffers sent to the device */ +- struct iovec dev_buffers[2] = { +- { .iov_base = s->cvq_cmd_out_buffer }, +- { .iov_base = s->cvq_cmd_in_buffer }, ++ /* Out buffer sent to both the vdpa device and the device model */ ++ struct iovec out = { ++ .iov_base = s->cvq_cmd_out_buffer, ++ }; ++ /* In buffer sent to the device */ ++ const struct iovec dev_in = { ++ .iov_base = s->cvq_cmd_in_buffer, ++ .iov_len = sizeof(virtio_net_ctrl_ack), + }; + /* in buffer used for device model */ + const struct iovec in = { +@@ -413,17 +414,15 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + int r = -EINVAL; + bool ok; + +- ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers); +- if (unlikely(!ok)) { +- goto out; +- } +- +- ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1); ++ out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, ++ s->cvq_cmd_out_buffer, ++ vhost_vdpa_net_cvq_cmd_len()); ++ ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len); + if (unlikely(!ok)) { + goto out; + } + +- r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem); ++ r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem); + if (unlikely(r != 0)) { + if (unlikely(r == -ENOSPC)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +@@ -443,13 +442,13 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- memcpy(&status, dev_buffers[1].iov_base, sizeof(status)); ++ memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); + if (status != VIRTIO_NET_OK) { + goto out; + } + + status = VIRTIO_NET_ERR; +- virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1); ++ virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, &out, 1); + if (status != VIRTIO_NET_OK) { + error_report("Bad CVQ processing in model"); + } +@@ -462,12 +461,6 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); +- if (dev_buffers[0].iov_base) { +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base); +- } +- if (dev_buffers[1].iov_base) { +- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base); +- } + return r; + } + +-- +2.27.0 + diff --git a/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch b/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch new file mode 100644 index 0000000..6778cde --- /dev/null +++ b/vdpa-Never-set-log_base-addr-if-SVQ-is-enabled.patch @@ -0,0 +1,36 @@ +From b34bcf052293861e8b88a41dad194d0889c6692f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:53 +0100 +Subject: [PATCH] vdpa: Never set log_base addr if SVQ is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Setting the log address would make the device start reporting invalid +dirty memory because the SVQ vrings are located in qemu's memory. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 428137f654..840141321a 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1092,7 +1092,8 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ struct vhost_vdpa *v = dev->opaque; ++ if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { + return 0; + } + +-- +2.27.0 + diff --git a/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch b/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch new file mode 100644 index 0000000..be0cb96 --- /dev/null +++ b/vdpa-Remove-SVQ-vring-from-iova_tree-at-shutdown.patch @@ -0,0 +1,40 @@ +From f52985fb819fbf8efb162a25096abb4c174b9f40 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:05 +0200 +Subject: [PATCH] vdpa: Remove SVQ vring from iova_tree at shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Although the device will be reset before usage, the right thing to do is +to clean it. + +Reported-by: Lei Yang +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 0f640f670b..3be6988e9c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -900,6 +900,12 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + + size = ROUND_UP(result->size, qemu_real_host_page_size); + r = vhost_vdpa_dma_unmap(v, result->iova, size); ++ if (unlikely(r < 0)) { ++ error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); ++ return false; ++ } ++ ++ vhost_iova_tree_remove(v->iova_tree, *result); + return r == 0; + } + +-- +2.27.0 + diff --git a/vdpa-Remove-shadow-CVQ-command-check.patch b/vdpa-Remove-shadow-CVQ-command-check.patch new file mode 100644 index 0000000..90ef701 --- /dev/null +++ b/vdpa-Remove-shadow-CVQ-command-check.patch @@ -0,0 +1,94 @@ +From 6cb9e17dcc07d6fc1467a585fb015991191a92da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 20 Oct 2022 10:02:30 +0200 +Subject: [PATCH] vdpa: Remove shadow CVQ command check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The guest will see undefined behavior if it issue not negotiate +commands, bit it is expected somehow. + +Simplify code deleting this check. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 48 ------------------------------------------------ + 1 file changed, 48 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index f4f6b8587f..c8c433002d 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -469,48 +469,6 @@ static NetClientInfo net_vhost_vdpa_cvq_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + +-/** +- * Do not forward commands not supported by SVQ. Otherwise, the device could +- * accept it and qemu would not know how to update the device model. +- */ +-static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) +-{ +- struct virtio_net_ctrl_hdr ctrl; +- +- if (unlikely(len < sizeof(ctrl))) { +- qemu_log_mask(LOG_GUEST_ERROR, +- "%s: invalid legnth of out buffer %zu\n", __func__, len); +- return false; +- } +- +- memcpy(&ctrl, out_buf, sizeof(ctrl)); +- switch (ctrl.class) { +- case VIRTIO_NET_CTRL_MAC: +- switch (ctrl.cmd) { +- case VIRTIO_NET_CTRL_MAC_ADDR_SET: +- return true; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mac cmd %u\n", +- __func__, ctrl.cmd); +- }; +- break; +- case VIRTIO_NET_CTRL_MQ: +- switch (ctrl.cmd) { +- case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: +- return true; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n", +- __func__, ctrl.cmd); +- }; +- break; +- default: +- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", +- __func__, ctrl.class); +- }; +- +- return false; +-} +- + /** + * Validate and copy control virtqueue commands. + * +@@ -534,16 +492,10 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + .iov_len = sizeof(status), + }; + ssize_t dev_written = -EINVAL; +- bool ok; + + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); +- ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len); +- if (unlikely(!ok)) { +- goto out; +- } +- + dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); + if (unlikely(dev_written < 0)) { + goto out; +-- +2.27.0 + diff --git a/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch new file mode 100644 index 0000000..6471c52 --- /dev/null +++ b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_-new.patch @@ -0,0 +1,63 @@ +From 8f2a04c1b5790f6e00160920c3bc88801b5afc16 Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 4 Jul 2023 11:34:34 +0800 +Subject: [PATCH] vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in + _load_mq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to VirtIO standard, "The class, command and +command-specific-data are set by the driver, +and the device sets the ack byte. +There is little it can do except issue a diagnostic +if ack is not VIRTIO_NET_OK." + +Therefore, QEMU should stop sending the queued SVQ commands and +cancel the device startup if the device's ack is not VIRTIO_NET_OK. + +Yet the problem is that, vhost_vdpa_net_load_mq() returns 1 based on +`*s->status != VIRTIO_NET_OK` when the device's ack is VIRTIO_NET_ERR. +As a result, net->nc->info->load() also returns 1, this makes +vhost_net_start_one() incorrectly assume the device state is +successfully loaded by vhost_vdpa_net_load() and return 0, instead of +goto `fail` label to cancel the device startup, as vhost_net_start_one() +only cancels the device startup when net->nc->info->load() returns a +negative value. + +This patch fixes this problem by returning -EIO when the device's +ack is not VIRTIO_NET_OK. + +Fixes: f64c7cda69 ("vdpa: Add vhost_vdpa_net_load_mq") +Signed-off-by: Hawkins Jiawei +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 9af9f6554e..8192045735 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -553,8 +553,11 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, + if (unlikely(dev_written < 0)) { + return dev_written; + } ++ if (*s->status != VIRTIO_NET_OK) { ++ return -EIO; ++ } + +- return *s->status != VIRTIO_NET_OK; ++ return 0; + } + + static int vhost_vdpa_net_load(NetClientState *nc) +-- +2.27.0 + diff --git a/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch new file mode 100644 index 0000000..f457ca3 --- /dev/null +++ b/vdpa-Return-EIO-if-device-ack-is-VIRTIO_NET_ERR-in-_.patch @@ -0,0 +1,62 @@ +From 1c9d6dde6fabf6c1f6a4aeb388921a83279d3071 Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 4 Jul 2023 11:34:33 +0800 +Subject: [PATCH] vdpa: Return -EIO if device ack is VIRTIO_NET_ERR in + _load_mac() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to VirtIO standard, "The class, command and +command-specific-data are set by the driver, +and the device sets the ack byte. +There is little it can do except issue a diagnostic +if ack is not VIRTIO_NET_OK." + +Therefore, QEMU should stop sending the queued SVQ commands and +cancel the device startup if the device's ack is not VIRTIO_NET_OK. + +Yet the problem is that, vhost_vdpa_net_load_mac() returns 1 based on +`*s->status != VIRTIO_NET_OK` when the device's ack is VIRTIO_NET_ERR. +As a result, net->nc->info->load() also returns 1, this makes +vhost_net_start_one() incorrectly assume the device state is +successfully loaded by vhost_vdpa_net_load() and return 0, instead of +goto `fail` label to cancel the device startup, as vhost_net_start_one() +only cancels the device startup when net->nc->info->load() returns a +negative value. + +This patch fixes this problem by returning -EIO when the device's +ack is not VIRTIO_NET_OK. + +Fixes: f73c0c43ac ("vdpa: extract vhost_vdpa_net_load_mac from vhost_vdpa_net_load") +Signed-off-by: Hawkins Jiawei +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index afca8740bc..9af9f6554e 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -527,8 +527,9 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) + if (unlikely(dev_written < 0)) { + return dev_written; + } +- +- return *s->status != VIRTIO_NET_OK; ++ if (*s->status != VIRTIO_NET_OK) { ++ return -EIO; ++ } + } + + return 0; +-- +2.27.0 + diff --git a/vdpa-Skip-the-maps-not-in-the-iova-tree.patch b/vdpa-Skip-the-maps-not-in-the-iova-tree.patch new file mode 100644 index 0000000..17e1320 --- /dev/null +++ b/vdpa-Skip-the-maps-not-in-the-iova-tree.patch @@ -0,0 +1,39 @@ +From a498bc3ae687778dad2f8161ff17532432df0c1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:02 +0200 +Subject: [PATCH] vdpa: Skip the maps not in the iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Next patch will skip the registering of dma maps that the vdpa device +rejects in the iova tree. We need to consider that here or we cause a +SIGSEGV accessing result. + +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index d0cf7a0745..c551665f5d 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -291,6 +291,10 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + }; + + result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); ++ if (!result) { ++ /* The memory listener map wasn't mapped */ ++ return; ++ } + iova = result->iova; + vhost_iova_tree_remove(v->iova_tree, result); + } +-- +2.27.0 + diff --git a/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch b/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch new file mode 100644 index 0000000..606084c --- /dev/null +++ b/vdpa-Use-ring-hwaddr-at-vhost_vdpa_svq_unmap_ring.patch @@ -0,0 +1,70 @@ +From 1c3e4f7326031d0b689821f655a4352bb746a405 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:08 +0200 +Subject: [PATCH] vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reduce code duplication. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 31c1b71498..d7bdc0f37c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -886,10 +886,12 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + /** + * Unmap a SVQ area in the device + */ +-static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, +- const DMAMap *needle) ++static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr) + { +- const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle); ++ const DMAMap needle = { ++ .translated_addr = addr, ++ }; ++ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, &needle); + hwaddr size; + int r; + +@@ -911,17 +913,14 @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, + static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, + const VhostShadowVirtqueue *svq) + { +- DMAMap needle = {}; + struct vhost_vdpa *v = dev->opaque; + struct vhost_vring_addr svq_addr; + + vhost_svq_get_vring_addr(svq, &svq_addr); + +- needle.translated_addr = svq_addr.desc_user_addr; +- vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr); + +- needle.translated_addr = svq_addr.used_user_addr; +- vhost_vdpa_svq_unmap_ring(v, &needle); ++ vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr); + } + + /** +@@ -999,7 +998,7 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, + ok = vhost_vdpa_svq_map_ring(v, &device_region, errp); + if (unlikely(!ok)) { + error_prepend(errp, "Cannot create vq device region: "); +- vhost_vdpa_svq_unmap_ring(v, &driver_region); ++ vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr); + } + addr->used_user_addr = device_region.iova; + +-- +2.27.0 + diff --git a/vdpa-adapt-vhost_ops-callbacks-to-svq.patch b/vdpa-adapt-vhost_ops-callbacks-to-svq.patch new file mode 100644 index 0000000..914e13a --- /dev/null +++ b/vdpa-adapt-vhost_ops-callbacks-to-svq.patch @@ -0,0 +1,104 @@ +From 1ae2ad1afcb032dc933104da5ad922173961caf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:46 +0100 +Subject: [PATCH] vdpa: adapt vhost_ops callbacks to svq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +First half of the buffers forwarding part, preparing vhost-vdpa +callbacks to SVQ to offer it. QEMU cannot enable it at this moment, so +this is effectively dead code at the moment, but it helps to reduce +patch size. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 48 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 7 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8ee63933a8..2f0e6a9bef 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -735,6 +735,13 @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, + return ret; + } + ++static int vhost_vdpa_set_dev_vring_base(struct vhost_dev *dev, ++ struct vhost_vring_state *ring) ++{ ++ trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); ++} ++ + static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +@@ -749,6 +756,18 @@ static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev, + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } + ++static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev, ++ struct vhost_vring_addr *addr) ++{ ++ trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags, ++ addr->desc_user_addr, addr->used_user_addr, ++ addr->avail_user_addr, ++ addr->log_guest_addr); ++ ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); ++ ++} ++ + /** + * Set the shadow virtqueue descriptors to the device + * +@@ -858,11 +877,17 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) + { +- trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags, +- addr->desc_user_addr, addr->used_user_addr, +- addr->avail_user_addr, +- addr->log_guest_addr); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ /* ++ * Device vring addr was set at device start. SVQ base is handled by ++ * VirtQueue code. ++ */ ++ return 0; ++ } ++ ++ return vhost_vdpa_set_vring_dev_addr(dev, addr); + } + + static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, +@@ -875,8 +900,17 @@ static int vhost_vdpa_set_vring_num(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { +- trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ /* ++ * Device vring base was set at device start. SVQ base is handled by ++ * VirtQueue code. ++ */ ++ return 0; ++ } ++ ++ return vhost_vdpa_set_dev_vring_base(dev, ring); + } + + static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, +-- +2.27.0 + diff --git a/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch b/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch new file mode 100644 index 0000000..0e6774f --- /dev/null +++ b/vdpa-add-asid-parameter-to-vhost_vdpa_dma_map-unmap.patch @@ -0,0 +1,227 @@ +From 657f5e7b200bec7b124ca5e2cf4d8e1b721cbfde Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:41 +0100 +Subject: [PATCH] vdpa: add asid parameter to vhost_vdpa_dma_map/unmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So the caller can choose which ASID is destined. + +No need to update the batch functions as they will always be called from +memory listener updates at the moment. Memory listener updates will +always update ASID 0, as it's the passthrough ASID. + +All vhost devices's ASID are 0 at this moment. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-10-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 4 +-- + hw/virtio/vhost-vdpa.c | 36 ++++++++++++++------ + include/hw/virtio/vhost-vdpa.h | 14 ++++++-- + include/standard-headers/linux/vhost_types.h | 2 +- + net/vhost-vdpa.c | 6 ++-- + 5 files changed, 42 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 35d4c00e59..edbbbeb621 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -29,8 +29,8 @@ vhost_user_read(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32"" + + # vhost-vdpa.c +-vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 +-vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 ++vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8 ++vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8 + vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8 + vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 450b5effd2..f4a0878e34 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -74,22 +74,28 @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section, + return false; + } + +-int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly) ++/* ++ * The caller must set asid = 0 if the device does not support asid. ++ * This is not an ABI break since it is set to 0 by the initializer anyway. ++ */ ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size, void *vaddr, bool readonly) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; ++ msg.asid = asid; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.uaddr = (uint64_t)(uintptr_t)vaddr; + msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW; + msg.iotlb.type = VHOST_IOTLB_UPDATE; + +- trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.iotlb.iova, msg.iotlb.size, +- msg.iotlb.uaddr, msg.iotlb.perm, msg.iotlb.type); ++ trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.asid, msg.iotlb.iova, ++ msg.iotlb.size, msg.iotlb.uaddr, msg.iotlb.perm, ++ msg.iotlb.type); + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { + error_report("failed to write, fd=%d, errno=%d (%s)", +@@ -100,18 +106,24 @@ int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, + return ret; + } + +-int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size) ++/* ++ * The caller must set asid = 0 if the device does not support asid. ++ * This is not an ABI break since it is set to 0 by the initializer anyway. ++ */ ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size) + { + struct vhost_msg_v2 msg = {}; + int fd = v->device_fd; + int ret = 0; + + msg.type = v->msg_type; ++ msg.asid = asid; + msg.iotlb.iova = iova; + msg.iotlb.size = size; + msg.iotlb.type = VHOST_IOTLB_INVALIDATE; + +- trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.iotlb.iova, ++ trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.asid, msg.iotlb.iova, + msg.iotlb.size, msg.iotlb.type); + + if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { +@@ -231,8 +243,8 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + } + + vhost_vdpa_iotlb_batch_begin_once(v); +- ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize), +- vaddr, section->readonly); ++ ret = vhost_vdpa_dma_map(v, VHOST_VDPA_GUEST_PA_ASID, iova, ++ int128_get64(llsize), vaddr, section->readonly); + if (ret) { + error_report("vhost vdpa map fail!"); + goto fail_map; +@@ -305,7 +317,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + vhost_iova_tree_remove(v->iova_tree, *result); + } + vhost_vdpa_iotlb_batch_begin_once(v); +- ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize)); ++ ret = vhost_vdpa_dma_unmap(v, VHOST_VDPA_GUEST_PA_ASID, iova, ++ int128_get64(llsize)); + if (ret) { + error_report("vhost_vdpa dma unmap error!"); + } +@@ -872,7 +885,7 @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr) + } + + size = ROUND_UP(result->size, qemu_real_host_page_size); +- r = vhost_vdpa_dma_unmap(v, result->iova, size); ++ r = vhost_vdpa_dma_unmap(v, v->address_space_id, result->iova, size); + if (unlikely(r < 0)) { + error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r); + return; +@@ -912,7 +925,8 @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle, + return false; + } + +- r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1, ++ r = vhost_vdpa_dma_map(v, v->address_space_id, needle->iova, ++ needle->size + 1, + (void *)(uintptr_t)needle->translated_addr, + needle->perm == IOMMU_RO); + if (unlikely(r != 0)) { +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 1111d85643..e57dfa1fd1 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -19,6 +19,12 @@ + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + ++/* ++ * ASID dedicated to map guest's addresses. If SVQ is disabled it maps GPA to ++ * qemu's IOVA. If SVQ is enabled it maps also the SVQ vring here ++ */ ++#define VHOST_VDPA_GUEST_PA_ASID 0 ++ + typedef struct VhostVDPAHostNotifier { + MemoryRegion mr; + void *addr; +@@ -29,6 +35,7 @@ typedef struct vhost_vdpa { + int index; + uint32_t msg_type; + bool iotlb_batch_begin_sent; ++ uint32_t address_space_id; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; + uint64_t acked_features; +@@ -42,8 +49,9 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + +-int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size, +- void *vaddr, bool readonly); +-int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova, hwaddr size); ++int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size, void *vaddr, bool readonly); ++int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, ++ hwaddr size); + + #endif +diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h +index 0bd2684a2a..fa267e39d4 100644 +--- a/include/standard-headers/linux/vhost_types.h ++++ b/include/standard-headers/linux/vhost_types.h +@@ -87,7 +87,7 @@ struct vhost_msg { + + struct vhost_msg_v2 { + uint32_t type; +- uint32_t reserved; ++ uint32_t asid; + union { + struct vhost_iotlb_msg iotlb; + uint8_t padding[64]; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index e250d34462..cb1cc2523d 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -266,7 +266,7 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + return; + } + +- r = vhost_vdpa_dma_unmap(v, map->iova, map->size + 1); ++ r = vhost_vdpa_dma_unmap(v, v->address_space_id, map->iova, map->size + 1); + if (unlikely(r != 0)) { + error_report("Device cannot unmap: %s(%d)", g_strerror(r), r); + } +@@ -306,8 +306,8 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, + return r; + } + +- r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf, +- !write); ++ r = vhost_vdpa_dma_map(v, v->address_space_id, map.iova, ++ vhost_vdpa_net_cvq_cmd_page_len(), buf, !write); + if (unlikely(r < 0)) { + goto dma_map_err; + } +-- +2.27.0 + diff --git a/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch b/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch new file mode 100644 index 0000000..f06ea91 --- /dev/null +++ b/vdpa-add-net_vhost_vdpa_cvq_info-NetClientInfo.patch @@ -0,0 +1,53 @@ +From a5717856457e72575a32dfc8e28ec6ba6dcf6d59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:32 +0200 +Subject: [PATCH] vdpa: add net_vhost_vdpa_cvq_info NetClientInfo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Next patches will add a new info callback to restore NIC status through +CVQ. Since only the CVQ vhost device is needed, create it with a new +NetClientInfo. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 8cfd086639..04cb08d418 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -342,6 +342,16 @@ static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s, + return true; + } + ++static NetClientInfo net_vhost_vdpa_cvq_info = { ++ .type = NET_CLIENT_DRIVER_VHOST_VDPA, ++ .size = sizeof(VhostVDPAState), ++ .receive = vhost_vdpa_receive, ++ .cleanup = vhost_vdpa_cleanup, ++ .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, ++ .has_ufo = vhost_vdpa_has_ufo, ++ .check_peer_type = vhost_vdpa_check_peer_type, ++}; ++ + /** + * Do not forward commands not supported by SVQ. Otherwise, the device could + * accept it and qemu would not know how to update the device model. +@@ -483,7 +493,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, + name); + } else { +- nc = qemu_new_net_control_client(&net_vhost_vdpa_info, peer, ++ nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer, + device, name); + } + snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); +-- +2.27.0 + diff --git a/vdpa-add-shadow_data-to-vhost_vdpa.patch b/vdpa-add-shadow_data-to-vhost_vdpa.patch new file mode 100644 index 0000000..6c45706 --- /dev/null +++ b/vdpa-add-shadow_data-to-vhost_vdpa.patch @@ -0,0 +1,86 @@ +From e64b1a8253b9161e16b0a7f6c3beb77fb854660d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:43 +0100 +Subject: [PATCH] vdpa: add shadow_data to vhost_vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The memory listener that thells the device how to convert GPA to qemu's +va is registered against CVQ vhost_vdpa. memory listener translations +are always ASID 0, CVQ ones are ASID 1 if supported. + +Let's tell the listener if it needs to register them on iova tree or +not. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-12-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 6 +++--- + include/hw/virtio/vhost-vdpa.h | 2 ++ + net/vhost-vdpa.c | 1 + + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f4a0878e34..6d0d85b733 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -226,7 +226,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + + llsize = int128_sub(llend, int128_make64(iova)); +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + int r; + + mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr, +@@ -253,7 +253,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + return; + + fail_map: +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + vhost_iova_tree_remove(v->iova_tree, mem_region); + } + +@@ -298,7 +298,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + +- if (v->shadow_vqs_enabled) { ++ if (v->shadow_data) { + const DMAMap *result; + const void *vaddr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region + +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index e57dfa1fd1..45b969a311 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -40,6 +40,8 @@ typedef struct vhost_vdpa { + struct vhost_vdpa_iova_range iova_range; + uint64_t acked_features; + bool shadow_vqs_enabled; ++ /* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */ ++ bool shadow_data; + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 7adba2c2b6..21fb89bb6b 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -580,6 +580,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->always_svq = svq; + s->vhost_vdpa.shadow_vqs_enabled = svq; + s->vhost_vdpa.iova_range = iova_range; ++ s->vhost_vdpa.shadow_data = svq; + s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, +-- +2.27.0 + diff --git a/vdpa-add-vhost_vdpa_net_valid_svq_features.patch b/vdpa-add-vhost_vdpa_net_valid_svq_features.patch new file mode 100644 index 0000000..622c890 --- /dev/null +++ b/vdpa-add-vhost_vdpa_net_valid_svq_features.patch @@ -0,0 +1,68 @@ +From 9cd4a76f615cea230ffc33d5b3666f84216f694b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:37 +0100 +Subject: [PATCH] vdpa: add vhost_vdpa_net_valid_svq_features +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It will be reused at vdpa device start so let's extract in its own +function. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-6-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index eae2ed364f..217d2545c1 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -105,6 +105,22 @@ VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + return s->vhost_net; + } + ++static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) ++{ ++ uint64_t invalid_dev_features = ++ features & ~vdpa_svq_device_features & ++ /* Transport are all accepted at this point */ ++ ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, ++ VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); ++ ++ if (invalid_dev_features) { ++ error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, ++ invalid_dev_features); ++ } ++ ++ return !invalid_dev_features; ++} ++ + static int vhost_vdpa_net_check_device_id(struct vhost_net *net) + { + uint32_t device_id; +@@ -683,15 +699,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (opts->x_svq) { + struct vhost_vdpa_iova_range iova_range; + +- uint64_t invalid_dev_features = +- features & ~vdpa_svq_device_features & +- /* Transport are all accepted at this point */ +- ~MAKE_64BIT_MASK(VIRTIO_TRANSPORT_F_START, +- VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START); +- +- if (invalid_dev_features) { +- error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, +- invalid_dev_features); ++ if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; + } + +-- +2.27.0 + diff --git a/vdpa-allocate-SVQ-array-unconditionally.patch b/vdpa-allocate-SVQ-array-unconditionally.patch new file mode 100644 index 0000000..9e8cc60 --- /dev/null +++ b/vdpa-allocate-SVQ-array-unconditionally.patch @@ -0,0 +1,42 @@ +From fea179d880cd502f291cc6079b565bc059612d48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:40 +0100 +Subject: [PATCH] vdpa: allocate SVQ array unconditionally +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SVQ may run or not in a device depending on runtime conditions (for +example, if the device can move CVQ to its own group or not). + +Allocate the SVQ array unconditionally at startup, since its hard to +move this allocation elsewhere. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-9-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 59bfdbfc24..450b5effd2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -535,10 +535,6 @@ static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) + struct vhost_vdpa *v = dev->opaque; + size_t idx; + +- if (!v->shadow_vqs) { +- return; +- } +- + for (idx = 0; idx < v->shadow_vqs->len; ++idx) { + vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx)); + } +-- +2.27.0 + diff --git a/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch b/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch new file mode 100644 index 0000000..32a59b8 --- /dev/null +++ b/vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch @@ -0,0 +1,224 @@ +From e2e9aeaacdb28b6c2a1bfcfef09113dc9b26a420 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:44 +0100 +Subject: [PATCH] vdpa: always start CVQ in SVQ mode if possible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Isolate control virtqueue in its own group, allowing to intercept control +commands but letting dataplane run totally passthrough to the guest. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221215113144.322011-13-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 +- + include/standard-headers/linux/vhost_types.h | 5 + + linux-headers/linux/vhost.h | 14 +++ + net/vhost-vdpa.c | 110 ++++++++++++++++++- + 4 files changed, 130 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 6d0d85b733..8b44f5a7b8 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -641,7 +641,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + { + uint64_t features; + uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | +- 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH; ++ 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | ++ 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID; + int r; + + if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { +diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h +index fa267e39d4..17833e320e 100644 +--- a/include/standard-headers/linux/vhost_types.h ++++ b/include/standard-headers/linux/vhost_types.h +@@ -153,4 +153,9 @@ struct vhost_vdpa_iova_range { + /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ + #define VHOST_NET_F_VIRTIO_NET_HDR 27 + ++/* IOTLB can accept address space identifier through V2 type of IOTLB ++ * message ++ */ ++#define VHOST_BACKEND_F_IOTLB_ASID 0x3 ++ + #endif +diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h +index 5d99e7c242..b6ded7f831 100644 +--- a/linux-headers/linux/vhost.h ++++ b/linux-headers/linux/vhost.h +@@ -157,4 +157,18 @@ + /* Get the count of all virtqueues */ + #define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + ++/* Get the group for a virtqueue: read index, write group in num, ++ * The virtqueue index is stored in the index field of ++ * vhost_vring_state. The group for this specific virtqueue is ++ * returned via num field of vhost_vring_state. ++ */ ++#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ ++ struct vhost_vring_state) ++/* Set the ASID for a virtqueue group. The group index is stored in ++ * the index field of vhost_vring_state, the ASID associated with this ++ * group is stored at num field of vhost_vring_state. ++ */ ++#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ ++ struct vhost_vring_state) ++ + #endif +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 21fb89bb6b..24c4c2ef51 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -100,6 +100,8 @@ static const uint64_t vdpa_svq_device_features = + BIT_ULL(VIRTIO_NET_F_RSC_EXT) | + BIT_ULL(VIRTIO_NET_F_STANDBY); + ++#define VHOST_VDPA_NET_CVQ_ASID 1 ++ + VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +@@ -250,6 +252,40 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) ++{ ++ struct vhost_vring_state state = { ++ .index = vq_index, ++ }; ++ int r = ioctl(device_fd, VHOST_VDPA_GET_VRING_GROUP, &state); ++ ++ if (unlikely(r < 0)) { ++ error_report("Cannot get VQ %u group: %s", vq_index, ++ g_strerror(errno)); ++ return r; ++ } ++ ++ return state.num; ++} ++ ++static int vhost_vdpa_set_address_space_id(struct vhost_vdpa *v, ++ unsigned vq_group, ++ unsigned asid_num) ++{ ++ struct vhost_vring_state asid = { ++ .index = vq_group, ++ .num = asid_num, ++ }; ++ int r; ++ ++ r = ioctl(v->device_fd, VHOST_VDPA_SET_GROUP_ASID, &asid); ++ if (unlikely(r < 0)) { ++ error_report("Can't set vq group %u asid %u, errno=%d (%s)", ++ asid.index, asid.num, errno, g_strerror(errno)); ++ } ++ return r; ++} ++ + static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) + { + VhostIOVATree *tree = v->iova_tree; +@@ -324,11 +360,75 @@ dma_map_err: + static int vhost_vdpa_net_cvq_start(NetClientState *nc) + { + VhostVDPAState *s; +- int r; ++ struct vhost_vdpa *v; ++ uint64_t backend_features; ++ int64_t cvq_group; ++ int cvq_index, r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + + s = DO_UPCAST(VhostVDPAState, nc, nc); ++ v = &s->vhost_vdpa; ++ ++ v->shadow_data = s->always_svq; ++ v->shadow_vqs_enabled = s->always_svq; ++ s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID; ++ ++ if (s->always_svq) { ++ /* SVQ is already configured for all virtqueues */ ++ goto out; ++ } ++ ++ /* ++ * If we early return in these cases SVQ will not be enabled. The migration ++ * will be blocked as long as vhost-vdpa backends will not offer _F_LOG. ++ * ++ * Calling VHOST_GET_BACKEND_FEATURES as they are not available in v->dev ++ * yet. ++ */ ++ r = ioctl(v->device_fd, VHOST_GET_BACKEND_FEATURES, &backend_features); ++ if (unlikely(r < 0)) { ++ error_report("Cannot get vdpa backend_features: %s(%d)", ++ g_strerror(errno), errno); ++ return -1; ++ } ++ if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || ++ !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { ++ return 0; ++ } ++ ++ /* ++ * Check if all the virtqueues of the virtio device are in a different vq ++ * than the last vq. VQ group of last group passed in cvq_group. ++ */ ++ cvq_index = v->dev->vq_index_end - 1; ++ cvq_group = vhost_vdpa_get_vring_group(v->device_fd, cvq_index); ++ if (unlikely(cvq_group < 0)) { ++ return cvq_group; ++ } ++ for (int i = 0; i < cvq_index; ++i) { ++ int64_t group = vhost_vdpa_get_vring_group(v->device_fd, i); ++ ++ if (unlikely(group < 0)) { ++ return group; ++ } ++ ++ if (group == cvq_group) { ++ return 0; ++ } ++ } ++ ++ r = vhost_vdpa_set_address_space_id(v, cvq_group, VHOST_VDPA_NET_CVQ_ASID); ++ if (unlikely(r < 0)) { ++ return r; ++ } ++ ++ v->iova_tree = vhost_iova_tree_new(v->iova_range.first, ++ v->iova_range.last); ++ v->shadow_vqs_enabled = true; ++ s->vhost_vdpa.address_space_id = VHOST_VDPA_NET_CVQ_ASID; ++ ++out: + if (!s->vhost_vdpa.shadow_vqs_enabled) { + return 0; + } +@@ -357,6 +457,14 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + if (s->vhost_vdpa.shadow_vqs_enabled) { + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer); + vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status); ++ if (!s->always_svq) { ++ /* ++ * If only the CVQ is shadowed we can delete this safely. ++ * If all the VQs are shadows this will be needed by the time the ++ * device is started again to register SVQ vrings and similar. ++ */ ++ g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete); ++ } + } + } + +-- +2.27.0 + diff --git a/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch b/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch new file mode 100644 index 0000000..6c805b2 --- /dev/null +++ b/vdpa-commit-all-host-notifier-MRs-in-a-single-MR-tra.patch @@ -0,0 +1,79 @@ +From aa9c65215f37fc54a280ce89a2cbfd6235e8ec9f Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Tue, 27 Dec 2022 15:20:15 +0800 +Subject: [PATCH] vdpa: commit all host notifier MRs in a single MR transaction +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows the vhost-vdpa device to batch the setup of all its MRs of +host notifiers. + +This significantly reduces the device starting time, e.g. the time spend +on setup the host notifier MRs reduce from 423ms to 32ms for a VM with +64 vCPUs and 3 vhost-vDPA generic devices (vdpa_sim_blk, 64vq per device). + +Signed-off-by: Longpeng +Message-Id: <20221227072015.3134-4-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f93fac538c..2fd7af1c6b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -522,9 +522,18 @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) + { + int i; + ++ /* ++ * Pack all the changes to the memory regions in a single ++ * transaction to avoid a few updating of the address space ++ * topology. ++ */ ++ memory_region_transaction_begin(); ++ + for (i = dev->vq_index; i < dev->vq_index + n; i++) { + vhost_vdpa_host_notifier_uninit(dev, i); + } ++ ++ memory_region_transaction_commit(); + } + + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) +@@ -537,17 +546,21 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + return; + } + ++ /* ++ * Pack all the changes to the memory regions in a single ++ * transaction to avoid a few updating of the address space ++ * topology. ++ */ ++ memory_region_transaction_begin(); ++ + for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) { + if (vhost_vdpa_host_notifier_init(dev, i)) { +- goto err; ++ vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); ++ break; + } + } + +- return; +- +-err: +- vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); +- return; ++ memory_region_transaction_commit(); + } + + static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) +-- +2.27.0 + diff --git a/vdpa-dev-get-iova-range-explicitly.patch b/vdpa-dev-get-iova-range-explicitly.patch new file mode 100644 index 0000000..f9f8e1a --- /dev/null +++ b/vdpa-dev-get-iova-range-explicitly.patch @@ -0,0 +1,104 @@ +From f5d338d28758db5066f199c35d56e0953edcc5d9 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 24 Dec 2022 19:48:47 +0800 +Subject: [PATCH] vdpa-dev: get iova range explicitly + +In commit a585fad26b ("vdpa: request iova_range only once") we remove +GET_IOVA_RANGE form vhost_vdpa_init, the generic vdpa device will start +without iova_range populated, so the device won't work. Let's call +GET_IOVA_RANGE ioctl explicitly. + +Fixes: a585fad26b2e6ccc ("vdpa: request iova_range only once") +Signed-off-by: Longpeng +Message-Id: <20221224114848.3062-2-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vdpa-dev.c | 9 +++++++++ + hw/virtio/vhost-vdpa.c | 7 +++++++ + include/hw/virtio/vhost-vdpa.h | 2 ++ + net/vhost-vdpa.c | 8 -------- + 4 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 465b08c0e3..254a213117 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -53,6 +53,7 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VhostVdpaDevice *v = VHOST_VDPA_DEVICE(vdev); ++ struct vhost_vdpa_iova_range iova_range; + uint16_t max_queue_size; + struct vhost_virtqueue *vqs; + int i, ret; +@@ -108,6 +109,14 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp) + v->dev.backend_features = 0; + v->started = false; + ++ ret = vhost_vdpa_get_iova_range(v->vhostfd, &iova_range); ++ if (ret < 0) { ++ error_setg(errp, "vhost-vdpa-device: get iova range failed: %s", ++ strerror(-ret)); ++ goto free_vqs; ++ } ++ v->vdpa.iova_range = iova_range; ++ + ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL); + if (ret < 0) { + error_setg(errp, "vhost-vdpa-device: vhost initialization failed: %s", +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c9289e2c01..f93fac538c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -380,6 +380,13 @@ static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + return 0; + } + ++int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range) ++{ ++ int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); ++ ++ return ret < 0 ? -errno : 0; ++} ++ + /* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 45b969a311..7997f09a8d 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -51,6 +51,8 @@ typedef struct vhost_vdpa { + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + ++int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range); ++ + int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, + hwaddr size, void *vaddr, bool readonly); + int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova, +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 3dcf341722..3c370f2dc5 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -717,14 +717,6 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + return nc; + } + +-static int vhost_vdpa_get_iova_range(int fd, +- struct vhost_vdpa_iova_range *iova_range) +-{ +- int ret = ioctl(fd, VHOST_VDPA_GET_IOVA_RANGE, iova_range); +- +- return ret < 0 ? -errno : 0; +-} +- + static int vhost_vdpa_get_features(int fd, uint64_t *features, Error **errp) + { + int ret = ioctl(fd, VHOST_GET_FEATURES, features); +-- +2.27.0 + diff --git a/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch b/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch new file mode 100644 index 0000000..4956a0f --- /dev/null +++ b/vdpa-do-not-block-migration-if-device-has-cvq-and-x-.patch @@ -0,0 +1,52 @@ +From 5bd89df7b5c1448f22f37a918569d0367458591b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 2 Jun 2023 16:38:52 +0200 +Subject: [PATCH] vdpa: do not block migration if device has cvq and x-svq=on +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was a mistake to forbid in all cases, as SVQ is already able to send +all the CVQ messages before start forwarding data vqs. It actually +caused a regression, making impossible to migrate device previously +migratable. + +Fixes: 36e4647247f2 ("vdpa: add vhost_vdpa_net_valid_svq_features") +Signed-off-by: Eugenio Pérez +Message-Id: <20230602143854.1879091-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index dc1b4c4be2..cdc54a7b54 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -723,13 +723,16 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.shadow_vq_ops_opaque = s; + + /* +- * TODO: We cannot migrate devices with CVQ as there is no way to set +- * the device state (MAC, MQ, etc) before starting the datapath. ++ * TODO: We cannot migrate devices with CVQ and no x-svq enabled as ++ * there is no way to set the device state (MAC, MQ, etc) before ++ * starting the datapath. + * + * Migration blocker ownership now belongs to s->vhost_vdpa. + */ +- error_setg(&s->vhost_vdpa.migration_blocker, +- "net vdpa cannot migrate with CVQ feature"); ++ if (!svq) { ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "net vdpa cannot migrate with CVQ feature"); ++ } + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch b/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch new file mode 100644 index 0000000..1fcc058 --- /dev/null +++ b/vdpa-do-not-handle-VIRTIO_NET_F_GUEST_ANNOUNCE-in-vh.patch @@ -0,0 +1,35 @@ +From 17cd7f504c47c532eae6b8ecfc21b0e5796e08da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 21 Dec 2022 12:50:15 +0100 +Subject: [PATCH] vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So qemu emulates it even in case the device does not support it. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221221115015.1400889-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 48dd9d15f6..3dcf341722 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -72,7 +72,6 @@ const int vdpa_feature_bits[] = { + VIRTIO_F_RING_PACKED, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_HASH_REPORT, +- VIRTIO_NET_F_GUEST_ANNOUNCE, + VIRTIO_NET_F_STATUS, + VHOST_INVALID_FEATURE_BIT + }; +-- +2.27.0 + diff --git a/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch b/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch new file mode 100644 index 0000000..e1b0244 --- /dev/null +++ b/vdpa-do-not-save-failed-dma-maps-in-SVQ-iova-tree.patch @@ -0,0 +1,74 @@ +From 556aa09e618b0fb40f038b11eafc69750c71f26e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:03 +0200 +Subject: [PATCH] vdpa: do not save failed dma maps in SVQ iova tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a map fails for whatever reason, it must not be saved in the tree. +Otherwise, qemu will try to unmap it in cleanup, leaving to more errors. + +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c551665f5d..02dab41c42 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -178,6 +178,7 @@ static void vhost_vdpa_listener_commit(MemoryListener *listener) + static void vhost_vdpa_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) + { ++ DMAMap mem_region = {}; + struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener); + hwaddr iova; + Int128 llend, llsize; +@@ -214,13 +215,13 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + + llsize = int128_sub(llend, int128_make64(iova)); + if (v->shadow_vqs_enabled) { +- DMAMap mem_region = { +- .translated_addr = (hwaddr)(uintptr_t)vaddr, +- .size = int128_get64(llsize) - 1, +- .perm = IOMMU_ACCESS_FLAG(true, section->readonly), +- }; ++ int r; + +- int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); ++ mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr, ++ mem_region.size = int128_get64(llsize) - 1, ++ mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly), ++ ++ r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region); + if (unlikely(r != IOVA_OK)) { + error_report("Can't allocate a mapping (%d)", r); + goto fail; +@@ -234,11 +235,16 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener, + vaddr, section->readonly); + if (ret) { + error_report("vhost vdpa map fail!"); +- goto fail; ++ goto fail_map; + } + + return; + ++fail_map: ++ if (v->shadow_vqs_enabled) { ++ vhost_iova_tree_remove(v->iova_tree, &mem_region); ++ } ++ + fail: + /* + * On the initfn path, store the first error in the container so we +-- +2.27.0 + diff --git a/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch b/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch new file mode 100644 index 0000000..5b2d4b5 --- /dev/null +++ b/vdpa-extract-vhost_vdpa_net_cvq_add-from-vhost_vdpa_.patch @@ -0,0 +1,144 @@ +From af761da9860bd79bd9d214c15d2d30010e73aafa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:34 +0200 +Subject: [PATCH] vdpa: extract vhost_vdpa_net_cvq_add from + vhost_vdpa_net_handle_ctrl_avail +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So we can reuse it to inject state messages. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +-- +v7: +* Remove double free error + +v6: +* Do not assume in buffer sent to the device is sizeof(virtio_net_ctrl_ack) + +v5: +* Do not use an artificial !NULL VirtQueueElement +* Use only out size instead of iovec dev_buffers for these functions. + +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 59 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 38 insertions(+), 21 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 882f5ee89c..b24e0919d0 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -339,6 +339,38 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc) + } + } + ++static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, ++ size_t in_len) ++{ ++ /* Buffers for the device */ ++ const struct iovec out = { ++ .iov_base = s->cvq_cmd_out_buffer, ++ .iov_len = out_len, ++ }; ++ const struct iovec in = { ++ .iov_base = s->cvq_cmd_in_buffer, ++ .iov_len = sizeof(virtio_net_ctrl_ack), ++ }; ++ VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0); ++ int r; ++ ++ r = vhost_svq_add(svq, &out, 1, &in, 1, NULL); ++ if (unlikely(r != 0)) { ++ if (unlikely(r == -ENOSPC)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", ++ __func__); ++ } ++ return r; ++ } ++ ++ /* ++ * We can poll here since we've had BQL from the time we sent the ++ * descriptor. Also, we need to take the answer before SVQ pulls by itself, ++ * when BQL is released ++ */ ++ return vhost_svq_poll(svq); ++} ++ + static NetClientInfo net_vhost_vdpa_cvq_info = { + .type = NET_CLIENT_DRIVER_VHOST_VDPA, + .size = sizeof(VhostVDPAState), +@@ -395,23 +427,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + void *opaque) + { + VhostVDPAState *s = opaque; +- size_t in_len, dev_written; ++ size_t in_len; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; + /* Out buffer sent to both the vdpa device and the device model */ + struct iovec out = { + .iov_base = s->cvq_cmd_out_buffer, + }; +- /* In buffer sent to the device */ +- const struct iovec dev_in = { +- .iov_base = s->cvq_cmd_in_buffer, +- .iov_len = sizeof(virtio_net_ctrl_ack), +- }; + /* in buffer used for device model */ + const struct iovec in = { + .iov_base = &status, + .iov_len = sizeof(status), + }; +- int r = -EINVAL; ++ ssize_t dev_written = -EINVAL; + bool ok; + + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, +@@ -422,21 +449,11 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + goto out; + } + +- r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem); +- if (unlikely(r != 0)) { +- if (unlikely(r == -ENOSPC)) { +- qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", +- __func__); +- } ++ dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); ++ if (unlikely(dev_written < 0)) { + goto out; + } + +- /* +- * We can poll here since we've had BQL from the time we sent the +- * descriptor. Also, we need to take the answer before SVQ pulls by itself, +- * when BQL is released +- */ +- dev_written = vhost_svq_poll(svq); + if (unlikely(dev_written < sizeof(status))) { + error_report("Insufficient written data (%zu)", dev_written); + goto out; +@@ -444,7 +461,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + + memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status)); + if (status != VIRTIO_NET_OK) { +- goto out; ++ return VIRTIO_NET_ERR; + } + + status = VIRTIO_NET_ERR; +@@ -461,7 +478,7 @@ out: + } + vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); + g_free(elem); +- return r; ++ return dev_written < 0 ? dev_written : 0; + } + + static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { +-- +2.27.0 + diff --git a/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch b/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch new file mode 100644 index 0000000..8695f98 --- /dev/null +++ b/vdpa-extract-vhost_vdpa_net_load_mac-from-vhost_vdpa.patch @@ -0,0 +1,106 @@ +From 2038b0811acd3255d315354c8468bc565a51a4af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:15 +0200 +Subject: [PATCH] vdpa: extract vhost_vdpa_net_load_mac from + vhost_vdpa_net_load +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since there may be many commands we need to issue to load the NIC +state, let's split them in individual functions + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 62 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 40 insertions(+), 22 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 2700ef656f..15cd38b52e 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -373,12 +373,47 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len, + return vhost_svq_poll(svq); + } + ++static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, ++ uint8_t cmd, const void *data, ++ size_t data_size) ++{ ++ const struct virtio_net_ctrl_hdr ctrl = { ++ .class = class, ++ .cmd = cmd, ++ }; ++ ++ assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl)); ++ ++ memcpy(s->cvq_cmd_out_buffer, &ctrl, sizeof(ctrl)); ++ memcpy(s->cvq_cmd_out_buffer + sizeof(ctrl), data, data_size); ++ ++ return vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + data_size, ++ sizeof(virtio_net_ctrl_ack)); ++} ++ ++static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) ++{ ++ uint64_t features = n->parent_obj.guest_features; ++ if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { ++ ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MAC, ++ VIRTIO_NET_CTRL_MAC_ADDR_SET, ++ n->mac, sizeof(n->mac)); ++ if (unlikely(dev_written < 0)) { ++ return dev_written; ++ } ++ ++ return *s->status != VIRTIO_NET_OK; ++ } ++ ++ return 0; ++} ++ + static int vhost_vdpa_net_load(NetClientState *nc) + { + VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); +- const struct vhost_vdpa *v = &s->vhost_vdpa; ++ struct vhost_vdpa *v = &s->vhost_vdpa; + const VirtIONet *n; +- uint64_t features; ++ int r; + + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); + +@@ -387,26 +422,9 @@ static int vhost_vdpa_net_load(NetClientState *nc) + } + + n = VIRTIO_NET(v->dev->vdev); +- features = n->parent_obj.guest_features; +- if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { +- const struct virtio_net_ctrl_hdr ctrl = { +- .class = VIRTIO_NET_CTRL_MAC, +- .cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET, +- }; +- char *cursor = s->cvq_cmd_out_buffer; +- ssize_t dev_written; +- +- memcpy(cursor, &ctrl, sizeof(ctrl)); +- cursor += sizeof(ctrl); +- memcpy(cursor, n->mac, sizeof(n->mac)); +- +- dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac), +- sizeof(virtio_net_ctrl_ack)); +- if (unlikely(dev_written < 0)) { +- return dev_written; +- } +- +- return *s->status != VIRTIO_NET_OK; ++ r = vhost_vdpa_net_load_mac(s, n); ++ if (unlikely(r < 0)) { ++ return r; + } + + return 0; +-- +2.27.0 + diff --git a/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch b/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch new file mode 100644 index 0000000..c2f2a87 --- /dev/null +++ b/vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch @@ -0,0 +1,38 @@ +From 404c9b2cb537a42be18a1b1aaf32df662ed951e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 17 Jan 2023 11:53:08 +0100 +Subject: [PATCH] vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VHOST_BACKEND_F_IOTLB_ASID is the feature bit, not the bitmask. Since +the device under test also provided VHOST_BACKEND_F_IOTLB_MSG_V2 and +VHOST_BACKEND_F_IOTLB_BATCH, this went unnoticed. + +Fixes: c1a1008685 ("vdpa: always start CVQ in SVQ mode if possible") +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index cdc54a7b54..a1b931ae2c 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -391,7 +391,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) + g_strerror(errno), errno); + return -1; + } +- if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) || ++ if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) || + !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { + return 0; + } +-- +2.27.0 + diff --git a/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch b/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch new file mode 100644 index 0000000..4603f6e --- /dev/null +++ b/vdpa-fix-not-using-CVQ-buffer-in-case-of-error.patch @@ -0,0 +1,39 @@ +From 5da8eddfa24d42a3ef60e111becafa29549e7100 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 2 Jun 2023 19:34:51 +0200 +Subject: [PATCH] vdpa: fix not using CVQ buffer in case of error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bug introducing when refactoring. Otherway, the guest never received +the used buffer. + +Fixes: be4278b65fc1 ("vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail") +Signed-off-by: Eugenio Pérez +Message-Id: <20230602173451.1917999-1-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 94f74b54ae..afca8740bc 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -642,7 +642,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + } + + if (*s->status != VIRTIO_NET_OK) { +- return VIRTIO_NET_ERR; ++ goto out; + } + + status = VIRTIO_NET_ERR; +-- +2.27.0 + diff --git a/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch b/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch new file mode 100644 index 0000000..7501a15 --- /dev/null +++ b/vdpa-handle-VIRTIO_NET_CTRL_ANNOUNCE-in-vhost_vdpa_n.patch @@ -0,0 +1,51 @@ +From f6fa1b81efa3ac728a2c528b3c694d8cb5f932f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 21 Dec 2022 12:50:14 +0100 +Subject: [PATCH] vdpa: handle VIRTIO_NET_CTRL_ANNOUNCE in + vhost_vdpa_net_handle_ctrl_avail +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since this capability is emulated by qemu shadowed CVQ cannot forward it +to the device. Process all that command within qemu. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221221115015.1400889-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 24c4c2ef51..48dd9d15f6 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -623,9 +623,18 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, + out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0, + s->cvq_cmd_out_buffer, + vhost_vdpa_net_cvq_cmd_len()); +- dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); +- if (unlikely(dev_written < 0)) { +- goto out; ++ if (*(uint8_t *)s->cvq_cmd_out_buffer == VIRTIO_NET_CTRL_ANNOUNCE) { ++ /* ++ * Guest announce capability is emulated by qemu, so don't forward to ++ * the device. ++ */ ++ dev_written = sizeof(status); ++ *s->status = VIRTIO_NET_OK; ++ } else { ++ dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status)); ++ if (unlikely(dev_written < 0)) { ++ goto out; ++ } + } + + if (unlikely(dev_written < sizeof(status))) { +-- +2.27.0 + diff --git a/vdpa-harden-the-error-path-if-get_iova_range-failed.patch b/vdpa-harden-the-error-path-if-get_iova_range-failed.patch new file mode 100644 index 0000000..af79c27 --- /dev/null +++ b/vdpa-harden-the-error-path-if-get_iova_range-failed.patch @@ -0,0 +1,39 @@ +From fe4dd977b4dec6a089992566bda4b29136ed62c9 Mon Sep 17 00:00:00 2001 +From: Longpeng +Date: Sat, 24 Dec 2022 19:48:48 +0800 +Subject: [PATCH] vdpa: harden the error path if get_iova_range failed + +We should stop if the GET_IOVA_RANGE ioctl failed. + +Signed-off-by: Longpeng +Message-Id: <20221224114848.3062-3-longpeng2@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 3c370f2dc5..fd5dc8c6aa 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -812,7 +812,13 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + +- vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ r = vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); ++ if (unlikely(r < 0)) { ++ error_setg(errp, "vhost-vdpa: get iova range failed: %s", ++ strerror(-r)); ++ goto err; ++ } ++ + if (opts->x_svq) { + if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; +-- +2.27.0 + diff --git a/vdpa-manual-forward-CVQ-buffers.patch b/vdpa-manual-forward-CVQ-buffers.patch new file mode 100644 index 0000000..79e47ce --- /dev/null +++ b/vdpa-manual-forward-CVQ-buffers.patch @@ -0,0 +1,146 @@ +From 1fd9319e66153dc18bc4a6adfd81f1a0bc6d3a2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:42 +0200 +Subject: [PATCH] vdpa: manual forward CVQ buffers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do a simple forwarding of CVQ buffers, the same work SVQ could do but +through callbacks. No functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 3 +- + include/hw/virtio/vhost-vdpa.h | 3 ++ + net/vhost-vdpa.c | 57 ++++++++++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8e962f511d..31b58aec59 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -421,7 +421,8 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + for (unsigned n = 0; n < hdev->nvqs; ++n) { + g_autoptr(VhostShadowVirtqueue) svq; + +- svq = vhost_svq_new(v->iova_tree, NULL, NULL); ++ svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, ++ v->shadow_vq_ops_opaque); + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); + return -1; +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 7214eb47dc..1111d85643 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -15,6 +15,7 @@ + #include + + #include "hw/virtio/vhost-iova-tree.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -35,6 +36,8 @@ typedef struct vhost_vdpa { + /* IOVA mapping used by the Shadow Virtqueue */ + VhostIOVATree *iova_tree; + GPtrArray *shadow_vqs; ++ const VhostShadowVirtqueueOps *shadow_vq_ops; ++ void *shadow_vq_ops_opaque; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 7201c79116..53a14bc756 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -11,11 +11,13 @@ + + #include "qemu/osdep.h" + #include "clients.h" ++#include "hw/virtio/virtio-net.h" + #include "net/vhost_net.h" + #include "net/vhost-vdpa.h" + #include "hw/virtio/vhost-vdpa.h" + #include "qemu/config-file.h" + #include "qemu/error-report.h" ++#include "qemu/log.h" + #include "qemu/option.h" + #include "qapi/error.h" + #include +@@ -195,6 +197,57 @@ static NetClientInfo net_vhost_vdpa_info = { + .check_peer_type = vhost_vdpa_check_peer_type, + }; + ++/** ++ * Forward buffer for the moment. ++ */ ++static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, ++ void *opaque) ++{ ++ unsigned int n = elem->out_num + elem->in_num; ++ g_autofree struct iovec *dev_buffers = g_new(struct iovec, n); ++ size_t in_len, dev_written; ++ virtio_net_ctrl_ack status = VIRTIO_NET_ERR; ++ int r; ++ ++ memcpy(dev_buffers, elem->out_sg, elem->out_num); ++ memcpy(dev_buffers + elem->out_num, elem->in_sg, elem->in_num); ++ ++ r = vhost_svq_add(svq, &dev_buffers[0], elem->out_num, &dev_buffers[1], ++ elem->in_num, elem); ++ if (unlikely(r != 0)) { ++ if (unlikely(r == -ENOSPC)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n", ++ __func__); ++ } ++ goto out; ++ } ++ ++ /* ++ * We can poll here since we've had BQL from the time we sent the ++ * descriptor. Also, we need to take the answer before SVQ pulls by itself, ++ * when BQL is released ++ */ ++ dev_written = vhost_svq_poll(svq); ++ if (unlikely(dev_written < sizeof(status))) { ++ error_report("Insufficient written data (%zu)", dev_written); ++ } ++ ++out: ++ in_len = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, ++ sizeof(status)); ++ if (unlikely(in_len < sizeof(status))) { ++ error_report("Bad device CVQ written length"); ++ } ++ vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status))); ++ g_free(elem); ++ return r; ++} ++ ++static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { ++ .avail_handler = vhost_vdpa_net_handle_ctrl_avail, ++}; ++ + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + const char *device, + const char *name, +@@ -219,6 +272,10 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ if (!is_datapath) { ++ s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; ++ s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { + qemu_del_net_client(nc); +-- +2.27.0 + diff --git a/vdpa-move-SVQ-vring-features-check-to-net.patch b/vdpa-move-SVQ-vring-features-check-to-net.patch new file mode 100644 index 0000000..f5eca1a --- /dev/null +++ b/vdpa-move-SVQ-vring-features-check-to-net.patch @@ -0,0 +1,110 @@ +From 1d56b9b5446b79613ed1668a1afea19a9a7df875 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:39 +0100 +Subject: [PATCH] vdpa: move SVQ vring features check to net/ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next patches will start control SVQ if possible. However, we don't +know if that will be possible at qemu boot anymore. + +Since the moved checks will be already evaluated at net/ to know if it +is ok to shadow CVQ, move them. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-8-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 32 ++------------------------------ + net/vhost-vdpa.c | 3 ++- + 2 files changed, 4 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index c0e645ec13..59bfdbfc24 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -391,29 +391,9 @@ static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, + return ret; + } + +-static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, +- Error **errp) ++static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) + { + g_autoptr(GPtrArray) shadow_vqs = NULL; +- uint64_t dev_features, svq_features; +- int r; +- bool ok; +- +- if (!v->shadow_vqs_enabled) { +- return 0; +- } +- +- r = vhost_vdpa_get_dev_features(hdev, &dev_features); +- if (r != 0) { +- error_setg_errno(errp, -r, "Can't get vdpa device features"); +- return r; +- } +- +- svq_features = dev_features; +- ok = vhost_svq_valid_features(svq_features, errp); +- if (unlikely(!ok)) { +- return -1; +- } + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +@@ -425,7 +405,6 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + } + + v->shadow_vqs = g_steal_pointer(&shadow_vqs); +- return 0; + } + + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) +@@ -450,10 +429,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + dev->opaque = opaque ; + v->listener = vhost_vdpa_memory_listener; + v->msg_type = VHOST_IOTLB_MSG_V2; +- ret = vhost_vdpa_init_svq(dev, v, errp); +- if (ret) { +- goto err; +- } ++ vhost_vdpa_init_svq(dev, v); + + if (!vhost_vdpa_first_dev(dev)) { + return 0; +@@ -463,10 +439,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + VIRTIO_CONFIG_S_DRIVER); + + return 0; +- +-err: +- ram_block_discard_disable(false); +- return ret; + } + + static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index be056a2553..e250d34462 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -116,9 +116,10 @@ static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) + if (invalid_dev_features) { + error_setg(errp, "vdpa svq does not work with features 0x%" PRIx64, + invalid_dev_features); ++ return false; + } + +- return !invalid_dev_features; ++ return vhost_svq_valid_features(features, errp); + } + + static int vhost_vdpa_net_check_device_id(struct vhost_net *net) +-- +2.27.0 + diff --git a/vdpa-net-block-migration-if-the-device-has-CVQ.patch b/vdpa-net-block-migration-if-the-device-has-CVQ.patch new file mode 100644 index 0000000..a700f8d --- /dev/null +++ b/vdpa-net-block-migration-if-the-device-has-CVQ.patch @@ -0,0 +1,70 @@ +From d97454d68f90b441d3fa19c496a7fe6916f50e31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Fri, 3 Mar 2023 18:24:41 +0100 +Subject: [PATCH] vdpa net: block migration if the device has CVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Devices with CVQ need to migrate state beyond vq state. Leaving this to +future series. + +Signed-off-by: Eugenio Pérez +Message-Id: <20230303172445.1089785-11-eperezma@redhat.com> +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 1 + + include/hw/virtio/vhost-vdpa.h | 1 + + net/vhost-vdpa.c | 9 +++++++++ + 3 files changed, 11 insertions(+) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index f5d816f5ec..dd1ba8878c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -450,6 +450,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + v->msg_type = VHOST_IOTLB_MSG_V2; + vhost_vdpa_init_svq(dev, v); + ++ error_propagate(&dev->migration_blocker, v->migration_blocker); + if (!vhost_vdpa_first_dev(dev)) { + return 0; + } +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 7997f09a8d..620a0f70ab 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -48,6 +48,7 @@ typedef struct vhost_vdpa { + const VhostShadowVirtqueueOps *shadow_vq_ops; + void *shadow_vq_ops_opaque; + struct vhost_dev *dev; ++ Error *migration_blocker; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 8192045735..dc1b4c4be2 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -721,6 +721,15 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; + s->vhost_vdpa.shadow_vq_ops_opaque = s; ++ ++ /* ++ * TODO: We cannot migrate devices with CVQ as there is no way to set ++ * the device state (MAC, MQ, etc) before starting the datapath. ++ * ++ * Migration blocker ownership now belongs to s->vhost_vdpa. ++ */ ++ error_setg(&s->vhost_vdpa.migration_blocker, ++ "net vdpa cannot migrate with CVQ feature"); + } + ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); + if (ret) { +-- +2.27.0 + diff --git a/vdpa-request-iova_range-only-once.patch b/vdpa-request-iova_range-only-once.patch new file mode 100644 index 0000000..c9ce07a --- /dev/null +++ b/vdpa-request-iova_range-only-once.patch @@ -0,0 +1,137 @@ +From 5ff455d55b2d58a726d2557076e0f5401496de02 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:38 +0100 +Subject: [PATCH] vdpa: request iova_range only once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently iova range is requested once per queue pair in the case of +net. Reduce the number of ioctls asking it once at initialization and +reusing that value for each vhost_vdpa. + +Signed-off-by: Eugenio Pérez +Message-Id: <20221215113144.322011-7-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 15 --------------- + net/vhost-vdpa.c | 27 ++++++++++++++------------- + 2 files changed, 14 insertions(+), 28 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 23e715b05c..c0e645ec13 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -367,19 +367,6 @@ static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + return 0; + } + +-static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) +-{ +- int ret = vhost_vdpa_call(v->dev, VHOST_VDPA_GET_IOVA_RANGE, +- &v->iova_range); +- if (ret != 0) { +- v->iova_range.first = 0; +- v->iova_range.last = UINT64_MAX; +- } +- +- trace_vhost_vdpa_get_iova_range(v->dev, v->iova_range.first, +- v->iova_range.last); +-} +- + /* + * The use of this function is for requests that only need to be + * applied once. Typically such request occurs at the beginning +@@ -468,8 +455,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + goto err; + } + +- vhost_vdpa_get_iova_range(v); +- + if (!vhost_vdpa_first_dev(dev)) { + return 0; + } +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 217d2545c1..be056a2553 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -548,14 +548,15 @@ static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { + }; + + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, +- const char *device, +- const char *name, +- int vdpa_device_fd, +- int queue_pair_index, +- int nvqs, +- bool is_datapath, +- bool svq, +- VhostIOVATree *iova_tree) ++ const char *device, ++ const char *name, ++ int vdpa_device_fd, ++ int queue_pair_index, ++ int nvqs, ++ bool is_datapath, ++ bool svq, ++ struct vhost_vdpa_iova_range iova_range, ++ VhostIOVATree *iova_tree) + { + NetClientState *nc = NULL; + VhostVDPAState *s; +@@ -574,6 +575,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; + s->vhost_vdpa.shadow_vqs_enabled = svq; ++ s->vhost_vdpa.iova_range = iova_range; + s->vhost_vdpa.iova_tree = iova_tree; + if (!is_datapath) { + s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size, +@@ -653,6 +655,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + int vdpa_device_fd; + g_autofree NetClientState **ncs = NULL; + g_autoptr(VhostIOVATree) iova_tree = NULL; ++ struct vhost_vdpa_iova_range iova_range; + NetClientState *nc; + int queue_pairs, r, i = 0, has_cvq = 0; + +@@ -696,14 +699,12 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + return queue_pairs; + } + ++ vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); + if (opts->x_svq) { +- struct vhost_vdpa_iova_range iova_range; +- + if (!vhost_vdpa_net_valid_svq_features(features, errp)) { + goto err_svq; + } + +- vhost_vdpa_get_iova_range(vdpa_device_fd, &iova_range); + iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last); + } + +@@ -712,7 +713,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + for (i = 0; i < queue_pairs; i++) { + ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, + vdpa_device_fd, i, 2, true, opts->x_svq, +- iova_tree); ++ iova_range, iova_tree); + if (!ncs[i]) + goto err; + } +@@ -720,7 +721,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + if (has_cvq) { + nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, + vdpa_device_fd, i, 1, false, +- opts->x_svq, iova_tree); ++ opts->x_svq, iova_range, iova_tree); + if (!nc) + goto err; + } +-- +2.27.0 + diff --git a/vdpa-stop-all-svq-on-device-deletion.patch b/vdpa-stop-all-svq-on-device-deletion.patch new file mode 100644 index 0000000..a6cb17e --- /dev/null +++ b/vdpa-stop-all-svq-on-device-deletion.patch @@ -0,0 +1,73 @@ +From 6b9c4a2607b88faf611da724ead81dc89a7b185b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 9 Feb 2023 18:00:04 +0100 +Subject: [PATCH] vdpa: stop all svq on device deletion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Not stopping them leave the device in a bad state when virtio-net +fronted device is unplugged with device_del monitor command. + +This is not triggable in regular poweroff or qemu forces shutdown +because cleanup is called right after vhost_vdpa_dev_start(false). But +devices hot unplug does not call vdpa device cleanups. This lead to all +the vhost_vdpa devices without stop the SVQ but the last. + +Fix it and clean the code, making it symmetric with +vhost_vdpa_svqs_start. + +Fixes: dff4426fa656 ("vhost: Add Shadow VirtQueue kick forwarding capabilities") +Reported-by: Lei Yang +Signed-off-by: Eugenio Pérez +Message-Id: <20230209170004.899472-1-eperezma@redhat.com> +Tested-by: Laurent Vivier +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index dd1ba8878c..986fc795bf 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -692,26 +692,11 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + return ret; + } + +-static void vhost_vdpa_reset_svq(struct vhost_vdpa *v) +-{ +- if (!v->shadow_vqs_enabled) { +- return; +- } +- +- for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); +- vhost_svq_stop(svq); +- } +-} +- + static int vhost_vdpa_reset_device(struct vhost_dev *dev) + { +- struct vhost_vdpa *v = dev->opaque; + int ret; + uint8_t status = 0; + +- vhost_vdpa_reset_svq(v); +- + ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); + trace_vhost_vdpa_reset_device(dev, status); + return ret; +@@ -1103,6 +1088,8 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ ++ vhost_svq_stop(svq); + vhost_vdpa_svq_unmap_rings(dev, svq); + + event_notifier_cleanup(&svq->hdev_kick); +-- +2.27.0 + diff --git a/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch b/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch new file mode 100644 index 0000000..96f5eae --- /dev/null +++ b/vdpa-store-x-svq-parameter-in-VhostVDPAState.patch @@ -0,0 +1,54 @@ +From 7a2278d9cdd9ac2a74bb9745fdf555395ff8dcd7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:42 +0100 +Subject: [PATCH] vdpa: store x-svq parameter in VhostVDPAState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CVQ can be shadowed two ways: +- Device has x-svq=on parameter (current way) +- The device can isolate CVQ in its own vq group + +QEMU needs to check for the second condition dynamically, because CVQ +index is not known before the driver ack the features. Since this is +dynamic, the CVQ isolation could vary with different conditions, making +it possible to go from "not isolated group" to "isolated". + +Saving the cmdline parameter in an extra field so we never disable CVQ +SVQ in case the device was started with x-svq cmdline. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-11-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index cb1cc2523d..7adba2c2b6 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -37,6 +37,8 @@ typedef struct VhostVDPAState { + void *cvq_cmd_out_buffer; + virtio_net_ctrl_ack *status; + ++ /* The device always have SVQ enabled */ ++ bool always_svq; + bool started; + } VhostVDPAState; + +@@ -575,6 +577,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, + + s->vhost_vdpa.device_fd = vdpa_device_fd; + s->vhost_vdpa.index = queue_pair_index; ++ s->always_svq = svq; + s->vhost_vdpa.shadow_vqs_enabled = svq; + s->vhost_vdpa.iova_range = iova_range; + s->vhost_vdpa.iova_tree = iova_tree; +-- +2.27.0 + diff --git a/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch b/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch new file mode 100644 index 0000000..2b22c8e --- /dev/null +++ b/vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch @@ -0,0 +1,50 @@ +From f2a41f2f0f16402772009efc8eac5e9a08fea0b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:33 +0100 +Subject: [PATCH] vdpa: use v->shadow_vqs_enabled in vhost_vdpa_svqs_start & + stop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function used to trust in v->shadow_vqs != NULL to know if it must +start svq or not. + +This is not going to be valid anymore, as qemu is going to allocate svq +array unconditionally (but it will only start them conditionally). + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 0f07c85b91..08f92bf781 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1031,7 +1031,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + Error *err = NULL; + unsigned i; + +- if (!v->shadow_vqs) { ++ if (!v->shadow_vqs_enabled) { + return true; + } + +@@ -1084,7 +1084,7 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + +- if (!v->shadow_vqs) { ++ if (!v->shadow_vqs_enabled) { + return; + } + +-- +2.27.0 + diff --git a/vdpa-validate-MQ-CVQ-commands.patch b/vdpa-validate-MQ-CVQ-commands.patch new file mode 100644 index 0000000..42627c1 --- /dev/null +++ b/vdpa-validate-MQ-CVQ-commands.patch @@ -0,0 +1,41 @@ +From c9aa596ad26ee9fa1d4f7433485a668e3485d4ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:17 +0200 +Subject: [PATCH] vdpa: validate MQ CVQ commands +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So we are sure we can update the device model properly before sending to +the device. + +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index b32fe5e68a..831709a270 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -494,6 +494,15 @@ static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len) + __func__, ctrl.cmd); + }; + break; ++ case VIRTIO_NET_CTRL_MQ: ++ switch (ctrl.cmd) { ++ case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: ++ return true; ++ default: ++ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n", ++ __func__, ctrl.cmd); ++ }; ++ break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n", + __func__, ctrl.class); +-- +2.27.0 + diff --git a/vga-avoid-crash-if-no-default-vga-card.patch b/vga-avoid-crash-if-no-default-vga-card.patch new file mode 100644 index 0000000..829bcae --- /dev/null +++ b/vga-avoid-crash-if-no-default-vga-card.patch @@ -0,0 +1,41 @@ +From 70b0d16c684364594443520fba504e665f167cc4 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:38:56 +0000 +Subject: [PATCH] vga: avoid crash if no default vga card mainline inclusion + commit 6985d8ede92494f3b791de01e8ee9306eb6d5e4a category: bugfix + +--------------------------------------------------------------- + +QEMU in some arch will crash when executing -vga help command, because +there is no default vga model. Add check to this case and avoid crash. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/978 + +Signed-off-by: Guo Zhi +Reviewed-by: Thomas Huth +Tested-by: Thomas Huth +Message-Id: <20220503091724.970009-1-qtxuning1999@sjtu.edu.cn> +Signed-off-by: Laurent Vivier + +Signed-off-by: tangbinzy +--- + softmmu/vl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/softmmu/vl.c b/softmmu/vl.c +index d8996f3d6e..e34c8a0646 100644 +--- a/softmmu/vl.c ++++ b/softmmu/vl.c +@@ -974,7 +974,8 @@ static void select_vgahw(const MachineClass *machine_class, const char *p) + + if (vga_interface_available(t) && ti->opt_name) { + printf("%-20s %s%s\n", ti->opt_name, ti->name ?: "", +- g_str_equal(ti->opt_name, def) ? " (default)" : ""); ++ (def && g_str_equal(ti->opt_name, def)) ? ++ " (default)" : ""); + } + } + exit(0); +-- +2.27.0 + diff --git a/vhost-Add-SVQDescState.patch b/vhost-Add-SVQDescState.patch new file mode 100644 index 0000000..748d326 --- /dev/null +++ b/vhost-Add-SVQDescState.patch @@ -0,0 +1,116 @@ +From f8caeca478eb902982879ecd7fad9ffa518ad3bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:34 +0200 +Subject: [PATCH] vhost: Add SVQDescState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will allow SVQ to add context to the different queue elements. + +This patch only store the actual element, no functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 16 ++++++++-------- + hw/virtio/vhost-shadow-virtqueue.h | 8 ++++++-- + 2 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 00f5ccddfb..5ddc04e9d6 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -255,7 +255,7 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + return -EINVAL; + } + +- svq->ring_id_maps[qemu_head] = elem; ++ svq->desc_state[qemu_head].elem = elem; + vhost_svq_kick(svq); + return 0; + } +@@ -410,21 +410,21 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- if (unlikely(!svq->ring_id_maps[used_elem.id])) { ++ if (unlikely(!svq->desc_state[used_elem.id].elem)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Device %s says index %u is used, but it was not available", + svq->vdev->name, used_elem.id); + return NULL; + } + +- num = svq->ring_id_maps[used_elem.id]->in_num + +- svq->ring_id_maps[used_elem.id]->out_num; ++ num = svq->desc_state[used_elem.id].elem->in_num + ++ svq->desc_state[used_elem.id].elem->out_num; + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +- return g_steal_pointer(&svq->ring_id_maps[used_elem.id]); ++ return g_steal_pointer(&svq->desc_state[used_elem.id].elem); + } + + static void vhost_svq_flush(VhostShadowVirtqueue *svq, +@@ -594,7 +594,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + memset(svq->vring.desc, 0, driver_size); + svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); + memset(svq->vring.used, 0, device_size); +- svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ svq->desc_state = g_new0(SVQDescState, svq->vring.num); + svq->desc_next = g_new0(uint16_t, svq->vring.num); + for (unsigned i = 0; i < svq->vring.num - 1; i++) { + svq->desc_next[i] = cpu_to_le16(i + 1); +@@ -619,7 +619,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + + for (unsigned i = 0; i < svq->vring.num; ++i) { + g_autofree VirtQueueElement *elem = NULL; +- elem = g_steal_pointer(&svq->ring_id_maps[i]); ++ elem = g_steal_pointer(&svq->desc_state[i].elem); + if (elem) { + virtqueue_detach_element(svq->vq, elem, 0); + } +@@ -631,7 +631,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + } + svq->vq = NULL; + g_free(svq->desc_next); +- g_free(svq->ring_id_maps); ++ g_free(svq->desc_state); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); + } +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index c132c994e9..d646c35054 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -15,6 +15,10 @@ + #include "standard-headers/linux/vhost_types.h" + #include "hw/virtio/vhost-iova-tree.h" + ++typedef struct SVQDescState { ++ VirtQueueElement *elem; ++} SVQDescState; ++ + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { + /* Shadow vring */ +@@ -47,8 +51,8 @@ typedef struct VhostShadowVirtqueue { + /* IOVA mapping */ + VhostIOVATree *iova_tree; + +- /* Map for use the guest's descriptors */ +- VirtQueueElement **ring_id_maps; ++ /* SVQ vring descriptors state */ ++ SVQDescState *desc_state; + + /* Next VirtQueue element that guest made available */ + VirtQueueElement *next_guest_avail_elem; +-- +2.27.0 + diff --git a/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch b/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch new file mode 100644 index 0000000..41fe5cf --- /dev/null +++ b/vhost-Add-Shadow-VirtQueue-call-forwarding-capabilit.patch @@ -0,0 +1,168 @@ +From 6ff532ef853499a16307e09d8bab18c57c03ecae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:43 +0100 +Subject: [PATCH] vhost: Add Shadow VirtQueue call forwarding capabilities +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will make qemu aware of the device used buffers, allowing it to +write the guest memory with its contents if needed. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 38 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 4 ++++ + hw/virtio/vhost-vdpa.c | 31 ++++++++++++++++++++++-- + 3 files changed, 71 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index e5da907b8e..55cb5414ef 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -26,6 +26,42 @@ static void vhost_handle_guest_kick(EventNotifier *n) + event_notifier_set(&svq->hdev_kick); + } + ++/** ++ * Forward vhost notifications ++ * ++ * @n: hdev call event notifier, the one that device set to notify svq. ++ */ ++static void vhost_svq_handle_call(EventNotifier *n) ++{ ++ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, ++ hdev_call); ++ event_notifier_test_and_clear(n); ++ event_notifier_set(&svq->svq_call); ++} ++ ++/** ++ * Set the call notifier for the SVQ to call the guest ++ * ++ * @svq: Shadow virtqueue ++ * @call_fd: call notifier ++ * ++ * Called on BQL context. ++ */ ++void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) ++{ ++ if (call_fd == VHOST_FILE_UNBIND) { ++ /* ++ * Fail event_notifier_set if called handling device call. ++ * ++ * SVQ still needs device notifications, since it needs to keep ++ * forwarding used buffers even with the unbind. ++ */ ++ memset(&svq->svq_call, 0, sizeof(svq->svq_call)); ++ } else { ++ event_notifier_init_fd(&svq->svq_call, call_fd); ++ } ++} ++ + /** + * Set a new file descriptor for the guest to kick the SVQ and notify for avail + * +@@ -93,6 +129,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + } + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); ++ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + return g_steal_pointer(&svq); + + err_init_hdev_call: +@@ -112,6 +149,7 @@ void vhost_svq_free(gpointer pvq) + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); ++ event_notifier_set_handler(&vq->hdev_call, NULL); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 1cbc87d5d8..cbc5213579 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -28,9 +28,13 @@ typedef struct VhostShadowVirtqueue { + * So shadow virtqueue must not clean it, or we would lose VirtQueue one. + */ + EventNotifier svq_kick; ++ ++ /* Guest's call notifier, where the SVQ calls guest. */ ++ EventNotifier svq_call; + } VhostShadowVirtqueue; + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); ++void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 7331c8ee04..29c720308f 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -727,6 +727,13 @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); + } + ++static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev, ++ struct vhost_vring_file *file) ++{ ++ trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); ++} ++ + /** + * Set the shadow virtqueue descriptors to the device + * +@@ -734,6 +741,9 @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, + * @svq: The shadow virtqueue + * @idx: The index of the virtqueue in the vhost device + * @errp: Error ++ * ++ * Note that this function does not rewind kick file descriptor if cannot set ++ * call one. + */ + static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + VhostShadowVirtqueue *svq, unsigned idx, +@@ -749,6 +759,14 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); ++ return false; ++ } ++ ++ event_notifier = &svq->hdev_call; ++ file.fd = event_notifier_get_fd(event_notifier); ++ r = vhost_vdpa_set_vring_dev_call(dev, &file); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Can't set device call fd"); + } + + return r == 0; +@@ -874,8 +892,17 @@ static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +- trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (v->shadow_vqs_enabled) { ++ int vdpa_idx = file->index - dev->vq_index; ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); ++ ++ vhost_svq_set_svq_call_fd(svq, file->fd); ++ return 0; ++ } else { ++ return vhost_vdpa_set_vring_dev_call(dev, file); ++ } + } + + static int vhost_vdpa_get_features(struct vhost_dev *dev, +-- +2.27.0 + diff --git a/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch b/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch new file mode 100644 index 0000000..fc8469e --- /dev/null +++ b/vhost-Add-Shadow-VirtQueue-kick-forwarding-capabilit.patch @@ -0,0 +1,395 @@ +From 41585669f68a3896d6d8a5bea868f192b30fad76 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:42 +0100 +Subject: [PATCH] vhost: Add Shadow VirtQueue kick forwarding capabilities +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +At this mode no buffer forwarding will be performed in SVQ mode: Qemu +will just forward the guest's kicks to the device. + +Host memory notifiers regions are left out for simplicity, and they will +not be addressed in this series. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 55 +++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 14 +++ + hw/virtio/vhost-vdpa.c | 144 ++++++++++++++++++++++++++++- + include/hw/virtio/vhost-vdpa.h | 4 + + 4 files changed, 215 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c1db02c53e..e5da907b8e 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -11,6 +11,59 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + + #include "qemu/error-report.h" ++#include "qemu/main-loop.h" ++#include "linux-headers/linux/vhost.h" ++ ++/** ++ * Forward guest notifications. ++ * ++ * @n: guest kick event notifier, the one that guest set to notify svq. ++ */ ++static void vhost_handle_guest_kick(EventNotifier *n) ++{ ++ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick); ++ event_notifier_test_and_clear(n); ++ event_notifier_set(&svq->hdev_kick); ++} ++ ++/** ++ * Set a new file descriptor for the guest to kick the SVQ and notify for avail ++ * ++ * @svq: The svq ++ * @svq_kick_fd: The svq kick fd ++ * ++ * Note that the SVQ will never close the old file descriptor. ++ */ ++void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) ++{ ++ EventNotifier *svq_kick = &svq->svq_kick; ++ bool poll_stop = VHOST_FILE_UNBIND != event_notifier_get_fd(svq_kick); ++ bool poll_start = svq_kick_fd != VHOST_FILE_UNBIND; ++ ++ if (poll_stop) { ++ event_notifier_set_handler(svq_kick, NULL); ++ } ++ ++ /* ++ * event_notifier_set_handler already checks for guest's notifications if ++ * they arrive at the new file descriptor in the switch, so there is no ++ * need to explicitly check for them. ++ */ ++ if (poll_start) { ++ event_notifier_init_fd(svq_kick, svq_kick_fd); ++ event_notifier_set(svq_kick); ++ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick); ++ } ++} ++ ++/** ++ * Stop the shadow virtqueue operation. ++ * @svq: Shadow Virtqueue ++ */ ++void vhost_svq_stop(VhostShadowVirtqueue *svq) ++{ ++ event_notifier_set_handler(&svq->svq_kick, NULL); ++} + + /** + * Creates vhost shadow virtqueue, and instructs the vhost device to use the +@@ -39,6 +92,7 @@ VhostShadowVirtqueue *vhost_svq_new(void) + goto err_init_hdev_call; + } + ++ event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + return g_steal_pointer(&svq); + + err_init_hdev_call: +@@ -56,6 +110,7 @@ err_init_hdev_kick: + void vhost_svq_free(gpointer pvq) + { + VhostShadowVirtqueue *vq = pvq; ++ vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index f1519e3c7b..1cbc87d5d8 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -18,8 +18,22 @@ typedef struct VhostShadowVirtqueue { + EventNotifier hdev_kick; + /* Shadow call notifier, sent to vhost */ + EventNotifier hdev_call; ++ ++ /* ++ * Borrowed virtqueue's guest to host notifier. To borrow it in this event ++ * notifier allows to recover the VhostShadowVirtqueue from the event loop ++ * easily. If we use the VirtQueue's one, we don't have an easy way to ++ * retrieve VhostShadowVirtqueue. ++ * ++ * So shadow virtqueue must not clean it, or we would lose VirtQueue one. ++ */ ++ EventNotifier svq_kick; + } VhostShadowVirtqueue; + ++void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); ++ ++void vhost_svq_stop(VhostShadowVirtqueue *svq); ++ + VhostShadowVirtqueue *vhost_svq_new(void); + + void vhost_svq_free(gpointer vq); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 25a2f570a2..7331c8ee04 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -17,12 +17,14 @@ + #include "hw/virtio/vhost.h" + #include "hw/virtio/vhost-backend.h" + #include "hw/virtio/virtio-net.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" + #include "hw/virtio/vhost-vdpa.h" + #include "exec/address-spaces.h" + #include "qemu/main-loop.h" + #include "cpu.h" + #include "trace.h" + #include "qemu-common.h" ++#include "qapi/error.h" + + static unsigned int vhost_vdpa_used_memslots; + +@@ -344,6 +346,30 @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) + return v->index != 0; + } + ++static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, ++ Error **errp) ++{ ++ g_autoptr(GPtrArray) shadow_vqs = NULL; ++ ++ if (!v->shadow_vqs_enabled) { ++ return 0; ++ } ++ ++ shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); ++ for (unsigned n = 0; n < hdev->nvqs; ++n) { ++ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); ++ ++ if (unlikely(!svq)) { ++ error_setg(errp, "Cannot create svq %u", n); ++ return -1; ++ } ++ g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq)); ++ } ++ ++ v->shadow_vqs = g_steal_pointer(&shadow_vqs); ++ return 0; ++} ++ + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + { + struct vhost_vdpa *v; +@@ -366,6 +392,10 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + dev->opaque = opaque ; + v->listener = vhost_vdpa_memory_listener; + v->msg_type = VHOST_IOTLB_MSG_V2; ++ ret = vhost_vdpa_init_svq(dev, v, errp); ++ if (ret) { ++ goto err; ++ } + + vhost_vdpa_get_iova_range(v); + +@@ -377,6 +407,10 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + VIRTIO_CONFIG_S_DRIVER); + + return 0; ++ ++err: ++ ram_block_discard_disable(false); ++ return ret; + } + + static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, +@@ -447,8 +481,14 @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) + + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) + { ++ struct vhost_vdpa *v = dev->opaque; + int i; + ++ if (v->shadow_vqs_enabled) { ++ /* FIXME SVQ is not compatible with host notifiers mr */ ++ return; ++ } ++ + for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) { + if (vhost_vdpa_host_notifier_init(dev, i)) { + goto err; +@@ -462,6 +502,21 @@ err: + return; + } + ++static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ size_t idx; ++ ++ if (!v->shadow_vqs) { ++ return; ++ } ++ ++ for (idx = 0; idx < v->shadow_vqs->len; ++idx) { ++ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx)); ++ } ++ g_ptr_array_free(v->shadow_vqs, true); ++} ++ + static int vhost_vdpa_cleanup(struct vhost_dev *dev) + { + struct vhost_vdpa *v; +@@ -470,6 +525,7 @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev) + trace_vhost_vdpa_cleanup(dev, v); + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + memory_listener_unregister(&v->listener); ++ vhost_vdpa_svq_cleanup(dev); + + dev->opaque = NULL; + ram_block_discard_disable(false); +@@ -561,11 +617,26 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + return ret; + } + ++static void vhost_vdpa_reset_svq(struct vhost_vdpa *v) ++{ ++ if (!v->shadow_vqs_enabled) { ++ return; ++ } ++ ++ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ vhost_svq_stop(svq); ++ } ++} ++ + static int vhost_vdpa_reset_device(struct vhost_dev *dev) + { ++ struct vhost_vdpa *v = dev->opaque; + int ret; + uint8_t status = 0; + ++ vhost_vdpa_reset_svq(v); ++ + ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); + trace_vhost_vdpa_reset_device(dev, status); + return ret; +@@ -649,13 +720,74 @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config, + return ret; + } + ++static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev, ++ struct vhost_vring_file *file) ++{ ++ trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd); ++ return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); ++} ++ ++/** ++ * Set the shadow virtqueue descriptors to the device ++ * ++ * @dev: The vhost device model ++ * @svq: The shadow virtqueue ++ * @idx: The index of the virtqueue in the vhost device ++ * @errp: Error ++ */ ++static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) ++{ ++ struct vhost_vring_file file = { ++ .index = dev->vq_index + idx, ++ }; ++ const EventNotifier *event_notifier = &svq->hdev_kick; ++ int r; ++ ++ file.fd = event_notifier_get_fd(event_notifier); ++ r = vhost_vdpa_set_vring_dev_kick(dev, &file); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Can't set device kick fd"); ++ } ++ ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ Error *err = NULL; ++ unsigned i; ++ ++ if (!v->shadow_vqs) { ++ return true; ++ } ++ ++ for (i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); ++ if (unlikely(!ok)) { ++ error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + { + struct vhost_vdpa *v = dev->opaque; ++ bool ok; + trace_vhost_vdpa_dev_start(dev, started); + + if (started) { + vhost_vdpa_host_notifiers_init(dev); ++ ok = vhost_vdpa_svqs_start(dev); ++ if (unlikely(!ok)) { ++ return -1; ++ } + vhost_vdpa_set_vring_ready(dev); + } else { + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); +@@ -727,8 +859,16 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev, + struct vhost_vring_file *file) + { +- trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd); +- return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file); ++ struct vhost_vdpa *v = dev->opaque; ++ int vdpa_idx = file->index - dev->vq_index; ++ ++ if (v->shadow_vqs_enabled) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); ++ vhost_svq_set_svq_kick_fd(svq, file->fd); ++ return 0; ++ } else { ++ return vhost_vdpa_set_vring_dev_kick(dev, file); ++ } + } + + static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, +diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h +index 3ce79a646d..009a9f3b6b 100644 +--- a/include/hw/virtio/vhost-vdpa.h ++++ b/include/hw/virtio/vhost-vdpa.h +@@ -12,6 +12,8 @@ + #ifndef HW_VIRTIO_VHOST_VDPA_H + #define HW_VIRTIO_VHOST_VDPA_H + ++#include ++ + #include "hw/virtio/virtio.h" + #include "standard-headers/linux/vhost_types.h" + +@@ -27,6 +29,8 @@ typedef struct vhost_vdpa { + bool iotlb_batch_begin_sent; + MemoryListener listener; + struct vhost_vdpa_iova_range iova_range; ++ bool shadow_vqs_enabled; ++ GPtrArray *shadow_vqs; + struct vhost_dev *dev; + VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostVDPA; +-- +2.27.0 + diff --git a/vhost-Add-VhostIOVATree.patch b/vhost-Add-VhostIOVATree.patch new file mode 100644 index 0000000..8f78f90 --- /dev/null +++ b/vhost-Add-VhostIOVATree.patch @@ -0,0 +1,200 @@ +From c938dd769a872c569c3985f06c8b5854231ed74c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:50 +0100 +Subject: [PATCH] vhost: Add VhostIOVATree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This tree is able to look for a translated address from an IOVA address. + +At first glance it is similar to util/iova-tree. However, SVQ working on +devices with limited IOVA space need more capabilities, like allocating +IOVA chunks or performing reverse translations (qemu addresses to iova). + +The allocation capability, as "assign a free IOVA address to this chunk +of memory in qemu's address space" allows shadow virtqueue to create a +new address space that is not restricted by guest's addressable one, so +we can allocate shadow vqs vrings outside of it. + +It duplicates the tree so it can search efficiently in both directions, +and it will signal overlap if iova or the translated address is present +in any tree. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 2 +- + hw/virtio/vhost-iova-tree.c | 110 ++++++++++++++++++++++++++++++++++++ + hw/virtio/vhost-iova-tree.h | 27 +++++++++ + 3 files changed, 138 insertions(+), 1 deletion(-) + create mode 100644 hw/virtio/vhost-iova-tree.c + create mode 100644 hw/virtio/vhost-iova-tree.h + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index eb46c05a25..c2e193f56d 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,7 +11,7 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) +diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c +new file mode 100644 +index 0000000000..55fed1fefb +--- /dev/null ++++ b/hw/virtio/vhost-iova-tree.c +@@ -0,0 +1,110 @@ ++/* ++ * vhost software live migration iova tree ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/iova-tree.h" ++#include "vhost-iova-tree.h" ++ ++#define iova_min_addr qemu_real_host_page_size ++ ++/** ++ * VhostIOVATree, able to: ++ * - Translate iova address ++ * - Reverse translate iova address (from translated to iova) ++ * - Allocate IOVA regions for translated range (linear operation) ++ */ ++struct VhostIOVATree { ++ /* First addressable iova address in the device */ ++ uint64_t iova_first; ++ ++ /* Last addressable iova address in the device */ ++ uint64_t iova_last; ++ ++ /* IOVA address to qemu memory maps. */ ++ IOVATree *iova_taddr_map; ++}; ++ ++/** ++ * Create a new IOVA tree ++ * ++ * Returns the new IOVA tree ++ */ ++VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last) ++{ ++ VhostIOVATree *tree = g_new(VhostIOVATree, 1); ++ ++ /* Some devices do not like 0 addresses */ ++ tree->iova_first = MAX(iova_first, iova_min_addr); ++ tree->iova_last = iova_last; ++ ++ tree->iova_taddr_map = iova_tree_new(); ++ return tree; ++} ++ ++/** ++ * Delete an iova tree ++ */ ++void vhost_iova_tree_delete(VhostIOVATree *iova_tree) ++{ ++ iova_tree_destroy(iova_tree->iova_taddr_map); ++ g_free(iova_tree); ++} ++ ++/** ++ * Find the IOVA address stored from a memory address ++ * ++ * @tree: The iova tree ++ * @map: The map with the memory address ++ * ++ * Return the stored mapping, or NULL if not found. ++ */ ++const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree, ++ const DMAMap *map) ++{ ++ return iova_tree_find_iova(tree->iova_taddr_map, map); ++} ++ ++/** ++ * Allocate a new mapping ++ * ++ * @tree: The iova tree ++ * @map: The iova map ++ * ++ * Returns: ++ * - IOVA_OK if the map fits in the container ++ * - IOVA_ERR_INVALID if the map does not make sense (like size overflow) ++ * - IOVA_ERR_NOMEM if tree cannot allocate more space. ++ * ++ * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK. ++ */ ++int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map) ++{ ++ /* Some vhost devices do not like addr 0. Skip first page */ ++ hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size; ++ ++ if (map->translated_addr + map->size < map->translated_addr || ++ map->perm == IOMMU_NONE) { ++ return IOVA_ERR_INVALID; ++ } ++ ++ /* Allocate a node in IOVA address */ ++ return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first, ++ tree->iova_last); ++} ++ ++/** ++ * Remove existing mappings from iova tree ++ * ++ * @iova_tree: The vhost iova tree ++ * @map: The map to remove ++ */ ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map) ++{ ++ iova_tree_remove(iova_tree->iova_taddr_map, map); ++} +diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h +new file mode 100644 +index 0000000000..6a4f24e0f9 +--- /dev/null ++++ b/hw/virtio/vhost-iova-tree.h +@@ -0,0 +1,27 @@ ++/* ++ * vhost software live migration iova tree ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef HW_VIRTIO_VHOST_IOVA_TREE_H ++#define HW_VIRTIO_VHOST_IOVA_TREE_H ++ ++#include "qemu/iova-tree.h" ++#include "exec/memory.h" ++ ++typedef struct VhostIOVATree VhostIOVATree; ++ ++VhostIOVATree *vhost_iova_tree_new(uint64_t iova_first, uint64_t iova_last); ++void vhost_iova_tree_delete(VhostIOVATree *iova_tree); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete); ++ ++const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree, ++ const DMAMap *map); ++int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map); ++void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map); ++ ++#endif +-- +2.27.0 + diff --git a/vhost-Add-VhostShadowVirtqueue.patch b/vhost-Add-VhostShadowVirtqueue.patch new file mode 100644 index 0000000..b4c668b --- /dev/null +++ b/vhost-Add-VhostShadowVirtqueue.patch @@ -0,0 +1,147 @@ +From 6f38bfce3fc45c1c68329412d146913a155962c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:41 +0100 +Subject: [PATCH] vhost: Add VhostShadowVirtqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Vhost shadow virtqueue (SVQ) is an intermediate jump for virtqueue +notifications and buffers, allowing qemu to track them. While qemu is +forwarding the buffers and virtqueue changes, it is able to commit the +memory it's being dirtied, the same way regular qemu's VirtIO devices +do. + +This commit only exposes basic SVQ allocation and free. Next patches of +the series add functionality like notifications and buffers forwarding. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 2 +- + hw/virtio/vhost-shadow-virtqueue.c | 62 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 28 ++++++++++++++ + 3 files changed, 91 insertions(+), 1 deletion(-) + create mode 100644 hw/virtio/vhost-shadow-virtqueue.c + create mode 100644 hw/virtio/vhost-shadow-virtqueue.h + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index 8e8943e20b..eb46c05a25 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,7 +11,7 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) + virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +new file mode 100644 +index 0000000000..c1db02c53e +--- /dev/null ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -0,0 +1,62 @@ ++/* ++ * vhost shadow virtqueue ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/virtio/vhost-shadow-virtqueue.h" ++ ++#include "qemu/error-report.h" ++ ++/** ++ * Creates vhost shadow virtqueue, and instructs the vhost device to use the ++ * shadow methods and file descriptors. ++ * ++ * Returns the new virtqueue or NULL. ++ * ++ * In case of error, reason is reported through error_report. ++ */ ++VhostShadowVirtqueue *vhost_svq_new(void) ++{ ++ g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); ++ int r; ++ ++ r = event_notifier_init(&svq->hdev_kick, 0); ++ if (r != 0) { ++ error_report("Couldn't create kick event notifier: %s (%d)", ++ g_strerror(errno), errno); ++ goto err_init_hdev_kick; ++ } ++ ++ r = event_notifier_init(&svq->hdev_call, 0); ++ if (r != 0) { ++ error_report("Couldn't create call event notifier: %s (%d)", ++ g_strerror(errno), errno); ++ goto err_init_hdev_call; ++ } ++ ++ return g_steal_pointer(&svq); ++ ++err_init_hdev_call: ++ event_notifier_cleanup(&svq->hdev_kick); ++ ++err_init_hdev_kick: ++ return NULL; ++} ++ ++/** ++ * Free the resources of the shadow virtqueue. ++ * ++ * @pvq: gpointer to SVQ so it can be used by autofree functions. ++ */ ++void vhost_svq_free(gpointer pvq) ++{ ++ VhostShadowVirtqueue *vq = pvq; ++ event_notifier_cleanup(&vq->hdev_kick); ++ event_notifier_cleanup(&vq->hdev_call); ++ g_free(vq); ++} +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +new file mode 100644 +index 0000000000..f1519e3c7b +--- /dev/null ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -0,0 +1,28 @@ ++/* ++ * vhost shadow virtqueue ++ * ++ * SPDX-FileCopyrightText: Red Hat, Inc. 2021 ++ * SPDX-FileContributor: Author: Eugenio Pérez ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef VHOST_SHADOW_VIRTQUEUE_H ++#define VHOST_SHADOW_VIRTQUEUE_H ++ ++#include "qemu/event_notifier.h" ++ ++/* Shadow virtqueue to relay notifications */ ++typedef struct VhostShadowVirtqueue { ++ /* Shadow kick notifier, sent to vhost */ ++ EventNotifier hdev_kick; ++ /* Shadow call notifier, sent to vhost */ ++ EventNotifier hdev_call; ++} VhostShadowVirtqueue; ++ ++VhostShadowVirtqueue *vhost_svq_new(void); ++ ++void vhost_svq_free(gpointer vq); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); ++ ++#endif +-- +2.27.0 + diff --git a/vhost-Add-svq-avail_handler-callback.patch b/vhost-Add-svq-avail_handler-callback.patch new file mode 100644 index 0000000..b288a39 --- /dev/null +++ b/vhost-Add-svq-avail_handler-callback.patch @@ -0,0 +1,145 @@ +From 14cc79b8bda66ace21616adccf6c2ccd65b7256a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:39 +0200 +Subject: [PATCH] vhost: Add svq avail_handler callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external handlers to be aware of new buffers that the guest +places in the virtqueue. + +When this callback is defined the ownership of the guest's virtqueue +element is transferred to the callback. This means that if the user +wants to forward the descriptor it needs to manually inject it. The +callback is also free to process the command by itself and use the +element with svq_push. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 14 ++++++++++++-- + hw/virtio/vhost-shadow-virtqueue.h | 31 +++++++++++++++++++++++++++++- + hw/virtio/vhost-vdpa.c | 3 ++- + 3 files changed, 44 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index d2676b94e0..ae443f54fe 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -305,7 +305,11 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- r = vhost_svq_add_element(svq, elem); ++ if (svq->ops) { ++ r = svq->ops->avail_handler(svq, elem, svq->ops_opaque); ++ } else { ++ r = vhost_svq_add_element(svq, elem); ++ } + if (unlikely(r != 0)) { + if (r == -ENOSPC) { + /* +@@ -684,12 +688,16 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * shadow methods and file descriptors. + * + * @iova_tree: Tree to perform descriptors translations ++ * @ops: SVQ owner callbacks ++ * @ops_opaque: ops opaque pointer + * + * Returns the new virtqueue or NULL. + * + * In case of error, reason is reported through error_report. + */ +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, ++ const VhostShadowVirtqueueOps *ops, ++ void *ops_opaque) + { + g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + int r; +@@ -711,6 +719,8 @@ VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree) + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->iova_tree = iova_tree; ++ svq->ops = ops; ++ svq->ops_opaque = ops_opaque; + return g_steal_pointer(&svq); + + err_init_hdev_call: +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index cf442f7dea..d04c34a589 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -25,6 +25,27 @@ typedef struct SVQDescState { + unsigned int ndescs; + } SVQDescState; + ++typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; ++ ++/** ++ * Callback to handle an avail buffer. ++ * ++ * @svq: Shadow virtqueue ++ * @elem: Element placed in the queue by the guest ++ * @vq_callback_opaque: Opaque ++ * ++ * Returns 0 if the vq is running as expected. ++ * ++ * Note that ownership of elem is transferred to the callback. ++ */ ++typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, ++ void *vq_callback_opaque); ++ ++typedef struct VhostShadowVirtqueueOps { ++ VirtQueueAvailCallback avail_handler; ++} VhostShadowVirtqueueOps; ++ + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { + /* Shadow vring */ +@@ -69,6 +90,12 @@ typedef struct VhostShadowVirtqueue { + */ + uint16_t *desc_next; + ++ /* Caller callbacks */ ++ const VhostShadowVirtqueueOps *ops; ++ ++ /* Caller callbacks opaque */ ++ void *ops_opaque; ++ + /* Next head to expose to the device */ + uint16_t shadow_avail_idx; + +@@ -102,7 +129,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree); ++VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, ++ const VhostShadowVirtqueueOps *ops, ++ void *ops_opaque); + + void vhost_svq_free(gpointer vq); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 73ff599f2b..a8d42655f0 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -420,8 +420,9 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree); ++ g_autoptr(VhostShadowVirtqueue) svq; + ++ svq = vhost_svq_new(v->iova_tree, NULL, NULL); + if (unlikely(!svq)) { + error_setg(errp, "Cannot create svq %u", n); + return -1; +-- +2.27.0 + diff --git a/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch b/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch new file mode 100644 index 0000000..53bb3be --- /dev/null +++ b/vhost-Add-vhost_svq_valid_features-to-shadow-vq.patch @@ -0,0 +1,133 @@ +From 2f41ff8e23ed358890fb66b6f524627a9747cc14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:44 +0100 +Subject: [PATCH] vhost: Add vhost_svq_valid_features to shadow vq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows SVQ to negotiate features with the guest and the device. For +the device, SVQ is a driver. While this function bypasses all +non-transport features, it needs to disable the features that SVQ does +not support when forwarding buffers. This includes packed vq layout, +indirect descriptors or event idx. + +Future changes can add support to offer more features to the guest, +since the use of VirtQueue gives this for free. This is left out at the +moment for simplicity. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 44 ++++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 2 ++ + hw/virtio/vhost-vdpa.c | 15 ++++++++++ + 3 files changed, 61 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 55cb5414ef..519328445c 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -11,9 +11,53 @@ + #include "hw/virtio/vhost-shadow-virtqueue.h" + + #include "qemu/error-report.h" ++#include "qapi/error.h" + #include "qemu/main-loop.h" + #include "linux-headers/linux/vhost.h" + ++/** ++ * Validate the transport device features that both guests can use with the SVQ ++ * and SVQs can use with the device. ++ * ++ * @dev_features: The features ++ * @errp: Error pointer ++ */ ++bool vhost_svq_valid_features(uint64_t features, Error **errp) ++{ ++ bool ok = true; ++ uint64_t svq_features = features; ++ ++ for (uint64_t b = VIRTIO_TRANSPORT_F_START; b <= VIRTIO_TRANSPORT_F_END; ++ ++b) { ++ switch (b) { ++ case VIRTIO_F_ANY_LAYOUT: ++ continue; ++ ++ case VIRTIO_F_ACCESS_PLATFORM: ++ /* SVQ trust in the host's IOMMU to translate addresses */ ++ case VIRTIO_F_VERSION_1: ++ /* SVQ trust that the guest vring is little endian */ ++ if (!(svq_features & BIT_ULL(b))) { ++ svq_features |= BIT_ULL(b); ++ ok = false; ++ } ++ continue; ++ ++ default: ++ if (svq_features & BIT_ULL(b)) { ++ svq_features &= ~BIT_ULL(b); ++ ok = false; ++ } ++ } ++ } ++ ++ if (!ok) { ++ error_setg(errp, "SVQ Invalid device feature flags, offer: 0x%"PRIx64 ++ ", ok: 0x%"PRIx64, features, svq_features); ++ } ++ return ok; ++} ++ + /** + * Forward guest notifications. + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index cbc5213579..9e12f77201 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -33,6 +33,8 @@ typedef struct VhostShadowVirtqueue { + EventNotifier svq_call; + } VhostShadowVirtqueue; + ++bool vhost_svq_valid_features(uint64_t features, Error **errp); ++ + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 29c720308f..8ee63933a8 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -350,11 +350,26 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + Error **errp) + { + g_autoptr(GPtrArray) shadow_vqs = NULL; ++ uint64_t dev_features, svq_features; ++ int r; ++ bool ok; + + if (!v->shadow_vqs_enabled) { + return 0; + } + ++ r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Can't get vdpa device features"); ++ return r; ++ } ++ ++ svq_features = dev_features; ++ ok = vhost_svq_valid_features(svq_features, errp); ++ if (unlikely(!ok)) { ++ return -1; ++ } ++ + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { + g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(); +-- +2.27.0 + diff --git a/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch b/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch new file mode 100644 index 0000000..e013942 --- /dev/null +++ b/vhost-Always-store-new-kick-fd-on-vhost_svq_set_svq_.patch @@ -0,0 +1,57 @@ +From 42cdf9d4b5c4ec0a6fbbebd79c21e5c39d831a48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:20:07 +0200 +Subject: [PATCH] vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We can unbind twice a file descriptor if we call twice +vhost_svq_set_svq_kick_fd because of this. Since it comes from vhost and +not from SVQ, that file descriptor could be a different thing that +guest's vhost notifier. + +Likewise, it can happens the same if a guest start and stop the device +multiple times. + +Reported-by: Lei Yang +Fixes: dff4426fa6 ("vhost: Add Shadow VirtQueue kick forwarding capabilities") +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 47e831667c..1ea7b5cf59 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -601,13 +601,13 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + event_notifier_set_handler(svq_kick, NULL); + } + ++ event_notifier_init_fd(svq_kick, svq_kick_fd); + /* + * event_notifier_set_handler already checks for guest's notifications if + * they arrive at the new file descriptor in the switch, so there is no + * need to explicitly check for them. + */ + if (poll_start) { +- event_notifier_init_fd(svq_kick, svq_kick_fd); + event_notifier_set(svq_kick); + event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier); + } +@@ -655,7 +655,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + */ + void vhost_svq_stop(VhostShadowVirtqueue *svq) + { +- event_notifier_set_handler(&svq->svq_kick, NULL); ++ vhost_svq_set_svq_kick_fd(svq, VHOST_FILE_UNBIND); + g_autofree VirtQueueElement *next_avail_elem = NULL; + + if (!svq->vq) { +-- +2.27.0 + diff --git a/vhost-Check-for-queue-full-at-vhost_svq_add.patch b/vhost-Check-for-queue-full-at-vhost_svq_add.patch new file mode 100644 index 0000000..98f4f8e --- /dev/null +++ b/vhost-Check-for-queue-full-at-vhost_svq_add.patch @@ -0,0 +1,115 @@ +From 53e6a3ff0ad77689e8cfb79b2e97ca30058949a9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:32 +0200 +Subject: [PATCH] vhost: Check for queue full at vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The series need to expose vhost_svq_add with full functionality, +including checking for full queue. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 59 +++++++++++++++++------------- + 1 file changed, 33 insertions(+), 26 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index b99630acee..7104004a81 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -232,21 +232,29 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * Add an element to a SVQ. + * + * The caller must check that there is enough slots for the new element. It +- * takes ownership of the element: In case of failure, it is free and the SVQ +- * is considered broken. ++ * takes ownership of the element: In case of failure not ENOSPC, it is free. ++ * ++ * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + { + unsigned qemu_head; +- bool ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ unsigned ndescs = elem->in_num + elem->out_num; ++ bool ok; ++ ++ if (unlikely(ndescs > vhost_svq_available_slots(svq))) { ++ return -ENOSPC; ++ } ++ ++ ok = vhost_svq_add_split(svq, elem, &qemu_head); + if (unlikely(!ok)) { + g_free(elem); +- return false; ++ return -EINVAL; + } + + svq->ring_id_maps[qemu_head] = elem; + vhost_svq_kick(svq); +- return true; ++ return 0; + } + + /** +@@ -273,7 +281,7 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + + while (true) { + VirtQueueElement *elem; +- bool ok; ++ int r; + + if (svq->next_guest_avail_elem) { + elem = g_steal_pointer(&svq->next_guest_avail_elem); +@@ -285,25 +293,24 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) { +- /* +- * This condition is possible since a contiguous buffer in GPA +- * does not imply a contiguous buffer in qemu's VA +- * scatter-gather segments. If that happens, the buffer exposed +- * to the device needs to be a chain of descriptors at this +- * moment. +- * +- * SVQ cannot hold more available buffers if we are here: +- * queue the current guest descriptor and ignore further kicks +- * until some elements are used. +- */ +- svq->next_guest_avail_elem = elem; +- return; +- } +- +- ok = vhost_svq_add(svq, elem); +- if (unlikely(!ok)) { +- /* VQ is broken, just return and ignore any other kicks */ ++ r = vhost_svq_add(svq, elem); ++ if (unlikely(r != 0)) { ++ if (r == -ENOSPC) { ++ /* ++ * This condition is possible since a contiguous buffer in ++ * GPA does not imply a contiguous buffer in qemu's VA ++ * scatter-gather segments. If that happens, the buffer ++ * exposed to the device needs to be a chain of descriptors ++ * at this moment. ++ * ++ * SVQ cannot hold more available buffers if we are here: ++ * queue the current guest descriptor and ignore kicks ++ * until some elements are used. ++ */ ++ svq->next_guest_avail_elem = elem; ++ } ++ ++ /* VQ is full or broken, just return and ignore kicks */ + return; + } + } +-- +2.27.0 + diff --git a/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch b/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch new file mode 100644 index 0000000..298fe6a --- /dev/null +++ b/vhost-Decouple-vhost_svq_add-from-VirtQueueElement.patch @@ -0,0 +1,119 @@ +From 1f484df7fb48cdf24e619118ddf67b8cd4e02231 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:33 +0200 +Subject: [PATCH] vhost: Decouple vhost_svq_add from VirtQueueElement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +VirtQueueElement comes from the guest, but we're heading SVQ to be able +to modify the element presented to the device without the guest's +knowledge. + +To do so, make SVQ accept sg buffers directly, instead of using +VirtQueueElement. + +Add vhost_svq_add_element to maintain element convenience. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 33 ++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 7104004a81..00f5ccddfb 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -171,30 +171,31 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +- VirtQueueElement *elem, unsigned *head) ++ const struct iovec *out_sg, size_t out_num, ++ const struct iovec *in_sg, size_t in_num, ++ unsigned *head) + { + unsigned avail_idx; + vring_avail_t *avail = svq->vring.avail; + bool ok; +- g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num)); ++ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(out_num, in_num)); + + *head = svq->free_head; + + /* We need some descriptors here */ +- if (unlikely(!elem->out_num && !elem->in_num)) { ++ if (unlikely(!out_num && !in_num)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Guest provided element with no descriptors"); + return false; + } + +- ok = vhost_svq_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, +- elem->in_num > 0, false); ++ ok = vhost_svq_vring_write_descs(svq, sgs, out_sg, out_num, in_num > 0, ++ false); + if (unlikely(!ok)) { + return false; + } + +- ok = vhost_svq_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, +- true); ++ ok = vhost_svq_vring_write_descs(svq, sgs, in_sg, in_num, false, true); + if (unlikely(!ok)) { + return false; + } +@@ -236,17 +237,19 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * + * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, ++ size_t in_num, VirtQueueElement *elem) + { + unsigned qemu_head; +- unsigned ndescs = elem->in_num + elem->out_num; ++ unsigned ndescs = in_num + out_num; + bool ok; + + if (unlikely(ndescs > vhost_svq_available_slots(svq))) { + return -ENOSPC; + } + +- ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head); + if (unlikely(!ok)) { + g_free(elem); + return -EINVAL; +@@ -257,6 +260,14 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + return 0; + } + ++/* Convenience wrapper to add a guest's element to SVQ */ ++static int vhost_svq_add_element(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem) ++{ ++ return vhost_svq_add(svq, elem->out_sg, elem->out_num, elem->in_sg, ++ elem->in_num, elem); ++} ++ + /** + * Forward available buffers. + * +@@ -293,7 +304,7 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + break; + } + +- r = vhost_svq_add(svq, elem); ++ r = vhost_svq_add_element(svq, elem); + if (unlikely(r != 0)) { + if (r == -ENOSPC) { + /* +-- +2.27.0 + diff --git a/vhost-Expose-vhost_svq_add.patch b/vhost-Expose-vhost_svq_add.patch new file mode 100644 index 0000000..d514ec4 --- /dev/null +++ b/vhost-Expose-vhost_svq_add.patch @@ -0,0 +1,54 @@ +From 9e4727140479522c62070069d552b378c73864f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:37 +0200 +Subject: [PATCH] vhost: Expose vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external parts of SVQ to forward custom buffers to the +device. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 6 +++--- + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 3b5d3bd3f3..5a85365478 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -237,9 +237,9 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + * + * Return -EINVAL if element is invalid, -ENOSPC if dev queue is full + */ +-static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, +- size_t out_num, const struct iovec *in_sg, +- size_t in_num, VirtQueueElement *elem) ++int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, size_t in_num, ++ VirtQueueElement *elem) + { + unsigned qemu_head; + unsigned ndescs = in_num + out_num; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d9fc1f1799..dd78f4bec2 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -86,6 +86,9 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp); + + void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + const VirtQueueElement *elem, uint32_t len); ++int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, ++ size_t out_num, const struct iovec *in_sg, size_t in_num, ++ VirtQueueElement *elem); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); +-- +2.27.0 + diff --git a/vhost-Fix-device-s-used-descriptor-dequeue.patch b/vhost-Fix-device-s-used-descriptor-dequeue.patch new file mode 100644 index 0000000..f1f751e --- /dev/null +++ b/vhost-Fix-device-s-used-descriptor-dequeue.patch @@ -0,0 +1,64 @@ +From a704fb13777c6820cb8a451dbe0b082f6840f9ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:43 +0200 +Subject: [PATCH] vhost: Fix device's used descriptor dequeue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only the first one of them were properly enqueued back. + +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-3-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 6057a437df..0b394694de 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -333,12 +333,22 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) + svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + } + ++static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq, ++ uint16_t num, uint16_t i) ++{ ++ for (uint16_t j = 0; j < (num - 1); ++j) { ++ i = le16_to_cpu(svq->desc_next[i]); ++ } ++ ++ return i; ++} ++ + static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + uint32_t *len) + { + const vring_used_t *used = svq->vring.used; + vring_used_elem_t used_elem; +- uint16_t last_used; ++ uint16_t last_used, last_used_chain, num; + + if (!vhost_svq_more_used(svq)) { + return NULL; +@@ -364,7 +374,10 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- svq->desc_next[used_elem.id] = svq->free_head; ++ num = svq->ring_id_maps[used_elem.id]->in_num + ++ svq->ring_id_maps[used_elem.id]->out_num; ++ last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); ++ svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +-- +2.27.0 + diff --git a/vhost-Fix-element-in-vhost_svq_add-failure.patch b/vhost-Fix-element-in-vhost_svq_add-failure.patch new file mode 100644 index 0000000..bad4669 --- /dev/null +++ b/vhost-Fix-element-in-vhost_svq_add-failure.patch @@ -0,0 +1,49 @@ +From 3f2c58f4a5abda763c2d4627c7da252ecf604bbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:47 +0200 +Subject: [PATCH] vhost: Fix element in vhost_svq_add failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Coverity rightly reports that is not free in that case. + +Fixes: Coverity CID 1487559 +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-7-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 0b394694de..cea2c3f8dd 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -198,11 +198,19 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return true; + } + ++/** ++ * Add an element to a SVQ. ++ * ++ * The caller must check that there is enough slots for the new element. It ++ * takes ownership of the element: In case of failure, it is free and the SVQ ++ * is considered broken. ++ */ + static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + { + unsigned qemu_head; + bool ok = vhost_svq_add_split(svq, elem, &qemu_head); + if (unlikely(!ok)) { ++ g_free(elem); + return false; + } + +-- +2.27.0 + diff --git a/vhost-Fix-false-positive-out-of-bounds.patch b/vhost-Fix-false-positive-out-of-bounds.patch new file mode 100644 index 0000000..1a6687e --- /dev/null +++ b/vhost-Fix-false-positive-out-of-bounds.patch @@ -0,0 +1,49 @@ +From 9c38d583be2704d7cb5a40e25c9ba0227cbe70cd Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Fri, 7 Jul 2023 23:27:31 +0800 +Subject: [PATCH] vhost: Fix false positive out-of-bounds + +QEMU uses vhost_svq_translate_addr() to translate addresses +between the QEMU's virtual address and the SVQ IOVA. In order +to validate this translation, QEMU checks whether the translated +range falls within the mapped range. + +Yet the problem is that, the value of `needle_last`, which is calculated +by `needle.translated_addr + iovec[i].iov_len`, should represent the +exclusive boundary of the translated range, rather than the last +inclusive addresses of the range. Consequently, QEMU fails the check +when the translated range matches the size of the mapped range. + +This patch solves this problem by fixing the `needle_last` value to +the last inclusive address of the translated range. + +Note that this bug cannot be triggered at the moment, because QEMU +is unable to translate such a big range due to the truncation of +the CVQ command in vhost_vdpa_net_handle_ctrl_avail(). + +Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ") +Signed-off-by: Hawkins Jiawei +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 8d99edb196..8b5902a8a5 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -109,7 +109,7 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, + addrs[i] = map->iova + off; + + needle_last = int128_add(int128_make64(needle.translated_addr), +- int128_make64(iovec[i].iov_len)); ++ int128_makes64(iovec[i].iov_len - 1)); + map_last = int128_make64(map->translated_addr + map->size); + if (unlikely(int128_gt(needle_last, map_last))) { + qemu_log_mask(LOG_GUEST_ERROR, +-- +2.27.0 + diff --git a/vhost-Get-vring-base-from-vq-not-svq.patch b/vhost-Get-vring-base-from-vq-not-svq.patch new file mode 100644 index 0000000..d388ff1 --- /dev/null +++ b/vhost-Get-vring-base-from-vq-not-svq.patch @@ -0,0 +1,78 @@ +From a11196160aaf5ba1102ba324c5a7926e83548f6b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 18 Jul 2022 14:05:45 +0200 +Subject: [PATCH] vhost: Get vring base from vq, not svq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SVQ vring used idx usually match with the guest visible one, as long +as all the guest buffers (GPA) maps to exactly one buffer within qemu's +VA. However, as we can see in virtqueue_map_desc, a single guest buffer +could map to many buffers in SVQ vring. + +Also, its also a mistake to rewind them at the source of migration. +Since VirtQueue is able to migrate the inflight descriptors, its +responsability of the destination to perform the rewind just in case it +cannot report the inflight descriptors to the device. + +This makes easier to migrate between backends or to recover them in +vhost devices that support set in flight descriptors. + +Fixes: 6d0b22266633 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") +Signed-off-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 5956ff4660..6304f174c2 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -1181,7 +1181,18 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; ++ VirtQueue *vq = virtio_get_queue(dev->vdev, ring->index); + ++ /* ++ * vhost-vdpa devices does not support in-flight requests. Set all of them ++ * as available. ++ * ++ * TODO: This is ok for networking, but other kinds of devices might ++ * have problems with these retransmissions. ++ */ ++ while (virtqueue_rewind(vq, 1)) { ++ continue; ++ } + if (v->shadow_vqs_enabled) { + /* + * Device vring base was set at device start. SVQ base is handled by +@@ -1197,21 +1208,10 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { + struct vhost_vdpa *v = dev->opaque; +- int vdpa_idx = ring->index - dev->vq_index; + int ret; + + if (v->shadow_vqs_enabled) { +- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); +- +- /* +- * Setting base as last used idx, so destination will see as available +- * all the entries that the device did not use, including the in-flight +- * processing ones. +- * +- * TODO: This is ok for networking, but other kinds of devices might +- * have problems with these retransmissions. +- */ +- ring->num = svq->last_used_idx; ++ ring->num = virtio_queue_get_last_avail_idx(dev->vdev, ring->index); + return 0; + } + +-- +2.27.0 + diff --git a/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch b/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch new file mode 100644 index 0000000..5636e94 --- /dev/null +++ b/vhost-Move-vhost_svq_kick-call-to-vhost_svq_add.patch @@ -0,0 +1,42 @@ +From ebce19945a9bbe3144affa6f5f4129b914e749a0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:31 +0200 +Subject: [PATCH] vhost: Move vhost_svq_kick call to vhost_svq_add +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The series needs to expose vhost_svq_add with full functionality, +including kick + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 1ba863b802..b99630acee 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -245,6 +245,7 @@ static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + } + + svq->ring_id_maps[qemu_head] = elem; ++ vhost_svq_kick(svq); + return true; + } + +@@ -305,7 +306,6 @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) + /* VQ is broken, just return and ignore any other kicks */ + return; + } +- vhost_svq_kick(svq); + } + + virtio_queue_set_notification(svq->vq, true); +-- +2.27.0 + diff --git a/vhost-Reorder-vhost_svq_kick.patch b/vhost-Reorder-vhost_svq_kick.patch new file mode 100644 index 0000000..459e354 --- /dev/null +++ b/vhost-Reorder-vhost_svq_kick.patch @@ -0,0 +1,69 @@ +From 5bf30b401a5fa16189589381d42bfc5f6cf8cf9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:30 +0200 +Subject: [PATCH] vhost: Reorder vhost_svq_kick +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Future code needs to call it from vhost_svq_add. + +No functional change intended. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index acf50a9a0b..1ba863b802 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -214,6 +214,20 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return true; + } + ++static void vhost_svq_kick(VhostShadowVirtqueue *svq) ++{ ++ /* ++ * We need to expose the available array entries before checking the used ++ * flags ++ */ ++ smp_mb(); ++ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { ++ return; ++ } ++ ++ event_notifier_set(&svq->hdev_kick); ++} ++ + /** + * Add an element to a SVQ. + * +@@ -234,20 +248,6 @@ static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) + return true; + } + +-static void vhost_svq_kick(VhostShadowVirtqueue *svq) +-{ +- /* +- * We need to expose the available array entries before checking the used +- * flags +- */ +- smp_mb(); +- if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { +- return; +- } +- +- event_notifier_set(&svq->hdev_kick); +-} +- + /** + * Forward available buffers. + * +-- +2.27.0 + diff --git a/vhost-Shadow-virtqueue-buffers-forwarding.patch b/vhost-Shadow-virtqueue-buffers-forwarding.patch new file mode 100644 index 0000000..5d38f7a --- /dev/null +++ b/vhost-Shadow-virtqueue-buffers-forwarding.patch @@ -0,0 +1,684 @@ +From bb7c23fd4979edaeeedf05e05cfed0d086430500 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:47 +0100 +Subject: [PATCH] vhost: Shadow virtqueue buffers forwarding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Initial version of shadow virtqueue that actually forward buffers. There +is no iommu support at the moment, and that will be addressed in future +patches of this series. Since all vhost-vdpa devices use forced IOMMU, +this means that SVQ is not usable at this point of the series on any +device. + +For simplicity it only supports modern devices, that expects vring +in little endian, with split ring and no event idx or indirect +descriptors. Support for them will not be added in this series. + +It reuses the VirtQueue code for the device part. The driver part is +based on Linux's virtio_ring driver, but with stripped functionality +and optimizations so it's easier to review. + +However, forwarding buffers have some particular pieces: One of the most +unexpected ones is that a guest's buffer can expand through more than +one descriptor in SVQ. While this is handled gracefully by qemu's +emulated virtio devices, it may cause unexpected SVQ queue full. This +patch also solves it by checking for this condition at both guest's +kicks and device's calls. The code may be more elegant in the future if +SVQ code runs in its own iocontext. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 351 ++++++++++++++++++++++++++++- + hw/virtio/vhost-shadow-virtqueue.h | 26 +++ + hw/virtio/vhost-vdpa.c | 155 ++++++++++++- + 3 files changed, 521 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 573ac0d9cf..46e94f0861 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -13,6 +13,7 @@ + #include "qemu/error-report.h" + #include "qapi/error.h" + #include "qemu/main-loop.h" ++#include "qemu/log.h" + #include "linux-headers/linux/vhost.h" + + /** +@@ -59,28 +60,307 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) + } + + /** +- * Forward guest notifications. ++ * Number of descriptors that the SVQ can make available from the guest. ++ * ++ * @svq: The svq ++ */ ++static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) ++{ ++ return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); ++} ++ ++static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, ++ const struct iovec *iovec, size_t num, ++ bool more_descs, bool write) ++{ ++ uint16_t i = svq->free_head, last = svq->free_head; ++ unsigned n; ++ uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0; ++ vring_desc_t *descs = svq->vring.desc; ++ ++ if (num == 0) { ++ return; ++ } ++ ++ for (n = 0; n < num; n++) { ++ if (more_descs || (n + 1 < num)) { ++ descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); ++ } else { ++ descs[i].flags = flags; ++ } ++ descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base); ++ descs[i].len = cpu_to_le32(iovec[n].iov_len); ++ ++ last = i; ++ i = cpu_to_le16(descs[i].next); ++ } ++ ++ svq->free_head = le16_to_cpu(descs[last].next); ++} ++ ++static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, ++ VirtQueueElement *elem, unsigned *head) ++{ ++ unsigned avail_idx; ++ vring_avail_t *avail = svq->vring.avail; ++ ++ *head = svq->free_head; ++ ++ /* We need some descriptors here */ ++ if (unlikely(!elem->out_num && !elem->in_num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Guest provided element with no descriptors"); ++ return false; ++ } ++ ++ vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0, ++ false); ++ vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true); ++ ++ /* ++ * Put the entry in the available array (but don't update avail->idx until ++ * they do sync). ++ */ ++ avail_idx = svq->shadow_avail_idx & (svq->vring.num - 1); ++ avail->ring[avail_idx] = cpu_to_le16(*head); ++ svq->shadow_avail_idx++; ++ ++ /* Update the avail index after write the descriptor */ ++ smp_wmb(); ++ avail->idx = cpu_to_le16(svq->shadow_avail_idx); ++ ++ return true; ++} ++ ++static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem) ++{ ++ unsigned qemu_head; ++ bool ok = vhost_svq_add_split(svq, elem, &qemu_head); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ svq->ring_id_maps[qemu_head] = elem; ++ return true; ++} ++ ++static void vhost_svq_kick(VhostShadowVirtqueue *svq) ++{ ++ /* ++ * We need to expose the available array entries before checking the used ++ * flags ++ */ ++ smp_mb(); ++ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) { ++ return; ++ } ++ ++ event_notifier_set(&svq->hdev_kick); ++} ++ ++/** ++ * Forward available buffers. ++ * ++ * @svq: Shadow VirtQueue ++ * ++ * Note that this function does not guarantee that all guest's available ++ * buffers are available to the device in SVQ avail ring. The guest may have ++ * exposed a GPA / GIOVA contiguous buffer, but it may not be contiguous in ++ * qemu vaddr. ++ * ++ * If that happens, guest's kick notifications will be disabled until the ++ * device uses some buffers. ++ */ ++static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq) ++{ ++ /* Clear event notifier */ ++ event_notifier_test_and_clear(&svq->svq_kick); ++ ++ /* Forward to the device as many available buffers as possible */ ++ do { ++ virtio_queue_set_notification(svq->vq, false); ++ ++ while (true) { ++ VirtQueueElement *elem; ++ bool ok; ++ ++ if (svq->next_guest_avail_elem) { ++ elem = g_steal_pointer(&svq->next_guest_avail_elem); ++ } else { ++ elem = virtqueue_pop(svq->vq, sizeof(*elem)); ++ } ++ ++ if (!elem) { ++ break; ++ } ++ ++ if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) { ++ /* ++ * This condition is possible since a contiguous buffer in GPA ++ * does not imply a contiguous buffer in qemu's VA ++ * scatter-gather segments. If that happens, the buffer exposed ++ * to the device needs to be a chain of descriptors at this ++ * moment. ++ * ++ * SVQ cannot hold more available buffers if we are here: ++ * queue the current guest descriptor and ignore further kicks ++ * until some elements are used. ++ */ ++ svq->next_guest_avail_elem = elem; ++ return; ++ } ++ ++ ok = vhost_svq_add(svq, elem); ++ if (unlikely(!ok)) { ++ /* VQ is broken, just return and ignore any other kicks */ ++ return; ++ } ++ vhost_svq_kick(svq); ++ } ++ ++ virtio_queue_set_notification(svq->vq, true); ++ } while (!virtio_queue_empty(svq->vq)); ++} ++ ++/** ++ * Handle guest's kick. + * + * @n: guest kick event notifier, the one that guest set to notify svq. + */ +-static void vhost_handle_guest_kick(EventNotifier *n) ++static void vhost_handle_guest_kick_notifier(EventNotifier *n) + { + VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick); + event_notifier_test_and_clear(n); +- event_notifier_set(&svq->hdev_kick); ++ vhost_handle_guest_kick(svq); ++} ++ ++static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) ++{ ++ if (svq->last_used_idx != svq->shadow_used_idx) { ++ return true; ++ } ++ ++ svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx); ++ ++ return svq->last_used_idx != svq->shadow_used_idx; + } + + /** +- * Forward vhost notifications ++ * Enable vhost device calls after disable them. ++ * ++ * @svq: The svq ++ * ++ * It returns false if there are pending used buffers from the vhost device, ++ * avoiding the possible races between SVQ checking for more work and enabling ++ * callbacks. True if SVQ used vring has no more pending buffers. ++ */ ++static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq) ++{ ++ svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); ++ /* Make sure the flag is written before the read of used_idx */ ++ smp_mb(); ++ return !vhost_svq_more_used(svq); ++} ++ ++static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) ++{ ++ svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); ++} ++ ++static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, ++ uint32_t *len) ++{ ++ vring_desc_t *descs = svq->vring.desc; ++ const vring_used_t *used = svq->vring.used; ++ vring_used_elem_t used_elem; ++ uint16_t last_used; ++ ++ if (!vhost_svq_more_used(svq)) { ++ return NULL; ++ } ++ ++ /* Only get used array entries after they have been exposed by dev */ ++ smp_rmb(); ++ last_used = svq->last_used_idx & (svq->vring.num - 1); ++ used_elem.id = le32_to_cpu(used->ring[last_used].id); ++ used_elem.len = le32_to_cpu(used->ring[last_used].len); ++ ++ svq->last_used_idx++; ++ if (unlikely(used_elem.id >= svq->vring.num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used", ++ svq->vdev->name, used_elem.id); ++ return NULL; ++ } ++ ++ if (unlikely(!svq->ring_id_maps[used_elem.id])) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "Device %s says index %u is used, but it was not available", ++ svq->vdev->name, used_elem.id); ++ return NULL; ++ } ++ ++ descs[used_elem.id].next = svq->free_head; ++ svq->free_head = used_elem.id; ++ ++ *len = used_elem.len; ++ return g_steal_pointer(&svq->ring_id_maps[used_elem.id]); ++} ++ ++static void vhost_svq_flush(VhostShadowVirtqueue *svq, ++ bool check_for_avail_queue) ++{ ++ VirtQueue *vq = svq->vq; ++ ++ /* Forward as many used buffers as possible. */ ++ do { ++ unsigned i = 0; ++ ++ vhost_svq_disable_notification(svq); ++ while (true) { ++ uint32_t len; ++ g_autofree VirtQueueElement *elem = vhost_svq_get_buf(svq, &len); ++ if (!elem) { ++ break; ++ } ++ ++ if (unlikely(i >= svq->vring.num)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "More than %u used buffers obtained in a %u size SVQ", ++ i, svq->vring.num); ++ virtqueue_fill(vq, elem, len, i); ++ virtqueue_flush(vq, i); ++ return; ++ } ++ virtqueue_fill(vq, elem, len, i++); ++ } ++ ++ virtqueue_flush(vq, i); ++ event_notifier_set(&svq->svq_call); ++ ++ if (check_for_avail_queue && svq->next_guest_avail_elem) { ++ /* ++ * Avail ring was full when vhost_svq_flush was called, so it's a ++ * good moment to make more descriptors available if possible. ++ */ ++ vhost_handle_guest_kick(svq); ++ } ++ } while (!vhost_svq_enable_notification(svq)); ++} ++ ++/** ++ * Forward used buffers. + * + * @n: hdev call event notifier, the one that device set to notify svq. ++ * ++ * Note that we are not making any buffers available in the loop, there is no ++ * way that it runs more than virtqueue size times. + */ + static void vhost_svq_handle_call(EventNotifier *n) + { + VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, + hdev_call); + event_notifier_test_and_clear(n); +- event_notifier_set(&svq->svq_call); ++ vhost_svq_flush(svq, true); + } + + /** +@@ -161,7 +441,41 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + if (poll_start) { + event_notifier_init_fd(svq_kick, svq_kick_fd); + event_notifier_set(svq_kick); +- event_notifier_set_handler(svq_kick, vhost_handle_guest_kick); ++ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier); ++ } ++} ++ ++/** ++ * Start the shadow virtqueue operation. ++ * ++ * @svq: Shadow Virtqueue ++ * @vdev: VirtIO device ++ * @vq: Virtqueue to shadow ++ */ ++void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, ++ VirtQueue *vq) ++{ ++ size_t desc_size, driver_size, device_size; ++ ++ svq->next_guest_avail_elem = NULL; ++ svq->shadow_avail_idx = 0; ++ svq->shadow_used_idx = 0; ++ svq->last_used_idx = 0; ++ svq->vdev = vdev; ++ svq->vq = vq; ++ ++ svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); ++ driver_size = vhost_svq_driver_area_size(svq); ++ device_size = vhost_svq_device_area_size(svq); ++ svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size); ++ desc_size = sizeof(vring_desc_t) * svq->vring.num; ++ svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size); ++ memset(svq->vring.desc, 0, driver_size); ++ svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); ++ memset(svq->vring.used, 0, device_size); ++ svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ for (unsigned i = 0; i < svq->vring.num - 1; i++) { ++ svq->vring.desc[i].next = cpu_to_le16(i + 1); + } + } + +@@ -172,6 +486,31 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + void vhost_svq_stop(VhostShadowVirtqueue *svq) + { + event_notifier_set_handler(&svq->svq_kick, NULL); ++ g_autofree VirtQueueElement *next_avail_elem = NULL; ++ ++ if (!svq->vq) { ++ return; ++ } ++ ++ /* Send all pending used descriptors to guest */ ++ vhost_svq_flush(svq, false); ++ ++ for (unsigned i = 0; i < svq->vring.num; ++i) { ++ g_autofree VirtQueueElement *elem = NULL; ++ elem = g_steal_pointer(&svq->ring_id_maps[i]); ++ if (elem) { ++ virtqueue_detach_element(svq->vq, elem, 0); ++ } ++ } ++ ++ next_avail_elem = g_steal_pointer(&svq->next_guest_avail_elem); ++ if (next_avail_elem) { ++ virtqueue_detach_element(svq->vq, next_avail_elem, 0); ++ } ++ svq->vq = NULL; ++ g_free(svq->ring_id_maps); ++ qemu_vfree(svq->vring.desc); ++ qemu_vfree(svq->vring.used); + } + + /** +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 82cea1c3fa..38b3b91ca7 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -36,6 +36,30 @@ typedef struct VhostShadowVirtqueue { + + /* Guest's call notifier, where the SVQ calls guest. */ + EventNotifier svq_call; ++ ++ /* Virtio queue shadowing */ ++ VirtQueue *vq; ++ ++ /* Virtio device */ ++ VirtIODevice *vdev; ++ ++ /* Map for use the guest's descriptors */ ++ VirtQueueElement **ring_id_maps; ++ ++ /* Next VirtQueue element that guest made available */ ++ VirtQueueElement *next_guest_avail_elem; ++ ++ /* Next head to expose to the device */ ++ uint16_t shadow_avail_idx; ++ ++ /* Next free descriptor */ ++ uint16_t free_head; ++ ++ /* Last seen used idx */ ++ uint16_t shadow_used_idx; ++ ++ /* Next head to consume from the device */ ++ uint16_t last_used_idx; + } VhostShadowVirtqueue; + + bool vhost_svq_valid_features(uint64_t features, Error **errp); +@@ -47,6 +71,8 @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, + size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); + size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + ++void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, ++ VirtQueue *vq); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + + VhostShadowVirtqueue *vhost_svq_new(void); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 2f0e6a9bef..db34f26246 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -779,9 +779,9 @@ static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev, + * Note that this function does not rewind kick file descriptor if cannot set + * call one. + */ +-static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, +- VhostShadowVirtqueue *svq, unsigned idx, +- Error **errp) ++static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) + { + struct vhost_vring_file file = { + .index = dev->vq_index + idx, +@@ -793,7 +793,7 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); +- return false; ++ return r; + } + + event_notifier = &svq->hdev_call; +@@ -803,6 +803,95 @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, + error_setg_errno(errp, -r, "Can't set device call fd"); + } + ++ return r; ++} ++ ++/** ++ * Unmap a SVQ area in the device ++ */ ++static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova, ++ hwaddr size) ++{ ++ int r; ++ ++ size = ROUND_UP(size, qemu_real_host_page_size); ++ r = vhost_vdpa_dma_unmap(v, iova, size); ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev, ++ const VhostShadowVirtqueue *svq) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ struct vhost_vring_addr svq_addr; ++ size_t device_size = vhost_svq_device_area_size(svq); ++ size_t driver_size = vhost_svq_driver_area_size(svq); ++ bool ok; ++ ++ vhost_svq_get_vring_addr(svq, &svq_addr); ++ ++ ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size); ++ if (unlikely(!ok)) { ++ return false; ++ } ++ ++ return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size); ++} ++ ++/** ++ * Map the shadow virtqueue rings in the device ++ * ++ * @dev: The vhost device ++ * @svq: The shadow virtqueue ++ * @addr: Assigned IOVA addresses ++ * @errp: Error pointer ++ */ ++static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev, ++ const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr, ++ Error **errp) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ size_t device_size = vhost_svq_device_area_size(svq); ++ size_t driver_size = vhost_svq_driver_area_size(svq); ++ int r; ++ ++ ERRP_GUARD(); ++ vhost_svq_get_vring_addr(svq, addr); ++ ++ r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size, ++ (void *)(uintptr_t)addr->desc_user_addr, true); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot create vq driver region: "); ++ return false; ++ } ++ ++ r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size, ++ (void *)(intptr_t)addr->used_user_addr, false); ++ if (unlikely(r != 0)) { ++ error_setg_errno(errp, -r, "Cannot create vq device region: "); ++ } ++ ++ return r == 0; ++} ++ ++static bool vhost_vdpa_svq_setup(struct vhost_dev *dev, ++ VhostShadowVirtqueue *svq, unsigned idx, ++ Error **errp) ++{ ++ uint16_t vq_index = dev->vq_index + idx; ++ struct vhost_vring_state s = { ++ .index = vq_index, ++ }; ++ int r; ++ ++ r = vhost_vdpa_set_dev_vring_base(dev, &s); ++ if (unlikely(r)) { ++ error_setg_errno(errp, -r, "Cannot set vring base"); ++ return false; ++ } ++ ++ r = vhost_vdpa_svq_set_fds(dev, svq, idx, errp); + return r == 0; + } + +@@ -817,10 +906,62 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + } + + for (i = 0; i < v->shadow_vqs->len; ++i) { ++ VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i); + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ struct vhost_vring_addr addr = { ++ .index = i, ++ }; ++ int r; + bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err); + if (unlikely(!ok)) { +- error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ goto err; ++ } ++ ++ vhost_svq_start(svq, dev->vdev, vq); ++ ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err); ++ if (unlikely(!ok)) { ++ goto err_map; ++ } ++ ++ /* Override vring GPA set by vhost subsystem */ ++ r = vhost_vdpa_set_vring_dev_addr(dev, &addr); ++ if (unlikely(r != 0)) { ++ error_setg_errno(&err, -r, "Cannot set device address"); ++ goto err_set_addr; ++ } ++ } ++ ++ return true; ++ ++err_set_addr: ++ vhost_vdpa_svq_unmap_rings(dev, g_ptr_array_index(v->shadow_vqs, i)); ++ ++err_map: ++ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, i)); ++ ++err: ++ error_reportf_err(err, "Cannot setup SVQ %u: ", i); ++ for (unsigned j = 0; j < i; ++j) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, j); ++ vhost_vdpa_svq_unmap_rings(dev, svq); ++ vhost_svq_stop(svq); ++ } ++ ++ return false; ++} ++ ++static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev) ++{ ++ struct vhost_vdpa *v = dev->opaque; ++ ++ if (!v->shadow_vqs) { ++ return true; ++ } ++ ++ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { ++ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); ++ bool ok = vhost_vdpa_svq_unmap_rings(dev, svq); ++ if (unlikely(!ok)) { + return false; + } + } +@@ -842,6 +983,10 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + vhost_vdpa_set_vring_ready(dev); + } else { ++ ok = vhost_vdpa_svqs_stop(dev); ++ if (unlikely(!ok)) { ++ return -1; ++ } + vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs); + } + +-- +2.27.0 + diff --git a/vhost-Track-descriptor-chain-in-private-at-SVQ.patch b/vhost-Track-descriptor-chain-in-private-at-SVQ.patch new file mode 100644 index 0000000..dbcdb74 --- /dev/null +++ b/vhost-Track-descriptor-chain-in-private-at-SVQ.patch @@ -0,0 +1,104 @@ +From de3c31598e00c4bcee42f3921f714b0928716535 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 12 May 2022 19:57:42 +0200 +Subject: [PATCH] vhost: Track descriptor chain in private at SVQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The device could have access to modify them, and it definitely have +access when we implement packed vq. Harden SVQ maintaining a private +copy of the descriptor chain. Other fields like buffer addresses are +already maintained sepparatedly. + +Signed-off-by: Eugenio Pérez +Message-Id: <20220512175747.142058-2-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 12 +++++++----- + hw/virtio/vhost-shadow-virtqueue.h | 6 ++++++ + 2 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c38b6b6ab5..6057a437df 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -137,6 +137,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + for (n = 0; n < num; n++) { + if (more_descs || (n + 1 < num)) { + descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT); ++ descs[i].next = cpu_to_le16(svq->desc_next[i]); + } else { + descs[i].flags = flags; + } +@@ -144,10 +145,10 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + descs[i].len = cpu_to_le32(iovec[n].iov_len); + + last = i; +- i = cpu_to_le16(descs[i].next); ++ i = cpu_to_le16(svq->desc_next[i]); + } + +- svq->free_head = le16_to_cpu(descs[last].next); ++ svq->free_head = le16_to_cpu(svq->desc_next[last]); + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +@@ -335,7 +336,6 @@ static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq) + static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + uint32_t *len) + { +- vring_desc_t *descs = svq->vring.desc; + const vring_used_t *used = svq->vring.used; + vring_used_elem_t used_elem; + uint16_t last_used; +@@ -364,7 +364,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- descs[used_elem.id].next = svq->free_head; ++ svq->desc_next[used_elem.id] = svq->free_head; + svq->free_head = used_elem.id; + + *len = used_elem.len; +@@ -539,8 +539,9 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size); + memset(svq->vring.used, 0, device_size); + svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num); ++ svq->desc_next = g_new0(uint16_t, svq->vring.num); + for (unsigned i = 0; i < svq->vring.num - 1; i++) { +- svq->vring.desc[i].next = cpu_to_le16(i + 1); ++ svq->desc_next[i] = cpu_to_le16(i + 1); + } + } + +@@ -573,6 +574,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + virtqueue_detach_element(svq->vq, next_avail_elem, 0); + } + svq->vq = NULL; ++ g_free(svq->desc_next); + g_free(svq->ring_id_maps); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index e5e24c536d..c132c994e9 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -53,6 +53,12 @@ typedef struct VhostShadowVirtqueue { + /* Next VirtQueue element that guest made available */ + VirtQueueElement *next_guest_avail_elem; + ++ /* ++ * Backup next field for each descriptor so we can recover securely, not ++ * needing to trust the device access. ++ */ ++ uint16_t *desc_next; ++ + /* Next head to expose to the device */ + uint16_t shadow_avail_idx; + +-- +2.27.0 + diff --git a/vhost-Track-number-of-descs-in-SVQDescState.patch b/vhost-Track-number-of-descs-in-SVQDescState.patch new file mode 100644 index 0000000..1c24789 --- /dev/null +++ b/vhost-Track-number-of-descs-in-SVQDescState.patch @@ -0,0 +1,62 @@ +From d76e2c5a5213d51dd8c48315e26c277423ade99f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:35 +0200 +Subject: [PATCH] vhost: Track number of descs in SVQDescState +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A guest's buffer continuos on GPA may need multiple descriptors on +qemu's VA, so SVQ should track its length sepparatedly. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + hw/virtio/vhost-shadow-virtqueue.h | 6 ++++++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 5ddc04e9d6..c10c74b91f 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -256,6 +256,7 @@ static int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + } + + svq->desc_state[qemu_head].elem = elem; ++ svq->desc_state[qemu_head].ndescs = ndescs; + vhost_svq_kick(svq); + return 0; + } +@@ -417,8 +418,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return NULL; + } + +- num = svq->desc_state[used_elem.id].elem->in_num + +- svq->desc_state[used_elem.id].elem->out_num; ++ num = svq->desc_state[used_elem.id].ndescs; + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d646c35054..5c7e7cbab6 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -17,6 +17,12 @@ + + typedef struct SVQDescState { + VirtQueueElement *elem; ++ ++ /* ++ * Number of descriptors exposed to the device. May or may not match ++ * guest's ++ */ ++ unsigned int ndescs; + } SVQDescState; + + /* Shadow virtqueue to relay notifications */ +-- +2.27.0 + diff --git a/vhost-add-support-for-configure-interrupt-new.patch b/vhost-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000..0be96f2 --- /dev/null +++ b/vhost-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,172 @@ +From 59957a4caee59e0c82b8d02ed1c1820db523ae64 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:48 +0800 +Subject: [PATCH] vhost: add support for configure interrupt + +Add functions to support configure interrupt. +The configure interrupt process will start in vhost_dev_start +and stop in vhost_dev_stop. + +Also add the functions to support vhost_config_pending and +vhost_config_mask. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-8-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 78 ++++++++++++++++++++++++++++++++++++++- + include/hw/virtio/vhost.h | 4 ++ + 2 files changed, 81 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 19ea9aef69..490c97424b 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1627,7 +1627,68 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); + r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); + if (r < 0) { +- VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); ++ error_report("vhost_set_vring_call failed %d", -r); ++ } ++} ++ ++bool vhost_config_pending(struct vhost_dev *hdev) ++{ ++ assert(hdev->vhost_ops); ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return false; ++ } ++ ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ return event_notifier_test_and_clear(notifier); ++} ++ ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) ++{ ++ int fd; ++ int r; ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ EventNotifier *config_notifier = &vdev->config_notifier; ++ assert(hdev->vhost_ops); ++ ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return; ++ } ++ if (mask) { ++ assert(vdev->use_guest_notifier_mask); ++ fd = event_notifier_get_fd(notifier); ++ } else { ++ fd = event_notifier_get_fd(config_notifier); ++ } ++ r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); ++ if (r < 0) { ++ error_report("vhost_set_config_call failed %d", -r); ++ } ++} ++ ++static void vhost_stop_config_intr(struct vhost_dev *dev) ++{ ++ int fd = -1; ++ assert(dev->vhost_ops); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ dev->vhost_ops->vhost_set_config_call(dev, fd); ++ } ++} ++ ++static void vhost_start_config_intr(struct vhost_dev *dev) ++{ ++ int r; ++ ++ assert(dev->vhost_ops); ++ int fd = event_notifier_get_fd(&dev->vdev->config_notifier); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ r = dev->vhost_ops->vhost_set_config_call(dev, fd); ++ if (!r) { ++ event_notifier_set(&dev->vdev->config_notifier); ++ } + } + } + +@@ -1867,6 +1928,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + } + } + ++ r = event_notifier_init( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ if (!vdev->use_guest_notifier_mask) { ++ vhost_config_mask(hdev, vdev, true); ++ } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1905,6 +1976,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } ++ vhost_start_config_intr(hdev); + return 0; + fail_start: + if (vrings) { +@@ -1934,6 +2006,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ event_notifier_test_and_clear(&vdev->config_notifier); + + trace_vhost_dev_stop(hdev, vdev->name, vrings); + +@@ -1956,6 +2031,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + } + memory_listener_unregister(&hdev->iommu_listener); + } ++ vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + vdev->vhost_started = false; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 662e0f4370..420f93e5cd 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -32,6 +32,7 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; ++ EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -40,6 +41,7 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) ++#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -163,6 +165,8 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + * Disable direct notifications to vhost device. + */ + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++bool vhost_config_pending(struct vhost_dev *hdev); ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /** + * vhost_dev_start() - start the vhost device +-- +2.27.0 + diff --git a/vhost-add-support-for-configure-interrupt.patch b/vhost-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..d8916c3 --- /dev/null +++ b/vhost-add-support-for-configure-interrupt.patch @@ -0,0 +1,170 @@ +From 9823b7bb536cea50c9750320436511fd60b797cd Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:52 +0800 +Subject: [PATCH] vhost: add support for configure interrupt + +Add functions to support configure interrupt. +The configure interrupt process will start in vhost_dev_start +and stop in vhost_dev_stop. + +Also add the functions to support vhost_config_pending and +vhost_config_mask, for masked_config_notifier, we only +use the notifier saved in vq 0. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-8-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 76 +++++++++++++++++++++++++++++++++++++++ + include/hw/virtio/vhost.h | 4 +++ + 2 files changed, 80 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2d11e3c2f8..c3f375f276 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1588,6 +1588,67 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + } + } + ++bool vhost_config_pending(struct vhost_dev *hdev) ++{ ++ assert(hdev->vhost_ops); ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return false; ++ } ++ ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ return event_notifier_test_and_clear(notifier); ++} ++ ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) ++{ ++ int fd; ++ int r; ++ EventNotifier *notifier = ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier; ++ EventNotifier *config_notifier = &vdev->config_notifier; ++ assert(hdev->vhost_ops); ++ ++ if ((hdev->started == false) || ++ (hdev->vhost_ops->vhost_set_config_call == NULL)) { ++ return; ++ } ++ if (mask) { ++ assert(vdev->use_guest_notifier_mask); ++ fd = event_notifier_get_fd(notifier); ++ } else { ++ fd = event_notifier_get_fd(config_notifier); ++ } ++ r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); ++ if (r < 0) { ++ VHOST_OPS_DEBUG("vhost_set_config_call failed"); ++ } ++} ++ ++static void vhost_stop_config_intr(struct vhost_dev *dev) ++{ ++ int fd = -1; ++ assert(dev->vhost_ops); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ dev->vhost_ops->vhost_set_config_call(dev, fd); ++ } ++} ++ ++static void vhost_start_config_intr(struct vhost_dev *dev) ++{ ++ int r; ++ ++ assert(dev->vhost_ops); ++ int fd = event_notifier_get_fd(&dev->vdev->config_notifier); ++ if (dev->vhost_ops->vhost_set_config_call) { ++ r = dev->vhost_ops->vhost_set_config_call(dev, fd); ++ if (!r) { ++ event_notifier_set(&dev->vdev->config_notifier); ++ } ++ } ++} ++ + uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features) + { +@@ -1800,6 +1861,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + ++ r = event_notifier_init( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ if (!vdev->use_guest_notifier_mask) { ++ vhost_config_mask(hdev, vdev, true); ++ } + if (hdev->log_enabled) { + uint64_t log_base; + +@@ -1833,6 +1904,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + vhost_device_iotlb_miss(hdev, vq->used_phys, true); + } + } ++ vhost_start_config_intr(hdev); + return 0; + fail_log: + vhost_log_put(hdev, false); +@@ -1858,6 +1930,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); ++ event_notifier_test_and_clear( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); ++ event_notifier_test_and_clear(&vdev->config_notifier); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); +@@ -1875,6 +1950,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + memory_listener_unregister(&hdev->iommu_listener); + } ++ vhost_stop_config_intr(hdev); + vhost_log_put(hdev, true); + hdev->started = false; + hdev->vdev = NULL; +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index 86f36f0106..2ae5c3bfd8 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -29,6 +29,7 @@ struct vhost_virtqueue { + unsigned long long used_phys; + unsigned used_size; + EventNotifier masked_notifier; ++ EventNotifier masked_config_notifier; + struct vhost_dev *dev; + }; + +@@ -37,6 +38,7 @@ typedef unsigned long vhost_log_chunk_t; + #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) + #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) + #define VHOST_INVALID_FEATURE_BIT (0xff) ++#define VHOST_QUEUE_NUM_CONFIG_INR 0 + + struct vhost_log { + unsigned long long size; +@@ -116,6 +118,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); + int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); ++bool vhost_config_pending(struct vhost_dev *hdev); ++void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask); + + /* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. +-- +2.27.0 + diff --git a/vhost-add-vhost_svq_poll.patch b/vhost-add-vhost_svq_poll.patch new file mode 100644 index 0000000..90b430a --- /dev/null +++ b/vhost-add-vhost_svq_poll.patch @@ -0,0 +1,73 @@ +From 65869116f29f0c92a394af2308c154c855938923 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:38 +0200 +Subject: [PATCH] vhost: add vhost_svq_poll +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It allows the Shadow Control VirtQueue to wait for the device to use the +available buffers. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 27 +++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 1 + + 2 files changed, 28 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 5a85365478..d2676b94e0 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -484,6 +484,33 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, + } while (!vhost_svq_enable_notification(svq)); + } + ++/** ++ * Poll the SVQ for one device used buffer. ++ * ++ * This function race with main event loop SVQ polling, so extra ++ * synchronization is needed. ++ * ++ * Return the length written by the device. ++ */ ++size_t vhost_svq_poll(VhostShadowVirtqueue *svq) ++{ ++ int64_t start_us = g_get_monotonic_time(); ++ do { ++ uint32_t len; ++ VirtQueueElement *elem = vhost_svq_get_buf(svq, &len); ++ if (elem) { ++ return len; ++ } ++ ++ if (unlikely(g_get_monotonic_time() - start_us > 10e6)) { ++ return 0; ++ } ++ ++ /* Make sure we read new used_idx */ ++ smp_rmb(); ++ } while (true); ++} ++ + /** + * Forward used buffers. + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index dd78f4bec2..cf442f7dea 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -89,6 +89,7 @@ void vhost_svq_push_elem(VhostShadowVirtqueue *svq, + int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + size_t out_num, const struct iovec *in_sg, size_t in_num, + VirtQueueElement *elem); ++size_t vhost_svq_poll(VhostShadowVirtqueue *svq); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); +-- +2.27.0 + diff --git a/vhost-add-vhost_svq_push_elem.patch b/vhost-add-vhost_svq_push_elem.patch new file mode 100644 index 0000000..395d975 --- /dev/null +++ b/vhost-add-vhost_svq_push_elem.patch @@ -0,0 +1,64 @@ +From ac243c5186493f41c9ff0d60558dabb651c56983 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:36 +0200 +Subject: [PATCH] vhost: add vhost_svq_push_elem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function allows external SVQ users to return guest's available +buffers. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 16 ++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 19 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index c10c74b91f..3b5d3bd3f3 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -427,6 +427,22 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + return g_steal_pointer(&svq->desc_state[used_elem.id].elem); + } + ++/** ++ * Push an element to SVQ, returning it to the guest. ++ */ ++void vhost_svq_push_elem(VhostShadowVirtqueue *svq, ++ const VirtQueueElement *elem, uint32_t len) ++{ ++ virtqueue_push(svq->vq, elem, len); ++ if (svq->next_guest_avail_elem) { ++ /* ++ * Avail ring was full when vhost_svq_flush was called, so it's a ++ * good moment to make more descriptors available if possible. ++ */ ++ vhost_handle_guest_kick(svq); ++ } ++} ++ + static void vhost_svq_flush(VhostShadowVirtqueue *svq, + bool check_for_avail_queue) + { +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 5c7e7cbab6..d9fc1f1799 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -84,6 +84,9 @@ typedef struct VhostShadowVirtqueue { + + bool vhost_svq_valid_features(uint64_t features, Error **errp); + ++void vhost_svq_push_elem(VhostShadowVirtqueue *svq, ++ const VirtQueueElement *elem, uint32_t len); ++ + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); + void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, +-- +2.27.0 + diff --git a/vhost-allocate-SVQ-device-file-descriptors-at-device.patch b/vhost-allocate-SVQ-device-file-descriptors-at-device.patch new file mode 100644 index 0000000..5b85e72 --- /dev/null +++ b/vhost-allocate-SVQ-device-file-descriptors-at-device.patch @@ -0,0 +1,162 @@ +From 539c46ecb41417007840c750d364b5332cbdc5b5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:35 +0100 +Subject: [PATCH] vhost: allocate SVQ device file descriptors at device start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next patches will start control SVQ if possible. However, we don't +know if that will be possible at qemu boot anymore. + +Delay device file descriptors until we know it at device start. This +will avoid to create them if the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-4-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 31 ++------------------------ + hw/virtio/vhost-vdpa.c | 35 ++++++++++++++++++++++++------ + 2 files changed, 30 insertions(+), 36 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index bc12bb42f3..47e831667c 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -692,43 +692,18 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * @iova_tree: Tree to perform descriptors translations + * @ops: SVQ owner callbacks + * @ops_opaque: ops opaque pointer +- * +- * Returns the new virtqueue or NULL. +- * +- * In case of error, reason is reported through error_report. + */ + VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, + const VhostShadowVirtqueueOps *ops, + void *ops_opaque) + { +- g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); +- int r; +- +- r = event_notifier_init(&svq->hdev_kick, 0); +- if (r != 0) { +- error_report("Couldn't create kick event notifier: %s (%d)", +- g_strerror(errno), errno); +- goto err_init_hdev_kick; +- } +- +- r = event_notifier_init(&svq->hdev_call, 0); +- if (r != 0) { +- error_report("Couldn't create call event notifier: %s (%d)", +- g_strerror(errno), errno); +- goto err_init_hdev_call; +- } ++ VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); + svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; +- return g_steal_pointer(&svq); +- +-err_init_hdev_call: +- event_notifier_cleanup(&svq->hdev_kick); +- +-err_init_hdev_kick: +- return NULL; ++ return svq; + } + + /** +@@ -740,7 +715,5 @@ void vhost_svq_free(gpointer pvq) + { + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); +- event_notifier_cleanup(&vq->hdev_kick); +- event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 08f92bf781..23e715b05c 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -430,15 +430,11 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v, + + shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free); + for (unsigned n = 0; n < hdev->nvqs; ++n) { +- g_autoptr(VhostShadowVirtqueue) svq; ++ VhostShadowVirtqueue *svq; + + svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, + v->shadow_vq_ops_opaque); +- if (unlikely(!svq)) { +- error_setg(errp, "Cannot create svq %u", n); +- return -1; +- } +- g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq)); ++ g_ptr_array_add(shadow_vqs, svq); + } + + v->shadow_vqs = g_steal_pointer(&shadow_vqs); +@@ -866,11 +862,23 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + const EventNotifier *event_notifier = &svq->hdev_kick; + int r; + ++ r = event_notifier_init(&svq->hdev_kick, 0); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Couldn't create kick event notifier"); ++ goto err_init_hdev_kick; ++ } ++ ++ r = event_notifier_init(&svq->hdev_call, 0); ++ if (r != 0) { ++ error_setg_errno(errp, -r, "Couldn't create call event notifier"); ++ goto err_init_hdev_call; ++ } ++ + file.fd = event_notifier_get_fd(event_notifier); + r = vhost_vdpa_set_vring_dev_kick(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device kick fd"); +- return r; ++ goto err_init_set_dev_fd; + } + + event_notifier = &svq->hdev_call; +@@ -878,8 +886,18 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev, + r = vhost_vdpa_set_vring_dev_call(dev, &file); + if (unlikely(r != 0)) { + error_setg_errno(errp, -r, "Can't set device call fd"); ++ goto err_init_set_dev_fd; + } + ++ return 0; ++ ++err_init_set_dev_fd: ++ event_notifier_set_handler(&svq->hdev_call, NULL); ++ ++err_init_hdev_call: ++ event_notifier_cleanup(&svq->hdev_kick); ++ ++err_init_hdev_kick: + return r; + } + +@@ -1091,6 +1109,9 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev) + for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { + VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); + vhost_vdpa_svq_unmap_rings(dev, svq); ++ ++ event_notifier_cleanup(&svq->hdev_kick); ++ event_notifier_cleanup(&svq->hdev_call); + } + } + +-- +2.27.0 + diff --git a/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch b/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch new file mode 100644 index 0000000..51fdba4 --- /dev/null +++ b/vhost-enable-vrings-in-vhost_dev_start-for-vhost-use.patch @@ -0,0 +1,453 @@ +From f0586baaa57c4042135b6d8f4d940da8a99e3737 Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Wed, 30 Nov 2022 11:24:36 +0000 +Subject: [PATCH] vhost: enable vrings in vhost_dev_start() for vhost-user + devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 02b61f38d3 ("hw/virtio: incorporate backend features in features") +properly negotiates VHOST_USER_F_PROTOCOL_FEATURES with the vhost-user +backend, but we forgot to enable vrings as specified in +docs/interop/vhost-user.rst: + + If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the + ring starts directly in the enabled state. + + If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is + initialized in a disabled state and is enabled by + ``VHOST_USER_SET_VRING_ENABLE`` with parameter 1. + +Some vhost-user front-ends already did this by calling +vhost_ops.vhost_set_vring_enable() directly: +- backends/cryptodev-vhost.c +- hw/net/virtio-net.c +- hw/virtio/vhost-user-gpio.c + +But most didn't do that, so we would leave the vrings disabled and some +backends would not work. We observed this issue with the rust version of +virtiofsd [1], which uses the event loop [2] provided by the +vhost-user-backend crate where requests are not processed if vring is +not enabled. + +Let's fix this issue by enabling the vrings in vhost_dev_start() for +vhost-user front-ends that don't already do this directly. Same thing +also in vhost_dev_stop() where we disable vrings. + +[1] https://gitlab.com/virtio-fs/virtiofsd +[2] https://github.com/rust-vmm/vhost/blob/240fc2966/crates/vhost-user-backend/src/event_loop.rs#L217 + +Fixes: 02b61f38d3 ("hw/virtio: incorporate backend features in features") +Reported-by: German Maglione +Tested-by: German Maglione +Signed-off-by: Stefano Garzarella +Acked-by: Raphael Norwitz +Message-Id: <20221123131630.52020-1-sgarzare@redhat.com> +Signed-off-by: Alex Bennée +Reviewed-by: Michael S. Tsirkin +Message-Id: <20221130112439.2527228-3-alex.bennee@linaro.org> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + backends/cryptodev-vhost.c | 4 ++-- + backends/vhost-user.c | 4 ++-- + hw/block/vhost-user-blk.c | 4 ++-- + hw/net/vhost_net.c | 6 ++--- + hw/scsi/vhost-scsi-common.c | 4 ++-- + hw/virtio/trace-events | 4 ++-- + hw/virtio/vdpa-dev.c | 4 ++-- + hw/virtio/vhost-user-fs.c | 4 ++-- + hw/virtio/vhost-user-i2c.c | 4 ++-- + hw/virtio/vhost-user-rng.c | 4 ++-- + hw/virtio/vhost-vsock-common.c | 4 ++-- + hw/virtio/vhost.c | 44 ++++++++++++++++++++++++++++++---- + include/hw/virtio/vhost.h | 9 +++++-- + 13 files changed, 69 insertions(+), 30 deletions(-) + +diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c +index bc13e466b4..572f87b3be 100644 +--- a/backends/cryptodev-vhost.c ++++ b/backends/cryptodev-vhost.c +@@ -94,7 +94,7 @@ cryptodev_vhost_start_one(CryptoDevBackendVhost *crypto, + goto fail_notifiers; + } + +- r = vhost_dev_start(&crypto->dev, dev); ++ r = vhost_dev_start(&crypto->dev, dev, false); + if (r < 0) { + goto fail_start; + } +@@ -111,7 +111,7 @@ static void + cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto, + VirtIODevice *dev) + { +- vhost_dev_stop(&crypto->dev, dev); ++ vhost_dev_stop(&crypto->dev, dev, false); + vhost_dev_disable_notifiers(&crypto->dev, dev); + } + +diff --git a/backends/vhost-user.c b/backends/vhost-user.c +index 10b39992d2..6632e2fe6f 100644 +--- a/backends/vhost-user.c ++++ b/backends/vhost-user.c +@@ -85,7 +85,7 @@ vhost_user_backend_start(VhostUserBackend *b) + } + + b->dev.acked_features = b->vdev->guest_features; +- ret = vhost_dev_start(&b->dev, b->vdev); ++ ret = vhost_dev_start(&b->dev, b->vdev, true); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; +@@ -120,7 +120,7 @@ vhost_user_backend_stop(VhostUserBackend *b) + return; + } + +- vhost_dev_stop(&b->dev, b->vdev); ++ vhost_dev_stop(&b->dev, b->vdev, true); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index 9bf18434c2..eddc5588fa 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -167,7 +167,7 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp) + goto err_guest_notifiers; + } + +- ret = vhost_dev_start(&s->dev, vdev); ++ ret = vhost_dev_start(&s->dev, vdev, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; +@@ -207,7 +207,7 @@ static void vhost_user_blk_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&s->dev, vdev); ++ vhost_dev_stop(&s->dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index f709c060b6..c950d7e2e8 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -319,7 +319,7 @@ static int vhost_net_start_one(struct vhost_net *net, + goto fail_notifiers; + } + +- r = vhost_dev_start(&net->dev, dev); ++ r = vhost_dev_start(&net->dev, dev, false); + if (r < 0) { + goto fail_start; + } +@@ -368,7 +368,7 @@ fail: + if (net->nc->info->poll) { + net->nc->info->poll(net->nc, true); + } +- vhost_dev_stop(&net->dev, dev); ++ vhost_dev_stop(&net->dev, dev, false); + fail_start: + vhost_dev_disable_notifiers(&net->dev, dev); + fail_notifiers: +@@ -389,7 +389,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); ++ vhost_dev_stop(&net->dev, dev, false); + if (net->nc->info->stop) { + net->nc->info->stop(net->nc); + } +diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c +index 767f827e55..18ea5dcfa1 100644 +--- a/hw/scsi/vhost-scsi-common.c ++++ b/hw/scsi/vhost-scsi-common.c +@@ -68,7 +68,7 @@ int vhost_scsi_common_start(VHostSCSICommon *vsc) + goto err_guest_notifiers; + } + +- ret = vhost_dev_start(&vsc->dev, vdev); ++ ret = vhost_dev_start(&vsc->dev, vdev, true); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; +@@ -101,7 +101,7 @@ void vhost_scsi_common_stop(VHostSCSICommon *vsc) + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret = 0; + +- vhost_dev_stop(&vsc->dev, vdev); ++ vhost_dev_stop(&vsc->dev, vdev, true); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index b8a33b2a83..35d4c00e59 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -9,8 +9,8 @@ vhost_section(const char *name) "%s" + vhost_reject_section(const char *name, int d) "%s:%d" + vhost_iotlb_miss(void *dev, int step) "%p step %d" + vhost_dev_cleanup(void *dev) "%p" +-vhost_dev_start(void *dev, const char *name) "%p:%s" +-vhost_dev_stop(void *dev, const char *name) "%p:%s" ++vhost_dev_start(void *dev, const char *name, bool vrings) "%p:%s vrings:%d" ++vhost_dev_stop(void *dev, const char *name, bool vrings) "%p:%s vrings:%d" + + + # vhost-user.c +diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c +index 1840f0e450..465b08c0e3 100644 +--- a/hw/virtio/vdpa-dev.c ++++ b/hw/virtio/vdpa-dev.c +@@ -242,7 +242,7 @@ static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp) + + s->dev.acked_features = vdev->guest_features; + +- ret = vhost_dev_start(&s->dev, vdev); ++ ret = vhost_dev_start(&s->dev, vdev, false); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error starting vhost"); + goto err_guest_notifiers; +@@ -283,7 +283,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&s->dev, vdev); ++ vhost_dev_stop(&s->dev, vdev, false); + + ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index 392b7d3aa1..c2739557f2 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -74,7 +74,7 @@ static void vuf_start(VirtIODevice *vdev) + } + + fs->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&fs->vhost_dev, vdev); ++ ret = vhost_dev_start(&fs->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost: %d", -ret); + goto err_guest_notifiers; +@@ -108,7 +108,7 @@ static void vuf_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&fs->vhost_dev, vdev); ++ vhost_dev_stop(&fs->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c +index d172632bb0..dcaf471115 100644 +--- a/hw/virtio/vhost-user-i2c.c ++++ b/hw/virtio/vhost-user-i2c.c +@@ -45,7 +45,7 @@ static void vu_i2c_start(VirtIODevice *vdev) + + i2c->vhost_dev.acked_features = vdev->guest_features; + +- ret = vhost_dev_start(&i2c->vhost_dev, vdev); ++ ret = vhost_dev_start(&i2c->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-i2c: %d", -ret); + goto err_guest_notifiers; +@@ -79,7 +79,7 @@ static void vu_i2c_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&i2c->vhost_dev, vdev); ++ vhost_dev_stop(&i2c->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, i2c->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c +index 543f3e3cef..f25b7cf624 100644 +--- a/hw/virtio/vhost-user-rng.c ++++ b/hw/virtio/vhost-user-rng.c +@@ -42,7 +42,7 @@ static void vu_rng_start(VirtIODevice *vdev) + } + + rng->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&rng->vhost_dev, vdev); ++ ret = vhost_dev_start(&rng->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost-user-rng: %d", -ret); + goto err_guest_notifiers; +@@ -76,7 +76,7 @@ static void vu_rng_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&rng->vhost_dev, vdev); ++ vhost_dev_stop(&rng->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index cd45aaf28e..42e4db4712 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -68,7 +68,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev) + } + + vvc->vhost_dev.acked_features = vdev->guest_features; +- ret = vhost_dev_start(&vvc->vhost_dev, vdev); ++ ret = vhost_dev_start(&vvc->vhost_dev, vdev, true); + if (ret < 0) { + error_report("Error starting vhost: %d", -ret); + goto err_guest_notifiers; +@@ -103,7 +103,7 @@ void vhost_vsock_common_stop(VirtIODevice *vdev) + return; + } + +- vhost_dev_stop(&vvc->vhost_dev, vdev); ++ vhost_dev_stop(&vvc->vhost_dev, vdev, true); + + ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); + if (ret < 0) { +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 86c727d2ab..22ec9e1ef7 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1760,15 +1760,36 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + return 0; + } + ++static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable) ++{ ++ if (!hdev->vhost_ops->vhost_set_vring_enable) { ++ return 0; ++ } ++ ++ /* ++ * For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not ++ * been negotiated, the rings start directly in the enabled state, and ++ * .vhost_set_vring_enable callback will fail since ++ * VHOST_USER_SET_VRING_ENABLE is not supported. ++ */ ++ if (hdev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER && ++ !virtio_has_feature(hdev->backend_features, ++ VHOST_USER_F_PROTOCOL_FEATURES)) { ++ return 0; ++ } ++ ++ return hdev->vhost_ops->vhost_set_vring_enable(hdev, enable); ++} ++ + /* Host notifiers must be enabled at this point. */ +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + { + int i, r; + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + +- trace_vhost_dev_start(hdev, vdev->name); ++ trace_vhost_dev_start(hdev, vdev->name, vrings); + + vdev->vhost_started = true; + hdev->started = true; +@@ -1813,10 +1834,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + goto fail_log; + } + } ++ if (vrings) { ++ r = vhost_dev_set_vring_enable(hdev, true); ++ if (r) { ++ goto fail_log; ++ } ++ } + if (hdev->vhost_ops->vhost_dev_start) { + r = hdev->vhost_ops->vhost_dev_start(hdev, true); + if (r) { +- goto fail_log; ++ goto fail_start; + } + } + if (vhost_dev_has_iommu(hdev) && +@@ -1831,6 +1858,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + } + } + return 0; ++fail_start: ++ if (vrings) { ++ vhost_dev_set_vring_enable(hdev, false); ++ } + fail_log: + vhost_log_put(hdev, false); + fail_vq: +@@ -1849,18 +1880,21 @@ fail_features: + } + + /* Host notifiers must be enabled at this point. */ +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + { + int i; + + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + +- trace_vhost_dev_stop(hdev, vdev->name); ++ trace_vhost_dev_stop(hdev, vdev->name, vrings); + + if (hdev->vhost_ops->vhost_dev_start) { + hdev->vhost_ops->vhost_dev_start(hdev, false); + } ++ if (vrings) { ++ vhost_dev_set_vring_enable(hdev, false); ++ } + for (i = 0; i < hdev->nvqs; ++i) { + vhost_virtqueue_stop(hdev, + vdev, +diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h +index d7ab2579ff..662e0f4370 100644 +--- a/include/hw/virtio/vhost.h ++++ b/include/hw/virtio/vhost.h +@@ -5,6 +5,9 @@ + #include "hw/virtio/virtio.h" + #include "exec/memory.h" + ++#define VHOST_F_DEVICE_IOTLB 63 ++#define VHOST_USER_F_PROTOCOL_FEATURES 30 ++ + /* Generic structures common for any vhost based device. */ + + struct vhost_inflight { +@@ -165,24 +168,26 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + * vhost_dev_start() - start the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure ++ * @vrings: true to have vrings enabled in this call + * + * Starts the vhost device. From this point VirtIO feature negotiation + * can start and the device can start processing VirtIO transactions. + * + * Return: 0 on success, < 0 on error. + */ +-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); ++int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + + /** + * vhost_dev_stop() - stop the vhost device + * @hdev: common vhost_dev structure + * @vdev: the VirtIODevice structure ++ * @vrings: true to have vrings disabled in this call + * + * Stop the vhost device. After the device is stopped the notifiers + * can be disabled (@vhost_dev_disable_notifiers) and the device can + * be torn down (@vhost_dev_cleanup). + */ +-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); ++void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); + + /** + * DOC: vhost device configuration handling +-- +2.27.0 + diff --git a/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch b/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch new file mode 100644 index 0000000..a21d4be --- /dev/null +++ b/vhost-fix-possible-wrap-in-SVQ-descriptor-ring.patch @@ -0,0 +1,108 @@ +From fdc4e7386f7fa5f0d47d6d7b582a01854073206e Mon Sep 17 00:00:00 2001 +From: Hawkins Jiawei +Date: Tue, 9 May 2023 16:48:17 +0800 +Subject: [PATCH] vhost: fix possible wrap in SVQ descriptor ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QEMU invokes vhost_svq_add() when adding a guest's element +into SVQ. In vhost_svq_add(), it uses vhost_svq_available_slots() +to check whether QEMU can add the element into SVQ. If there is +enough space, then QEMU combines some out descriptors and some +in descriptors into one descriptor chain, and adds it into +`svq->vring.desc` by vhost_svq_vring_write_descs(). + +Yet the problem is that, `svq->shadow_avail_idx - svq->shadow_used_idx` +in vhost_svq_available_slots() returns the number of occupied elements, +or the number of descriptor chains, instead of the number of occupied +descriptors, which may cause wrapping in SVQ descriptor ring. + +Here is an example. In vhost_handle_guest_kick(), QEMU forwards +as many available buffers to device by virtqueue_pop() and +vhost_svq_add_element(). virtqueue_pop() returns a guest's element, +and then this element is added into SVQ by vhost_svq_add_element(), +a wrapper to vhost_svq_add(). If QEMU invokes virtqueue_pop() and +vhost_svq_add_element() `svq->vring.num` times, +vhost_svq_available_slots() thinks QEMU just ran out of slots and +everything should work fine. But in fact, virtqueue_pop() returns +`svq->vring.num` elements or descriptor chains, more than +`svq->vring.num` descriptors due to guest memory fragmentation, +and this causes wrapping in SVQ descriptor ring. + +This bug is valid even before marking the descriptors used. +If the guest memory is fragmented, SVQ must add chains +so it can try to add more descriptors than possible. + +This patch solves it by adding `num_free` field in +VhostShadowVirtqueue structure and updating this field +in vhost_svq_add() and vhost_svq_get_buf(), to record +the number of free descriptors. + +Fixes: 100890f7ca ("vhost: Shadow virtqueue buffers forwarding") +Signed-off-by: Hawkins Jiawei +Acked-by: Eugenio Pérez +Message-Id: <20230509084817.3973-1-yin31149@gmail.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 5 ++++- + hw/virtio/vhost-shadow-virtqueue.h | 3 +++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 7d6afcb528..8d99edb196 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -66,7 +66,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp) + */ + static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq) + { +- return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx); ++ return svq->num_free; + } + + /** +@@ -255,6 +255,7 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, + return -EINVAL; + } + ++ svq->num_free -= ndescs; + svq->desc_state[qemu_head].elem = elem; + svq->desc_state[qemu_head].ndescs = ndescs; + vhost_svq_kick(svq); +@@ -426,6 +427,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, + last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id); + svq->desc_next[last_used_chain] = svq->free_head; + svq->free_head = used_elem.id; ++ svq->num_free += num; + + *len = used_elem.len; + return g_steal_pointer(&svq->desc_state[used_elem.id].elem); +@@ -636,6 +638,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->iova_tree = iova_tree; + + svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); ++ svq->num_free = svq->vring.num; + driver_size = vhost_svq_driver_area_size(svq); + device_size = vhost_svq_device_area_size(svq); + svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size); +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 926a4897b1..6efe051a70 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -107,6 +107,9 @@ typedef struct VhostShadowVirtqueue { + + /* Next head to consume from the device */ + uint16_t last_used_idx; ++ ++ /* Size of SVQ vring free descriptors */ ++ uint16_t num_free; + } VhostShadowVirtqueue; + + bool vhost_svq_valid_features(uint64_t features, Error **errp); +-- +2.27.0 + diff --git a/vhost-fix-the-fd-leak.patch b/vhost-fix-the-fd-leak.patch new file mode 100644 index 0000000..2ccc183 --- /dev/null +++ b/vhost-fix-the-fd-leak.patch @@ -0,0 +1,37 @@ +From 2fb147eb0189ee24a74ebf784b9a682667288d3d Mon Sep 17 00:00:00 2001 +From: Li Feng +Date: Mon, 31 Jul 2023 20:10:06 +0800 +Subject: [PATCH] vhost: fix the fd leak + +When the vhost-user reconnect to the backend, the notifer should be +cleanup. Otherwise, the fd resource will be exhausted. + +Fixes: f9a09ca3ea ("vhost: add support for configure interrupt") + +Signed-off-by: Li Feng +Reviewed-by: Raphael Norwitz +Message-Id: <20230731121018.2856310-2-fengli@smartx.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Fiona Ebner +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 490c97424b..63ddcb3e6d 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -2009,6 +2009,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + event_notifier_test_and_clear(&vdev->config_notifier); ++ event_notifier_cleanup( ++ &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); + + trace_vhost_dev_stop(hdev, vdev->name, vrings); + +-- +2.27.0 + diff --git a/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch b/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch new file mode 100644 index 0000000..9854a13 --- /dev/null +++ b/vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch @@ -0,0 +1,143 @@ +From 1f8330f9b4cba6ce8d88d227aeae4849c0062cf0 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 16 Dec 2022 11:35:52 +0800 +Subject: [PATCH] vhost: fix vq dirty bitmap syncing when vIOMMU is enabled + +When vIOMMU is enabled, the vq->used_phys is actually the IOVA not +GPA. So we need to translate it to GPA before the syncing otherwise we +may hit the following crash since IOVA could be out of the scope of +the GPA log size. This could be noted when using virtio-IOMMU with +vhost using 1G memory. + +Fixes: c471ad0e9bd46 ("vhost_net: device IOTLB support") +Cc: qemu-stable@nongnu.org +Tested-by: Lei Yang +Reported-by: Yalan Zhang +Signed-off-by: Jason Wang +Message-Id: <20221216033552.77087-1-jasowang@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 84 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 64 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 8e8657fb0d..19ea9aef69 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -20,6 +20,7 @@ + #include "qemu/range.h" + #include "qemu/error-report.h" + #include "qemu/memfd.h" ++#include "qemu/log.h" + #include "standard-headers/linux/vhost_types.h" + #include "hw/virtio/virtio-bus.h" + #include "hw/virtio/virtio-access.h" +@@ -110,6 +111,24 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, + } + } + ++static bool vhost_dev_has_iommu(struct vhost_dev *dev) ++{ ++ VirtIODevice *vdev = dev->vdev; ++ ++ /* ++ * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support ++ * incremental memory mapping API via IOTLB API. For platform that ++ * does not have IOMMU, there's no need to enable this feature ++ * which may cause unnecessary IOTLB miss/update transactions. ++ */ ++ if (vdev) { ++ return virtio_bus_device_iommu_enabled(vdev) && ++ virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); ++ } else { ++ return false; ++ } ++} ++ + static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + MemoryRegionSection *section, + hwaddr first, +@@ -141,8 +160,51 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + continue; + } + +- vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys, +- range_get_last(vq->used_phys, vq->used_size)); ++ if (vhost_dev_has_iommu(dev)) { ++ IOMMUTLBEntry iotlb; ++ hwaddr used_phys = vq->used_phys, used_size = vq->used_size; ++ hwaddr phys, s, offset; ++ ++ while (used_size) { ++ rcu_read_lock(); ++ iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as, ++ used_phys, ++ true, ++ MEMTXATTRS_UNSPECIFIED); ++ rcu_read_unlock(); ++ ++ if (!iotlb.target_as) { ++ qemu_log_mask(LOG_GUEST_ERROR, "translation " ++ "failure for used_iova %"PRIx64"\n", ++ used_phys); ++ return -EINVAL; ++ } ++ ++ offset = used_phys & iotlb.addr_mask; ++ phys = iotlb.translated_addr + offset; ++ ++ /* ++ * Distance from start of used ring until last byte of ++ * IOMMU page. ++ */ ++ s = iotlb.addr_mask - offset; ++ /* ++ * Size of used ring, or of the part of it until end ++ * of IOMMU page. To avoid zero result, do the adding ++ * outside of MIN(). ++ */ ++ s = MIN(s, used_size - 1) + 1; ++ ++ vhost_dev_sync_region(dev, section, start_addr, end_addr, phys, ++ range_get_last(phys, s)); ++ used_size -= s; ++ used_phys += s; ++ } ++ } else { ++ vhost_dev_sync_region(dev, section, start_addr, ++ end_addr, vq->used_phys, ++ range_get_last(vq->used_phys, vq->used_size)); ++ } + } + return 0; + } +@@ -310,24 +372,6 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + dev->log_size = size; + } + +-static bool vhost_dev_has_iommu(struct vhost_dev *dev) +-{ +- VirtIODevice *vdev = dev->vdev; +- +- /* +- * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support +- * incremental memory mapping API via IOTLB API. For platform that +- * does not have IOMMU, there's no need to enable this feature +- * which may cause unnecessary IOTLB miss/update transactions. +- */ +- if (vdev) { +- return virtio_bus_device_iommu_enabled(vdev) && +- virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); +- } else { +- return false; +- } +-} +- + static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, + hwaddr *plen, bool is_write) + { +-- +2.27.0 + diff --git a/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch b/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch new file mode 100644 index 0000000..b1e7a94 --- /dev/null +++ b/vhost-introduce-new-VhostOps-vhost_set_config_call-new.patch @@ -0,0 +1,42 @@ +From 0e8cd86ad1cc2c67fb3bd31493b534d740c9ac28 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:45 +0800 +Subject: [PATCH] vhost: introduce new VhostOps vhost_set_config_call + +This patch introduces new VhostOps vhost_set_config_call. +This function allows the qemu to set the config +event fd to kernel driver. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-5-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + include/hw/virtio/vhost-backend.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index a64708f456..bd1c7dfe4f 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,6 +125,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); ++typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, ++ int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -173,6 +175,7 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; ++ vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/vhost-introduce-new-VhostOps-vhost_set_config_call.patch b/vhost-introduce-new-VhostOps-vhost_set_config_call.patch new file mode 100644 index 0000000..92b4c26 --- /dev/null +++ b/vhost-introduce-new-VhostOps-vhost_set_config_call.patch @@ -0,0 +1,41 @@ +From af8377d0e9437401ad30d80a27ab1fcf8252fad1 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:57 +0800 +Subject: [PATCH] vhost: introduce new VhostOps vhost_set_config_call + +This patch introduces new VhostOps vhost_set_config_call. This function allows the +vhost to set the event fd to kernel + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-5-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + include/hw/virtio/vhost-backend.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index a64708f456..bd1c7dfe4f 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -125,6 +125,8 @@ typedef int (*vhost_vq_get_addr_op)(struct vhost_dev *dev, + typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id); + + typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); ++typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev, ++ int fd); + typedef void (*vhost_set_used_memslots_op)(struct vhost_dev *dev); + typedef unsigned int (*vhost_get_used_memslots_op)(void); + +@@ -173,6 +175,7 @@ typedef struct VhostOps { + vhost_vq_get_addr_op vhost_vq_get_addr; + vhost_get_device_id_op vhost_get_device_id; + vhost_force_iommu_op vhost_force_iommu; ++ vhost_set_config_call_op vhost_set_config_call; + vhost_set_used_memslots_op vhost_set_used_memslots; + vhost_get_used_memslots_op vhost_get_used_memslots; + } VhostOps; +-- +2.27.0 + diff --git a/vhost-move-descriptor-translation-to-vhost_svq_vring.patch b/vhost-move-descriptor-translation-to-vhost_svq_vring.patch new file mode 100644 index 0000000..a45e88f --- /dev/null +++ b/vhost-move-descriptor-translation-to-vhost_svq_vring.patch @@ -0,0 +1,101 @@ +From 16fdc235caece008e3802934250f434e9ca03dd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:26 +0200 +Subject: [PATCH] vhost: move descriptor translation to + vhost_svq_vring_write_descs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's done for both in and out descriptors so it's better placed here. + +Acked-by: Jason Wang +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 38 +++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index cea2c3f8dd..da1e1ce3c7 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -121,17 +121,35 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq, + return true; + } + +-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, +- const struct iovec *iovec, size_t num, +- bool more_descs, bool write) ++/** ++ * Write descriptors to SVQ vring ++ * ++ * @svq: The shadow virtqueue ++ * @sg: Cache for hwaddr ++ * @iovec: The iovec from the guest ++ * @num: iovec length ++ * @more_descs: True if more descriptors come in the chain ++ * @write: True if they are writeable descriptors ++ * ++ * Return true if success, false otherwise and print error. ++ */ ++static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, ++ const struct iovec *iovec, size_t num, ++ bool more_descs, bool write) + { + uint16_t i = svq->free_head, last = svq->free_head; + unsigned n; + uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0; + vring_desc_t *descs = svq->vring.desc; ++ bool ok; + + if (num == 0) { +- return; ++ return true; ++ } ++ ++ ok = vhost_svq_translate_addr(svq, sg, iovec, num); ++ if (unlikely(!ok)) { ++ return false; + } + + for (n = 0; n < num; n++) { +@@ -149,6 +167,7 @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + } + + svq->free_head = le16_to_cpu(svq->desc_next[last]); ++ return true; + } + + static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, +@@ -168,21 +187,18 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq, + return false; + } + +- ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num); ++ ok = vhost_svq_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, ++ elem->in_num > 0, false); + if (unlikely(!ok)) { + return false; + } +- vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num, +- elem->in_num > 0, false); +- + +- ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num); ++ ok = vhost_svq_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, ++ true); + if (unlikely(!ok)) { + return false; + } + +- vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true); +- + /* + * Put the entry in the available array (but don't update avail->idx until + * they do sync). +-- +2.27.0 + diff --git a/vhost-move-iova_tree-set-to-vhost_svq_start.patch b/vhost-move-iova_tree-set-to-vhost_svq_start.patch new file mode 100644 index 0000000..93cccc1 --- /dev/null +++ b/vhost-move-iova_tree-set-to-vhost_svq_start.patch @@ -0,0 +1,114 @@ +From 7c93447234412390e6cd3bae1d5001426287a362 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:36 +0100 +Subject: [PATCH] vhost: move iova_tree set to vhost_svq_start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since we don't know if we will use SVQ at qemu initialization, let's +allocate iova_tree only if needed. To do so, accept it at SVQ start, not +at initialization. + +This will avoid to create it if the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-5-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 9 ++++----- + hw/virtio/vhost-shadow-virtqueue.h | 5 ++--- + hw/virtio/vhost-vdpa.c | 5 ++--- + 3 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 1ea7b5cf59..7d6afcb528 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -619,9 +619,10 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) + * @svq: Shadow Virtqueue + * @vdev: VirtIO device + * @vq: Virtqueue to shadow ++ * @iova_tree: Tree to perform descriptors translations + */ + void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, +- VirtQueue *vq) ++ VirtQueue *vq, VhostIOVATree *iova_tree) + { + size_t desc_size, driver_size, device_size; + +@@ -632,6 +633,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->last_used_idx = 0; + svq->vdev = vdev; + svq->vq = vq; ++ svq->iova_tree = iova_tree; + + svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); + driver_size = vhost_svq_driver_area_size(svq); +@@ -689,18 +691,15 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + * Creates vhost shadow virtqueue, and instructs the vhost device to use the + * shadow methods and file descriptors. + * +- * @iova_tree: Tree to perform descriptors translations + * @ops: SVQ owner callbacks + * @ops_opaque: ops opaque pointer + */ +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, +- const VhostShadowVirtqueueOps *ops, ++VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque) + { + VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1); + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); +- svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; + return svq; +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index d04c34a589..926a4897b1 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -126,11 +126,10 @@ size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); + size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + + void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, +- VirtQueue *vq); ++ VirtQueue *vq, VhostIOVATree *iova_tree); + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, +- const VhostShadowVirtqueueOps *ops, ++VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, + void *ops_opaque); + + void vhost_svq_free(gpointer vq); +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 2fd7af1c6b..f5d816f5ec 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -419,8 +419,7 @@ static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) + for (unsigned n = 0; n < hdev->nvqs; ++n) { + VhostShadowVirtqueue *svq; + +- svq = vhost_svq_new(v->iova_tree, v->shadow_vq_ops, +- v->shadow_vq_ops_opaque); ++ svq = vhost_svq_new(v->shadow_vq_ops, v->shadow_vq_ops_opaque); + g_ptr_array_add(shadow_vqs, svq); + } + +@@ -1060,7 +1059,7 @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev) + goto err; + } + +- vhost_svq_start(svq, dev->vdev, vq); ++ vhost_svq_start(svq, dev->vdev, vq, v->iova_tree); + ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err); + if (unlikely(!ok)) { + goto err_map; +-- +2.27.0 + diff --git a/vhost-release-virtqueue-objects-in-error-path.patch b/vhost-release-virtqueue-objects-in-error-path.patch new file mode 100644 index 0000000..895d2b2 --- /dev/null +++ b/vhost-release-virtqueue-objects-in-error-path.patch @@ -0,0 +1,39 @@ +From ec9c8583bee8ba140274abd3f5e8366442ceaa8e Mon Sep 17 00:00:00 2001 +From: Prasad Pandit +Date: Mon, 29 May 2023 17:13:33 +0530 +Subject: [PATCH] vhost: release virtqueue objects in error path + +vhost_dev_start function does not release virtqueue objects when +event_notifier_init() function fails. Release virtqueue objects +and log a message about function failure. + +Signed-off-by: Prasad Pandit +Message-Id: <20230529114333.31686-3-ppandit@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Fixes: f9a09ca3ea ("vhost: add support for configure interrupt") +Reviewed-by: Peter Xu +Cc: qemu-stable@nongnu.org +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 63ddcb3e6d..59a12735f9 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1931,7 +1931,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) + r = event_notifier_init( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); + if (r < 0) { +- return r; ++ VHOST_OPS_DEBUG(r, "event_notifier_init failed"); ++ goto fail_vq; + } + event_notifier_test_and_clear( + &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); +-- +2.27.0 + diff --git a/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch b/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch new file mode 100644 index 0000000..1d95b5c --- /dev/null +++ b/vhost-set-SVQ-device-call-handler-at-SVQ-start.patch @@ -0,0 +1,65 @@ +From 462ece480c425ef9de419f5454ec2b7293c35e16 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Thu, 15 Dec 2022 12:31:34 +0100 +Subject: [PATCH] vhost: set SVQ device call handler at SVQ start +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By the end of this series CVQ is shadowed as long as the features +support it. + +Since we don't know at the beginning of qemu running if this is +supported, move the event notifier handler setting to the start of the +SVQ, instead of the start of qemu run. This will avoid to create them if +the device does not support SVQ. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Message-Id: <20221215113144.322011-3-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index ae443f54fe..bc12bb42f3 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -625,6 +625,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + { + size_t desc_size, driver_size, device_size; + ++ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->next_guest_avail_elem = NULL; + svq->shadow_avail_idx = 0; + svq->shadow_used_idx = 0; +@@ -681,6 +682,7 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) + g_free(svq->desc_state); + qemu_vfree(svq->vring.desc); + qemu_vfree(svq->vring.used); ++ event_notifier_set_handler(&svq->hdev_call, NULL); + } + + /** +@@ -717,7 +719,6 @@ VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree, + } + + event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND); +- event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); + svq->iova_tree = iova_tree; + svq->ops = ops; + svq->ops_opaque = ops_opaque; +@@ -740,7 +741,6 @@ void vhost_svq_free(gpointer pvq) + VhostShadowVirtqueue *vq = pvq; + vhost_svq_stop(vq); + event_notifier_cleanup(&vq->hdev_kick); +- event_notifier_set_handler(&vq->hdev_call, NULL); + event_notifier_cleanup(&vq->hdev_call); + g_free(vq); + } +-- +2.27.0 + diff --git a/vhost-stick-to-errno-error-return-convention.patch b/vhost-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000..2607c44 --- /dev/null +++ b/vhost-stick-to-errno-error-return-convention.patch @@ -0,0 +1,349 @@ +From a5d0727f516b27e39b1f223e8dcf57b4c1bf95ea Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:56 +0800 +Subject: [PATCH] vhost: stick to -errno error return convention + +The generic vhost code expects that many of the VhostOps methods in the +respective backends set errno on errors. However, none of the existing +backends actually bothers to do so. In a number of those methods errno +from the failed call is clobbered by successful later calls to some +library functions; on a few code paths the generic vhost code then +negates and returns that errno, thus making failures look as successes +to the caller. + +As a result, in certain scenarios (e.g. live migration) the device +doesn't notice the first failure and goes on through its state +transitions as if everything is ok, instead of taking recovery actions +(break and reestablish the vhost-user connection, cancel migration, etc) +before it's too late. + +To fix this, consolidate on the convention to return negated errno on +failures throughout generic vhost, and use it for error propagation. + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-10-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost.c | 100 +++++++++++++++++++++------------------------- + 1 file changed, 46 insertions(+), 54 deletions(-) + +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index c3f375f276..caa53443ab 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -34,11 +34,13 @@ + #define _VHOST_DEBUG 1 + + #ifdef _VHOST_DEBUG +-#define VHOST_OPS_DEBUG(fmt, ...) \ +- do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ +- strerror(errno), errno); } while (0) ++#define VHOST_OPS_DEBUG(retval, fmt, ...) \ ++ do { \ ++ error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ ++ strerror(-retval), -retval); \ ++ } while (0) + #else +-#define VHOST_OPS_DEBUG(fmt, ...) \ ++#define VHOST_OPS_DEBUG(retval, fmt, ...) \ + do { } while (0) + #endif + +@@ -300,7 +302,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) + releasing the current log, to ensure no logging is lost */ + r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_log_base failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + } + + vhost_log_put(dev, true); +@@ -552,7 +554,7 @@ static void vhost_commit(MemoryListener *listener) + if (!dev->log_enabled) { + r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + } + goto out; + } +@@ -566,7 +568,7 @@ static void vhost_commit(MemoryListener *listener) + } + r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + } + /* To log less, can only decrease log size after table update. */ + if (dev->log_size > log_size + VHOST_LOG_BUFFER) { +@@ -817,8 +819,8 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, + if (dev->vhost_ops->vhost_vq_get_addr) { + r = dev->vhost_ops->vhost_vq_get_addr(dev, &addr, vq); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_vq_get_addr failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_vq_get_addr failed"); ++ return r; + } + } else { + addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc; +@@ -830,10 +832,9 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, + addr.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0; + r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_vring_addr failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_addr failed"); + } +- return 0; ++ return r; + } + + static int vhost_dev_set_features(struct vhost_dev *dev, +@@ -854,19 +855,19 @@ static int vhost_dev_set_features(struct vhost_dev *dev, + } + r = dev->vhost_ops->vhost_set_features(dev, features); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_features failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_features failed"); + goto out; + } + if (dev->vhost_ops->vhost_set_backend_cap) { + r = dev->vhost_ops->vhost_set_backend_cap(dev); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_backend_cap failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_backend_cap failed"); + goto out; + } + } + + out: +- return r < 0 ? -errno : 0; ++ return r; + } + + static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) +@@ -1021,22 +1022,17 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, + bool is_big_endian, + int vhost_vq_index) + { ++ int r; + struct vhost_vring_state s = { + .index = vhost_vq_index, + .num = is_big_endian + }; + +- if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) { +- return 0; +- } +- +- VHOST_OPS_DEBUG("vhost_set_vring_endian failed"); +- if (errno == ENOTTY) { +- error_report("vhost does not support cross-endian"); +- return -ENOSYS; ++ r = dev->vhost_ops->vhost_set_vring_endian(dev, &s); ++ if (r < 0) { ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_endian failed"); + } +- +- return -errno; ++ return r; + } + + static int vhost_memory_region_lookup(struct vhost_dev *hdev, +@@ -1128,15 +1124,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + vq->num = state.num = virtio_queue_get_num(vdev, idx); + r = dev->vhost_ops->vhost_set_vring_num(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_num failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_num failed"); ++ return r; + } + + state.num = virtio_queue_get_last_avail_idx(vdev, idx); + r = dev->vhost_ops->vhost_set_vring_base(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_base failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_base failed"); ++ return r; + } + + if (vhost_needs_vring_endian(vdev)) { +@@ -1144,7 +1140,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + virtio_is_big_endian(vdev), + vhost_vq_index); + if (r) { +- return -errno; ++ return r; + } + } + +@@ -1172,15 +1168,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, + + r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); + if (r < 0) { +- r = -errno; + goto fail_alloc; + } + + file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); + r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_kick failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_kick failed"); + goto fail_kick; + } + +@@ -1240,7 +1234,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, + + r = dev->vhost_ops->vhost_get_vring_base(dev, &state); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost VQ %u ring restore failed: %d", idx, r); ++ VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r); + /* Connection to the backend is broken, so let's sync internal + * last avail idx to the device used idx. + */ +@@ -1284,7 +1278,7 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, + + r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_busyloop_timeout failed"); + return r; + } + +@@ -1306,8 +1300,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, + file.fd = event_notifier_get_fd(&vq->masked_notifier); + r = dev->vhost_ops->vhost_set_vring_call(dev, &file); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_vring_call failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); + goto fail_call; + } + +@@ -1584,7 +1577,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); + r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_vring_call failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); + } + } + +@@ -1622,7 +1615,7 @@ void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask) + } + r = hdev->vhost_ops->vhost_set_config_call(hdev, fd); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_config_call failed"); ++ VHOST_OPS_DEBUG(r, "vhost_set_config_call failed"); + } + } + +@@ -1687,7 +1680,7 @@ int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, + } + + error_setg(errp, "vhost_get_config not implemented"); +- return -ENOTSUP; ++ return -ENOSYS; + } + + int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, +@@ -1700,7 +1693,7 @@ int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, + size, flags); + } + +- return -1; ++ return -ENOSYS; + } + + void vhost_dev_set_config_notifier(struct vhost_dev *hdev, +@@ -1729,7 +1722,7 @@ static int vhost_dev_resize_inflight(struct vhost_inflight *inflight, + + if (err) { + error_report_err(err); +- return -1; ++ return -ENOMEM; + } + + vhost_dev_free_inflight(inflight); +@@ -1762,8 +1755,9 @@ int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f) + } + + if (inflight->size != size) { +- if (vhost_dev_resize_inflight(inflight, size)) { +- return -1; ++ int ret = vhost_dev_resize_inflight(inflight, size); ++ if (ret < 0) { ++ return ret; + } + } + inflight->queue_size = qemu_get_be16(f); +@@ -1786,7 +1780,7 @@ int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev) + + r = vhost_dev_set_features(hdev, hdev->log_enabled); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_dev_prepare_inflight failed"); ++ VHOST_OPS_DEBUG(r, "vhost_dev_prepare_inflight failed"); + return r; + } + +@@ -1801,8 +1795,8 @@ int vhost_dev_set_inflight(struct vhost_dev *dev, + if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) { + r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight); + if (r) { +- VHOST_OPS_DEBUG("vhost_set_inflight_fd failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_inflight_fd failed"); ++ return r; + } + } + +@@ -1817,8 +1811,8 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, + if (dev->vhost_ops->vhost_get_inflight_fd) { + r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight); + if (r) { +- VHOST_OPS_DEBUG("vhost_get_inflight_fd failed"); +- return -errno; ++ VHOST_OPS_DEBUG(r, "vhost_get_inflight_fd failed"); ++ return r; + } + } + +@@ -1847,8 +1841,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + + r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_mem_table failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed"); + goto fail_mem; + } + for (i = 0; i < hdev->nvqs; ++i) { +@@ -1882,8 +1875,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + hdev->log_size ? log_base : 0, + hdev->log); + if (r < 0) { +- VHOST_OPS_DEBUG("vhost_set_log_base failed"); +- r = -errno; ++ VHOST_OPS_DEBUG(r, "vhost_set_log_base failed"); + goto fail_log; + } + } +@@ -1963,7 +1955,7 @@ int vhost_net_set_backend(struct vhost_dev *hdev, + return hdev->vhost_ops->vhost_net_set_backend(hdev, file); + } + +- return -1; ++ return -ENOSYS; + } + + bool used_memslots_is_exceeded(void) +-- +2.27.0 + diff --git a/vhost-user-stick-to-errno-error-return-convention.patch b/vhost-user-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000..037c3a2 --- /dev/null +++ b/vhost-user-stick-to-errno-error-return-convention.patch @@ -0,0 +1,1100 @@ +From f6c384a73aaaa7dfc52ed3ceb8ec135f33551629 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:55 +0800 +Subject: [PATCH] vhost-user: stick to -errno error return convention + +VhostOps methods in user_ops are not very consistent in their error +returns: some return negated errno while others just -1. + +Make sure all of them consistently return negated errno. This also +helps error propagation from the functions being called inside. +Besides, this synchronizes the error return convention with the other +two vhost backends, kernel and vdpa, and will therefore allow for +consistent error propagation in the generic vhost code (in a followup +patch). + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-9-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user.c | 401 +++++++++++++++++++++++------------------ + 1 file changed, 223 insertions(+), 178 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 24f80d5d18..358dc82010 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -283,9 +283,10 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + + r = qemu_chr_fe_read_all(chr, p, size); + if (r != size) { ++ int saved_errno = errno; + error_report("Failed to read msg header. Read %d instead of %d." + " Original request %d.", r, size, msg->hdr.request); +- return -1; ++ return r < 0 ? -saved_errno : -EIO; + } + + /* validate received flags */ +@@ -293,7 +294,7 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + error_report("Failed to read msg header." + " Flags 0x%x instead of 0x%x.", msg->hdr.flags, + VHOST_USER_REPLY_MASK | VHOST_USER_VERSION); +- return -1; ++ return -EPROTO; + } + + return 0; +@@ -317,8 +318,9 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + uint8_t *p = (uint8_t *) msg; + int r, size; + +- if (vhost_user_read_header(dev, msg) < 0) { +- data->ret = -1; ++ r = vhost_user_read_header(dev, msg); ++ if (r < 0) { ++ data->ret = r; + goto end; + } + +@@ -327,7 +329,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + error_report("Failed to read msg header." + " Size %d exceeds the maximum %zu.", msg->hdr.size, + VHOST_USER_PAYLOAD_SIZE); +- data->ret = -1; ++ data->ret = -EPROTO; + goto end; + } + +@@ -336,9 +338,10 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + size = msg->hdr.size; + r = qemu_chr_fe_read_all(chr, p, size); + if (r != size) { ++ int saved_errno = errno; + error_report("Failed to read msg payload." + " Read %d instead of %d.", r, msg->hdr.size); +- data->ret = -1; ++ data->ret = r < 0 ? -saved_errno : -EIO; + goto end; + } + } +@@ -421,24 +424,26 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + static int process_message_reply(struct vhost_dev *dev, + const VhostUserMsg *msg) + { ++ int ret; + VhostUserMsg msg_reply; + + if ((msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) == 0) { + return 0; + } + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + if (msg_reply.hdr.request != msg->hdr.request) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + msg->hdr.request, msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + +- return msg_reply.payload.u64 ? -1 : 0; ++ return msg_reply.payload.u64 ? -EIO : 0; + } + + static bool vhost_user_one_time_request(VhostUserRequest request) +@@ -475,14 +480,15 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, + + if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) { + error_report("Failed to set msg fds."); +- return -1; ++ return -EINVAL; + } + + ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size); + if (ret != size) { ++ int saved_errno = errno; + error_report("Failed to write msg." + " Wrote %d instead of %d.", ret, size); +- return -1; ++ return ret < 0 ? -saved_errno : -EIO; + } + + return 0; +@@ -505,6 +511,7 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + size_t fd_num = 0; + bool shmfd = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_LOG_SHMFD); ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_SET_LOG_BASE, + .hdr.flags = VHOST_USER_VERSION, +@@ -517,21 +524,23 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, + fds[fd_num++] = log->fd; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + + if (shmfd) { + msg.hdr.size = 0; +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_SET_LOG_BASE) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_SET_LOG_BASE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + } + +@@ -591,7 +600,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, + u->region_rb[i] = mr->ram_block; + } else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) { + error_report("Failed preparing vhost-user memory table msg"); +- return -1; ++ return -ENOBUFS; + } + vhost_user_fill_msg_region(®ion_buffer, reg, offset); + msg->payload.memory.regions[*fd_num] = region_buffer; +@@ -607,14 +616,14 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, + if (!*fd_num) { + error_report("Failed initializing vhost-user memory map, " + "consider using -object memory-backend-file share=on"); +- return -1; ++ return -EINVAL; + } + + msg->hdr.size = sizeof(msg->payload.memory.nregions); + msg->hdr.size += sizeof(msg->payload.memory.padding); + msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion); + +- return 1; ++ return 0; + } + + static inline bool reg_equal(struct vhost_memory_region *shadow_reg, +@@ -744,8 +753,9 @@ static int send_remove_regions(struct vhost_dev *dev, + vhost_user_fill_msg_region(®ion_buffer, shadow_reg, 0); + msg->payload.mem_reg.region = region_buffer; + +- if (vhost_user_write(dev, msg, &fd, 1) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, &fd, 1); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -804,15 +814,17 @@ static int send_add_regions(struct vhost_dev *dev, + vhost_user_fill_msg_region(®ion_buffer, reg, offset); + msg->payload.mem_reg.region = region_buffer; + +- if (vhost_user_write(dev, msg, &fd, 1) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, &fd, 1); ++ if (ret < 0) { ++ return ret; + } + + if (track_ramblocks) { + uint64_t reply_gpa; + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + reply_gpa = msg_reply.payload.mem_reg.region.guest_phys_addr; +@@ -822,7 +834,7 @@ static int send_add_regions(struct vhost_dev *dev, + "Expected %d received %d", __func__, + VHOST_USER_ADD_MEM_REG, + msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + + /* +@@ -833,7 +845,7 @@ static int send_add_regions(struct vhost_dev *dev, + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg->hdr.size); +- return -1; ++ return -EPROTO; + } + + /* Get the postcopy client base from the backend's reply. */ +@@ -849,7 +861,7 @@ static int send_add_regions(struct vhost_dev *dev, + "Got guest physical address %" PRIX64 ", expected " + "%" PRIX64, __func__, reply_gpa, + dev->mem->regions[reg_idx].guest_phys_addr); +- return -1; ++ return -EPROTO; + } + } else if (reply_supported) { + ret = process_message_reply(dev, msg); +@@ -890,6 +902,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS]; + uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {}; + int nr_add_reg, nr_rem_reg; ++ int ret; + + msg->hdr.size = sizeof(msg->payload.mem_reg); + +@@ -897,16 +910,20 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg, + shadow_pcb, track_ramblocks); + +- if (nr_rem_reg && send_remove_regions(dev, rem_reg, nr_rem_reg, msg, +- reply_supported) < 0) +- { +- goto err; ++ if (nr_rem_reg) { ++ ret = send_remove_regions(dev, rem_reg, nr_rem_reg, msg, ++ reply_supported); ++ if (ret < 0) { ++ goto err; ++ } + } + +- if (nr_add_reg && send_add_regions(dev, add_reg, nr_add_reg, msg, +- shadow_pcb, reply_supported, track_ramblocks) < 0) +- { +- goto err; ++ if (nr_add_reg) { ++ ret = send_add_regions(dev, add_reg, nr_add_reg, msg, shadow_pcb, ++ reply_supported, track_ramblocks); ++ if (ret < 0) { ++ goto err; ++ } + } + + if (track_ramblocks) { +@@ -921,8 +938,9 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, + msg->hdr.size = sizeof(msg->payload.u64); + msg->payload.u64 = 0; /* OK */ + +- if (vhost_user_write(dev, msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + } + +@@ -934,7 +952,7 @@ err: + sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); + } + +- return -1; ++ return ret; + } + + static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, +@@ -947,6 +965,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + size_t fd_num = 0; + VhostUserMsg msg_reply; + int region_i, msg_i; ++ int ret; + + VhostUserMsg msg = { + .hdr.flags = VHOST_USER_VERSION, +@@ -964,29 +983,32 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + } + + if (config_mem_slots) { +- if (vhost_user_add_remove_regions(dev, &msg, reply_supported, +- true) < 0) { +- return -1; ++ ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, true); ++ if (ret < 0) { ++ return ret; + } + } else { +- if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, +- true) < 0) { +- return -1; ++ ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ++ true); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg_reply) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg_reply); ++ if (ret < 0) { ++ return ret; + } + + if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) { + error_report("%s: Received unexpected msg type." + "Expected %d received %d", __func__, + VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request); +- return -1; ++ return -EPROTO; + } + + /* +@@ -997,7 +1019,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + error_report("%s: Unexpected size for postcopy reply " + "%d vs %d", __func__, msg_reply.hdr.size, + msg.hdr.size); +- return -1; ++ return -EPROTO; + } + + memset(u->postcopy_client_bases, 0, +@@ -1027,7 +1049,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + error_report("%s: postcopy reply not fully consumed " + "%d vs %zd", + __func__, msg_i, fd_num); +- return -1; ++ return -EIO; + } + + /* +@@ -1038,8 +1060,9 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, + /* TODO: Use this for failure cases as well with a bad value. */ + msg.hdr.size = sizeof(msg.payload.u64); + msg.payload.u64 = 0; /* OK */ +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + } + +@@ -1058,6 +1081,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, + bool config_mem_slots = + virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS); ++ int ret; + + if (do_postcopy) { + /* +@@ -1077,17 +1101,20 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, + } + + if (config_mem_slots) { +- if (vhost_user_add_remove_regions(dev, &msg, reply_supported, +- false) < 0) { +- return -1; ++ ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, false); ++ if (ret < 0) { ++ return ret; + } + } else { +- if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, +- false) < 0) { +- return -1; ++ ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ++ false); ++ if (ret < 0) { ++ return ret; + } +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; ++ ++ ret = vhost_user_write(dev, &msg, fds, fd_num); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -1112,14 +1139,10 @@ static int vhost_user_set_vring_endian(struct vhost_dev *dev, + + if (!cross_endian) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_set_vring(struct vhost_dev *dev, +@@ -1133,11 +1156,7 @@ static int vhost_set_vring(struct vhost_dev *dev, + .hdr.size = sizeof(msg.payload.state), + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_set_vring_num(struct vhost_dev *dev, +@@ -1180,16 +1199,25 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) + int i; + + if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) { +- return -1; ++ return -EINVAL; + } + + for (i = 0; i < dev->nvqs; ++i) { ++ int ret; + struct vhost_vring_state state = { + .index = dev->vq_index + i, + .num = enable, + }; + +- vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); ++ ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); ++ if (ret < 0) { ++ /* ++ * Restoring the previous state is likely infeasible, as well as ++ * proceeding regardless the error, so just bail out and hope for ++ * the device-level recovery. ++ */ ++ return ret; ++ } + } + + return 0; +@@ -1198,6 +1226,7 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) + static int vhost_user_get_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_VRING_BASE, + .hdr.flags = VHOST_USER_VERSION, +@@ -1208,23 +1237,25 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, + + vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_VRING_BASE) { + error_report("Received unexpected msg type. Expected %d received %d", + VHOST_USER_GET_VRING_BASE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.state)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + *ring = msg.payload.state; +@@ -1251,11 +1282,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev, + msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK; + } + +- if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, fds, fd_num); + } + + static int vhost_user_set_vring_kick(struct vhost_dev *dev, +@@ -1273,6 +1300,7 @@ static int vhost_user_set_vring_call(struct vhost_dev *dev, + + static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = request, + .hdr.flags = VHOST_USER_VERSION, +@@ -1282,23 +1310,25 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) + return 0; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != request) { + error_report("Received unexpected msg type. Expected %d received %d", + request, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.u64)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + *u64 = msg.payload.u64; +@@ -1336,6 +1366,7 @@ static int enforce_reply(struct vhost_dev *dev, + static int vhost_user_set_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_SET_VRING_ADDR, + .hdr.flags = VHOST_USER_VERSION, +@@ -1356,8 +1387,9 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (wait_for_reply) { +@@ -1376,6 +1408,7 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, + .payload.u64 = u64, + .hdr.size = sizeof(msg.payload.u64), + }; ++ int ret; + + if (wait_for_reply) { + bool reply_supported = virtio_has_feature(dev->protocol_features, +@@ -1385,8 +1418,9 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, + } + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (wait_for_reply) { +@@ -1423,11 +1457,7 @@ static int vhost_user_set_owner(struct vhost_dev *dev) + .hdr.flags = VHOST_USER_VERSION, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -EPROTO; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_get_max_memslots(struct vhost_dev *dev, +@@ -1458,26 +1488,16 @@ static int vhost_user_reset_device(struct vhost_dev *dev) + ? VHOST_USER_RESET_DEVICE + : VHOST_USER_RESET_OWNER; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, NULL, 0); + } + + static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) + { +- int ret = -1; +- +- if (!dev->config_ops) { +- return -1; ++ if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { ++ return -ENOSYS; + } + +- if (dev->config_ops->vhost_dev_config_notifier) { +- ret = dev->config_ops->vhost_dev_config_notifier(dev); +- } +- +- return ret; ++ return dev->config_ops->vhost_dev_config_notifier(dev); + } + + static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, +@@ -1496,7 +1516,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) || + vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) { +- return -1; ++ return -EINVAL; + } + + n = &user->notifier[queue_idx]; +@@ -1509,13 +1529,13 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + + /* Sanity check. */ + if (area->size != page_size) { +- return -1; ++ return -EINVAL; + } + + addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, area->offset); + if (addr == MAP_FAILED) { +- return -1; ++ return -EFAULT; + } + + name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", +@@ -1531,7 +1551,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, + if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { + object_unparent(OBJECT(&n->mr)); + munmap(addr, page_size); +- return -1; ++ return -ENXIO; + } + + n->addr = addr; +@@ -1660,14 +1680,15 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { ++ int saved_errno = errno; + error_report("socketpair() failed"); +- return -1; ++ return -saved_errno; + } + + ioc = QIO_CHANNEL(qio_channel_socket_new_fd(sv[0], &local_err)); + if (!ioc) { + error_report_err(local_err); +- return -1; ++ return -ECONNREFUSED; + } + u->slave_ioc = ioc; + slave_update_read_handler(dev, NULL); +@@ -1774,35 +1795,38 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + int ufd; ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_POSTCOPY_ADVISE, + .hdr.flags = VHOST_USER_VERSION, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_advise to vhost"); +- return -1; ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { + error_setg(errp, "Failed to get postcopy_advise reply from vhost"); +- return -1; ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_POSTCOPY_ADVISE) { + error_setg(errp, "Unexpected msg type. Expected %d received %d", + VHOST_USER_POSTCOPY_ADVISE, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size) { + error_setg(errp, "Received bad msg size."); +- return -1; ++ return -EPROTO; + } + ufd = qemu_chr_fe_get_msgfd(chr); + if (ufd < 0) { + error_setg(errp, "%s: Failed to get ufd", __func__); +- return -1; ++ return -EIO; + } + qemu_set_nonblock(ufd); + +@@ -1816,7 +1840,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) + return 0; + #else + error_setg(errp, "Postcopy not supported on non-Linux systems"); +- return -1; ++ return -ENOSYS; + #endif + } + +@@ -1832,10 +1856,13 @@ static int vhost_user_postcopy_listen(struct vhost_dev *dev, Error **errp) + .hdr.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, + }; + u->postcopy_listen = true; ++ + trace_vhost_user_postcopy_listen(); +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_listen to vhost"); +- return -1; ++ return ret; + } + + ret = process_message_reply(dev, &msg); +@@ -1860,9 +1887,11 @@ static int vhost_user_postcopy_end(struct vhost_dev *dev, Error **errp) + struct vhost_user *u = dev->opaque; + + trace_vhost_user_postcopy_end_entry(); +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ++ ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { + error_setg(errp, "Failed to send postcopy_end to vhost"); +- return -1; ++ return ret; + } + + ret = process_message_reply(dev, &msg); +@@ -2141,7 +2170,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) + + return vhost_user_write(dev, &msg, NULL, 0); + } +- return -1; ++ return -ENOTSUP; + } + + static bool vhost_user_can_merge(struct vhost_dev *dev, +@@ -2162,6 +2191,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + VhostUserMsg msg; + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); ++ int ret; + + if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) { + return 0; +@@ -2175,8 +2205,9 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + /* If reply_ack supported, slave has to ack specified MTU is valid */ +@@ -2190,6 +2221,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) + static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev, + struct vhost_iotlb_msg *imsg) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_IOTLB_MSG, + .hdr.size = sizeof(msg.payload.iotlb), +@@ -2197,8 +2229,9 @@ static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev, + .payload.iotlb = *imsg, + }; + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -EFAULT; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + return process_message_reply(dev, &msg); +@@ -2213,6 +2246,7 @@ static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled) + static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + uint32_t config_len, Error **errp) + { ++ int ret; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GET_CONFIG, + .hdr.flags = VHOST_USER_VERSION, +@@ -2229,26 +2263,28 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + + msg.payload.config.offset = 0; + msg.payload.config.size = config_len; +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_setg_errno(errp, EPROTO, "vhost_get_config failed"); +- return -EPROTO; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "vhost_get_config failed"); ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- error_setg_errno(errp, EPROTO, "vhost_get_config failed"); +- return -EPROTO; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "vhost_get_config failed"); ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_CONFIG) { + error_setg(errp, + "Received unexpected msg type. Expected %d received %d", + VHOST_USER_GET_CONFIG, msg.hdr.request); +- return -EINVAL; ++ return -EPROTO; + } + + if (msg.hdr.size != VHOST_USER_CONFIG_HDR_SIZE + config_len) { + error_setg(errp, "Received bad msg size."); +- return -EINVAL; ++ return -EPROTO; + } + + memcpy(config, msg.payload.config.region, config_len); +@@ -2259,6 +2295,7 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, + static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size, uint32_t flags) + { ++ int ret; + uint8_t *p; + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); +@@ -2271,7 +2308,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { +- return -1; ++ return -ENOTSUP; + } + + if (reply_supported) { +@@ -2279,7 +2316,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + } + + if (size > VHOST_USER_MAX_CONFIG_SIZE) { +- return -1; ++ return -EINVAL; + } + + msg.payload.config.offset = offset, +@@ -2288,8 +2325,9 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, + p = msg.payload.config.region; + memcpy(p, data, size); + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + + if (reply_supported) { +@@ -2303,6 +2341,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + void *session_info, + uint64_t *session_id) + { ++ int ret; + bool crypto_session = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); + CryptoDevBackendSymSessionInfo *sess_info = session_info; +@@ -2316,7 +2355,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + + if (!crypto_session) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + + memcpy(&msg.payload.session.session_setup_data, sess_info, +@@ -2329,31 +2368,35 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + memcpy(&msg.payload.session.auth_key, sess_info->auth_key, + sess_info->auth_key_len); + } +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_report("vhost_user_write() return -1, create session failed"); +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_report("vhost_user_write() return %d, create session failed", ++ ret); ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- error_report("vhost_user_read() return -1, create session failed"); +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ error_report("vhost_user_read() return %d, create session failed", ++ ret); ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) { + error_report("Received unexpected msg type. Expected %d received %d", + VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.session)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + if (msg.payload.session.session_id < 0) { + error_report("Bad session id: %" PRId64 "", + msg.payload.session.session_id); +- return -1; ++ return -EINVAL; + } + *session_id = msg.payload.session.session_id; + +@@ -2363,6 +2406,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, + static int + vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) + { ++ int ret; + bool crypto_session = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); + VhostUserMsg msg = { +@@ -2374,12 +2418,14 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) + + if (!crypto_session) { + error_report("vhost-user trying to send unhandled ioctl"); +- return -1; ++ return -ENOTSUP; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- error_report("vhost_user_write() return -1, close session failed"); +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ error_report("vhost_user_write() return %d, close session failed", ++ ret); ++ return ret; + } + + return 0; +@@ -2401,6 +2447,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + { + void *addr; + int fd; ++ int ret; + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + VhostUserMsg msg = { +@@ -2416,24 +2463,26 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + return 0; + } + +- if (vhost_user_write(dev, &msg, NULL, 0) < 0) { +- return -1; ++ ret = vhost_user_write(dev, &msg, NULL, 0); ++ if (ret < 0) { ++ return ret; + } + +- if (vhost_user_read(dev, &msg) < 0) { +- return -1; ++ ret = vhost_user_read(dev, &msg); ++ if (ret < 0) { ++ return ret; + } + + if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) { + error_report("Received unexpected msg type. " + "Expected %d received %d", + VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request); +- return -1; ++ return -EPROTO; + } + + if (msg.hdr.size != sizeof(msg.payload.inflight)) { + error_report("Received bad msg size."); +- return -1; ++ return -EPROTO; + } + + if (!msg.payload.inflight.mmap_size) { +@@ -2443,7 +2492,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + fd = qemu_chr_fe_get_msgfd(chr); + if (fd < 0) { + error_report("Failed to get mem fd"); +- return -1; ++ return -EIO; + } + + addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE, +@@ -2452,7 +2501,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev, + if (addr == MAP_FAILED) { + error_report("Failed to mmap mem fd"); + close(fd); +- return -1; ++ return -EFAULT; + } + + inflight->addr = addr; +@@ -2482,11 +2531,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev, + return 0; + } + +- if (vhost_user_write(dev, &msg, &inflight->fd, 1) < 0) { +- return -1; +- } +- +- return 0; ++ return vhost_user_write(dev, &msg, &inflight->fd, 1); + } + + bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) +-- +2.27.0 + diff --git a/vhost-vdpa-add-support-for-config-interrupt-new.patch b/vhost-vdpa-add-support-for-config-interrupt-new.patch new file mode 100644 index 0000000..9d67395 --- /dev/null +++ b/vhost-vdpa-add-support-for-config-interrupt-new.patch @@ -0,0 +1,62 @@ +From 1a5b6648f563f7991fba0c4cb07a3a4d05834c83 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:46 +0800 +Subject: [PATCH] vhost-vdpa: add support for config interrupt + +Add new call back function in vhost-vdpa, The function +vhost_set_config_call can set the event fd to kernel. +This function will be called in the vhost_dev_start +and vhost_dev_stop + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-6-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 + + hw/virtio/vhost-vdpa.c | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index edbbbeb621..0396518241 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -61,6 +61,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 ++vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 8b44f5a7b8..c9289e2c01 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -719,6 +719,13 @@ static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev) + return 0; + } + ++static int vhost_vdpa_set_config_call(struct vhost_dev *dev, ++ int fd) ++{ ++ trace_vhost_vdpa_set_config_call(dev, fd); ++ return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); ++} ++ + static void vhost_vdpa_dump_config(struct vhost_dev *dev, const uint8_t *config, + uint32_t config_len) + { +@@ -1311,6 +1318,7 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/vhost-vdpa-add-support-for-config-interrupt.patch b/vhost-vdpa-add-support-for-config-interrupt.patch new file mode 100644 index 0000000..f154b19 --- /dev/null +++ b/vhost-vdpa-add-support-for-config-interrupt.patch @@ -0,0 +1,59 @@ +From cc9df379f703274eb600dd6af7dbacae4d457d5f Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:51 +0800 +Subject: [PATCH] vhost-vdpa: add support for config interrupt + +Add new call back function in vhost-vdpa, this function will +set the event fd to kernel. This function will be called +in the vhost_dev_start and vhost_dev_stop + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-6-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/trace-events | 1 + + hw/virtio/vhost-vdpa.c | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events +index 650e521e35..39c36ff7a6 100644 +--- a/hw/virtio/trace-events ++++ b/hw/virtio/trace-events +@@ -53,6 +53,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI + vhost_vdpa_set_owner(void *dev) "dev: %p" + vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 + vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 ++vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d" + + # virtio.c + virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 287025ef93..b7bbd65cdd 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -728,6 +728,12 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev, + trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); + return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); + } ++static int vhost_vdpa_set_config_call(struct vhost_dev *dev, ++ int fd) ++{ ++ trace_vhost_vdpa_set_config_call(dev, fd); ++ return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd); ++} + + static int vhost_vdpa_get_features(struct vhost_dev *dev, + uint64_t *features) +@@ -808,6 +814,7 @@ const VhostOps vdpa_ops = { + .vhost_get_device_id = vhost_vdpa_get_device_id, + .vhost_vq_get_addr = vhost_vdpa_vq_get_addr, + .vhost_force_iommu = vhost_vdpa_force_iommu, ++ .vhost_set_config_call = vhost_vdpa_set_config_call, + .vhost_set_used_memslots = vhost_vdpa_set_used_memslots, + .vhost_get_used_memslots = vhost_vdpa_get_used_memslots, + }; +-- +2.27.0 + diff --git a/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch b/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch new file mode 100644 index 0000000..c17fb9d --- /dev/null +++ b/vhost-vdpa-allow-passing-opened-vhostfd-to-vhost-vdp.patch @@ -0,0 +1,114 @@ +From 2feaf4260eae797c518c86d181f24eca5948b8b0 Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Sat, 8 Oct 2022 00:58:58 -0700 +Subject: [PATCH] vhost-vdpa: allow passing opened vhostfd to vhost-vdpa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar to other vhost backends, vhostfd can be passed to vhost-vdpa +backend as another parameter to instantiate vhost-vdpa net client. +This would benefit the use case where only open file descriptors, as +opposed to raw vhost-vdpa device paths, are accessible from the QEMU +process. + +(qemu) netdev_add type=vhost-vdpa,vhostfd=61,id=vhost-vdpa1 + +Signed-off-by: Si-Wei Liu +Acked-by: Eugenio Pérez +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 25 ++++++++++++++++++++----- + qapi/net.json | 3 +++ + qemu-options.hx | 6 ++++-- + 3 files changed, 27 insertions(+), 7 deletions(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index c8c433002d..58225649f9 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -642,14 +642,29 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); + opts = &netdev->u.vhost_vdpa; +- if (!opts->vhostdev) { +- error_setg(errp, "vdpa character device not specified with vhostdev"); ++ if (!opts->has_vhostdev && !opts->has_vhostfd) { ++ error_setg(errp, ++ "vhost-vdpa: neither vhostdev= nor vhostfd= was specified"); + return -1; + } + +- vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); +- if (vdpa_device_fd == -1) { +- return -errno; ++ if (opts->has_vhostdev && opts->has_vhostfd) { ++ error_setg(errp, ++ "vhost-vdpa: vhostdev= and vhostfd= are mutually exclusive"); ++ return -1; ++ } ++ ++ if (opts->has_vhostdev) { ++ vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp); ++ if (vdpa_device_fd == -1) { ++ return -errno; ++ } ++ } else if (opts->has_vhostfd) { ++ vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp); ++ if (vdpa_device_fd == -1) { ++ error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: "); ++ return -1; ++ } + } + + r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp); +diff --git a/qapi/net.json b/qapi/net.json +index 6a5460ce56..a38a7b611b 100644 +--- a/qapi/net.json ++++ b/qapi/net.json +@@ -442,6 +442,8 @@ + # @vhostdev: path of vhost-vdpa device + # (default:'/dev/vhost-vdpa-0') + # ++# @vhostfd: file descriptor of an already opened vhost vdpa device ++# + # @queues: number of queues to be created for multiqueue vhost-vdpa + # (default: 1) + # +@@ -456,6 +458,7 @@ + { 'struct': 'NetdevVhostVDPAOptions', + 'data': { + '*vhostdev': 'str', ++ '*vhostfd': 'str', + '*queues': 'int', + '*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } } + +diff --git a/qemu-options.hx b/qemu-options.hx +index e329ec58ca..e25b76771d 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -2739,8 +2739,10 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, + " configure a vhost-user network, backed by a chardev 'dev'\n" + #endif + #ifdef __linux__ +- "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" ++ "-netdev vhost-vdpa,id=str[,vhostdev=/path/to/dev][,vhostfd=h]\n" + " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" ++ " use 'vhostdev=/path/to/dev' to open a vhost vdpa device\n" ++ " use 'vhostfd=h' to connect to an already opened vhost vdpa device\n" + #endif + "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" + " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) +@@ -3220,7 +3222,7 @@ SRST + -netdev type=vhost-user,id=net0,chardev=chr0 \ + -device virtio-net-pci,netdev=net0 + +-``-netdev vhost-vdpa,vhostdev=/path/to/dev`` ++``-netdev vhost-vdpa[,vhostdev=/path/to/dev][,vhostfd=h]`` + Establish a vhost-vdpa netdev. + + vDPA device is a device that uses a datapath which complies with +-- +2.27.0 + diff --git a/vhost-vdpa-backend-feature-should-set-only-once.patch b/vhost-vdpa-backend-feature-should-set-only-once.patch new file mode 100644 index 0000000..b14e65f --- /dev/null +++ b/vhost-vdpa-backend-feature-should-set-only-once.patch @@ -0,0 +1,49 @@ +From a089328f183371ec7f7cd641f46beeeea2c9decc Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:16 -0700 +Subject: [PATCH] vhost-vdpa: backend feature should set only once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The vhost_vdpa_one_time_request() branch in +vhost_vdpa_set_backend_cap() incorrectly sends down +ioctls on vhost_dev with non-zero index. This may +end up with multiple VHOST_SET_BACKEND_FEATURES +ioctl calls sent down on the vhost-vdpa fd that is +shared between all these vhost_dev's. + +To fix it, send down ioctl only once via the first +vhost_dev with index 0. Toggle the polarity of the +vhost_vdpa_one_time_request() test should do the +trick. + +Fixes: 4d191cfdc7de ("vhost-vdpa: classify one time request") +Signed-off-by: Si-Wei Liu +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Acked-by: Eugenio Pérez +Message-Id: <1651890498-24478-6-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 1360f2eaf7..cb74d71b80 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -669,7 +669,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_one_time_request(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +-- +2.27.0 + diff --git a/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch b/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch new file mode 100644 index 0000000..3c67ccd --- /dev/null +++ b/vhost-vdpa-change-name-and-polarity-for-vhost_vdpa_o.patch @@ -0,0 +1,111 @@ +From fdf8d168adeac8e91bb61d4940756af0df3b8d2c Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:17 -0700 +Subject: [PATCH] vhost-vdpa: change name and polarity for + vhost_vdpa_one_time_request() + +The name vhost_vdpa_one_time_request() was confusing. No +matter whatever it returns, its typical occurrence had +always been at requests that only need to be applied once. +And the name didn't suggest what it actually checks for. +Change it to vhost_vdpa_first_dev() with polarity flipped +for better readibility of code. That way it is able to +reflect what the check is really about. + +This call is applicable to request which performs operation +only once, before queues are set up, and usually at the beginning +of the caller function. Document the requirement for it in place. + +Signed-off-by: Si-Wei Liu +Message-Id: <1651890498-24478-7-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Acked-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index cb74d71b80..73ff599f2b 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -370,11 +370,18 @@ static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) + v->iova_range.last); + } + +-static bool vhost_vdpa_one_time_request(struct vhost_dev *dev) ++/* ++ * The use of this function is for requests that only need to be ++ * applied once. Typically such request occurs at the beginning ++ * of operation, and before setting up queues. It should not be ++ * used for request that performs operation until all queues are ++ * set, which would need to check dev->vq_index_end instead. ++ */ ++static bool vhost_vdpa_first_dev(struct vhost_dev *dev) + { + struct vhost_vdpa *v = dev->opaque; + +- return v->index != 0; ++ return v->index == 0; + } + + static int vhost_vdpa_get_dev_features(struct vhost_dev *dev, +@@ -455,7 +462,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) + + vhost_vdpa_get_iova_range(v); + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -598,7 +605,7 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev) + static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + struct vhost_memory *mem) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -627,7 +634,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + struct vhost_vdpa *v = dev->opaque; + int ret; + +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -669,7 +676,7 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) + + features &= f; + +- if (!vhost_vdpa_one_time_request(dev)) { ++ if (vhost_vdpa_first_dev(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; +@@ -1122,7 +1129,7 @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, + struct vhost_log *log) + { + struct vhost_vdpa *v = dev->opaque; +- if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) { ++ if (v->shadow_vqs_enabled || !vhost_vdpa_first_dev(dev)) { + return 0; + } + +@@ -1244,7 +1251,7 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, + + static int vhost_vdpa_set_owner(struct vhost_dev *dev) + { +- if (vhost_vdpa_one_time_request(dev)) { ++ if (!vhost_vdpa_first_dev(dev)) { + return 0; + } + +-- +2.27.0 + diff --git a/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch b/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch new file mode 100644 index 0000000..b49311e --- /dev/null +++ b/vhost-vdpa-fix-assert-virtio_net_get_subqueue-nc-asy.patch @@ -0,0 +1,75 @@ +From 0462d79e6b607799538ac96b9486b60ee6819e9f Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Tue, 8 Nov 2022 12:19:28 +0800 +Subject: [PATCH] vhost-vdpa: fix assert + !virtio_net_get_subqueue(nc)->async_tx.elem in virtio_net_reset + +The citing commit has incorrect code in vhost_vdpa_receive() that returns +zero instead of full packet size to the caller. This renders pending packets +unable to be freed so then get clogged in the tx queue forever. When device +is being reset later on, below assertion failure ensues: + +0 0x00007f86d53bb387 in raise () from /lib64/libc.so.6 +1 0x00007f86d53bca78 in abort () from /lib64/libc.so.6 +2 0x00007f86d53b41a6 in __assert_fail_base () from /lib64/libc.so.6 +3 0x00007f86d53b4252 in __assert_fail () from /lib64/libc.so.6 +4 0x000055b8f6ff6fcc in virtio_net_reset (vdev=) at /usr/src/debug/qemu/hw/net/virtio-net.c:563 +5 0x000055b8f7012fcf in virtio_reset (opaque=0x55b8faf881f0) at /usr/src/debug/qemu/hw/virtio/virtio.c:1993 +6 0x000055b8f71f0086 in virtio_bus_reset (bus=bus@entry=0x55b8faf88178) at /usr/src/debug/qemu/hw/virtio/virtio-bus.c:102 +7 0x000055b8f71f1620 in virtio_pci_reset (qdev=) at /usr/src/debug/qemu/hw/virtio/virtio-pci.c:1845 +8 0x000055b8f6fafc6c in memory_region_write_accessor (mr=, addr=, value=, + size=, shift=, mask=, attrs=...) at /usr/src/debug/qemu/memory.c:483 +9 0x000055b8f6fadce9 in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f867e7fb7e8, size=size@entry=1, + access_size_min=, access_size_max=, access_fn=0x55b8f6fafc20 , + mr=0x55b8faf80a50, attrs=...) at /usr/src/debug/qemu/memory.c:544 +10 0x000055b8f6fb1d0b in memory_region_dispatch_write (mr=mr@entry=0x55b8faf80a50, addr=addr@entry=20, data=0, op=, + attrs=attrs@entry=...) at /usr/src/debug/qemu/memory.c:1470 +11 0x000055b8f6f62ada in flatview_write_continue (fv=fv@entry=0x7f86ac04cd20, addr=addr@entry=549755813908, attrs=..., + attrs@entry=..., buf=buf@entry=0x7f86d0223028
, len=len@entry=1, addr1=20, l=1, + mr=0x55b8faf80a50) at /usr/src/debug/qemu/exec.c:3266 +12 0x000055b8f6f62c8f in flatview_write (fv=0x7f86ac04cd20, addr=549755813908, attrs=..., + buf=0x7f86d0223028
, len=1) at /usr/src/debug/qemu/exec.c:3306 +13 0x000055b8f6f674cb in address_space_write (as=, addr=, attrs=..., buf=, + len=) at /usr/src/debug/qemu/exec.c:3396 +14 0x000055b8f6f67575 in address_space_rw (as=, addr=, attrs=..., attrs@entry=..., + buf=buf@entry=0x7f86d0223028
, len=, is_write=) + at /usr/src/debug/qemu/exec.c:3406 +15 0x000055b8f6fc1cc8 in kvm_cpu_exec (cpu=cpu@entry=0x55b8f9aa0e10) at /usr/src/debug/qemu/accel/kvm/kvm-all.c:2410 +16 0x000055b8f6fa5f5e in qemu_kvm_cpu_thread_fn (arg=0x55b8f9aa0e10) at /usr/src/debug/qemu/cpus.c:1318 +17 0x000055b8f7336e16 in qemu_thread_start (args=0x55b8f9ac8480) at /usr/src/debug/qemu/util/qemu-thread-posix.c:519 +18 0x00007f86d575aea5 in start_thread () from /lib64/libpthread.so.0 +19 0x00007f86d5483b2d in clone () from /lib64/libc.so.6 + +Make vhost_vdpa_receive() return the size passed in as is, so that the +caller qemu_deliver_packet_iov() would eventually propagate it back to +virtio_net_flush_tx() to release pending packets from the async_tx queue. +Which corresponds to the drop path where qemu_sendv_packet_async() returns +non-zero in virtio_net_flush_tx(). + +Fixes: 846a1e85da64 ("vdpa: Add dummy receive callback") +Cc: Eugenio Perez Martin +Signed-off-by: Si-Wei Liu +Signed-off-by: Jason Wang +Signed-off-by: Stefan Hajnoczi +Message-Id: <20221108041929.18417-2-jasowang@redhat.com> +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index c89f9d1243..eae2ed364f 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -218,7 +218,7 @@ static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc, + static ssize_t vhost_vdpa_receive(NetClientState *nc, const uint8_t *buf, + size_t size) + { +- return 0; ++ return size; + } + + static NetClientInfo net_vhost_vdpa_info = { +-- +2.27.0 + diff --git a/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch b/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch new file mode 100644 index 0000000..ecb4519 --- /dev/null +++ b/vhost-vdpa-fix-improper-cleanup-in-net_init_vhost_vd.patch @@ -0,0 +1,36 @@ +From ddd117ccb7dfc57dcd45d52d35cd71f746d81c3a Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:14 -0700 +Subject: [PATCH] vhost-vdpa: fix improper cleanup in net_init_vhost_vdpa + +... such that no memory leaks on dangling net clients in case of +error. + +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-4-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + net/vhost-vdpa.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index 9ba0f7bfca..7201c79116 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -314,7 +314,9 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, + + err: + if (i) { +- qemu_del_net_client(ncs[0]); ++ for (i--; i >= 0; i--) { ++ qemu_del_net_client(ncs[i]); ++ } + } + qemu_close(vdpa_device_fd); + +-- +2.27.0 + diff --git a/vhost-vdpa-fix-typo-in-a-comment.patch b/vhost-vdpa-fix-typo-in-a-comment.patch new file mode 100644 index 0000000..b55cff0 --- /dev/null +++ b/vhost-vdpa-fix-typo-in-a-comment.patch @@ -0,0 +1,35 @@ +From 208e92b8d029d8483f994858304d49af5b6d875a Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Mon, 28 Mar 2022 17:20:22 +0200 +Subject: [PATCH] vhost-vdpa: fix typo in a comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Replace vpda with vdpa. + +Signed-off-by: Stefano Garzarella +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20220328152022.73245-1-sgarzare@redhat.com> +Signed-off-by: Laurent Vivier +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index 3b5456cc0e..b66697da6e 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -301,7 +301,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, + memory_region_unref(section->mr); + } + /* +- * IOTLB API is used by vhost-vpda which requires incremental updating ++ * IOTLB API is used by vhost-vdpa which requires incremental updating + * of the mapping. So we can not use generic vhost memory listener which + * depends on the addnop(). + */ +-- +2.27.0 + diff --git a/vhost-vdpa-stick-to-errno-error-return-convention.patch b/vhost-vdpa-stick-to-errno-error-return-convention.patch new file mode 100644 index 0000000..1ef8091 --- /dev/null +++ b/vhost-vdpa-stick-to-errno-error-return-convention.patch @@ -0,0 +1,107 @@ +From 69fdbac8d37a02cfc91e6c849a768e58e57dd15f Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:55 +0800 +Subject: [PATCH] vhost-vdpa: stick to -errno error return convention + +Almost all VhostOps methods in vdpa_ops follow the convention of +returning negated errno on error. + +Adjust the few that don't. To that end, rework vhost_vdpa_add_status to +check if setting of the requested status bits has succeeded and return +the respective error code it hasn't, and propagate the error codes +wherever it's appropriate. + +Signed-off-by: Roman Kagan +Message-Id: <20211111153354.18807-8-rvkagan@yandex-team.ru> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-vdpa.c | 37 +++++++++++++++++++++++-------------- + 1 file changed, 23 insertions(+), 14 deletions(-) + +diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c +index b7bbd65cdd..d8fba0b714 100644 +--- a/hw/virtio/vhost-vdpa.c ++++ b/hw/virtio/vhost-vdpa.c +@@ -294,18 +294,34 @@ static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request, + return ret < 0 ? -errno : ret; + } + +-static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) ++static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) + { + uint8_t s; ++ int ret; + + trace_vhost_vdpa_add_status(dev, status); +- if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) { +- return; ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s); ++ if (ret < 0) { ++ return ret; + } + + s |= status; + +- vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (!(s & status)) { ++ return -EIO; ++ } ++ ++ return 0; + } + + static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) +@@ -487,7 +503,7 @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev, + } + } + if (mem->padding) { +- return -1; ++ return -EINVAL; + } + + return 0; +@@ -504,14 +520,11 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, + + trace_vhost_vdpa_set_features(dev, features); + ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); +- uint8_t status = 0; + if (ret) { + return ret; + } +- vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); +- vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); + +- return !(status & VIRTIO_CONFIG_S_FEATURES_OK); ++ return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); + } + + static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) +@@ -653,12 +666,8 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) + } + + if (started) { +- uint8_t status = 0; + memory_listener_register(&v->listener, &address_space_memory); +- vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); +- vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status); +- +- return !(status & VIRTIO_CONFIG_S_DRIVER_OK); ++ return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); + } else { + vhost_vdpa_reset_device(dev); + vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | +-- +2.27.0 + diff --git a/vhost_net-Add-NetClientInfo-start-callback.patch b/vhost_net-Add-NetClientInfo-start-callback.patch new file mode 100644 index 0000000..546c4ef --- /dev/null +++ b/vhost_net-Add-NetClientInfo-start-callback.patch @@ -0,0 +1,64 @@ +From 533bcae898152213703a1f15b3d4a938292fd23f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:30 +0200 +Subject: [PATCH] vhost_net: Add NetClientInfo start callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is used by the backend to perform actions before the device is +started. + +In particular, vdpa net use it to map CVQ buffers to the device, so it +can send control commands using them. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 7 +++++++ + include/net/net.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index bea053a742..92df7558bf 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -307,6 +307,13 @@ static int vhost_net_start_one(struct vhost_net *net, + struct vhost_vring_file file = { }; + int r; + ++ if (net->nc->info->start) { ++ r = net->nc->info->start(net->nc); ++ if (r < 0) { ++ return r; ++ } ++ } ++ + r = vhost_dev_enable_notifiers(&net->dev, dev); + if (r < 0) { + goto fail_notifiers; +diff --git a/include/net/net.h b/include/net/net.h +index 523136c7ac..ad9e80083a 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -44,6 +44,7 @@ typedef struct NICConf { + + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); ++typedef int (NetStart)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); + typedef void (NetCleanup) (NetClientState *); +@@ -71,6 +72,7 @@ typedef struct NetClientInfo { + NetReceive *receive_raw; + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; ++ NetStart *start; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; + QueryRxFilter *query_rx_filter; +-- +2.27.0 + diff --git a/vhost_net-Add-NetClientInfo-stop-callback.patch b/vhost_net-Add-NetClientInfo-stop-callback.patch new file mode 100644 index 0000000..80cbd52 --- /dev/null +++ b/vhost_net-Add-NetClientInfo-stop-callback.patch @@ -0,0 +1,59 @@ +From d25c4237821c994e36b7a23e0a0c609993707d47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:31 +0200 +Subject: [PATCH] vhost_net: Add NetClientInfo stop callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Used by the backend to perform actions after the device is stopped. + +In particular, vdpa net use it to unmap CVQ buffers to the device, +cleaning the actions performed in prepare(). + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 3 +++ + include/net/net.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index 92df7558bf..fe6932171b 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -383,6 +383,9 @@ static void vhost_net_stop_one(struct vhost_net *net, + net->nc->info->poll(net->nc, true); + } + vhost_dev_stop(&net->dev, dev); ++ if (net->nc->info->stop) { ++ net->nc->info->stop(net->nc); ++ } + vhost_dev_disable_notifiers(&net->dev, dev); + } + +diff --git a/include/net/net.h b/include/net/net.h +index ad9e80083a..476ad45b9a 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -45,6 +45,7 @@ typedef struct NICConf { + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); + typedef int (NetStart)(NetClientState *); ++typedef void (NetStop)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); + typedef void (NetCleanup) (NetClientState *); +@@ -73,6 +74,7 @@ typedef struct NetClientInfo { + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; + NetStart *start; ++ NetStop *stop; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; + QueryRxFilter *query_rx_filter; +-- +2.27.0 + diff --git a/vhost_net-add-NetClientState-load-callback.patch b/vhost_net-add-NetClientState-load-callback.patch new file mode 100644 index 0000000..39d9352 --- /dev/null +++ b/vhost_net-add-NetClientState-load-callback.patch @@ -0,0 +1,64 @@ +From 4b0c6e40f26af49416d00b186840344b424b48ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 23 Aug 2022 20:30:35 +0200 +Subject: [PATCH] vhost_net: add NetClientState->load() callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It allows per-net client operations right after device's successful +start. In particular, to load the device status. + +Vhost-vdpa net will use it to add the CVQ buffers to restore the device +status. + +Signed-off-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 7 +++++++ + include/net/net.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index fe6932171b..f709c060b6 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -344,6 +344,13 @@ static int vhost_net_start_one(struct vhost_net *net, + } + } + } ++ ++ if (net->nc->info->load) { ++ r = net->nc->info->load(net->nc); ++ if (r < 0) { ++ goto fail; ++ } ++ } + return 0; + fail: + file.fd = -1; +diff --git a/include/net/net.h b/include/net/net.h +index 476ad45b9a..81d0b21def 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -45,6 +45,7 @@ typedef struct NICConf { + typedef void (NetPoll)(NetClientState *, bool enable); + typedef bool (NetCanReceive)(NetClientState *); + typedef int (NetStart)(NetClientState *); ++typedef int (NetLoad)(NetClientState *); + typedef void (NetStop)(NetClientState *); + typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); + typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); +@@ -74,6 +75,7 @@ typedef struct NetClientInfo { + NetReceiveIOV *receive_iov; + NetCanReceive *can_receive; + NetStart *start; ++ NetLoad *load; + NetStop *stop; + NetCleanup *cleanup; + LinkStatusChanged *link_status_changed; +-- +2.27.0 + diff --git a/virtio-Add-vhost_svq_get_vring_addr.patch b/virtio-Add-vhost_svq_get_vring_addr.patch new file mode 100644 index 0000000..67f864e --- /dev/null +++ b/virtio-Add-vhost_svq_get_vring_addr.patch @@ -0,0 +1,96 @@ +From c9b863e96be5277e775cb424cf8ea34f8f921776 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Mon, 14 Mar 2022 18:34:45 +0100 +Subject: [PATCH] virtio: Add vhost_svq_get_vring_addr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It reports the shadow virtqueue address from qemu virtual address space. + +Since this will be different from the guest's vaddr, but the device can +access it, SVQ takes special care about its alignment & lack of garbage +data. It assumes that IOMMU will work in host_page_size ranges for that. + +Signed-off-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/virtio/vhost-shadow-virtqueue.c | 29 +++++++++++++++++++++++++++++ + hw/virtio/vhost-shadow-virtqueue.h | 9 +++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index 519328445c..573ac0d9cf 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -106,6 +106,35 @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd) + } + } + ++/** ++ * Get the shadow vq vring address. ++ * @svq: Shadow virtqueue ++ * @addr: Destination to store address ++ */ ++void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr) ++{ ++ addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc; ++ addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail; ++ addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used; ++} ++ ++size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq) ++{ ++ size_t desc_size = sizeof(vring_desc_t) * svq->vring.num; ++ size_t avail_size = offsetof(vring_avail_t, ring) + ++ sizeof(uint16_t) * svq->vring.num; ++ ++ return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size); ++} ++ ++size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq) ++{ ++ size_t used_size = offsetof(vring_used_t, ring) + ++ sizeof(vring_used_elem_t) * svq->vring.num; ++ return ROUND_UP(used_size, qemu_real_host_page_size); ++} ++ + /** + * Set a new file descriptor for the guest to kick the SVQ and notify for avail + * +diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h +index 9e12f77201..82cea1c3fa 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.h ++++ b/hw/virtio/vhost-shadow-virtqueue.h +@@ -11,9 +11,14 @@ + #define VHOST_SHADOW_VIRTQUEUE_H + + #include "qemu/event_notifier.h" ++#include "hw/virtio/virtio.h" ++#include "standard-headers/linux/vhost_types.h" + + /* Shadow virtqueue to relay notifications */ + typedef struct VhostShadowVirtqueue { ++ /* Shadow vring */ ++ struct vring vring; ++ + /* Shadow kick notifier, sent to vhost */ + EventNotifier hdev_kick; + /* Shadow call notifier, sent to vhost */ +@@ -37,6 +42,10 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp); + + void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); + void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); ++void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, ++ struct vhost_vring_addr *addr); ++size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); ++size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); + + void vhost_svq_stop(VhostShadowVirtqueue *svq); + +-- +2.27.0 + diff --git a/virtio-add-support-for-configure-interrupt-new.patch b/virtio-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000..72a1347 --- /dev/null +++ b/virtio-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,102 @@ +From 90152f58401b828febbb060cff86330827e6befe Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:47 +0800 +Subject: [PATCH] virtio: add support for configure interrupt + +Add the functions to support the configure interrupt in virtio +The function virtio_config_guest_notifier_read will notify the +guest if there is an configure interrupt. +The function virtio_config_set_guest_notifier_fd_handler is +to set the fd hander for the notifier + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-7-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 +++++++++++++++++++++++++++++ + include/hw/virtio/virtio.h | 4 ++++ + 2 files changed, 33 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 12f4a8ab3d..e3f392fc59 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3548,7 +3548,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } ++static void virtio_config_guest_notifier_read(EventNotifier *n) ++{ ++ VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + ++ if (event_notifier_test_and_clear(n)) { ++ virtio_notify_config(vdev); ++ } ++} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3565,6 +3572,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd) ++{ ++ EventNotifier *n; ++ n = &vdev->config_notifier; ++ if (assign && !with_irqfd) { ++ event_notifier_set_handler(n, virtio_config_guest_notifier_read); ++ } else { ++ event_notifier_set_handler(n, NULL); ++ } ++ if (!assign) { ++ /* Test and clear notifier before closing it,*/ ++ /* in case poll callback didn't have time to run. */ ++ virtio_config_guest_notifier_read(n); ++ } ++} ++ + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3638,6 +3662,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) ++{ ++ return &vdev->config_notifier; ++} ++ + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 91d1c3433a..43509b33ff 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -114,6 +114,7 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; ++ EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -329,6 +330,9 @@ void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, + VirtIOHandleAIOOutput handle_output); + VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); + VirtQueue *virtio_vector_next_queue(VirtQueue *vq); ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd); + + static inline void virtio_add_feature(uint64_t *features, unsigned int fbit) + { +-- +2.27.0 + diff --git a/virtio-add-support-for-configure-interrupt.patch b/virtio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..b5bc73a --- /dev/null +++ b/virtio-add-support-for-configure-interrupt.patch @@ -0,0 +1,106 @@ +From 3ada114454dba1f4b8c6c30e64dfeedd41a6efc8 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:52 +0800 +Subject: [PATCH] virtio: add support for configure interrupt + +Add the functions to support the configure interrupt in virtio +The function virtio_config_guest_notifier_read will notify the +guest if there is an configure interrupt. +The function virtio_config_set_guest_notifier_fd_handler is +to set the fd hander for the notifier + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-7-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 29 +++++++++++++++++++++++++++++ + include/hw/virtio/virtio.h | 4 ++++ + 2 files changed, 33 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 071668e3e0..d90cabe868 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3546,7 +3546,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n) + virtio_irq(vq); + } + } ++static void virtio_config_guest_notifier_read(EventNotifier *n) ++{ ++ VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier); + ++ if (event_notifier_test_and_clear(n)) { ++ virtio_notify_config(vdev); ++ } ++} + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd) + { +@@ -3563,6 +3570,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + } + } + ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd) ++{ ++ EventNotifier *n; ++ n = &vdev->config_notifier; ++ if (assign && !with_irqfd) { ++ event_notifier_set_handler(n, virtio_config_guest_notifier_read); ++ } else { ++ event_notifier_set_handler(n, NULL); ++ } ++ if (!assign) { ++ /* Test and clear notifier before closing it,*/ ++ /* in case poll callback didn't have time to run. */ ++ virtio_config_guest_notifier_read(n); ++ } ++} ++ + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) + { + return &vq->guest_notifier; +@@ -3636,6 +3660,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev) ++{ ++ return &vdev->config_notifier; ++} ++ + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) + { + vq->host_notifier_enabled = enabled; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index c113a5b864..8788ccd1f3 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -112,6 +112,7 @@ struct VirtIODevice + bool use_guest_notifier_mask; + AddressSpace *dma_as; + QLIST_HEAD(, VirtQueue) *vector_queues; ++ EventNotifier config_notifier; + }; + + struct VirtioDeviceClass { +@@ -315,11 +316,14 @@ uint16_t virtio_get_queue_index(VirtQueue *vq); + EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); + void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd); ++void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev, ++ bool assign, bool with_irqfd); + int virtio_device_start_ioeventfd(VirtIODevice *vdev); + int virtio_device_grab_ioeventfd(VirtIODevice *vdev); + void virtio_device_release_ioeventfd(VirtIODevice *vdev); + bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); + EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); ++EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev); + void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); + void virtio_queue_host_notifier_read(EventNotifier *n); + void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, +-- +2.27.0 + diff --git a/virtio-add-vhost-support-for-virtio-devices.patch b/virtio-add-vhost-support-for-virtio-devices.patch new file mode 100644 index 0000000..5d94480 --- /dev/null +++ b/virtio-add-vhost-support-for-virtio-devices.patch @@ -0,0 +1,336 @@ +From b51d5c0def1e902a716bd3896d2f1868c635c554 Mon Sep 17 00:00:00 2001 +From: Jonah Palmer +Date: Fri, 1 Apr 2022 09:23:19 -0400 +Subject: [PATCH] virtio: add vhost support for virtio devices + +This patch adds a get_vhost() callback function for VirtIODevices that +returns the device's corresponding vhost_dev structure, if the vhost +device is running. This patch also adds a vhost_started flag for +VirtIODevices. + +Previously, a VirtIODevice wouldn't be able to tell if its corresponding +vhost device was active or not. + +Signed-off-by: Jonah Palmer +Message-Id: <1648819405-25696-3-git-send-email-jonah.palmer@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/block/vhost-user-blk.c | 7 +++++++ + hw/display/vhost-user-gpu.c | 7 +++++++ + hw/input/vhost-user-input.c | 7 +++++++ + hw/net/virtio-net.c | 9 +++++++++ + hw/scsi/vhost-scsi.c | 8 ++++++++ + hw/virtio/vhost-user-fs.c | 7 +++++++ + hw/virtio/vhost-user-rng.c | 7 +++++++ + hw/virtio/vhost-vsock-common.c | 7 +++++++ + hw/virtio/vhost.c | 4 +++- + hw/virtio/virtio-crypto.c | 10 ++++++++++ + hw/virtio/virtio.c | 1 + + include/hw/virtio/virtio.h | 3 +++ + 12 files changed, 76 insertions(+), 1 deletion(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index bcc3f83c4b..9bf18434c2 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -573,6 +573,12 @@ static void vhost_user_blk_instance_init(Object *obj) + "/disk@0,0", DEVICE(obj)); + } + ++static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserBlk *s = VHOST_USER_BLK(vdev); ++ return &s->dev; ++} ++ + static const VMStateDescription vmstate_vhost_user_blk = { + .name = "vhost-user-blk", + .minimum_version_id = 1, +@@ -607,6 +613,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data) + vdc->get_features = vhost_user_blk_get_features; + vdc->set_status = vhost_user_blk_set_status; + vdc->reset = vhost_user_blk_reset; ++ vdc->get_vhost = vhost_user_blk_get_vhost; + } + + static const TypeInfo vhost_user_blk_info = { +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 49df56cd14..6e93b463d6 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -565,6 +565,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) + g->vhost_gpu_fd = -1; + } + ++static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev) ++{ ++ VhostUserGPU *g = VHOST_USER_GPU(vdev); ++ return &g->vhost->dev; ++} ++ + static Property vhost_user_gpu_properties[] = { + VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf), + DEFINE_PROP_END_OF_LIST(), +@@ -586,6 +592,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data) + vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending; + vdc->get_config = vhost_user_gpu_get_config; + vdc->set_config = vhost_user_gpu_set_config; ++ vdc->get_vhost = vhost_user_gpu_get_vhost; + + device_class_set_props(dc, vhost_user_gpu_properties); + } +diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c +index 273e96a7b1..43d2ff3816 100644 +--- a/hw/input/vhost-user-input.c ++++ b/hw/input/vhost-user-input.c +@@ -79,6 +79,12 @@ static void vhost_input_set_config(VirtIODevice *vdev, + virtio_notify_config(vdev); + } + ++static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserInput *vhi = VHOST_USER_INPUT(vdev); ++ return &vhi->vhost->dev; ++} ++ + static const VMStateDescription vmstate_vhost_input = { + .name = "vhost-user-input", + .unmigratable = 1, +@@ -93,6 +99,7 @@ static void vhost_input_class_init(ObjectClass *klass, void *data) + dc->vmsd = &vmstate_vhost_input; + vdc->get_config = vhost_input_get_config; + vdc->set_config = vhost_input_set_config; ++ vdc->get_vhost = vhost_input_get_vhost; + vic->realize = vhost_input_realize; + vic->change_active = vhost_input_change_active; + } +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 3bd786cc22..41bb4010b0 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3644,6 +3644,14 @@ static bool dev_unplug_pending(void *opaque) + return vdc->primary_unplug_pending(dev); + } + ++static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev) ++{ ++ VirtIONet *n = VIRTIO_NET(vdev); ++ NetClientState *nc = qemu_get_queue(n->nic); ++ struct vhost_net *net = get_vhost_net(nc->peer); ++ return &net->dev; ++} ++ + static const VMStateDescription vmstate_virtio_net = { + .name = "virtio-net", + .minimum_version_id = VIRTIO_NET_VM_VERSION, +@@ -3785,6 +3793,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) + vdc->post_load = virtio_net_post_load_virtio; + vdc->vmsd = &vmstate_virtio_net_device; + vdc->primary_unplug_pending = primary_unplug_pending; ++ vdc->get_vhost = virtio_net_get_vhost; + } + + static const TypeInfo virtio_net_info = { +diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c +index 039caf2614..b0a9c45e43 100644 +--- a/hw/scsi/vhost-scsi.c ++++ b/hw/scsi/vhost-scsi.c +@@ -264,6 +264,13 @@ static void vhost_scsi_unrealize(DeviceState *dev) + virtio_scsi_common_unrealize(dev); + } + ++static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev) ++{ ++ VHostSCSI *s = VHOST_SCSI(vdev); ++ VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); ++ return &vsc->dev; ++} ++ + static Property vhost_scsi_properties[] = { + DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd), + DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn), +@@ -298,6 +305,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) + vdc->get_features = vhost_scsi_common_get_features; + vdc->set_config = vhost_scsi_common_set_config; + vdc->set_status = vhost_scsi_set_status; ++ vdc->get_vhost = vhost_scsi_get_vhost; + fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; + } + +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index fc7dcc96ef..392b7d3aa1 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -277,6 +277,12 @@ static void vuf_device_unrealize(DeviceState *dev) + g_free(vhost_vqs); + } + ++static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserFS *fs = VHOST_USER_FS(vdev); ++ return &fs->vhost_dev; ++} ++ + static const VMStateDescription vuf_vmstate = { + .name = "vhost-user-fs", + .unmigratable = 1, +@@ -314,6 +320,7 @@ static void vuf_class_init(ObjectClass *klass, void *data) + vdc->set_status = vuf_set_status; + vdc->guest_notifier_mask = vuf_guest_notifier_mask; + vdc->guest_notifier_pending = vuf_guest_notifier_pending; ++ vdc->get_vhost = vuf_get_vhost; + } + + static const TypeInfo vuf_info = { +diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c +index 209ee5bf9a..543f3e3cef 100644 +--- a/hw/virtio/vhost-user-rng.c ++++ b/hw/virtio/vhost-user-rng.c +@@ -247,6 +247,12 @@ static void vu_rng_device_unrealize(DeviceState *dev) + vhost_user_cleanup(&rng->vhost_user); + } + ++static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) ++{ ++ VHostUserRNG *rng = VHOST_USER_RNG(vdev); ++ return &rng->vhost_dev; ++} ++ + static const VMStateDescription vu_rng_vmstate = { + .name = "vhost-user-rng", + .unmigratable = 1, +@@ -272,6 +278,7 @@ static void vu_rng_class_init(ObjectClass *klass, void *data) + vdc->set_status = vu_rng_set_status; + vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; + vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; ++ vdc->get_vhost = vu_rng_get_vhost; + } + + static const TypeInfo vu_rng_info = { +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index ed706681ac..cd45aaf28e 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -259,6 +259,12 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev) + virtio_cleanup(vdev); + } + ++static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev) ++{ ++ VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); ++ return &vvc->vhost_dev; ++} ++ + static Property vhost_vsock_common_properties[] = { + DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, + ON_OFF_AUTO_AUTO), +@@ -274,6 +280,7 @@ static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; + vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; ++ vdc->get_vhost = vhost_vsock_common_get_vhost; + } + + static const TypeInfo vhost_vsock_common_info = { +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 2f9bb96d63..c1f5cb5b91 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -1766,6 +1766,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) + /* should only be called after backend is connected */ + assert(hdev->vhost_ops); + ++ vdev->vhost_started = true; + hdev->started = true; + hdev->vdev = vdev; + +@@ -1838,7 +1839,7 @@ fail_vq: + + fail_mem: + fail_features: +- ++ vdev->vhost_started = false; + hdev->started = false; + return r; + } +@@ -1869,6 +1870,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) + } + vhost_log_put(hdev, true); + hdev->started = false; ++ vdev->vhost_started = false; + hdev->vdev = NULL; + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 274c7b4dea..f9d849fa43 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -966,6 +966,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + ++static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) ++{ ++ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); ++ CryptoDevBackend *b = vcrypto->cryptodev; ++ CryptoDevBackendClient *cc = b->conf.peers.ccs[0]; ++ CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0); ++ return &vhost_crypto->dev; ++} ++ + static void virtio_crypto_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); +@@ -982,6 +991,7 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data) + vdc->set_status = virtio_crypto_set_status; + vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask; + vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending; ++ vdc->get_vhost = virtio_crypto_get_vhost; + } + + static void virtio_crypto_instance_init(Object *obj) +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index c1497f59aa..12f4a8ab3d 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -3298,6 +3298,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, + + vdev->start_on_kick = false; + vdev->started = false; ++ vdev->vhost_started = false; + vdev->device_id = device_id; + vdev->status = 0; + qatomic_set(&vdev->isr, 0); +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 7472145821..223e82436f 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -22,6 +22,7 @@ + #include "standard-headers/linux/virtio_config.h" + #include "standard-headers/linux/virtio_ring.h" + #include "qom/object.h" ++#include "hw/virtio/vhost.h" + + /* A guest should never accept this. It implies negotiation is broken. */ + #define VIRTIO_F_BAD_FEATURE 30 +@@ -103,6 +104,7 @@ struct VirtIODevice + bool started; + bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */ + bool disable_legacy_check; ++ bool vhost_started; + VMChangeStateEntry *vmstate; + char *bus_name; + uint8_t device_endian; +@@ -162,6 +164,7 @@ struct VirtioDeviceClass { + int (*post_load)(VirtIODevice *vdev); + const VMStateDescription *vmsd; + bool (*primary_unplug_pending)(void *opaque); ++ struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); + }; + + void virtio_instance_init_common(Object *proxy_obj, void *data, +-- +2.27.0 + diff --git a/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch b/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch new file mode 100644 index 0000000..76ce5d7 --- /dev/null +++ b/virtio-crypto-verify-src-dst-buffer-length-for-sym-request.patch @@ -0,0 +1,46 @@ +From 9110c9bf711a39b3c9a1bdbe2fc84f38930d3094 Mon Sep 17 00:00:00 2001 +From: zhenwei pi +Date: Thu, 3 Aug 2023 10:43:13 +0800 +Subject: [PATCH] virtio-crypto: verify src&dst buffer length for sym request + +For symmetric algorithms, the length of ciphertext must be as same +as the plaintext. +The missing verification of the src_len and the dst_len in +virtio_crypto_sym_op_helper() may lead buffer overflow/divulged. + +This patch is originally written by Yiming Tao for QEMU-SECURITY, +resend it(a few changes of error message) in qemu-devel. + +Fixes: CVE-2023-3180 +Fixes: 04b9b37edda("virtio-crypto: add data queue processing handler") +Cc: Gonglei +Cc: Mauro Matteo Cascella +Cc: Yiming Tao +Signed-off-by: zhenwei pi +Message-Id: <20230803024314.29962-2-pizhenwei@bytedance.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-crypto.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 98304184cd..9f7dcc88ba 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -466,6 +466,11 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, + return NULL; + } + ++ if (unlikely(src_len != dst_len)) { ++ virtio_error(vdev, "sym request src len is different from dst len"); ++ return NULL; ++ } ++ + max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; + if (unlikely(max_len > vcrypto->conf.max_size)) { + virtio_error(vdev, "virtio-crypto too big length"); +-- +2.27.0 + diff --git a/virtio-fix-enable-vhost-user-build-on-non-Linux.patch b/virtio-fix-enable-vhost-user-build-on-non-Linux.patch new file mode 100644 index 0000000..c124baf --- /dev/null +++ b/virtio-fix-enable-vhost-user-build-on-non-Linux.patch @@ -0,0 +1,39 @@ +From 558472cd6040b5515baaf860b5bba0c1c511d18b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 28 Mar 2022 17:58:27 +0200 +Subject: [PATCH] virtio: fix --enable-vhost-user build on non-Linux +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The vhost-shadow-virtqueue.c build requires include files from +linux-headers/, so it cannot be built on non-Linux systems. +Fortunately it is only needed by vhost-vdpa, so move it there. + +Acked-by: Eugenio Pérez +Acked-by: Jason Wang +Signed-off-by: Paolo Bonzini +Signed-off-by: fangyi +--- + hw/virtio/meson.build | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index c2e193f56d..c2da69616f 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -11,9 +11,9 @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c')) + + virtio_ss = ss.source_set() + virtio_ss.add(files('virtio.c')) +-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c')) ++virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) + virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c')) +-virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c')) ++virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-shadow-virtqueue.c', 'vhost-vdpa.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) + virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) + virtio_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VIRTIO_PCI'], if_true: files('virtio-crypto-pci.c')) +-- +2.27.0 + diff --git a/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch b/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch new file mode 100644 index 0000000..79c916c --- /dev/null +++ b/virtio-i2c-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch @@ -0,0 +1,55 @@ +From 7f25adf1fd99b5b8f9455537d0c6108837ee25de Mon Sep 17 00:00:00 2001 +From: Viresh Kumar +Date: Tue, 18 Apr 2023 09:24:54 +0530 +Subject: [PATCH] virtio: i2c: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX + +Since the driver doesn't support interrupts, we must return early when +index is set to VIRTIO_CONFIG_IRQ_IDX. + +Fixes: 544f0278afca ("virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX") +Signed-off-by: Viresh Kumar +Message-Id: +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/vhost-user-i2c.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c +index dcaf471115..19add4a707 100644 +--- a/hw/virtio/vhost-user-i2c.c ++++ b/hw/virtio/vhost-user-i2c.c +@@ -129,6 +129,14 @@ static void vu_i2c_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ + vhost_virtqueue_mask(&i2c->vhost_dev, vdev, idx, mask); + } + +@@ -136,6 +144,14 @@ static bool vu_i2c_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } ++ + return vhost_virtqueue_pending(&i2c->vhost_dev, idx); + } + +-- +2.27.0 + diff --git a/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch b/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000..c46da01 --- /dev/null +++ b/virtio-introduce-macro-IRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,166 @@ +From 438e224baf7c2debab5ac109739316d9db562e2c Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:50 +0800 +Subject: [PATCH] virtio: introduce macro IRTIO_CONFIG_IRQ_IDX + +To support configure interrupt for vhost-vdpa +Introduce VIRTIO_CONFIG_IRQ_IDX -1 as configure interrupt's queue index, +Then we can reuse the functions guest_notifier_mask and guest_notifier_pending. +Add the check of queue index in these drivers, if the driver does not support +configure interrupt, the function will just return + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-2-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 6 ++++++ + hw/net/virtio-net.c | 10 ++++++++-- + hw/virtio/vhost-user-fs.c | 6 ++++++ + hw/virtio/vhost-vsock-common.c | 6 ++++++ + hw/virtio/virtio-crypto.c | 6 ++++++ + include/hw/virtio/virtio.h | 3 +++ + 6 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 49df56cd14..73ad3d84c9 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,6 +485,9 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -493,6 +496,9 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 3bd786cc22..7537f44d10 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3195,6 +3195,9 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3204,8 +3207,11 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); + assert(n->vhost_started); +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), +- vdev, idx, mask); ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index fc7dcc96ef..90c2bc9c5d 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,6 +161,9 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -168,6 +171,9 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index ed706681ac..b1f0d46209 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,6 +125,9 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -133,6 +136,9 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 274c7b4dea..52ba34ef1e 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,6 +953,9 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -963,6 +966,9 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 7472145821..c113a5b864 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -68,6 +68,9 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + ++/* special index value used internally for config irqs */ ++#define VIRTIO_CONFIG_IRQ_IDX -1 ++ + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch b/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch new file mode 100644 index 0000000..67c848b --- /dev/null +++ b/virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch @@ -0,0 +1,227 @@ +From 61630772adbe254719e312fb7704a8edd00cc72b Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:42 +0800 +Subject: [PATCH] virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX + +To support configure interrupt for vhost-vdpa +Introduce VIRTIO_CONFIG_IRQ_IDX -1 as configure interrupt's queue index, +Then we can reuse the functions guest_notifier_mask and guest_notifier_pending. +Add the check of queue index in these drivers, if the driver does not support +configure interrupt, the function will just return + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-2-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/display/vhost-user-gpu.c | 18 ++++++++++++++++++ + hw/net/virtio-net.c | 22 ++++++++++++++++++++-- + hw/virtio/vhost-user-fs.c | 18 ++++++++++++++++++ + hw/virtio/vhost-vsock-common.c | 18 ++++++++++++++++++ + hw/virtio/virtio-crypto.c | 18 ++++++++++++++++++ + include/hw/virtio/virtio.h | 3 +++ + 6 files changed, 95 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c +index 6e93b463d6..1c78272a83 100644 +--- a/hw/display/vhost-user-gpu.c ++++ b/hw/display/vhost-user-gpu.c +@@ -485,6 +485,15 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&g->vhost->dev, idx); + } + +@@ -493,6 +502,15 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VhostUserGPU *g = VHOST_USER_GPU(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); + } + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 867a1e77dc..304f501da5 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3232,6 +3232,15 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return false ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3255,8 +3264,17 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + } else { + nc = qemu_get_subqueue(n->nic, vq2q(idx)); + } +- vhost_net_virtqueue_mask(get_vhost_net(nc->peer), +- vdev, idx, mask); ++ /* ++ *Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ ++ vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + + static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) +diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c +index c2739557f2..0c6ecd3b4f 100644 +--- a/hw/virtio/vhost-user-fs.c ++++ b/hw/virtio/vhost-user-fs.c +@@ -161,6 +161,15 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); + } + +@@ -168,6 +177,15 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserFS *fs = VHOST_USER_FS(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&fs->vhost_dev, idx); + } + +diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c +index 42e4db4712..e4a8d90f4c 100644 +--- a/hw/virtio/vhost-vsock-common.c ++++ b/hw/virtio/vhost-vsock-common.c +@@ -125,6 +125,15 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); + } + +@@ -133,6 +142,15 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, + { + VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return vhost_virtqueue_pending(&vvc->vhost_dev, idx); + } + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index f9d849fa43..98304184cd 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -953,6 +953,15 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, + + assert(vcrypto->vhost_started); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } + cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); + } + +@@ -963,6 +972,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx) + + assert(vcrypto->vhost_started); + ++ /* ++ * Add the check for configure interrupt, Use VIRTIO_CONFIG_IRQ_IDX -1 ++ * as the Marco of configure interrupt's IDX, If this driver does not ++ * support, the function will return ++ */ ++ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } + return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); + } + +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 223e82436f..91d1c3433a 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -69,6 +69,9 @@ typedef struct VirtQueueElement + + #define VIRTIO_NO_VECTOR 0xffff + ++/* special index value used internally for config irqs */ ++#define VIRTIO_CONFIG_IRQ_IDX -1 ++ + #define TYPE_VIRTIO_DEVICE "virtio-device" + OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) + +-- +2.27.0 + diff --git a/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch b/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch new file mode 100644 index 0000000..4ae4766 --- /dev/null +++ b/virtio-iommu-Fix-the-partial-copy-of-probe-request.patch @@ -0,0 +1,60 @@ +From 1e73eaa18c753157046d22e43333fd9bc711eaa9 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Fri, 17 Nov 2023 09:55:19 +0000 +Subject: [PATCH] virtio-iommu: Fix the partial copy of probe request mainline + inclusion commit 45461aace83d961e933b27519b81d17b4c690514 category: bugfix + +--------------------------------------------------------------- + +The structure of probe request doesn't include the tail, this leads +to a few field missed to be copied. Currently this isn't an issue as +those missed field belong to reserved field, just in case reserved +field will be used in the future. + +Changed 4th parameter of virtio_iommu_iov_to_req() to receive size +of device-readable part. + +Fixes: 1733eebb9e75b ("virtio-iommu: Implement RESV_MEM probe request") +Signed-off-by: Zhenzhong Duan +Message-Id: <20220623023152.3473231-1-zhenzhong.duan@intel.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Jean-Philippe Brucker +Reviewed-by: Eric Auger + +Signed-off-by: tangbinzy +--- + hw/virtio/virtio-iommu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c +index ed47d4cb64..ae33d93b11 100644 +--- a/hw/virtio/virtio-iommu.c ++++ b/hw/virtio/virtio-iommu.c +@@ -547,11 +547,10 @@ static int virtio_iommu_probe(VirtIOIOMMU *s, + + static int virtio_iommu_iov_to_req(struct iovec *iov, + unsigned int iov_cnt, +- void *req, size_t req_sz) ++ void *req, size_t payload_sz) + { +- size_t sz, payload_sz = req_sz - sizeof(struct virtio_iommu_req_tail); ++ size_t sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); + +- sz = iov_to_buf(iov, iov_cnt, 0, req, payload_sz); + if (unlikely(sz != payload_sz)) { + return VIRTIO_IOMMU_S_INVAL; + } +@@ -564,7 +563,8 @@ static int virtio_iommu_handle_ ## __req(VirtIOIOMMU *s, \ + unsigned int iov_cnt) \ + { \ + struct virtio_iommu_req_ ## __req req; \ +- int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req)); \ ++ int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, \ ++ sizeof(req) - sizeof(struct virtio_iommu_req_tail));\ + \ + return ret ? ret : virtio_iommu_ ## __req(s, &req); \ + } +-- +2.27.0 + diff --git a/virtio-mmio-add-support-for-configure-interrupt-new.patch b/virtio-mmio-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000..c0900ca --- /dev/null +++ b/virtio-mmio-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,67 @@ +From 3f5311e1a80539a9cc21905fd3134709417e3747 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:50 +0800 +Subject: [PATCH] virtio-mmio: add support for configure interrupt + +Add configure interrupt support in virtio-mmio bus. +add function to set configure guest notifier. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-10-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 72da12fea5..508dd4cdb7 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,7 +673,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } ++static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign, ++ bool with_irqfd) ++{ ++ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); ++ EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); ++ int r = 0; + ++ if (assign) { ++ r = event_notifier_init(notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ event_notifier_cleanup(notifier); ++ } ++ if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { ++ vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); ++ } ++ return r; ++} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -695,6 +718,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } ++ r = virtio_mmio_set_config_guest_notifier(d, assign, with_irqfd); ++ if (r < 0) { ++ goto assign_error; ++ } + + return 0; + +-- +2.27.0 + diff --git a/virtio-mmio-add-support-for-configure-interrupt.patch b/virtio-mmio-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..0b4d425 --- /dev/null +++ b/virtio-mmio-add-support-for-configure-interrupt.patch @@ -0,0 +1,66 @@ +From 89b329c73a84ca3f1376f8d8533154306bc50187 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:54 +0800 +Subject: [PATCH] virtio-mmio: add support for configure interrupt + +Add configure interrupt support for virtio-mmio bus. This +interrupt will be working while the backend is vhost-vdpa + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-10-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-mmio.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c +index 72da12fea5..809132018b 100644 +--- a/hw/virtio/virtio-mmio.c ++++ b/hw/virtio/virtio-mmio.c +@@ -673,7 +673,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign, + + return 0; + } ++static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign) ++{ ++ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); ++ bool with_irqfd = false; ++ EventNotifier *notifier = virtio_config_get_guest_notifier(vdev); ++ int r = 0; + ++ if (assign) { ++ r = event_notifier_init(notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ event_notifier_cleanup(notifier); ++ } ++ if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) { ++ vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign); ++ } ++ return r; ++} + static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + bool assign) + { +@@ -695,6 +718,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, + goto assign_error; + } + } ++ r = virtio_mmio_set_config_guest_notifier(d, assign); ++ if (r < 0) { ++ goto assign_error; ++ } + + return 0; + +-- +2.27.0 + diff --git a/virtio-net-Expose-MAC_TABLE_ENTRIES.patch b/virtio-net-Expose-MAC_TABLE_ENTRIES.patch new file mode 100644 index 0000000..15e7405 --- /dev/null +++ b/virtio-net-Expose-MAC_TABLE_ENTRIES.patch @@ -0,0 +1,50 @@ +From c8ee92256e06a7fec7cfff3bf18e21ec03016613 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:27 +0200 +Subject: [PATCH] virtio-net: Expose MAC_TABLE_ENTRIES +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +vhost-vdpa control virtqueue needs to know the maximum entries supported +by the virtio-net device, so we know if it is possible to apply the +filter. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 1 - + include/hw/virtio/virtio-net.h | 3 +++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 512b37eb76..36d24b47bb 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -48,7 +48,6 @@ + + #define VIRTIO_NET_VM_VERSION 11 + +-#define MAC_TABLE_ENTRIES 64 + #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ + + /* previously fixed value */ +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index eb87032627..cce1c554f7 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -35,6 +35,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET) + * and latency. */ + #define TX_BURST 256 + ++/* Maximum VIRTIO_NET_CTRL_MAC_TABLE_SET unicast + multicast entries. */ ++#define MAC_TABLE_ENTRIES 64 ++ + typedef struct virtio_net_conf + { + uint32_t txtimer; +-- +2.27.0 + diff --git a/virtio-net-Expose-ctrl-virtqueue-logic.patch b/virtio-net-Expose-ctrl-virtqueue-logic.patch new file mode 100644 index 0000000..fc50d20 --- /dev/null +++ b/virtio-net-Expose-ctrl-virtqueue-logic.patch @@ -0,0 +1,149 @@ +From 4987c967fb3b9b403bde7a1103f5ea1bf20445c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Wed, 20 Jul 2022 08:59:28 +0200 +Subject: [PATCH] virtio-net: Expose ctrl virtqueue logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows external vhost-net devices to modify the state of the +VirtIO device model once the vhost-vdpa device has acknowledged the +control commands. + +Signed-off-by: Eugenio Pérez +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 83 ++++++++++++++++++++-------------- + include/hw/virtio/virtio-net.h | 4 ++ + 2 files changed, 53 insertions(+), 34 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 36d24b47bb..999072921d 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1452,56 +1452,71 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_OK; + } + +-static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ++size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, ++ const struct iovec *in_sg, unsigned in_num, ++ const struct iovec *out_sg, ++ unsigned out_num) + { + VirtIONet *n = VIRTIO_NET(vdev); + struct virtio_net_ctrl_hdr ctrl; + virtio_net_ctrl_ack status = VIRTIO_NET_ERR; +- VirtQueueElement *elem; + size_t s; + struct iovec *iov, *iov2; +- unsigned int iov_cnt; ++ ++ if (iov_size(in_sg, in_num) < sizeof(status) || ++ iov_size(out_sg, out_num) < sizeof(ctrl)) { ++ virtio_error(vdev, "virtio-net ctrl missing headers"); ++ return 0; ++ } ++ ++ iov2 = iov = g_memdup(out_sg, sizeof(struct iovec) * out_num); ++ s = iov_to_buf(iov, out_num, 0, &ctrl, sizeof(ctrl)); ++ iov_discard_front(&iov, &out_num, sizeof(ctrl)); ++ if (s != sizeof(ctrl)) { ++ status = VIRTIO_NET_ERR; ++ } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { ++ status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { ++ status = virtio_net_handle_mac(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { ++ status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { ++ status = virtio_net_handle_announce(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { ++ status = virtio_net_handle_mq(n, ctrl.cmd, iov, out_num); ++ } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { ++ status = virtio_net_handle_offloads(n, ctrl.cmd, iov, out_num); ++ } ++ ++ s = iov_from_buf(in_sg, in_num, 0, &status, sizeof(status)); ++ assert(s == sizeof(status)); ++ ++ g_free(iov2); ++ return sizeof(status); ++} ++ ++static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ++{ ++ VirtQueueElement *elem; + + for (;;) { ++ size_t written; + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } +- if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || +- iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { +- virtio_error(vdev, "virtio-net ctrl missing headers"); ++ ++ written = virtio_net_handle_ctrl_iov(vdev, elem->in_sg, elem->in_num, ++ elem->out_sg, elem->out_num); ++ if (written > 0) { ++ virtqueue_push(vq, elem, written); ++ virtio_notify(vdev, vq); ++ g_free(elem); ++ } else { + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; + } +- +- iov_cnt = elem->out_num; +- iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num); +- s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); +- iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); +- if (s != sizeof(ctrl)) { +- status = VIRTIO_NET_ERR; +- } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { +- status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { +- status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { +- status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) { +- status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { +- status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt); +- } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) { +- status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt); +- } +- +- s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status)); +- assert(s == sizeof(status)); +- +- virtqueue_push(vq, elem, sizeof(status)); +- virtio_notify(vdev, vq); +- g_free(iov2); +- g_free(elem); + } + } + +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index cce1c554f7..ef234ffe7e 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -221,6 +221,10 @@ struct VirtIONet { + struct EBPFRSSContext ebpf_rss; + }; + ++size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, ++ const struct iovec *in_sg, unsigned in_num, ++ const struct iovec *out_sg, ++ unsigned out_num); + void virtio_net_set_netclient_name(VirtIONet *n, const char *name, + const char *type); + +-- +2.27.0 + diff --git a/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch b/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch new file mode 100644 index 0000000..fb9f7ad --- /dev/null +++ b/virtio-net-Update-virtio-net-curr_queue_pairs-in-vdp.patch @@ -0,0 +1,53 @@ +From 49c90114e00fb1cbbe25eeaee825981210c24f41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 6 Sep 2022 17:07:18 +0200 +Subject: [PATCH] virtio-net: Update virtio-net curr_queue_pairs in vdpa + backends +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was returned as error before. Instead of it, simply update the +corresponding field so qemu can send it in the migration data. + +Signed-off-by: Eugenio Pérez +Acked-by: Si-Wei Liu +Signed-off-by: Jason Wang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 999072921d..867a1e77dc 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1431,19 +1431,14 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_ERR; + } + +- /* Avoid changing the number of queue_pairs for vdpa device in +- * userspace handler. A future fix is needed to handle the mq +- * change in userspace handler with vhost-vdpa. Let's disable +- * the mq handling from userspace for now and only allow get +- * done through the kernel. Ripples may be seen when falling +- * back to userspace, but without doing it qemu process would +- * crash on a recursive entry to virtio_net_set_status(). +- */ ++ n->curr_queue_pairs = queue_pairs; + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { +- return VIRTIO_NET_ERR; ++ /* ++ * Avoid updating the backend for a vdpa device: We're only interested ++ * in updating the device model queues. ++ */ ++ return VIRTIO_NET_OK; + } +- +- n->curr_queue_pairs = queue_pairs; + /* stop the backend before changing the number of queue_pairs to avoid handling a + * disabled queue */ + virtio_net_set_status(vdev, vdev->status); +-- +2.27.0 + diff --git a/virtio-net-add-support-for-configure-interrupt-new.patch b/virtio-net-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000..006222d --- /dev/null +++ b/virtio-net-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,102 @@ +From e55e9f52865565415000834b4cacb741b0abb2d8 Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:49 +0800 +Subject: [PATCH] virtio-net: add support for configure interrupt + +Add functions to support configure interrupt in virtio_net +Add the functions to support vhost_net_config_pending +and vhost_net_config_mask. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-9-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net-stub.c | 9 +++++++++ + hw/net/vhost_net.c | 9 +++++++++ + hw/net/virtio-net.c | 4 ++-- + include/net/vhost_net.h | 2 ++ + 4 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c +index 199b09952a..db171829b4 100644 +--- a/hw/net/vhost_net-stub.c ++++ b/hw/net/vhost_net-stub.c +@@ -82,6 +82,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + { + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return false; ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++} ++ + int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) + { + return -1; +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index c950d7e2e8..d226dba83c 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -541,6 +541,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return vhost_config_pending(&net->dev); ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++ vhost_config_mask(&net->dev, dev, mask); ++} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 304f501da5..bc26f5347a 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -3239,7 +3239,7 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { +- return false; ++ return vhost_net_config_pending(get_vhost_net(nc->peer)); + } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } +@@ -3271,9 +3271,9 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + */ + + if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ vhost_net_config_mask(get_vhost_net(nc->peer), vdev, mask); + return; + } +- + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask); + } + +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 7bdbf484e4..1844f0ed46 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); ++bool vhost_net_config_pending(VHostNetState *net); ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/virtio-net-add-support-for-configure-interrupt.patch b/virtio-net-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..98ac5d2 --- /dev/null +++ b/virtio-net-add-support-for-configure-interrupt.patch @@ -0,0 +1,56 @@ +From 0ae5aeef8aa5bf2d32fdf393cf66c36172c3e974 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:53 +0800 +Subject: [PATCH] virtio-net: add support for configure interrupt + +Add functions to support configure interrupt in virtio_net +The functions are config_pending and config_mask, while +this input idx is VIRTIO_CONFIG_IRQ_IDX will check the +function of configure interrupt. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-9-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/vhost_net.c | 9 +++++++++ + include/net/vhost_net.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index bea053a742..d5a92144bb 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -524,6 +524,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + vhost_virtqueue_mask(&net->dev, dev, idx, mask); + } + ++bool vhost_net_config_pending(VHostNetState *net) ++{ ++ return vhost_config_pending(&net->dev); ++} ++ ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask) ++{ ++ vhost_config_mask(&net->dev, dev, mask); ++} + VHostNetState *get_vhost_net(NetClientState *nc) + { + VHostNetState *vhost_net = 0; +diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h +index 7bdbf484e4..1844f0ed46 100644 +--- a/include/net/vhost_net.h ++++ b/include/net/vhost_net.h +@@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data, + bool vhost_net_virtqueue_pending(VHostNetState *net, int n); + void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); ++bool vhost_net_config_pending(VHostNetState *net); ++void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask); + int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); + VHostNetState *get_vhost_net(NetClientState *nc); + +-- +2.27.0 + diff --git a/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch b/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch new file mode 100644 index 0000000..2c86d64 --- /dev/null +++ b/virtio-net-align-ctrl_vq-index-for-non-mq-guest-for-.patch @@ -0,0 +1,131 @@ +From 9bfeaccd2adb6bc4d4e7efacc508324112e5651f Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:13 -0700 +Subject: [PATCH] virtio-net: align ctrl_vq index for non-mq guest for + vhost_vdpa + +With MQ enabled vdpa device and non-MQ supporting guest e.g. +booting vdpa with mq=on over OVMF of single vqp, below assert +failure is seen: + +../hw/virtio/vhost-vdpa.c:560: vhost_vdpa_get_vq_index: Assertion `idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs' failed. + +0 0x00007f8ce3ff3387 in raise () at /lib64/libc.so.6 +1 0x00007f8ce3ff4a78 in abort () at /lib64/libc.so.6 +2 0x00007f8ce3fec1a6 in __assert_fail_base () at /lib64/libc.so.6 +3 0x00007f8ce3fec252 in () at /lib64/libc.so.6 +4 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:563 +5 0x0000558f52d79421 in vhost_vdpa_get_vq_index (dev=, idx=) at ../hw/virtio/vhost-vdpa.c:558 +6 0x0000558f52d7329a in vhost_virtqueue_mask (hdev=0x558f55c01800, vdev=0x558f568f91f0, n=2, mask=) at ../hw/virtio/vhost.c:1557 +7 0x0000558f52c6b89a in virtio_pci_set_guest_notifier (d=d@entry=0x558f568f0f60, n=n@entry=2, assign=assign@entry=true, with_irqfd=with_irqfd@entry=false) + at ../hw/virtio/virtio-pci.c:974 +8 0x0000558f52c6c0d8 in virtio_pci_set_guest_notifiers (d=0x558f568f0f60, nvqs=3, assign=true) at ../hw/virtio/virtio-pci.c:1019 +9 0x0000558f52bf091d in vhost_net_start (dev=dev@entry=0x558f568f91f0, ncs=0x558f56937cd0, data_queue_pairs=data_queue_pairs@entry=1, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:361 +10 0x0000558f52d4e5e7 in virtio_net_set_status (status=, n=0x558f568f91f0) at ../hw/net/virtio-net.c:289 +11 0x0000558f52d4e5e7 in virtio_net_set_status (vdev=0x558f568f91f0, status=15 '\017') at ../hw/net/virtio-net.c:370 +12 0x0000558f52d6c4b2 in virtio_set_status (vdev=vdev@entry=0x558f568f91f0, val=val@entry=15 '\017') at ../hw/virtio/virtio.c:1945 +13 0x0000558f52c69eff in virtio_pci_common_write (opaque=0x558f568f0f60, addr=, val=, size=) at ../hw/virtio/virtio-pci.c:1292 +14 0x0000558f52d15d6e in memory_region_write_accessor (mr=0x558f568f19d0, addr=20, value=, size=1, shift=, mask=, attrs=...) + at ../softmmu/memory.c:492 +15 0x0000558f52d127de in access_with_adjusted_size (addr=addr@entry=20, value=value@entry=0x7f8cdbffe748, size=size@entry=1, access_size_min=, access_size_max=, access_fn=0x558f52d15cf0 , mr=0x558f568f19d0, attrs=...) at ../softmmu/memory.c:554 +16 0x0000558f52d157ef in memory_region_dispatch_write (mr=mr@entry=0x558f568f19d0, addr=20, data=, op=, attrs=attrs@entry=...) + at ../softmmu/memory.c:1504 +17 0x0000558f52d078e7 in flatview_write_continue (fv=fv@entry=0x7f8accbc3b90, addr=addr@entry=103079215124, attrs=..., ptr=ptr@entry=0x7f8ce6300028, len=len@entry=1, addr1=, l=, mr=0x558f568f19d0) at /home/opc/qemu-upstream/include/qemu/host-utils.h:165 +18 0x0000558f52d07b06 in flatview_write (fv=0x7f8accbc3b90, addr=103079215124, attrs=..., buf=0x7f8ce6300028, len=1) at ../softmmu/physmem.c:2822 +19 0x0000558f52d0b36b in address_space_write (as=, addr=, attrs=..., buf=buf@entry=0x7f8ce6300028, len=) + at ../softmmu/physmem.c:2914 +20 0x0000558f52d0b3da in address_space_rw (as=, addr=, attrs=..., + attrs@entry=..., buf=buf@entry=0x7f8ce6300028, len=, is_write=) at ../softmmu/physmem.c:2924 +21 0x0000558f52dced09 in kvm_cpu_exec (cpu=cpu@entry=0x558f55c2da60) at ../accel/kvm/kvm-all.c:2903 +22 0x0000558f52dcfabd in kvm_vcpu_thread_fn (arg=arg@entry=0x558f55c2da60) at ../accel/kvm/kvm-accel-ops.c:49 +23 0x0000558f52f9f04a in qemu_thread_start (args=) at ../util/qemu-thread-posix.c:556 +24 0x00007f8ce4392ea5 in start_thread () at /lib64/libpthread.so.0 +25 0x00007f8ce40bb9fd in clone () at /lib64/libc.so.6 + +The cause for the assert failure is due to that the vhost_dev index +for the ctrl vq was not aligned with actual one in use by the guest. +Upon multiqueue feature negotiation in virtio_net_set_multiqueue(), +if guest doesn't support multiqueue, the guest vq layout would shrink +to a single queue pair, consisting of 3 vqs in total (rx, tx and ctrl). +This results in ctrl_vq taking a different vhost_dev group index than +the default. We can map vq to the correct vhost_dev group by checking +if MQ is supported by guest and successfully negotiated. Since the +MQ feature is only present along with CTRL_VQ, we ensure the index +2 is only meant for the control vq while MQ is not supported by guest. + +Fixes: 22288fe ("virtio-net: vhost control virtqueue support") +Suggested-by: Jason Wang +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-3-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 33 +++++++++++++++++++++++++++++++-- + 1 file changed, 31 insertions(+), 2 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 41bb4010b0..eed3fb5cd3 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -14,6 +14,7 @@ + #include "qemu/osdep.h" + #include "qemu/atomic.h" + #include "qemu/iov.h" ++#include "qemu/log.h" + #include "qemu/main-loop.h" + #include "qemu/module.h" + #include "hw/virtio/virtio.h" +@@ -3193,8 +3194,22 @@ static NetClientInfo net_virtio_info = { + static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return false; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); + } + +@@ -3202,8 +3217,22 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) + { + VirtIONet *n = VIRTIO_NET(vdev); +- NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ NetClientState *nc; + assert(n->vhost_started); ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ) && idx == 2) { ++ /* Must guard against invalid features and bogus queue index ++ * from being set by malicious guest, or penetrated through ++ * buggy migration stream. ++ */ ++ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { ++ qemu_log_mask(LOG_GUEST_ERROR, ++ "%s: bogus vq index ignored\n", __func__); ++ return; ++ } ++ nc = qemu_get_subqueue(n->nic, n->max_queue_pairs); ++ } else { ++ nc = qemu_get_subqueue(n->nic, vq2q(idx)); ++ } + vhost_net_virtqueue_mask(get_vhost_net(nc->peer), + vdev, idx, mask); + } +-- +2.27.0 + diff --git a/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch b/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch new file mode 100644 index 0000000..8ead121 --- /dev/null +++ b/virtio-net-clear-guest_announce-feature-if-no-cvq-ba.patch @@ -0,0 +1,67 @@ +From 7c85ae20bc8a6bb2e08794d01e6f65af7626a05d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= +Date: Tue, 24 Jan 2023 17:11:59 +0100 +Subject: [PATCH] virtio-net: clear guest_announce feature if no cvq backend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since GUEST_ANNOUNCE is emulated the feature bit could be set without +backend support. This happens in the vDPA case. + +However, backend vDPA parent may not have CVQ support. This causes an +incoherent feature set, and the driver may refuse to start. This +happens in virtio-net Linux driver. + +This may be solved differently in the future. Qemu is able to emulate a +CVQ just for guest_announce purposes, helping guest to notify the new +location with vDPA devices that does not support it. However, this is +left as a TODO as it is way more complex to backport. + +Tested with vdpa_net_sim, toggling manually VIRTIO_NET_F_CTRL_VQ in the +driver and migrating it with x-svq=on. + +Fixes: 980003debddd ("vdpa: do not handle VIRTIO_NET_F_GUEST_ANNOUNCE in vhost-vdpa") +Reported-by: Dawar, Gautam +Signed-off-by: Eugenio Pérez +Message-Id: <20230124161159.2182117-1-eperezma@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: David Edmondson +Reviewed-by: Gautam Dawar +Tested-by: Gautam Dawar +Tested-by: Lei Yang +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index bc26f5347a..ae37b3461b 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -771,6 +771,21 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, + features |= (1ULL << VIRTIO_NET_F_MTU); + } + ++ /* ++ * Since GUEST_ANNOUNCE is emulated the feature bit could be set without ++ * enabled. This happens in the vDPA case. ++ * ++ * Make sure the feature set is not incoherent, as the driver could refuse ++ * to start. ++ * ++ * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes, ++ * helping guest to notify the new location with vDPA devices that does not ++ * support it. ++ */ ++ if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) { ++ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE); ++ } ++ + return features; + } + +-- +2.27.0 + diff --git a/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch b/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch new file mode 100644 index 0000000..27e2366 --- /dev/null +++ b/virtio-net-don-t-handle-mq-request-in-userspace-hand.patch @@ -0,0 +1,97 @@ +From f45beb1e364dc0a6d42425d716f5e31b69d7710d Mon Sep 17 00:00:00 2001 +From: Si-Wei Liu +Date: Fri, 6 May 2022 19:28:18 -0700 +Subject: [PATCH] virtio-net: don't handle mq request in userspace handler for + vhost-vdpa + +virtio_queue_host_notifier_read() tends to read pending event +left behind on ioeventfd in the vhost_net_stop() path, and +attempts to handle outstanding kicks from userspace vq handler. +However, in the ctrl_vq handler, virtio_net_handle_mq() has a +recursive call into virtio_net_set_status(), which may lead to +segmentation fault as shown in below stack trace: + +0 0x000055f800df1780 in qdev_get_parent_bus (dev=0x0) at ../hw/core/qdev.c:376 +1 0x000055f800c68ad8 in virtio_bus_device_iommu_enabled (vdev=vdev@entry=0x0) at ../hw/virtio/virtio-bus.c:331 +2 0x000055f800d70d7f in vhost_memory_unmap (dev=) at ../hw/virtio/vhost.c:318 +3 0x000055f800d70d7f in vhost_memory_unmap (dev=, buffer=0x7fc19bec5240, len=2052, is_write=1, access_len=2052) at ../hw/virtio/vhost.c:336 +4 0x000055f800d71867 in vhost_virtqueue_stop (dev=dev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590, vq=0x55f8037cceb0, idx=0) at ../hw/virtio/vhost.c:1241 +5 0x000055f800d7406c in vhost_dev_stop (hdev=hdev@entry=0x55f8037ccc30, vdev=vdev@entry=0x55f8044ec590) at ../hw/virtio/vhost.c:1839 +6 0x000055f800bf00a7 in vhost_net_stop_one (net=0x55f8037ccc30, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:315 +7 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +8 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +9 0x000055f800d4e628 in virtio_net_set_status (vdev=vdev@entry=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +10 0x000055f800d534d8 in virtio_net_handle_ctrl (iov_cnt=, iov=, cmd=0 '\000', n=0x55f8044ec590) at ../hw/net/virtio-net.c:1408 +11 0x000055f800d534d8 in virtio_net_handle_ctrl (vdev=0x55f8044ec590, vq=0x7fc1a7e888d0) at ../hw/net/virtio-net.c:1452 +12 0x000055f800d69f37 in virtio_queue_host_notifier_read (vq=0x7fc1a7e888d0) at ../hw/virtio/virtio.c:2331 +13 0x000055f800d69f37 in virtio_queue_host_notifier_read (n=n@entry=0x7fc1a7e8894c) at ../hw/virtio/virtio.c:3575 +14 0x000055f800c688e6 in virtio_bus_cleanup_host_notifier (bus=, n=n@entry=14) at ../hw/virtio/virtio-bus.c:312 +15 0x000055f800d73106 in vhost_dev_disable_notifiers (hdev=hdev@entry=0x55f8035b51b0, vdev=vdev@entry=0x55f8044ec590) + at ../../../include/hw/virtio/virtio-bus.h:35 +16 0x000055f800bf00b2 in vhost_net_stop_one (net=0x55f8035b51b0, dev=0x55f8044ec590) at ../hw/net/vhost_net.c:316 +17 0x000055f800bf0678 in vhost_net_stop (dev=dev@entry=0x55f8044ec590, ncs=0x55f80452bae0, data_queue_pairs=data_queue_pairs@entry=7, cvq=cvq@entry=1) + at ../hw/net/vhost_net.c:423 +18 0x000055f800d4e628 in virtio_net_set_status (status=, n=0x55f8044ec590) at ../hw/net/virtio-net.c:296 +19 0x000055f800d4e628 in virtio_net_set_status (vdev=0x55f8044ec590, status=15 '\017') at ../hw/net/virtio-net.c:370 +20 0x000055f800d6c4b2 in virtio_set_status (vdev=0x55f8044ec590, val=) at ../hw/virtio/virtio.c:1945 +21 0x000055f800d11d9d in vm_state_notify (running=running@entry=false, state=state@entry=RUN_STATE_SHUTDOWN) at ../softmmu/runstate.c:333 +22 0x000055f800d04e7a in do_vm_stop (state=state@entry=RUN_STATE_SHUTDOWN, send_stop=send_stop@entry=false) at ../softmmu/cpus.c:262 +23 0x000055f800d04e99 in vm_shutdown () at ../softmmu/cpus.c:280 +24 0x000055f800d126af in qemu_cleanup () at ../softmmu/runstate.c:812 +25 0x000055f800ad5b13 in main (argc=, argv=, envp=) at ../softmmu/main.c:51 + +For now, temporarily disable handling MQ request from the ctrl_vq +userspace hanlder to avoid the recursive virtio_net_set_status() +call. Some rework is needed to allow changing the number of +queues without going through a full virtio_net_set_status cycle, +particularly for vhost-vdpa backend. + +This patch will need to be reverted as soon as future patches of +having the change of #queues handled in userspace is merged. + +Fixes: 402378407db ("vhost-vdpa: multiqueue support") +Signed-off-by: Si-Wei Liu +Acked-by: Jason Wang +Message-Id: <1651890498-24478-8-git-send-email-si-wei.liu@oracle.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/net/virtio-net.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index eed3fb5cd3..512b37eb76 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1400,6 +1400,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + { + VirtIODevice *vdev = VIRTIO_DEVICE(n); + uint16_t queue_pairs; ++ NetClientState *nc = qemu_get_queue(n->nic); + + virtio_net_disable_rss(n); + if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) { +@@ -1431,6 +1432,18 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + return VIRTIO_NET_ERR; + } + ++ /* Avoid changing the number of queue_pairs for vdpa device in ++ * userspace handler. A future fix is needed to handle the mq ++ * change in userspace handler with vhost-vdpa. Let's disable ++ * the mq handling from userspace for now and only allow get ++ * done through the kernel. Ripples may be seen when falling ++ * back to userspace, but without doing it qemu process would ++ * crash on a recursive entry to virtio_net_set_status(). ++ */ ++ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ++ return VIRTIO_NET_ERR; ++ } ++ + n->curr_queue_pairs = queue_pairs; + /* stop the backend before changing the number of queue_pairs to avoid handling a + * disabled queue */ +-- +2.27.0 + diff --git a/virtio-pci-add-support-for-configure-interrupt-new.patch b/virtio-pci-add-support-for-configure-interrupt-new.patch new file mode 100644 index 0000000..91715da --- /dev/null +++ b/virtio-pci-add-support-for-configure-interrupt-new.patch @@ -0,0 +1,261 @@ +From 7e8f9690b0558a99001d45751754df7caf2ff32b Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:51 +0800 +Subject: [PATCH] virtio-pci: add support for configure interrupt + +Add process to handle the configure interrupt, The function's +logic is the same with vq interrupt.Add extra process to check +the configure interrupt + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-11-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 118 ++++++++++++++++++++++++++++++++++------- + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 102 insertions(+), 20 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..82706b8b32 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,7 +812,8 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; ++ *n = virtio_config_get_guest_notifier(vdev); ++ *vector = vdev->config_vector; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -872,7 +873,7 @@ undo: + } + return ret; + } +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_vq_use(VirtIOPCIProxy *proxy, int nvqs) + { + int queue_no; + int ret = 0; +@@ -887,6 +888,10 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + ++static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) ++{ ++ return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -911,7 +916,7 @@ static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++static void kvm_virtio_pci_vector_vq_release(VirtIOPCIProxy *proxy, int nvqs) + { + int queue_no; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +@@ -924,6 +929,11 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + ++static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) ++{ ++ kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} ++ + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1005,9 +1015,19 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- ++ /* unmask config intr */ ++ if (vector == vdev->config_vector) { ++ n = virtio_config_get_guest_notifier(vdev); ++ ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, ++ msg, n); ++ if (ret < 0) { ++ goto undo_config; ++ } ++ } + return 0; +- ++undo_config: ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1041,6 +1061,11 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } ++ ++ if (vector == vdev->config_vector) { ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); ++ } + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1072,6 +1097,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } ++ /* poll the config intr */ ++ ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, ++ &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector < vector_start || vector >= vector_end || ++ !msix_is_masked(dev, vector)) { ++ return; ++ } ++ if (k->guest_notifier_pending) { ++ if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { ++ msix_set_pending(dev, vector); ++ } ++ } else if (event_notifier_test_and_clear(notifier)) { ++ msix_set_pending(dev, vector); ++ } ++} ++ ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd) ++{ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); ++ } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1080,17 +1133,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, n); +- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); ++ VirtQueue *vq = NULL; ++ EventNotifier *notifier = NULL; ++ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ notifier = virtio_config_get_guest_notifier(vdev); ++ } else { ++ vq = virtio_get_queue(vdev, n); ++ notifier = virtio_queue_get_guest_notifier(vq); ++ } + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); + } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, ++ with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1128,10 +1189,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + proxy->nvqs_with_notifiers = nvqs; + + /* Must unset vector notifier while guest notifier is still assigned */ +- if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) { ++ if ((proxy->vector_irqfd || ++ (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && ++ !assign) { + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { +- kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_vq_release(proxy, nvqs); ++ kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1147,20 +1211,30 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- ++ r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, ++ with_irqfd); ++ if (r < 0) { ++ goto config_assign_error; ++ } + /* Must set vector notifier after guest notifier has been assigned */ +- if ((with_irqfd || k->guest_notifier_mask) && assign) { ++ if ((with_irqfd || ++ (vdev->use_guest_notifier_mask && k->guest_notifier_mask)) && ++ assign) { + if (with_irqfd) { + proxy->vector_irqfd = + g_malloc0(sizeof(*proxy->vector_irqfd) * + msix_nr_vectors_allocated(&proxy->pci_dev)); +- r = kvm_virtio_pci_vector_use(proxy, nvqs); ++ r = kvm_virtio_pci_vector_vq_use(proxy, nvqs); ++ if (r < 0) { ++ goto config_assign_error; ++ } ++ r = kvm_virtio_pci_vector_config_use(proxy); + if (r < 0) { +- goto assign_error; ++ goto config_error; + } + } +- r = msix_set_vector_notifiers(&proxy->pci_dev, +- virtio_pci_vector_unmask, ++ ++ r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1173,9 +1247,15 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + notifiers_error: + if (with_irqfd) { + assert(assign); +- kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_vq_release(proxy, nvqs); + } +- ++config_error: ++ if (with_irqfd) { ++ kvm_virtio_pci_vector_config_release(proxy); ++ } ++config_assign_error: ++ virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, ++ with_irqfd); + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index d95b1a13a5..6d8e071d8d 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,5 +256,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +- ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd); + #endif +-- +2.27.0 + diff --git a/virtio-pci-add-support-for-configure-interrupt.patch b/virtio-pci-add-support-for-configure-interrupt.patch new file mode 100644 index 0000000..9aa53c1 --- /dev/null +++ b/virtio-pci-add-support-for-configure-interrupt.patch @@ -0,0 +1,218 @@ +From ce91ab22c29c56e4e18ee2e861b65657f7bb3e90 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:54 +0800 +Subject: [PATCH] virtio-pci: add support for configure interrupt + +Add support for configure interrupt, The process is used kvm_irqfd_assign +to set the gsi to kernel. When the configure notifier was signal by +host, qemu will inject a msix interrupt to guest + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-11-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 92 ++++++++++++++++++++++++++++++++++++------ + hw/virtio/virtio-pci.h | 4 +- + 2 files changed, 83 insertions(+), 13 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 75be770971..90237f523e 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -812,7 +812,8 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + VirtQueue *vq; + + if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { +- return -1; ++ *n = virtio_config_get_guest_notifier(vdev); ++ *vector = vdev->config_vector; + } else { + if (!virtio_queue_get_num(vdev, queue_no)) { + return -1; +@@ -887,6 +888,10 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + return ret; + } + ++static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy) ++{ ++ return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} + + static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, + int queue_no) +@@ -924,6 +929,11 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + } + } + ++static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy) ++{ ++ kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX); ++} ++ + static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +@@ -1005,9 +1015,17 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + } + vq = virtio_vector_next_queue(vq); + } +- ++ /* unmask config intr */ ++ n = virtio_config_get_guest_notifier(vdev); ++ ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, ++ msg, n); ++ if (ret < 0) { ++ goto undo_config; ++ } + return 0; +- ++undo_config: ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + undo: + vq = virtio_vector_first_queue(vdev, vector); + while (vq && unmasked >= 0) { +@@ -1041,6 +1059,8 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + } + vq = virtio_vector_next_queue(vq); + } ++ n = virtio_config_get_guest_notifier(vdev); ++ virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n); + } + + static void virtio_pci_vector_poll(PCIDevice *dev, +@@ -1072,6 +1092,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + msix_set_pending(dev, vector); + } + } ++ /* poll the config intr */ ++ ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, ¬ifier, ++ &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector < vector_start || vector >= vector_end || ++ !msix_is_masked(dev, vector)) { ++ return; ++ } ++ if (k->guest_notifier_pending) { ++ if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) { ++ msix_set_pending(dev, vector); ++ } ++ } else if (event_notifier_test_and_clear(notifier)) { ++ msix_set_pending(dev, vector); ++ } ++} ++ ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd) ++{ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd); ++ } else { ++ virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd); ++ } + } + + static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, +@@ -1080,17 +1128,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, n); +- EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); ++ VirtQueue *vq = NULL; ++ EventNotifier *notifier = NULL; ++ ++ if (n == VIRTIO_CONFIG_IRQ_IDX) { ++ notifier = virtio_config_get_guest_notifier(vdev); ++ } else { ++ vq = virtio_get_queue(vdev, n); ++ notifier = virtio_queue_get_guest_notifier(vq); ++ } + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } +- virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd); + } else { +- virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); ++ virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false, ++ with_irqfd); + event_notifier_cleanup(notifier); + } + +@@ -1132,6 +1188,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_unset_vector_notifiers(&proxy->pci_dev); + if (proxy->vector_irqfd) { + kvm_virtio_pci_vector_release(proxy, nvqs); ++ kvm_virtio_pci_vector_config_release(proxy); + g_free(proxy->vector_irqfd); + proxy->vector_irqfd = NULL; + } +@@ -1147,7 +1204,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + goto assign_error; + } + } +- ++ r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign, ++ with_irqfd); ++ if (r < 0) { ++ goto config_assign_error; ++ } + /* Must set vector notifier after guest notifier has been assigned */ + if ((with_irqfd || k->guest_notifier_mask) && assign) { + if (with_irqfd) { +@@ -1156,11 +1217,14 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) + msix_nr_vectors_allocated(&proxy->pci_dev)); + r = kvm_virtio_pci_vector_use(proxy, nvqs); + if (r < 0) { +- goto assign_error; ++ goto config_assign_error; + } + } +- r = msix_set_vector_notifiers(&proxy->pci_dev, +- virtio_pci_vector_unmask, ++ r = kvm_virtio_pci_vector_config_use(proxy); ++ if (r < 0) { ++ goto config_error; ++ } ++ r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask, + virtio_pci_vector_mask, + virtio_pci_vector_poll); + if (r < 0) { +@@ -1175,7 +1239,11 @@ notifiers_error: + assert(assign); + kvm_virtio_pci_vector_release(proxy, nvqs); + } +- ++config_error: ++ kvm_virtio_pci_vector_config_release(proxy); ++config_assign_error: ++ virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign, ++ with_irqfd); + assign_error: + /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ + assert(assign); +diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h +index d95b1a13a5..6d8e071d8d 100644 +--- a/hw/virtio/virtio-pci.h ++++ b/hw/virtio/virtio-pci.h +@@ -256,5 +256,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t); + * @fixed_queues. + */ + unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); +- ++void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq, ++ int n, bool assign, ++ bool with_irqfd); + #endif +-- +2.27.0 + diff --git a/virtio-pci-decouple-notifier-from-interrupt-process-new.patch b/virtio-pci-decouple-notifier-from-interrupt-process-new.patch new file mode 100644 index 0000000..89380b3 --- /dev/null +++ b/virtio-pci-decouple-notifier-from-interrupt-process-new.patch @@ -0,0 +1,259 @@ +From e7e028565dd2620b86e884f953761b96a1ecdfdc Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:43 +0800 +Subject: [PATCH] virtio-pci: decouple notifier from interrupt process + +To reuse the notifier process. We add the virtio_pci_get_notifier +to get the notifier and vector. The INPUT for this function is IDX, +The OUTPUT is the notifier and the vector + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-3-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++++++++++++++--------------- + 1 file changed, 57 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 21c0ec3b1b..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,29 +789,41 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n , + unsigned int vector) + { +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } ++static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, ++ EventNotifier **n, unsigned int *vector) ++{ ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq; ++ ++ if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { ++ return -1; ++ } else { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; ++ } ++ *vector = virtio_queue_vector(vdev, queue_no); ++ vq = virtio_get_queue(vdev, queue_no); ++ *n = virtio_queue_get_guest_notifier(vq); ++ } ++ return 0; ++} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -820,12 +832,15 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- ++ EventNotifier *n; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -837,7 +852,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -853,7 +868,11 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -867,12 +886,16 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -880,21 +903,20 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg) ++ MSIMessage msg, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -921,14 +943,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + } + return ret; + } + +-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector) ++ unsigned int vector, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -939,7 +962,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + } + +@@ -949,6 +972,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -957,7 +981,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); ++ n = virtio_queue_get_guest_notifier(vq); ++ ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); + if (ret < 0) { + goto undo; + } +@@ -973,7 +998,8 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ n = virtio_queue_get_guest_notifier(vq); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -986,15 +1012,17 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); ++ n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1010,19 +1038,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- VirtQueue *vq; ++ int ret; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); ++ if (ret < 0) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } +- vq = virtio_get_queue(vdev, queue_no); +- notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/virtio-pci-decouple-notifier-from-interrupt-process.patch b/virtio-pci-decouple-notifier-from-interrupt-process.patch new file mode 100644 index 0000000..0c3d620 --- /dev/null +++ b/virtio-pci-decouple-notifier-from-interrupt-process.patch @@ -0,0 +1,259 @@ +From 22998eab50bc17b9af19e377df04d1583a7ddbda Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:50 +0800 +Subject: [PATCH] virtio-pci: decouple notifier from interrupt process + +To reuse the notifier process in configure interrupt. +Use the virtio_pci_get_notifier function to get the notifier. +the INPUT of this function is the IDX, the OUTPUT is notifier and +the vector + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-3-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 88 +++++++++++++++++++++++++++--------------- + 1 file changed, 57 insertions(+), 31 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 21c0ec3b1b..85d7357f66 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -789,29 +789,41 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + } + + static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + } + + static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, +- unsigned int queue_no, ++ EventNotifier *n , + unsigned int vector) + { +- VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); + assert(ret == 0); + } ++static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, ++ EventNotifier **n, unsigned int *vector) ++{ ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ VirtQueue *vq; ++ ++ if (queue_no == VIRTIO_CONFIG_IRQ_IDX) { ++ return -1; ++ } else { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; ++ } ++ *vector = virtio_queue_vector(vdev, queue_no); ++ vq = virtio_get_queue(vdev, queue_no); ++ *n = virtio_queue_get_guest_notifier(vq); ++ } ++ return 0; ++} + + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + { +@@ -820,12 +832,15 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + unsigned int vector; + int ret, queue_no; +- ++ EventNotifier *n; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -837,7 +852,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, delay until unmasked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; +@@ -853,7 +868,11 @@ undo: + continue; + } + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +@@ -867,12 +886,16 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + unsigned int vector; + int queue_no; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- ++ EventNotifier *n; ++ int ret ; + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ break; ++ } + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } +@@ -880,21 +903,20 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) + * Otherwise, it was cleaned when masked in the frontend. + */ + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + } + +-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, ++static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, +- MSIMessage msg) ++ MSIMessage msg, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- VirtQueue *vq = virtio_get_queue(vdev, queue_no); +- EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd; + int ret = 0; + +@@ -921,14 +943,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + event_notifier_set(n); + } + } else { +- ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + } + return ret; + } + +-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, ++static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy, + unsigned int queue_no, +- unsigned int vector) ++ unsigned int vector, ++ EventNotifier *n) + { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +@@ -939,7 +962,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, + if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { + k->guest_notifier_mask(vdev, queue_no, true); + } else { +- kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); + } + } + +@@ -949,6 +972,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int ret, index, unmasked = 0; + + while (vq) { +@@ -957,7 +981,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, + break; + } + if (index < proxy->nvqs_with_notifiers) { +- ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); ++ n = virtio_queue_get_guest_notifier(vq); ++ ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n); + if (ret < 0) { + goto undo; + } +@@ -973,7 +998,8 @@ undo: + while (vq && unmasked >= 0) { + index = virtio_get_queue_index(vq); + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ n = virtio_queue_get_guest_notifier(vq); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + --unmasked; + } + vq = virtio_vector_next_queue(vq); +@@ -986,15 +1012,17 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_vector_first_queue(vdev, vector); ++ EventNotifier *n; + int index; + + while (vq) { + index = virtio_get_queue_index(vq); ++ n = virtio_queue_get_guest_notifier(vq); + if (!virtio_queue_get_num(vdev, index)) { + break; + } + if (index < proxy->nvqs_with_notifiers) { +- virtio_pci_vq_vector_mask(proxy, index, vector); ++ virtio_pci_one_vector_mask(proxy, index, vector, n); + } + vq = virtio_vector_next_queue(vq); + } +@@ -1010,19 +1038,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev, + int queue_no; + unsigned int vector; + EventNotifier *notifier; +- VirtQueue *vq; ++ int ret; + + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, ¬ifier, &vector); ++ if (ret < 0) { + break; + } +- vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } +- vq = virtio_get_queue(vdev, queue_no); +- notifier = virtio_queue_get_guest_notifier(vq); + if (k->guest_notifier_pending) { + if (k->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); +-- +2.27.0 + diff --git a/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch b/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch new file mode 100644 index 0000000..1bff279 --- /dev/null +++ b/virtio-pci-decouple-the-single-vector-from-the-inter-new.patch @@ -0,0 +1,198 @@ +From 99e35c22ecd4847c652f136334c5949651e8419d Mon Sep 17 00:00:00 2001 +From: Cindy Lu +Date: Thu, 22 Dec 2022 15:04:44 +0800 +Subject: [PATCH] virtio-pci: decouple the single vector from the interrupt + process + +To reuse the interrupt process in configure interrupt +Need to decouple the single vector from the interrupt process. +We add new function kvm_virtio_pci_vector_use_one and _release_one. +These functions are used for the single vector, the whole process will +finish in the loop with vq number. + +Signed-off-by: Cindy Lu +Message-Id: <20221222070451.936503-4-lulu@redhat.com> +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 +++++++++++++++++++++++------------------ + 1 file changed, 73 insertions(+), 58 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,7 +762,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -825,87 +824,103 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) + { ++ unsigned int vector; ++ int ret; ++ EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- unsigned int vector; +- int ret, queue_no; +- EventNotifier *n; +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- break; +- } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return 0; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, vector); ++ if (ret < 0) { ++ goto undo; ++ } ++ /* ++ * If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } +- /* If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); +- if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); +- goto undo; +- } +- } + } +- return 0; + ++ return 0; + undo: +- while (--queue_no >= 0) { +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; ++ ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return ret; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; + } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ return ret; ++} ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ int ret = 0; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; + } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + } + return ret; + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++ ++static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, ++ int queue_no) + { +- PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- int queue_no; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + EventNotifier *n; +- int ret ; ++ int ret; ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ PCIDevice *dev = &proxy->pci_dev; ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++} ++ ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- /* If guest supports masking, clean up irqfd now. +- * Otherwise, it was cleaned when masked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ kvm_virtio_pci_vector_release_one(proxy, queue_no); + } + } + +-- +2.27.0 + diff --git a/virtio-pci-decouple-the-single-vector-from-the-inter.patch b/virtio-pci-decouple-the-single-vector-from-the-inter.patch new file mode 100644 index 0000000..a6989f9 --- /dev/null +++ b/virtio-pci-decouple-the-single-vector-from-the-inter.patch @@ -0,0 +1,196 @@ +From b3223ddde84840ccc6bb2282dfc146616b85a362 Mon Sep 17 00:00:00 2001 +From: fangyi +Date: Thu, 16 Nov 2023 09:54:51 +0800 +Subject: [PATCH] virtio-pci: decouple the single vector from the interrupt + process + +To reuse the interrupt process in configure interrupt +Need to decouple the single vector from the interrupt process. Add new function +kvm_virtio_pci_vector_use_one and _release_one. These functions are use +for the single vector, the whole process will finish in a loop for the vq number. + +Signed-off-by: Cindy Lu +Message-Id: <20211104164827.21911-4-lulu@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio-pci.c | 131 +++++++++++++++++++++++------------------ + 1 file changed, 73 insertions(+), 58 deletions(-) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 85d7357f66..75be770971 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -762,7 +762,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, + } + + static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, +- unsigned int queue_no, + unsigned int vector) + { + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; +@@ -825,87 +824,103 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no, + return 0; + } + +-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no) + { ++ unsigned int vector; ++ int ret; ++ EventNotifier *n; + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- unsigned int vector; +- int ret, queue_no; +- EventNotifier *n; +- for (queue_no = 0; queue_no < nvqs; queue_no++) { +- if (!virtio_queue_get_num(vdev, queue_no)) { +- break; +- } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return 0; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(proxy, vector); ++ if (ret < 0) { ++ goto undo; ++ } ++ /* ++ * If guest supports masking, set up irqfd now. ++ * Otherwise, delay until unmasked in the frontend. ++ */ ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); + if (ret < 0) { ++ kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } +- /* If guest supports masking, set up irqfd now. +- * Otherwise, delay until unmasked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = kvm_virtio_pci_irqfd_use(proxy, n, vector); +- if (ret < 0) { +- kvm_virtio_pci_vq_vector_release(proxy, vector); +- goto undo; +- } +- } + } +- return 0; + ++ return 0; + undo: +- while (--queue_no >= 0) { +- vector = virtio_queue_vector(vdev, queue_no); +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; ++ ++ vector = virtio_queue_vector(vdev, queue_no); ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return ret; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return ret; + } +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ return ret; ++} ++static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ int ret = 0; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ ++ for (queue_no = 0; queue_no < nvqs; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ return -1; + } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ ret = kvm_virtio_pci_vector_use_one(proxy, queue_no); + } + return ret; + } + +-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++ ++static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy, ++ int queue_no) + { +- PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + unsigned int vector; +- int queue_no; +- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + EventNotifier *n; +- int ret ; ++ int ret; ++ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); ++ PCIDevice *dev = &proxy->pci_dev; ++ ++ ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); ++ if (ret < 0) { ++ return; ++ } ++ if (vector >= msix_nr_vectors_allocated(dev)) { ++ return; ++ } ++ if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { ++ kvm_virtio_pci_irqfd_release(proxy, n, vector); ++ } ++ kvm_virtio_pci_vq_vector_release(proxy, vector); ++} ++ ++static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ++{ ++ int queue_no; ++ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); ++ + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } +- ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector); +- if (ret < 0) { +- break; +- } +- if (vector >= msix_nr_vectors_allocated(dev)) { +- continue; +- } +- /* If guest supports masking, clean up irqfd now. +- * Otherwise, it was cleaned when masked in the frontend. +- */ +- if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { +- kvm_virtio_pci_irqfd_release(proxy, n, vector); +- } +- kvm_virtio_pci_vq_vector_release(proxy, vector); ++ kvm_virtio_pci_vector_release_one(proxy, queue_no); + } + } + +-- +2.27.0 + diff --git a/virtio-signal-after-wrapping-packed-used_idx.patch b/virtio-signal-after-wrapping-packed-used_idx.patch new file mode 100644 index 0000000..3fa3b63 --- /dev/null +++ b/virtio-signal-after-wrapping-packed-used_idx.patch @@ -0,0 +1,51 @@ +From 671f0830d70c1e35deb63cc66db7ce8b713e8967 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Tue, 30 Nov 2021 13:45:10 +0000 +Subject: [PATCH] virtio: signal after wrapping packed used_idx + +Packed Virtqueues wrap used_idx instead of letting it run freely like +Split Virtqueues do. If the used ring wraps more than once there is no +way to compare vq->signalled_used and vq->used_idx in +virtio_packed_should_notify() since they are modulo vq->vring.num. + +This causes the device to stop sending used buffer notifications when +when virtio_packed_should_notify() is called less than once each time +around the used ring. + +It is possible to trigger this with virtio-blk's dataplane +notify_guest_bh() irq coalescing optimization. The call to +virtio_notify_irqfd() (and virtio_packed_should_notify()) is deferred to +a BH. If the guest driver is polling it can complete and submit more +requests before the BH executes, causing the used ring to wrap more than +once. The result is that the virtio-blk device ceases to raise +interrupts and I/O hangs. + +Cc: Tiwei Bie +Cc: Jason Wang +Cc: Michael S. Tsirkin +Signed-off-by: Stefan Hajnoczi +Message-Id: <20211130134510.267382-1-stefanha@redhat.com> +Fixes: 86044b24e865fb9596ed77a4d0f3af8b90a088a1 ("virtio: basic packed virtqueue support") +Acked-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: fangyi +--- + hw/virtio/virtio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index d90cabe868..05409b84d1 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -885,6 +885,7 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count) + if (vq->used_idx >= vq->vring.num) { + vq->used_idx -= vq->vring.num; + vq->used_wrap_counter ^= 1; ++ vq->signalled_used_valid = false; + } + } + +-- +2.27.0 + -- Gitee