QemuMutex queued_requests_lock; /* protects queued_requests */
CoQueue queued_requests;
bool disable_request_queuing; /* atomic */
+ int start_request_count; /* atomic */
VMChangeStateEntry *vmsh;
bool force_allow_inactivate;
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
-static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
+static void coroutine_fn blk_wait_while_drained(BlockBackend *blk,
+ BdrvRequestFlags flags)
{
assert(blk->in_flight > 0);
+ if (flags & BDRV_REQ_NO_QUEUE) {
+ assert(qatomic_read(&blk->start_request_count));
+ return;
+ }
+
if (qatomic_read(&blk->quiesce_counter) &&
!qatomic_read(&blk->disable_request_queuing)) {
/*
BlockDriverState *bs;
IO_CODE();
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, flags);
GRAPH_RDLOCK_GUARD();
/* Call blk_bs() only after waiting, the graph may have changed */
BlockDriverState *bs;
IO_CODE();
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, flags);
GRAPH_RDLOCK_GUARD();
/* Call blk_bs() only after waiting, the graph may have changed */
aio_wait_kick();
}
+void coroutine_fn blk_co_start_request(BlockBackend *blk)
+{
+ blk_inc_in_flight(blk);
+ blk_wait_while_drained(blk, 0);
+ qatomic_inc(&blk->start_request_count);
+}
+
+void blk_end_request(BlockBackend *blk)
+{
+ qatomic_dec(&blk->start_request_count);
+ blk_dec_in_flight(blk);
+}
+
static void error_callback_bh(void *opaque)
{
struct BlockBackendAIOCB *acb = opaque;
{
IO_CODE();
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, 0);
GRAPH_RDLOCK_GUARD();
if (!blk_co_is_available(blk)) {
int ret;
IO_CODE();
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, 0);
GRAPH_RDLOCK_GUARD();
ret = blk_check_byte_request(blk, offset, bytes);
static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
{
IO_CODE();
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, 0);
GRAPH_RDLOCK_GUARD();
if (!blk_co_is_available(blk)) {
IO_CODE();
blk_inc_in_flight(blk); /* increase before waiting */
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, 0);
GRAPH_RDLOCK_GUARD();
if (!blk_is_available(blk)) {
blk_dec_in_flight(blk);
IO_CODE();
blk_inc_in_flight(blk);
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, 0);
GRAPH_RDLOCK_GUARD();
ret = blk_check_byte_request(blk, offset, len);
IO_CODE();
blk_inc_in_flight(blk);
- blk_wait_while_drained(blk);
+ blk_wait_while_drained(blk, flags);
GRAPH_RDLOCK_GUARD();
if (!blk_is_available(blk)) {
blk_dec_in_flight(blk);
*/
BDRV_REQ_NO_WAIT = 0x400,
+ /*
+ * Used between blk_co_start_request() and blk_end_request() to avoid
+ * that the request waits in a drained BlockBackend until the drained
+ * section ends. Waiting would cause a deadlock because drain waits for
+ * blk_end_request() to be called, but the request never completes
+ * because it waits for the drain to end.
+ */
+ BDRV_REQ_NO_QUEUE = 0x800,
+
/* Mask of valid flags */
- BDRV_REQ_MASK = 0x7ff,
+ BDRV_REQ_MASK = 0xfff,
} BdrvRequestFlags;
#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */