From 73895f3838cd7fdaf185cf1dbc47be58844a966f Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Wed, 6 Oct 2021 17:19:33 +0200 Subject: jobs: Give Job.force_cancel more meaning We largely have two cancel modes for jobs: First, there is actual cancelling. The job is terminated as soon as possible, without trying to reach a consistent result. Second, we have mirror in the READY state. Technically, the job is not really cancelled, but it just is a different completion mode. The job can still run for an indefinite amount of time while it tries to reach a consistent result. We want to be able to clearly distinguish which cancel mode a job is in (when it has been cancelled). We can use Job.force_cancel for this, but right now it only reflects cancel requests from the user with force=true, but clearly, jobs that do not even distinguish between force=false and force=true are effectively always force-cancelled. So this patch has Job.force_cancel signify whether the job will terminate as soon as possible (force_cancel=true) or whether it will effectively remain running despite being "cancelled" (force_cancel=false). To this end, we let jobs that provide JobDriver.cancel() tell the generic job code whether they will terminate as soon as possible or not, and for jobs that do not provide that method we assume they will. Signed-off-by: Hanna Reitz Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20211006151940.214590-7-hreitz@redhat.com> Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/backup.c | 3 ++- block/mirror.c | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'block') diff --git a/block/backup.c b/block/backup.c index 8b072db5d9..21d5983779 100644 --- a/block/backup.c +++ b/block/backup.c @@ -327,11 +327,12 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed) } } -static void backup_cancel(Job *job, bool force) +static bool backup_cancel(Job *job, bool force) { BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); bdrv_cancel_in_flight(s->target_bs); + return true; } static const BlockJobDriver backup_job_driver = { diff --git a/block/mirror.c b/block/mirror.c index 035106bbb4..010b9e1672 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1094,9 +1094,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) trace_mirror_before_sleep(s, cnt, job_is_ready(&s->common.job), delay_ns); job_sleep_ns(&s->common.job, delay_ns); - if (job_is_cancelled(&s->common.job) && - (!job_is_ready(&s->common.job) || s->common.job.force_cancel)) - { + if (job_is_cancelled(&s->common.job) && s->common.job.force_cancel) { break; } s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); @@ -1109,7 +1107,7 @@ immediate_exit: * the target is a copy of the source. */ assert(ret < 0 || - ((s->common.job.force_cancel || !job_is_ready(&s->common.job)) && + (s->common.job.force_cancel && job_is_cancelled(&s->common.job))); assert(need_drain); mirror_wait_for_all_io(s); @@ -1195,14 +1193,27 @@ static bool mirror_drained_poll(BlockJob *job) return !!s->in_flight; } -static void mirror_cancel(Job *job, bool force) +static bool mirror_cancel(Job *job, bool force) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); BlockDriverState *target = blk_bs(s->target); - if (force || !job_is_ready(job)) { + /* + * Before the job is READY, we treat any cancellation like a + * force-cancellation. + */ + force = force || !job_is_ready(job); + + if (force) { bdrv_cancel_in_flight(target); } + return force; +} + +static bool commit_active_cancel(Job *job, bool force) +{ + /* Same as above in mirror_cancel() */ + return force || !job_is_ready(job); } static const BlockJobDriver mirror_job_driver = { @@ -1232,6 +1243,7 @@ static const BlockJobDriver commit_active_job_driver = { .abort = mirror_abort, .pause = mirror_pause, .complete = mirror_complete, + .cancel = commit_active_cancel, }, .drained_poll = mirror_drained_poll, }; -- cgit v1.2.3