Skip to content

Commit

Permalink
block: add BDRV_REQ_SERIALISING flag
Browse files Browse the repository at this point in the history
Serialized writes should be used in copy-on-write of backup(sync=none)
for image fleecing scheme.

We need to change an assert in bdrv_aligned_pwritev, added in
28de2dc. The assert may fail now, because call to
wait_serialising_requests here may become first call to it for this
request with serializing flag set. It occurs if the request is aligned
(otherwise, we should already set serializing flag before calling
bdrv_aligned_pwritev and correspondingly waited for all intersecting
requests). However, for aligned requests, we should not care about
outdating of previously read data, as there no such data. Therefore,
let's just update an assert to not care about aligned requests.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
Vladimir Sementsov-Ogievskiy authored and kevmw committed Jul 10, 2018
1 parent 67b51fb commit 09d2f94
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
28 changes: 27 additions & 1 deletion block/io.c
Expand Up @@ -637,6 +637,18 @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
req->overlap_bytes = MAX(req->overlap_bytes, overlap_bytes);
}

static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req)
{
/*
* If the request is serialising, overlap_offset and overlap_bytes are set,
* so we can check if the request is aligned. Otherwise, don't care and
* return false.
*/

return req->serialising && (req->offset == req->overlap_offset) &&
(req->bytes == req->overlap_bytes);
}

/**
* Round a region to cluster boundaries
*/
Expand Down Expand Up @@ -1311,6 +1323,9 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
mark_request_serialising(req, bdrv_get_cluster_size(bs));
}

/* BDRV_REQ_SERIALISING is only for write operation */
assert(!(flags & BDRV_REQ_SERIALISING));

if (!(flags & BDRV_REQ_NO_SERIALISING)) {
wait_serialising_requests(req);
}
Expand Down Expand Up @@ -1594,8 +1609,14 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,

/* BDRV_REQ_NO_SERIALISING is only for read operation */
assert(!(flags & BDRV_REQ_NO_SERIALISING));

if (flags & BDRV_REQ_SERIALISING) {
mark_request_serialising(req, bdrv_get_cluster_size(bs));
}

waited = wait_serialising_requests(req);
assert(!waited || !req->serialising);
assert(!waited || !req->serialising ||
is_request_serialising_and_aligned(req));
assert(req->overlap_offset <= offset);
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
Expand Down Expand Up @@ -2949,6 +2970,8 @@ static int coroutine_fn bdrv_co_copy_range_internal(
tracked_request_begin(&req, src->bs, src_offset, bytes,
BDRV_TRACKED_READ);

/* BDRV_REQ_SERIALISING is only for write operation */
assert(!(read_flags & BDRV_REQ_SERIALISING));
if (!(read_flags & BDRV_REQ_NO_SERIALISING)) {
wait_serialising_requests(&req);
}
Expand All @@ -2968,6 +2991,9 @@ static int coroutine_fn bdrv_co_copy_range_internal(

/* BDRV_REQ_NO_SERIALISING is only for read operation */
assert(!(write_flags & BDRV_REQ_NO_SERIALISING));
if (write_flags & BDRV_REQ_SERIALISING) {
mark_request_serialising(&req, bdrv_get_cluster_size(dst->bs));
}
wait_serialising_requests(&req);

ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
Expand Down
14 changes: 13 additions & 1 deletion include/block/block.h
Expand Up @@ -70,8 +70,20 @@ typedef enum {
* content. */
BDRV_REQ_WRITE_UNCHANGED = 0x40,

/*
* BDRV_REQ_SERIALISING forces request serialisation for writes.
* It is used to ensure that writes to the backing file of a backup process
* target cannot race with a read of the backup target that defers to the
* backing file.
*
* Note, that BDRV_REQ_SERIALISING is _not_ opposite in meaning to
* BDRV_REQ_NO_SERIALISING. A more descriptive name for the latter might be
* _DO_NOT_WAIT_FOR_SERIALISING, except that is too long.
*/
BDRV_REQ_SERIALISING = 0x80,

/* Mask of valid flags */
BDRV_REQ_MASK = 0x7f,
BDRV_REQ_MASK = 0xff,
} BdrvRequestFlags;

typedef struct BlockSizes {
Expand Down

0 comments on commit 09d2f94

Please sign in to comment.