Skip to content

Commit cd47d79

Browse files
Fam Zhengkevmw
Fam Zheng
authored andcommitted
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 <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 5416a11 commit cd47d79

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

block/io.c

+35-20
Original file line numberDiff line numberDiff line change
@@ -1604,14 +1604,24 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
16041604
is_request_serialising_and_aligned(req));
16051605
assert(req->overlap_offset <= offset);
16061606
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
1607+
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
16071608

1608-
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
1609-
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
1610-
} else {
1611-
assert(child->perm & BLK_PERM_WRITE);
1609+
switch (req->type) {
1610+
case BDRV_TRACKED_WRITE:
1611+
case BDRV_TRACKED_DISCARD:
1612+
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
1613+
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
1614+
} else {
1615+
assert(child->perm & BLK_PERM_WRITE);
1616+
}
1617+
return notifier_with_return_list_notify(&bs->before_write_notifiers,
1618+
req);
1619+
case BDRV_TRACKED_TRUNCATE:
1620+
assert(child->perm & BLK_PERM_RESIZE);
1621+
return 0;
1622+
default:
1623+
abort();
16121624
}
1613-
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
1614-
return notifier_with_return_list_notify(&bs->before_write_notifiers, req);
16151625
}
16161626

16171627
static inline void coroutine_fn
@@ -1631,8 +1641,9 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
16311641
* beyond EOF cannot expand the image anyway.
16321642
*/
16331643
if (ret == 0 &&
1634-
end_sector > bs->total_sectors &&
1635-
req->type != BDRV_TRACKED_DISCARD) {
1644+
(req->type == BDRV_TRACKED_TRUNCATE ||
1645+
end_sector > bs->total_sectors) &&
1646+
req->type != BDRV_TRACKED_DISCARD) {
16361647
bs->total_sectors = end_sector;
16371648
bdrv_parent_cb_resize(bs);
16381649
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,
31113122
int64_t old_size, new_bytes;
31123123
int ret;
31133124

3114-
assert(child->perm & BLK_PERM_RESIZE);
31153125

31163126
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
31173127
if (!drv) {
@@ -3144,7 +3154,18 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
31443154
* concurrently or they might be overwritten by preallocation. */
31453155
if (new_bytes) {
31463156
mark_request_serialising(&req, 1);
3147-
wait_serialising_requests(&req);
3157+
}
3158+
if (bs->read_only) {
3159+
error_setg(errp, "Image is read-only");
3160+
ret = -EACCES;
3161+
goto out;
3162+
}
3163+
ret = bdrv_co_write_req_prepare(child, offset - new_bytes, new_bytes, &req,
3164+
0);
3165+
if (ret < 0) {
3166+
error_setg_errno(errp, -ret,
3167+
"Failed to prepare request for truncation");
3168+
goto out;
31483169
}
31493170

31503171
if (!drv->bdrv_co_truncate) {
@@ -3156,13 +3177,6 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
31563177
ret = -ENOTSUP;
31573178
goto out;
31583179
}
3159-
if (bs->read_only) {
3160-
error_setg(errp, "Image is read-only");
3161-
ret = -EACCES;
3162-
goto out;
3163-
}
3164-
3165-
assert(!(bs->open_flags & BDRV_O_INACTIVE));
31663180

31673181
ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
31683182
if (ret < 0) {
@@ -3174,9 +3188,10 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
31743188
} else {
31753189
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
31763190
}
3177-
bdrv_dirty_bitmap_truncate(bs, offset);
3178-
bdrv_parent_cb_resize(bs);
3179-
atomic_inc(&bs->write_gen);
3191+
/* It's possible that truncation succeeded but refresh_total_sectors
3192+
* failed, but the latter doesn't affect how we should finish the request.
3193+
* Pass 0 as the last parameter so that dirty bitmaps etc. are handled. */
3194+
bdrv_co_write_req_finish(child, offset - new_bytes, new_bytes, &req, 0);
31803195

31813196
out:
31823197
tracked_request_end(&req);

0 commit comments

Comments
 (0)