Allow QMP users to manipulate the granularity used in the block-commit command.
Signed-off-by: Max Reitz <mre...@redhat.com> --- block/commit.c | 16 +++++++++++++--- block/mirror.c | 4 ++-- blockdev.c | 23 +++++++++++++++++------ include/block/block_int.h | 6 ++++-- qapi-schema.json | 6 +++++- 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/block/commit.c b/block/commit.c index acec4ac..cf0e500 100644 --- a/block/commit.c +++ b/block/commit.c @@ -37,6 +37,7 @@ typedef struct CommitBlockJob { BlockdevOnError on_error; int base_flags; int orig_overlay_flags; + int64_t granularity; } CommitBlockJob; static int coroutine_fn commit_populate(BlockDriverState *bs, @@ -93,7 +94,7 @@ static void coroutine_fn commit_run(void *opaque) } end = s->common.len >> BDRV_SECTOR_BITS; - buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); + buf = qemu_blockalign(top, s->granularity); for (sector_num = 0; sector_num < end; sector_num += n) { uint64_t delay_ns = 0; @@ -109,7 +110,7 @@ wait: } /* Copy if allocated above the base */ ret = bdrv_is_allocated_above(top, base, sector_num, - COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, + s->granularity / BDRV_SECTOR_SIZE, &n); copy = (ret == 1); trace_commit_one_iteration(s, sector_num, n, ret); @@ -180,7 +181,7 @@ static const BlockJobDriver commit_job_driver = { }; void commit_start(BlockDriverState *bs, BlockDriverState *base, - BlockDriverState *top, int64_t speed, + BlockDriverState *top, int64_t speed, int64_t granularity, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { @@ -214,6 +215,13 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, orig_base_flags = bdrv_get_flags(base); orig_overlay_flags = bdrv_get_flags(overlay_bs); + if (!granularity) { + granularity = COMMIT_BUFFER_SIZE; + } + + assert(granularity >= BDRV_SECTOR_SIZE); + assert(is_power_of_2(granularity)); + /* convert base & overlay_bs to r/w, if necessary */ if (!(orig_base_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, base, @@ -244,6 +252,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, s->base_flags = orig_base_flags; s->orig_overlay_flags = orig_overlay_flags; + s->granularity = granularity; + s->on_error = on_error; s->common.co = qemu_coroutine_create(commit_run); diff --git a/block/mirror.c b/block/mirror.c index 0ef41f9..5b1ebb2 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -632,7 +632,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, } void commit_active_start(BlockDriverState *bs, BlockDriverState *base, - int64_t speed, + int64_t speed, int64_t granularity, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) @@ -674,7 +674,7 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, } bdrv_ref(base); - mirror_start_job(bs, base, speed, 0, 0, + mirror_start_job(bs, base, speed, granularity, 0, on_error, on_error, cb, opaque, &local_err, &commit_active_job_driver, false, base); if (error_is_set(&local_err)) { diff --git a/blockdev.c b/blockdev.c index c3422a1..b988cc5 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1865,8 +1865,8 @@ void qmp_block_stream(const char *device, bool has_base, void qmp_block_commit(const char *device, bool has_base, const char *base, const char *top, - bool has_speed, int64_t speed, - Error **errp) + bool has_speed, int64_t speed, bool has_granularity, + int64_t granularity, Error **errp) { BlockDriverState *bs; BlockDriverState *base_bs, *top_bs; @@ -1876,6 +1876,17 @@ void qmp_block_commit(const char *device, */ BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT; + if (!has_granularity) { + granularity = 0; + } + + if (granularity && + (granularity < BDRV_SECTOR_SIZE || !is_power_of_2(granularity))) + { + error_set(errp, QERR_INVALID_PARAMETER, "granularity"); + return; + } + /* drain all i/o before commits */ bdrv_drain_all(); @@ -1911,11 +1922,11 @@ void qmp_block_commit(const char *device, } if (top_bs == bs) { - commit_active_start(bs, base_bs, speed, on_error, block_job_cb, - bs, &local_err); + commit_active_start(bs, base_bs, speed, granularity, on_error, + block_job_cb, bs, &local_err); } else { - commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs, - &local_err); + commit_start(bs, base_bs, top_bs, speed, granularity, on_error, + block_job_cb, bs, &local_err); } if (local_err != NULL) { error_propagate(errp, local_err); diff --git a/include/block/block_int.h b/include/block/block_int.h index cd5bc73..2e4b470 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -426,6 +426,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, * @top: Top block device to be committed. * @base: Block device that will be written into, and become the new top. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @granularity: The granularity, in bytes, or 0 for a default value. * @on_error: The action to take upon error. * @cb: Completion function for the job. * @opaque: Opaque pointer value passed to @cb. @@ -433,7 +434,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, * */ void commit_start(BlockDriverState *bs, BlockDriverState *base, - BlockDriverState *top, int64_t speed, + BlockDriverState *top, int64_t speed, int64_t granularity, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); /** @@ -441,6 +442,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @bs: Active block device to be committed. * @base: Block device that will be written into, and become the new top. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @granularity: The granularity, in bytes, or 0 for cluster size. * @on_error: The action to take upon error. * @cb: Completion function for the job. * @opaque: Opaque pointer value passed to @cb. @@ -448,7 +450,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * */ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, - int64_t speed, + int64_t speed, int64_t granularity, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/qapi-schema.json b/qapi-schema.json index 391356f..151fad3 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2112,6 +2112,10 @@ # # @speed: #optional the maximum speed, in bytes per second # +# @granularity: #optional the granularity to be used for the operation, in +# bytes; has to be a power of two and at least 512, or 0 for the +# default value (since 2.1) +# # Returns: Nothing on success # If commit or stream is already active on this device, DeviceInUse # If @device does not exist, DeviceNotFound @@ -2124,7 +2128,7 @@ ## { 'command': 'block-commit', 'data': { 'device': 'str', '*base': 'str', 'top': 'str', - '*speed': 'int' } } + '*speed': 'int', '*granularity': 'int' } } ## # @drive-backup -- 1.9.1