[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 33/47] rcu: Introduce force_rcu notifier
From: |
Michael Roth |
Subject: |
[PATCH 33/47] rcu: Introduce force_rcu notifier |
Date: |
Tue, 14 Dec 2021 18:01:11 -0600 |
From: Greg Kurz <groug@kaod.org>
The drain_rcu_call() function can be blocked as long as an RCU reader
stays in a read-side critical section. This is typically what happens
when a TCG vCPU is executing a busy loop. It can deadlock the QEMU
monitor as reported in https://gitlab.com/qemu-project/qemu/-/issues/650 .
This can be avoided by allowing drain_rcu_call() to enforce an RCU grace
period. Since each reader might need to do specific actions to end a
read-side critical section, do it with notifiers.
Prepare ground for this by adding a notifier list to the RCU reader
struct and use it in wait_for_readers() if drain_rcu_call() is in
progress. An API is added for readers to register their notifiers.
This is largely based on a draft from Paolo Bonzini.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211109183523.47726-2-groug@kaod.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ef149763a8fcce70b85dfda27cc1222ecf765750)
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
include/qemu/rcu.h | 15 +++++++++++++++
util/rcu.c | 19 +++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h
index 515d327cf1..e69efbd47f 100644
--- a/include/qemu/rcu.h
+++ b/include/qemu/rcu.h
@@ -27,6 +27,7 @@
#include "qemu/thread.h"
#include "qemu/queue.h"
#include "qemu/atomic.h"
+#include "qemu/notify.h"
#include "qemu/sys_membarrier.h"
#ifdef __cplusplus
@@ -66,6 +67,13 @@ struct rcu_reader_data {
/* Data used for registry, protected by rcu_registry_lock */
QLIST_ENTRY(rcu_reader_data) node;
+
+ /*
+ * NotifierList used to force an RCU grace period. Accessed under
+ * rcu_registry_lock. Note that the notifier is called _outside_
+ * the thread!
+ */
+ NotifierList force_rcu;
};
extern __thread struct rcu_reader_data rcu_reader;
@@ -180,6 +188,13 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto,
rcu_read_auto_unlock)
#define RCU_READ_LOCK_GUARD() \
g_autoptr(RCUReadAuto) _rcu_read_auto __attribute__((unused)) =
rcu_read_auto_lock()
+/*
+ * Force-RCU notifiers tell readers that they should exit their
+ * read-side critical section.
+ */
+void rcu_add_force_rcu_notifier(Notifier *n);
+void rcu_remove_force_rcu_notifier(Notifier *n);
+
#ifdef __cplusplus
}
#endif
diff --git a/util/rcu.c b/util/rcu.c
index 13ac0f75cb..c91da9f137 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -46,6 +46,7 @@
unsigned long rcu_gp_ctr = RCU_GP_LOCKED;
QemuEvent rcu_gp_event;
+static int in_drain_call_rcu;
static QemuMutex rcu_registry_lock;
static QemuMutex rcu_sync_lock;
@@ -107,6 +108,8 @@ static void wait_for_readers(void)
* get some extra futex wakeups.
*/
qatomic_set(&index->waiting, false);
+ } else if (qatomic_read(&in_drain_call_rcu)) {
+ notifier_list_notify(&index->force_rcu, NULL);
}
}
@@ -339,8 +342,10 @@ void drain_call_rcu(void)
* assumed.
*/
+ qatomic_inc(&in_drain_call_rcu);
call_rcu1(&rcu_drain.rcu, drain_rcu_callback);
qemu_event_wait(&rcu_drain.drain_complete_event);
+ qatomic_dec(&in_drain_call_rcu);
if (locked) {
qemu_mutex_lock_iothread();
@@ -363,6 +368,20 @@ void rcu_unregister_thread(void)
qemu_mutex_unlock(&rcu_registry_lock);
}
+void rcu_add_force_rcu_notifier(Notifier *n)
+{
+ qemu_mutex_lock(&rcu_registry_lock);
+ notifier_list_add(&rcu_reader.force_rcu, n);
+ qemu_mutex_unlock(&rcu_registry_lock);
+}
+
+void rcu_remove_force_rcu_notifier(Notifier *n)
+{
+ qemu_mutex_lock(&rcu_registry_lock);
+ notifier_remove(n);
+ qemu_mutex_unlock(&rcu_registry_lock);
+}
+
static void rcu_init_complete(void)
{
QemuThread thread;
--
2.25.1
- [PATCH 24/47] tests/acpi/bios-tables-test: add and allow changes to a new q35 DSDT table blob, (continued)
- [PATCH 24/47] tests/acpi/bios-tables-test: add and allow changes to a new q35 DSDT table blob, Michael Roth, 2021/12/14
- [PATCH 25/47] tests/acpi/pcihp: add unit tests for hotplug on multifunction bridges for q35, Michael Roth, 2021/12/14
- [PATCH 26/47] tests/acpi/bios-tables-test: update DSDT blob for multifunction bridge test, Michael Roth, 2021/12/14
- [PATCH 27/47] block/file-posix: Fix return value translation for AIO discards, Michael Roth, 2021/12/14
- [PATCH 28/47] Partially revert "build: -no-pie is no functional linker flag", Michael Roth, 2021/12/14
- [PATCH 29/47] target-i386: mmu: use pg_mode instead of HF_LMA_MASK, Michael Roth, 2021/12/14
- [PATCH 30/47] target-i386: mmu: fix handling of noncanonical virtual addresses, Michael Roth, 2021/12/14
- [PATCH 02/47] target/arm: Don't skip M-profile reset entirely in user mode, Michael Roth, 2021/12/14
- [PATCH 31/47] hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT commands, Michael Roth, 2021/12/14
- [PATCH 32/47] hw: m68k: virt: Add compat machine for 6.1, Michael Roth, 2021/12/14
- [PATCH 33/47] rcu: Introduce force_rcu notifier,
Michael Roth <=
- [PATCH 34/47] accel/tcg: Register a force_rcu notifier, Michael Roth, 2021/12/14
- [PATCH 35/47] pcie: rename 'native-hotplug' to 'x-native-hotplug', Michael Roth, 2021/12/14
- [PATCH 36/47] virtio: use virtio accessor to access packed descriptor flags, Michael Roth, 2021/12/14
- [PATCH 37/47] virtio: use virtio accessor to access packed event, Michael Roth, 2021/12/14
- [PATCH 38/47] vfio: Fix memory leak of hostwin, Michael Roth, 2021/12/14
- [PATCH 39/47] nbd/server: Don't complain on certain client disconnects, Michael Roth, 2021/12/14
- [PATCH 40/47] hw/nvme: fix buffer overrun in nvme_changed_nslist (CVE-2021-3947), Michael Roth, 2021/12/14
- [PATCH 03/47] virtio-net: fix use after unmap/free for sg, Michael Roth, 2021/12/14
- [PATCH 41/47] chardev/wctable: don't free the instance in wctablet_chr_finalize, Michael Roth, 2021/12/14
- [PATCH 42/47] hw/block/fdc: Extract blk_create_empty_drive(), Michael Roth, 2021/12/14