提交 cd47d792 编写于 作者: F Fam Zheng 提交者: Kevin Wolf

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: NFam Zheng <famz@redhat.com>
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
上级 5416a11e
...@@ -1604,14 +1604,24 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes, ...@@ -1604,14 +1604,24 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
is_request_serialising_and_aligned(req)); is_request_serialising_and_aligned(req));
assert(req->overlap_offset <= offset); assert(req->overlap_offset <= offset);
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes); assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
if (flags & BDRV_REQ_WRITE_UNCHANGED) { switch (req->type) {
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE)); case BDRV_TRACKED_WRITE:
} else { case BDRV_TRACKED_DISCARD:
assert(child->perm & BLK_PERM_WRITE); 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();
} }
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
return notifier_with_return_list_notify(&bs->before_write_notifiers, req);
} }
static inline void coroutine_fn static inline void coroutine_fn
...@@ -1631,8 +1641,9 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes, ...@@ -1631,8 +1641,9 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
* beyond EOF cannot expand the image anyway. * beyond EOF cannot expand the image anyway.
*/ */
if (ret == 0 && if (ret == 0 &&
end_sector > bs->total_sectors && (req->type == BDRV_TRACKED_TRUNCATE ||
req->type != BDRV_TRACKED_DISCARD) { end_sector > bs->total_sectors) &&
req->type != BDRV_TRACKED_DISCARD) {
bs->total_sectors = end_sector; bs->total_sectors = end_sector;
bdrv_parent_cb_resize(bs); bdrv_parent_cb_resize(bs);
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS); 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, ...@@ -3111,7 +3122,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
int64_t old_size, new_bytes; int64_t old_size, new_bytes;
int ret; int ret;
assert(child->perm & BLK_PERM_RESIZE);
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
if (!drv) { if (!drv) {
...@@ -3144,7 +3154,18 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ...@@ -3144,7 +3154,18 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
* concurrently or they might be overwritten by preallocation. */ * concurrently or they might be overwritten by preallocation. */
if (new_bytes) { if (new_bytes) {
mark_request_serialising(&req, 1); 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) { if (!drv->bdrv_co_truncate) {
...@@ -3156,13 +3177,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ...@@ -3156,13 +3177,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
ret = -ENOTSUP; ret = -ENOTSUP;
goto out; 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); ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
if (ret < 0) { if (ret < 0) {
...@@ -3174,9 +3188,10 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ...@@ -3174,9 +3188,10 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
} else { } else {
offset = bs->total_sectors * BDRV_SECTOR_SIZE; offset = bs->total_sectors * BDRV_SECTOR_SIZE;
} }
bdrv_dirty_bitmap_truncate(bs, offset); /* It's possible that truncation succeeded but refresh_total_sectors
bdrv_parent_cb_resize(bs); * failed, but the latter doesn't affect how we should finish the request.
atomic_inc(&bs->write_gen); * 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: out:
tracked_request_end(&req); tracked_request_end(&req);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册