/* Protects the list of aiocontext and orphaned_reader_count */
static QemuMutex aio_context_list_lock;
-#if 0
/* Written and read with atomic operations. */
static int has_writer;
-#endif
/*
* A reader coroutine could move from an AioContext to another.
g_free(ctx->bdrv_graph);
}
-#if 0
static uint32_t reader_count(void)
{
BdrvGraphRWlock *brdv_graph;
QEMU_LOCK_GUARD(&aio_context_list_lock);
- /* rd can temporarly be negative, but the total will *always* be >= 0 */
+ /* rd can temporarily be negative, but the total will *always* be >= 0 */
rd = orphaned_reader_count;
QTAILQ_FOREACH(brdv_graph, &aio_context_list, next_aio) {
rd += qatomic_read(&brdv_graph->reader_count);
assert((int32_t)rd >= 0);
return rd;
}
-#endif
-void bdrv_graph_wrlock(void)
+void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
{
+ AioContext *ctx = NULL;
+
GLOBAL_STATE_CODE();
+ assert(!qatomic_read(&has_writer));
+ assert(!qemu_in_coroutine());
+
/*
- * TODO Some callers hold an AioContext lock when this is called, which
- * causes deadlocks. Reenable once the AioContext locking is cleaned up (or
- * AioContext locks are gone).
+ * Release only non-mainloop AioContext. The mainloop often relies on the
+ * BQL and doesn't lock the main AioContext before doing things.
*/
-#if 0
- assert(!qatomic_read(&has_writer));
+ if (bs) {
+ ctx = bdrv_get_aio_context(bs);
+ if (ctx != qemu_get_aio_context()) {
+ aio_context_release(ctx);
+ } else {
+ ctx = NULL;
+ }
+ }
/* Make sure that constantly arriving new I/O doesn't cause starvation */
bdrv_drain_all_begin_nopoll();
} while (reader_count() >= 1);
bdrv_drain_all_end();
-#endif
+
+ if (ctx) {
+ aio_context_acquire(bdrv_get_aio_context(bs));
+ }
}
void bdrv_graph_wrunlock(void)
{
GLOBAL_STATE_CODE();
-#if 0
- QEMU_LOCK_GUARD(&aio_context_list_lock);
assert(qatomic_read(&has_writer));
+ WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
+ /*
+ * No need for memory barriers, this works in pair with
+ * the slow path of rdlock() and both take the lock.
+ */
+ qatomic_store_release(&has_writer, 0);
+
+ /* Wake up all coroutines that are waiting to read the graph */
+ qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
+ }
+
/*
- * No need for memory barriers, this works in pair with
- * the slow path of rdlock() and both take the lock.
+ * Run any BHs that were scheduled during the wrlock section and that
+ * callers might expect to have finished (in particular, this is important
+ * for bdrv_schedule_unref()).
+ *
+ * Do this only after restarting coroutines so that nested event loops in
+ * BHs don't deadlock if their condition relies on the coroutine making
+ * progress.
*/
- qatomic_store_release(&has_writer, 0);
-
- /* Wake up all coroutine that are waiting to read the graph */
- qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
-#endif
+ aio_bh_poll(qemu_get_aio_context());
}
void coroutine_fn bdrv_graph_co_rdlock(void)
{
- /* TODO Reenable when wrlock is reenabled */
-#if 0
BdrvGraphRWlock *bdrv_graph;
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
qemu_co_queue_wait(&reader_queue, &aio_context_list_lock);
}
}
-#endif
}
void coroutine_fn bdrv_graph_co_rdunlock(void)
{
-#if 0
BdrvGraphRWlock *bdrv_graph;
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
if (qatomic_read(&has_writer)) {
aio_wait_kick();
}
-#endif
}
void bdrv_graph_rdlock_main_loop(void)
void assert_bdrv_graph_readable(void)
{
/* reader_count() is slow due to aio_context_list_lock lock contention */
- /* TODO Reenable when wrlock is reenabled */
-#if 0
#ifdef CONFIG_DEBUG_GRAPH_LOCK
assert(qemu_in_main_thread() || reader_count());
#endif
-#endif
}
void assert_bdrv_graph_writable(void)
{
assert(qemu_in_main_thread());
- /* TODO Reenable when wrlock is reenabled */
-#if 0
assert(qatomic_read(&has_writer));
-#endif
}