diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2024-09-12 16:17:26 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2024-09-12 16:17:27 +0100 |
| commit | 3baa3c9d62bb35904cf6dadbf152922d87f06e8f (patch) | |
| tree | 7d01a459bc5307d0e4b2b82fc58043f41d7528ce /hw/net/vhost_net.c | |
| parent | 4b7ea33074450bc6148c8e1545d78f179e64adb4 (diff) | |
| parent | 6e3c2d58e967cde3dadae298e81c5e8eb9fb9080 (diff) | |
| download | focaccia-qemu-3baa3c9d62bb35904cf6dadbf152922d87f06e8f.tar.gz focaccia-qemu-3baa3c9d62bb35904cf6dadbf152922d87f06e8f.zip | |
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
virtio,pc,pci: features, fixes, cleanups i286 acpi speedup by precomputing _PRT by Ricardo Ribalda vhost_net speedup by using MR transactions by Zuo Boqun ich9 gained support for periodic and swsmi timer by Dominic Prinz Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmbhoCUPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRptpUH/iR5AmJFpvAItqlPOvJiYDEch46C73tyrSws # Kk/1EbGSL7mFFD5sfdSSV4Rw8CQBsmM/Dt5VDkJKsWnOLjkBQ2CYH0MYHktnrKcJ # LlSk32HnY5p1DsXnJhgm5M7St8T3mV/oFdJCJAFgCmpx5uT8IRLrKETN8+30OaiY # xo35xAKOAS296+xsWeVubKkMq7H4y2tdZLE/22gb8rlA8d96BJIeVLQ3y3IjeUPR # 24q6c7zpObzGhYNZ/PzAKOn+YcVsV/lLAzKRZJTzTUPyG24BcjJTyyr/zNSYAgfk # lLXzIZID3GThBmrCAiDZ1z6sfo3MRg2wNS/FBXtK6fPIuFxed+8= # =ySRy # -----END PGP SIGNATURE----- # gpg: Signature made Wed 11 Sep 2024 14:50:29 BST # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: hw/acpi/ich9: Add periodic and swsmi timer virtio-mem: don't warn about THP sizes on a kernel without THP support hw/audio/virtio-sound: fix heap buffer overflow hw/cxl: fix physical address field in get scan media results output virtio-pci: Add lookup subregion of VirtIOPCIRegion MR vhost_net: configure all host notifiers in a single MR transaction tests/acpi: pc: update golden masters for DSDT hw/i386/acpi-build: Return a pre-computed _PRT table tests/acpi: pc: allow DSDT acpi table changes intel_iommu: Make PASID-cache and PIOTLB type invalid in legacy mode intel_iommu: Fix invalidation descriptor type field virtio: rename virtio_split_packed_update_used_idx hw/pci/pci-hmp-cmds: Avoid displaying bogus size in 'info pci' pci: don't skip function 0 occupancy verification for devfn auto assign hw/isa/vt82c686.c: Embed i8259 irq in device state instead of allocating hw: Move declaration of IRQState to header and add init function virtio: Always reset vhost devices virtio: Allow .get_vhost() without vhost_started Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/net/vhost_net.c')
| -rw-r--r-- | hw/net/vhost_net.c | 155 |
1 files changed, 143 insertions, 12 deletions
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index dedf9ad7c2..997aab0557 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -162,6 +162,135 @@ void vhost_net_save_acked_features(NetClientState *nc) #endif } +static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int nvhosts) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j; + NetClientState *peer; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + false); + if (r < 0) { + error_report("vhost %d VQ %d notifier cleanup failed: %d", + i, j, -r); + } + assert(r >= 0); + } + } + /* + * The transaction expects the ioeventfds to be open when it + * commits. Do it now, before the cleanup loop. + */ + memory_region_transaction_commit(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + for (j = 0; j < hdev->nvqs; j++) { + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j); + } + virtio_device_release_ioeventfd(dev); + } +} + +static int vhost_net_enable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + VirtIONet *n = VIRTIO_NET(dev); + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev))); + int nvhosts = data_queue_pairs + cvq; + struct vhost_net *net; + struct vhost_dev *hdev; + int r, i, j; + NetClientState *peer; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvhosts; i++) { + if (i < data_queue_pairs) { + peer = qemu_get_peer(ncs, i); + } else { + peer = qemu_get_peer(ncs, n->max_queue_pairs); + } + + net = get_vhost_net(peer); + hdev = &net->dev; + /* + * We will pass the notifiers to the kernel, make sure that QEMU + * doesn't interfere. + */ + r = virtio_device_grab_ioeventfd(dev); + if (r < 0) { + error_report("binding does not support host notifiers"); + memory_region_transaction_commit(); + goto fail_nvhosts; + } + + for (j = 0; j < hdev->nvqs; j++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), + hdev->vq_index + j, + true); + if (r < 0) { + error_report("vhost %d VQ %d notifier binding failed: %d", + i, j, -r); + memory_region_transaction_commit(); + vhost_dev_disable_notifiers_nvqs(hdev, dev, j); + goto fail_nvhosts; + } + } + } + + memory_region_transaction_commit(); + + return 0; +fail_nvhosts: + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i); + return r; +} + +/* + * Stop processing guest IO notifications in qemu. + * Start processing them in vhost in kernel. + */ +static void vhost_net_disable_notifiers(VirtIODevice *dev, + NetClientState *ncs, int data_queue_pairs, int cvq) +{ + vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, + data_queue_pairs + cvq); +} + static int vhost_net_get_fd(NetClientState *backend) { switch (backend->info->type) { @@ -272,11 +401,6 @@ static int vhost_net_start_one(struct vhost_net *net, } } - r = vhost_dev_enable_notifiers(&net->dev, dev); - if (r < 0) { - goto fail_notifiers; - } - r = vhost_dev_start(&net->dev, dev, false); if (r < 0) { goto fail_start; @@ -328,8 +452,6 @@ fail: } vhost_dev_stop(&net->dev, dev, false); fail_start: - vhost_dev_disable_notifiers(&net->dev, dev); -fail_notifiers: return r; } @@ -351,7 +473,6 @@ static void vhost_net_stop_one(struct vhost_net *net, if (net->nc->info->stop) { net->nc->info->stop(net->nc); } - vhost_dev_disable_notifiers(&net->dev, dev); } int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, @@ -396,10 +517,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, } } + r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq); + if (r < 0) { + error_report("Error enabling host notifiers: %d", -r); + goto err; + } + r = k->set_guest_notifiers(qbus->parent, total_notifiers, true); if (r < 0) { error_report("Error binding guest notifier: %d", -r); - goto err; + goto err_host_notifiers; } for (i = 0; i < nvhosts; i++) { @@ -414,19 +541,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, r = vhost_set_vring_enable(peer, peer->vring_enable); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } r = vhost_net_start_one(get_vhost_net(peer), dev); if (r < 0) { - goto err_start; + goto err_guest_notifiers; } } return 0; -err_start: +err_guest_notifiers: while (--i >= 0) { peer = qemu_get_peer(ncs, i < data_queue_pairs ? i : n->max_queue_pairs); @@ -437,6 +564,8 @@ err_start: fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); fflush(stderr); } +err_host_notifiers: + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); err: return r; } @@ -468,6 +597,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, fflush(stderr); } assert(r >= 0); + + vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq); } void vhost_net_cleanup(struct vhost_net *net) |