[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL v2 10/47] vhost-user: fix VirtQ notifier cleanup
From: |
Michael S. Tsirkin |
Subject: |
[PULL v2 10/47] vhost-user: fix VirtQ notifier cleanup |
Date: |
Mon, 7 Mar 2022 05:01:51 -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 v2 00/47] virtio,pc,pci: features, cleanups, fixes, Michael S. Tsirkin, 2022/03/07
- [PULL v2 01/47] qom: assert integer does not overflow, Michael S. Tsirkin, 2022/03/07
- [PULL v2 02/47] ACPI ERST: specification for ERST support, Michael S. Tsirkin, 2022/03/07
- [PULL v2 03/47] MAINTAINERS: no need to add my name explicitly as a reviewer for VIOT tables, Michael S. Tsirkin, 2022/03/07
- [PULL v2 04/47] docs/acpi/erst: add device id for ACPI ERST device in pci-ids.txt, Michael S. Tsirkin, 2022/03/07
- [PULL v2 05/47] hw/acpi/erst: clean up unused IS_UEFI_CPER_RECORD macro, Michael S. Tsirkin, 2022/03/07
- [PULL v2 06/47] hw/smbios: code cleanup - use macro definitions for table header handles, Michael S. Tsirkin, 2022/03/07
- [PULL v2 07/47] hw/smbios: fix overlapping table handle numbers with large memory vms, Michael S. Tsirkin, 2022/03/07
- [PULL v2 08/47] hw/smbios: add assertion to ensure handles of tables 19 and 32 do not collide, Michael S. Tsirkin, 2022/03/07
- [PULL v2 09/47] vhost-user: remove VirtQ notifier restore, Michael S. Tsirkin, 2022/03/07
- [PULL v2 10/47] vhost-user: fix VirtQ notifier cleanup,
Michael S. Tsirkin <=
- [PULL v2 11/47] virtio: fix the condition for iommu_platform not supported, Michael S. Tsirkin, 2022/03/07
- [PULL v2 13/47] hw/virtio: vdpa: Fix leak of host-notifier memory-region, Michael S. Tsirkin, 2022/03/07
- [PULL v2 15/47] intel_iommu: support snoop control, Michael S. Tsirkin, 2022/03/07
- [PULL v2 12/47] hw/vhost-user-i2c: Add support for VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, Michael S. Tsirkin, 2022/03/07
- [PULL v2 14/47] vhost-vdpa: make notifiers _init()/_uninit() symmetric, Michael S. Tsirkin, 2022/03/07
- [PULL v2 17/47] hw/i386: Replace magic number with field length calculation, Michael S. Tsirkin, 2022/03/07
- [PULL v2 16/47] hw/i386: Improve bounds checking in OVMF table parsing, Michael S. Tsirkin, 2022/03/07
- [PULL v2 18/47] virtio-iommu: Default to bypass during boot, Michael S. Tsirkin, 2022/03/07
- [PULL v2 19/47] virtio-iommu: Support bypass domain, Michael S. Tsirkin, 2022/03/07
- [PULL v2 21/47] hw/i386/pc_piix: Mark the machine types from version 1.4 to 1.7 as deprecated, Michael S. Tsirkin, 2022/03/07