block: Use common write req handling in truncate
Truncation is the last to convert from open coded req handling to reusing helpers. This time the permission check in prepare has to adapt to the new caller: it checks a different permission bit, and doesn't trigger the before write notifier. Also, truncation should always trigger a bs->total_sectors update and in turn call parent resize_cb. Update the condition in finish helper, too. It's intended to do a duplicated bs->read_only check before calling bdrv_co_write_req_prepare() so that we can be more informative with the error message, as bdrv_co_write_req_prepare() doesn't have Error parameter. Signed-off-by: Fam Zheng <famz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
5416a11eb5
commit
cd47d792d7
57
block/io.c
57
block/io.c
@ -1604,14 +1604,24 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
|
||||
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) {
|
||||
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
} else {
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
}
|
||||
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
return notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
switch (req->type) {
|
||||
case BDRV_TRACKED_WRITE:
|
||||
case BDRV_TRACKED_DISCARD:
|
||||
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
|
||||
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
} else {
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
}
|
||||
return notifier_with_return_list_notify(&bs->before_write_notifiers,
|
||||
req);
|
||||
case BDRV_TRACKED_TRUNCATE:
|
||||
assert(child->perm & BLK_PERM_RESIZE);
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void coroutine_fn
|
||||
@ -1631,8 +1641,9 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
|
||||
* beyond EOF cannot expand the image anyway.
|
||||
*/
|
||||
if (ret == 0 &&
|
||||
end_sector > bs->total_sectors &&
|
||||
req->type != BDRV_TRACKED_DISCARD) {
|
||||
(req->type == BDRV_TRACKED_TRUNCATE ||
|
||||
end_sector > bs->total_sectors) &&
|
||||
req->type != BDRV_TRACKED_DISCARD) {
|
||||
bs->total_sectors = end_sector;
|
||||
bdrv_parent_cb_resize(bs);
|
||||
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
|
||||
@ -3111,7 +3122,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
|
||||
int64_t old_size, new_bytes;
|
||||
int ret;
|
||||
|
||||
assert(child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
|
||||
if (!drv) {
|
||||
@ -3144,7 +3154,18 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
|
||||
* concurrently or they might be overwritten by preallocation. */
|
||||
if (new_bytes) {
|
||||
mark_request_serialising(&req, 1);
|
||||
wait_serialising_requests(&req);
|
||||
}
|
||||
if (bs->read_only) {
|
||||
error_setg(errp, "Image is read-only");
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
ret = bdrv_co_write_req_prepare(child, offset - new_bytes, new_bytes, &req,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Failed to prepare request for truncation");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!drv->bdrv_co_truncate) {
|
||||
@ -3156,13 +3177,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
|
||||
ret = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
if (bs->read_only) {
|
||||
error_setg(errp, "Image is read-only");
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
||||
|
||||
ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
|
||||
if (ret < 0) {
|
||||
@ -3174,9 +3188,10 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
|
||||
} else {
|
||||
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||
}
|
||||
bdrv_dirty_bitmap_truncate(bs, offset);
|
||||
bdrv_parent_cb_resize(bs);
|
||||
atomic_inc(&bs->write_gen);
|
||||
/* It's possible that truncation succeeded but refresh_total_sectors
|
||||
* failed, but the latter doesn't affect how we should finish the request.
|
||||
* Pass 0 as the last parameter so that dirty bitmaps etc. are handled. */
|
||||
bdrv_co_write_req_finish(child, offset - new_bytes, new_bytes, &req, 0);
|
||||
|
||||
out:
|
||||
tracked_request_end(&req);
|
||||
|
Loading…
Reference in New Issue
Block a user