block: Assert serialisation assumptions in pwritev
If a request calls wait_serialising_requests() and actually has to wait in this function (i.e. a coroutine yield), other requests can run and previously read data (like the head or tail buffer) could become outdated. In this case, we would have to restart from the beginning to read in the updated data. However, we're lucky and don't actually need to do that: A request can only wait in the first call of wait_serialising_requests() because we mark it as serialising before that call, so any later requests would wait. So as we don't wait in practice, we don't have to reload the data. This is an important assumption that may not be broken or data corruption will happen. Document it with some assertions. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
3b8242e0ea
commit
28de2dcd88
16
block.c
16
block.c
|
@ -2303,14 +2303,15 @@ static bool tracked_request_overlaps(BdrvTrackedRequest *req,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = self->bs;
|
BlockDriverState *bs = self->bs;
|
||||||
BdrvTrackedRequest *req;
|
BdrvTrackedRequest *req;
|
||||||
bool retry;
|
bool retry;
|
||||||
|
bool waited = false;
|
||||||
|
|
||||||
if (!bs->serialising_in_flight) {
|
if (!bs->serialising_in_flight) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -2336,11 +2337,14 @@ static void coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||||
qemu_co_queue_wait(&req->wait_queue);
|
qemu_co_queue_wait(&req->wait_queue);
|
||||||
self->waiting_for = NULL;
|
self->waiting_for = NULL;
|
||||||
retry = true;
|
retry = true;
|
||||||
|
waited = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (retry);
|
} while (retry);
|
||||||
|
|
||||||
|
return waited;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3191,6 +3195,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||||
QEMUIOVector *qiov, int flags)
|
QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
bool waited;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
int64_t sector_num = offset >> BDRV_SECTOR_BITS;
|
int64_t sector_num = offset >> BDRV_SECTOR_BITS;
|
||||||
|
@ -3199,7 +3204,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
|
|
||||||
wait_serialising_requests(req);
|
waited = wait_serialising_requests(req);
|
||||||
|
assert(!waited || !req->serialising);
|
||||||
|
|
||||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||||
|
|
||||||
|
@ -3299,9 +3305,11 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||||
QEMUIOVector tail_qiov;
|
QEMUIOVector tail_qiov;
|
||||||
struct iovec tail_iov;
|
struct iovec tail_iov;
|
||||||
size_t tail_bytes;
|
size_t tail_bytes;
|
||||||
|
bool waited;
|
||||||
|
|
||||||
mark_request_serialising(&req, align);
|
mark_request_serialising(&req, align);
|
||||||
wait_serialising_requests(&req);
|
waited = wait_serialising_requests(&req);
|
||||||
|
assert(!waited || !use_local_qiov);
|
||||||
|
|
||||||
tail_buf = qemu_blockalign(bs, align);
|
tail_buf = qemu_blockalign(bs, align);
|
||||||
tail_iov = (struct iovec) {
|
tail_iov = (struct iovec) {
|
||||||
|
|
Loading…
Reference in a new issue