[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 10/45] vhost-user: fix VirtQ notifier cleanup
From: |
Michael S. Tsirkin |
Subject: |
[PULL 10/45] vhost-user: fix VirtQ notifier cleanup |
Date: |
Fri, 4 Mar 2022 08:38:32 -0500 |
From: Xueming Li <xuemingl@nvidia.com>
When vhost-user device cleanup, remove notifier MR and munmaps notifier
address in the event-handling thread, VM CPU thread writing the notifier
in concurrent fails with an error of accessing invalid address. It
happens because MR is still being referenced and accessed in another
thread while the underlying notifier mmap address is being freed and
becomes invalid.
This patch calls RCU and munmap notifiers in the callback after the
memory flatview update finish.
Fixes: 44866521bd6e ("vhost-user: support registering external host notifiers")
Cc: qemu-stable@nongnu.org
Signed-off-by: Xueming Li <xuemingl@nvidia.com>
Message-Id: <20220207071929.527149-3-xuemingl@nvidia.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
include/hw/virtio/vhost-user.h | 2 ++
hw/virtio/vhost-user.c | 48 ++++++++++++++++++++--------------
2 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
index f6012b2078..e44a41bb70 100644
--- a/include/hw/virtio/vhost-user.h
+++ b/include/hw/virtio/vhost-user.h
@@ -12,8 +12,10 @@
#include "hw/virtio/virtio.h"
typedef struct VhostUserHostNotifier {
+ struct rcu_head rcu;
MemoryRegion mr;
void *addr;
+ void *unmap_addr;
} VhostUserHostNotifier;
typedef struct VhostUserState {
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index ebe9bd58d0..6abbc9da32 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -25,6 +25,7 @@
#include "migration/migration.h"
#include "migration/postcopy-ram.h"
#include "trace.h"
+#include "exec/ramblock.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -1162,15 +1163,26 @@ static int vhost_user_set_vring_num(struct vhost_dev
*dev,
return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
}
-static void vhost_user_host_notifier_remove(struct vhost_dev *dev,
- int queue_idx)
+static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
{
- struct vhost_user *u = dev->opaque;
- VhostUserHostNotifier *n = &u->user->notifier[queue_idx];
- VirtIODevice *vdev = dev->vdev;
+ assert(n && n->unmap_addr);
+ munmap(n->unmap_addr, qemu_real_host_page_size);
+ n->unmap_addr = NULL;
+}
+
+static void vhost_user_host_notifier_remove(VhostUserState *user,
+ VirtIODevice *vdev, int queue_idx)
+{
+ VhostUserHostNotifier *n = &user->notifier[queue_idx];
if (n->addr) {
- virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
+ if (vdev) {
+ virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
+ }
+ assert(!n->unmap_addr);
+ n->unmap_addr = n->addr;
+ n->addr = NULL;
+ call_rcu(n, vhost_user_host_notifier_free, rcu);
}
}
@@ -1219,8 +1231,9 @@ static int vhost_user_get_vring_base(struct vhost_dev
*dev,
.payload.state = *ring,
.hdr.size = sizeof(msg.payload.state),
};
+ struct vhost_user *u = dev->opaque;
- vhost_user_host_notifier_remove(dev, ring->index);
+ vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index);
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
@@ -1506,12 +1519,7 @@ static int
vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
n = &user->notifier[queue_idx];
- if (n->addr) {
- virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
- object_unparent(OBJECT(&n->mr));
- munmap(n->addr, page_size);
- n->addr = NULL;
- }
+ vhost_user_host_notifier_remove(user, vdev, queue_idx);
if (area->u64 & VHOST_USER_VRING_NOFD_MASK) {
return 0;
@@ -1530,9 +1538,12 @@ static int
vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
user, queue_idx);
- if (!n->mr.ram) /* Don't init again after suspend. */
+ if (!n->mr.ram) { /* Don't init again after suspend. */
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr);
+ } else {
+ n->mr.ram_block->host = addr;
+ }
g_free(name);
if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) {
@@ -2505,17 +2516,16 @@ bool vhost_user_init(VhostUserState *user, CharBackend
*chr, Error **errp)
void vhost_user_cleanup(VhostUserState *user)
{
int i;
+ VhostUserHostNotifier *n;
if (!user->chr) {
return;
}
memory_region_transaction_begin();
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (user->notifier[i].addr) {
- object_unparent(OBJECT(&user->notifier[i].mr));
- munmap(user->notifier[i].addr, qemu_real_host_page_size);
- user->notifier[i].addr = NULL;
- }
+ n = &user->notifier[i];
+ vhost_user_host_notifier_remove(user, NULL, i);
+ object_unparent(OBJECT(&n->mr));
}
memory_region_transaction_commit();
user->chr = NULL;
--
MST
- [PULL 00/45] virtio,pc,pci: features, cleanups, fixes, Michael S. Tsirkin, 2022/03/04
- [PULL 01/45] qom: assert integer does not overflow, Michael S. Tsirkin, 2022/03/04
- [PULL 02/45] ACPI ERST: specification for ERST support, Michael S. Tsirkin, 2022/03/04
- [PULL 03/45] MAINTAINERS: no need to add my name explicitly as a reviewer for VIOT tables, Michael S. Tsirkin, 2022/03/04
- [PULL 04/45] docs/acpi/erst: add device id for ACPI ERST device in pci-ids.txt, Michael S. Tsirkin, 2022/03/04
- [PULL 05/45] hw/acpi/erst: clean up unused IS_UEFI_CPER_RECORD macro, Michael S. Tsirkin, 2022/03/04
- [PULL 06/45] hw/smbios: code cleanup - use macro definitions for table header handles, Michael S. Tsirkin, 2022/03/04
- [PULL 08/45] hw/smbios: add assertion to ensure handles of tables 19 and 32 do not collide, Michael S. Tsirkin, 2022/03/04
- [PULL 07/45] hw/smbios: fix overlapping table handle numbers with large memory vms, Michael S. Tsirkin, 2022/03/04
- [PULL 09/45] vhost-user: remove VirtQ notifier restore, Michael S. Tsirkin, 2022/03/04
- [PULL 10/45] vhost-user: fix VirtQ notifier cleanup,
Michael S. Tsirkin <=
- [PULL 11/45] virtio: fix the condition for iommu_platform not supported, Michael S. Tsirkin, 2022/03/04
- [PULL 12/45] hw/vhost-user-i2c: Add support for VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, Michael S. Tsirkin, 2022/03/04
- [PULL 13/45] tests/qtest/libqos/pci: Introduce pio_limit, Michael S. Tsirkin, 2022/03/04
- [PULL 14/45] tests/qtest/libqos: Skip hotplug tests if pci root bus is not hotpluggable, Michael S. Tsirkin, 2022/03/04
- [PULL 15/45] tests/qtest/vhost-user-blk-test: Temporary hack to get tests passing on aarch64, Michael S. Tsirkin, 2022/03/04
- [PULL 16/45] tests/qtest/libqos: Add generic pci host bridge in arm-virt machine, Michael S. Tsirkin, 2022/03/04
- [PULL 17/45] hw/virtio: vdpa: Fix leak of host-notifier memory-region, Michael S. Tsirkin, 2022/03/04
- [PULL 18/45] vhost-vdpa: make notifiers _init()/_uninit() symmetric, Michael S. Tsirkin, 2022/03/04