Allow change job speed through job-change command. Old block-job-set-speed would be deprecated soon. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@xxxxxxxxxxxxxx> --- block/backup.c | 8 ++++++ block/commit.c | 10 ++++++- block/mirror.c | 60 ++++++++++++++++++++++++---------------- block/stream.c | 8 ++++++ blockjob.c | 13 +++++++++ include/block/blockjob.h | 7 +++++ include/qemu/job.h | 2 +- qapi/block-core.json | 23 +++++++++++++-- 8 files changed, 103 insertions(+), 28 deletions(-) diff --git a/block/backup.c b/block/backup.c index ec29d6b810..bf086dc5f9 100644 --- a/block/backup.c +++ b/block/backup.c @@ -336,6 +336,13 @@ static bool backup_cancel(Job *job, bool force) return true; } +static bool backup_change(Job *job, JobChangeOptions *opts, Error **errp) +{ + BlockJob *bjob = container_of(job, BlockJob, job); + + return block_job_change(bjob, &opts->u.backup, errp); +} + static const BlockJobDriver backup_job_driver = { .job_driver = { .instance_size = sizeof(BackupBlockJob), @@ -348,6 +355,7 @@ static const BlockJobDriver backup_job_driver = { .clean = backup_clean, .pause = backup_pause, .cancel = backup_cancel, + .change = backup_change, }, .set_speed = backup_set_speed, }; diff --git a/block/commit.c b/block/commit.c index 7c3fdcb0ca..ccb6097679 100644 --- a/block/commit.c +++ b/block/commit.c @@ -204,6 +204,13 @@ static int coroutine_fn commit_run(Job *job, Error **errp) return 0; } +static bool commit_change(Job *job, JobChangeOptions *opts, Error **errp) +{ + BlockJob *bjob = container_of(job, BlockJob, job); + + return block_job_change(bjob, &opts->u.commit, errp); +} + static const BlockJobDriver commit_job_driver = { .job_driver = { .instance_size = sizeof(CommitBlockJob), @@ -213,7 +220,8 @@ static const BlockJobDriver commit_job_driver = { .run = commit_run, .prepare = commit_prepare, .abort = commit_abort, - .clean = commit_clean + .clean = commit_clean, + .change = commit_change, }, }; diff --git a/block/mirror.c b/block/mirror.c index e670d0dd4f..f474b87079 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1251,41 +1251,45 @@ static bool commit_active_cancel(Job *job, bool force) return force || !job_is_ready(job); } -static void mirror_change(Job *job, JobChangeOptions *opts, Error **errp) +static bool mirror_change(Job *job, JobChangeOptions *opts, Error **errp) { + BlockJob *bjob = container_of(job, BlockJob, job); MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); JobChangeOptionsMirror *change_opts = &opts->u.mirror; - MirrorCopyMode current; - - /* - * The implementation relies on the fact that copy_mode is only written - * under the BQL. Otherwise, further synchronization would be required. - */ + MirrorCopyMode old_mode; GLOBAL_STATE_CODE(); - if (!change_opts->has_copy_mode) { - /* Nothing to do */ - return; - } + if (change_opts->has_copy_mode) { + old_mode = qatomic_read(&s->copy_mode); - if (qatomic_read(&s->copy_mode) == change_opts->copy_mode) { - return; - } + if (old_mode != change_opts->copy_mode) { + if (change_opts->copy_mode != MIRROR_COPY_MODE_WRITE_BLOCKING) { + error_setg(errp, "Change to copy mode '%s' is not implemented", + MirrorCopyMode_str(change_opts->copy_mode)); + return false; + } - if (change_opts->copy_mode != MIRROR_COPY_MODE_WRITE_BLOCKING) { - error_setg(errp, "Change to copy mode '%s' is not implemented", - MirrorCopyMode_str(change_opts->copy_mode)); - return; + if (old_mode != MIRROR_COPY_MODE_BACKGROUND) { + error_setg(errp, "Expected current copy mode '%s', got '%s'", + MirrorCopyMode_str(MIRROR_COPY_MODE_BACKGROUND), + MirrorCopyMode_str(old_mode)); + return false; + } + } } - current = qatomic_cmpxchg(&s->copy_mode, MIRROR_COPY_MODE_BACKGROUND, - change_opts->copy_mode); - if (current != MIRROR_COPY_MODE_BACKGROUND) { - error_setg(errp, "Expected current copy mode '%s', got '%s'", - MirrorCopyMode_str(MIRROR_COPY_MODE_BACKGROUND), - MirrorCopyMode_str(current)); + if (!block_job_change(bjob, qapi_JobChangeOptionsMirror_base(change_opts), + errp)) + { + return false; } + + old_mode = qatomic_cmpxchg(&s->copy_mode, MIRROR_COPY_MODE_BACKGROUND, + change_opts->copy_mode); + assert(old_mode == MIRROR_COPY_MODE_BACKGROUND); + + return true; } static void mirror_query(BlockJob *job, BlockJobInfo *info) @@ -1315,6 +1319,13 @@ static const BlockJobDriver mirror_job_driver = { .query = mirror_query, }; +static bool commit_active_change(Job *job, JobChangeOptions *opts, Error **errp) +{ + BlockJob *bjob = container_of(job, BlockJob, job); + + return block_job_change(bjob, &opts->u.commit, errp); +} + static const BlockJobDriver commit_active_job_driver = { .job_driver = { .instance_size = sizeof(MirrorBlockJob), @@ -1327,6 +1338,7 @@ static const BlockJobDriver commit_active_job_driver = { .pause = mirror_pause, .complete = mirror_complete, .cancel = commit_active_cancel, + .change = commit_active_change, }, .drained_poll = mirror_drained_poll, }; diff --git a/block/stream.c b/block/stream.c index 7031eef12b..34f4588537 100644 --- a/block/stream.c +++ b/block/stream.c @@ -239,6 +239,13 @@ static int coroutine_fn stream_run(Job *job, Error **errp) return error; } +static bool stream_change(Job *job, JobChangeOptions *opts, Error **errp) +{ + BlockJob *bjob = container_of(job, BlockJob, job); + + return block_job_change(bjob, &opts->u.stream, errp); +} + static const BlockJobDriver stream_job_driver = { .job_driver = { .instance_size = sizeof(StreamBlockJob), @@ -248,6 +255,7 @@ static const BlockJobDriver stream_job_driver = { .prepare = stream_prepare, .clean = stream_clean, .user_resume = block_job_user_resume, + .change = stream_change, }, }; diff --git a/blockjob.c b/blockjob.c index 2769722b37..d3cd4f4fbf 100644 --- a/blockjob.c +++ b/blockjob.c @@ -312,6 +312,19 @@ static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) return block_job_set_speed_locked(job, speed, errp); } +bool block_job_change(BlockJob *job, JobChangeOptionsBlockJob *opts, + Error **errp) +{ + GLOBAL_STATE_CODE(); + + if (!opts->has_speed) { + /* Nothing to do */ + return true; + } + + return block_job_set_speed(job, opts->speed, errp); +} + void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n) { IO_CODE(); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index 72e849a140..fe433c8d35 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -224,4 +224,11 @@ bool block_job_is_internal(BlockJob *job); */ const BlockJobDriver *block_job_driver(BlockJob *job); +/** + * Common part of .change handler for block-jobs. + * Applies changes described in opts to the job. + */ +bool block_job_change(BlockJob *job, JobChangeOptionsBlockJob *opts, + Error **errp); + #endif diff --git a/include/qemu/job.h b/include/qemu/job.h index d44cdb0cc8..1c9da74a0c 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -313,7 +313,7 @@ struct JobDriver { * * Note that this can already be called before the job coroutine is running. */ - void (*change)(Job *job, JobChangeOptions *opts, Error **errp); + bool (*change)(Job *job, JobChangeOptions *opts, Error **errp); /** * Called when the job is freed. diff --git a/qapi/block-core.json b/qapi/block-core.json index f5cefa441b..93f96e747e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3062,6 +3062,17 @@ { 'command': 'block-job-finalize', 'data': { 'id': 'str' }, 'allow-preconfig': true } +## +# @JobChangeOptionsBlockJob: +# +# @speed: Change job speed (in bytes per second). Supported for +# for backup, mirror, commit and stream jobs. +# +# Since: 9.1 +## +{ 'struct': 'JobChangeOptionsBlockJob', + 'data': { '*speed' : 'uint64' } } + ## # @JobChangeOptionsMirror: # @@ -3071,12 +3082,17 @@ # Since: 8.2 ## { 'struct': 'JobChangeOptionsMirror', + 'base': 'JobChangeOptionsBlockJob', 'data': { '*copy-mode' : 'MirrorCopyMode' } } + ## # @JobChangeOptions: # -# Block job options that can be changed after job creation. +# Job options that can be changed after job creation. When option is +# not specified the corresponding job parameter remains unchanged. +# The change is transactional: on success all changes are applied +# successfully, on failure nothing is changed. # # @id: The job identifier # @@ -3093,7 +3109,10 @@ 'base': { 'id': 'str', '*type': { 'type': 'JobType', 'features': ['deprecated'] } }, 'discriminator': 'JobType', - 'data': { 'mirror': 'JobChangeOptionsMirror' } } + 'data': { 'mirror': 'JobChangeOptionsMirror', + 'backup': 'JobChangeOptionsBlockJob', + 'stream': 'JobChangeOptionsBlockJob', + 'commit': 'JobChangeOptionsBlockJob' } } ## # @block-job-change: -- 2.34.1 _______________________________________________ Devel mailing list -- devel@xxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx