block: Allow wait_serialising_requests() at any point
We can only have a single wait_serialising_requests() call per request because otherwise we can run into deadlocks where requests are waiting for each other. The same is true when wait_serialising_requests() is not at the very beginning of a request, so that other requests can be issued between the start of the tracking and wait_serialising_requests(). Fix this by changing wait_serialising_requests() to ignore requests that are already (directly or indirectly) waiting for the calling request. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Benoit Canet <benoit@irqsave.net>
This commit is contained in:
parent
7327145f63
commit
6460440f34
13
block.c
13
block.c
@ -2328,9 +2328,16 @@ static void coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
|||||||
*/
|
*/
|
||||||
assert(qemu_coroutine_self() != req->co);
|
assert(qemu_coroutine_self() != req->co);
|
||||||
|
|
||||||
qemu_co_queue_wait(&req->wait_queue);
|
/* If the request is already (indirectly) waiting for us, or
|
||||||
retry = true;
|
* will wait for us as soon as it wakes up, then just go on
|
||||||
break;
|
* (instead of producing a deadlock in the former case). */
|
||||||
|
if (!req->waiting_for) {
|
||||||
|
self->waiting_for = req;
|
||||||
|
qemu_co_queue_wait(&req->wait_queue);
|
||||||
|
self->waiting_for = NULL;
|
||||||
|
retry = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (retry);
|
} while (retry);
|
||||||
|
@ -68,6 +68,8 @@ typedef struct BdrvTrackedRequest {
|
|||||||
QLIST_ENTRY(BdrvTrackedRequest) list;
|
QLIST_ENTRY(BdrvTrackedRequest) list;
|
||||||
Coroutine *co; /* owner, used for deadlock detection */
|
Coroutine *co; /* owner, used for deadlock detection */
|
||||||
CoQueue wait_queue; /* coroutines blocked on this request */
|
CoQueue wait_queue; /* coroutines blocked on this request */
|
||||||
|
|
||||||
|
struct BdrvTrackedRequest *waiting_for;
|
||||||
} BdrvTrackedRequest;
|
} BdrvTrackedRequest;
|
||||||
|
|
||||||
struct BlockDriver {
|
struct BlockDriver {
|
||||||
|
Loading…
Reference in New Issue
Block a user