block: Move bdrv_truncate() implementation to io.c

This moves the bdrv_truncate() implementation from block.c to block/io.c
so it can have access to the tracked requests infrastructure.

This involves making refresh_total_sectors() public (in block_int.h).

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Kevin Wolf 2018-06-26 13:55:20 +02:00
parent 47e86b868d
commit 3d9f2d2af6
3 changed files with 112 additions and 110 deletions

111
block.c
View File

@ -725,7 +725,7 @@ static int find_image_format(BlockBackend *file, const char *filename,
* Set the current 'total_sectors' value * Set the current 'total_sectors' value
* Return 0 on success, -errno on error. * Return 0 on success, -errno on error.
*/ */
static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
@ -2226,16 +2226,6 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load)
} }
} }
static void bdrv_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->role->resize) {
c->role->resize(c);
}
}
}
/* /*
* Sets the backing file link of a BDS. A new reference is created; callers * Sets the backing file link of a BDS. A new reference is created; callers
* which don't need their own reference any more must call bdrv_unref(). * which don't need their own reference any more must call bdrv_unref().
@ -3785,105 +3775,6 @@ exit:
return ret; return ret;
} }
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
int ret;
assert(child->perm & BLK_PERM_RESIZE);
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
if (!drv) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
if (offset < 0) {
error_setg(errp, "Image size cannot be negative");
return -EINVAL;
}
bdrv_inc_in_flight(bs);
if (!drv->bdrv_co_truncate) {
if (bs->file && drv->is_filter) {
ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
goto out;
}
error_setg(errp, "Image format driver does not support resize");
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) {
goto out;
}
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count");
} else {
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
}
bdrv_dirty_bitmap_truncate(bs, offset);
bdrv_parent_cb_resize(bs);
atomic_inc(&bs->write_gen);
out:
bdrv_dec_in_flight(bs);
return ret;
}
typedef struct TruncateCo {
BdrvChild *child;
int64_t offset;
PreallocMode prealloc;
Error **errp;
int ret;
} TruncateCo;
static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
{
TruncateCo *tco = opaque;
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
tco->errp);
}
int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
Error **errp)
{
Coroutine *co;
TruncateCo tco = {
.child = child,
.offset = offset,
.prealloc = prealloc,
.errp = errp,
.ret = NOT_DONE,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_truncate_co_entry(&tco);
} else {
co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
qemu_coroutine_enter(co);
BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
}
return tco.ret;
}
/** /**
* Length of a allocated file in bytes. Sparse files are counted by actual * Length of a allocated file in bytes. Sparse files are counted by actual
* allocated space. Return < 0 if error or unknown. * allocated space. Return < 0 if error or unknown.

View File

@ -3020,3 +3020,112 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
bdrv_dec_in_flight(dst_bs); bdrv_dec_in_flight(dst_bs);
return ret; return ret;
} }
static void bdrv_parent_cb_resize(BlockDriverState *bs)
{
BdrvChild *c;
QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->role->resize) {
c->role->resize(c);
}
}
}
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
int ret;
assert(child->perm & BLK_PERM_RESIZE);
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
if (!drv) {
error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
if (offset < 0) {
error_setg(errp, "Image size cannot be negative");
return -EINVAL;
}
bdrv_inc_in_flight(bs);
if (!drv->bdrv_co_truncate) {
if (bs->file && drv->is_filter) {
ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
goto out;
}
error_setg(errp, "Image format driver does not support resize");
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) {
goto out;
}
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count");
} else {
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
}
bdrv_dirty_bitmap_truncate(bs, offset);
bdrv_parent_cb_resize(bs);
atomic_inc(&bs->write_gen);
out:
bdrv_dec_in_flight(bs);
return ret;
}
typedef struct TruncateCo {
BdrvChild *child;
int64_t offset;
PreallocMode prealloc;
Error **errp;
int ret;
} TruncateCo;
static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
{
TruncateCo *tco = opaque;
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
tco->errp);
}
int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
Error **errp)
{
Coroutine *co;
TruncateCo tco = {
.child = child,
.offset = offset,
.prealloc = prealloc,
.errp = errp,
.ret = NOT_DONE,
};
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_truncate_co_entry(&tco);
} else {
co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco);
qemu_coroutine_enter(co);
BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
}
return tco.ret;
}

View File

@ -1157,4 +1157,6 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes, BdrvRequestFlags flags); uint64_t bytes, BdrvRequestFlags flags);
int refresh_total_sectors(BlockDriverState *bs, int64_t hint);
#endif /* BLOCK_INT_H */ #endif /* BLOCK_INT_H */