[PATCH v5 07/13] job: Do not soft-cancel after a job is done

Hanna Reitz posted 13 patches 4 years, 4 months ago
Maintainers: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>, Xie Changlong <xiechanglong.d@gmail.com>, Hanna Reitz <hreitz@redhat.com>, Markus Armbruster <armbru@redhat.com>, Wen Congyang <wencongyang2@huawei.com>, John Snow <jsnow@redhat.com>, Kevin Wolf <kwolf@redhat.com>
[PATCH v5 07/13] job: Do not soft-cancel after a job is done
Posted by Hanna Reitz 4 years, 4 months ago
The only job that supports a soft cancel mode is the mirror job, and in
such a case it resets its .cancelled field before it leaves its .run()
function, so it does not really count as cancelled.

However, it is possible to cancel the job after .run() returns and
before job_exit() (which is run in the main loop) is executed.  Then,
.cancelled would still be true and the job would count as cancelled.
This does not seem to be in the interest of the mirror job, so adjust
job_cancel_async() to not set .cancelled in such a case, and
job_cancel() to not invoke job_completed_txn_abort().

Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
 job.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/job.c b/job.c
index 81c016eb10..44e741ebd4 100644
--- a/job.c
+++ b/job.c
@@ -734,9 +734,19 @@ static void job_cancel_async(Job *job, bool force)
         assert(job->pause_count > 0);
         job->pause_count--;
     }
-    job->cancelled = true;
-    /* To prevent 'force == false' overriding a previous 'force == true' */
-    job->force_cancel |= force;
+
+    /*
+     * Ignore soft cancel requests after the job is already done
+     * (We will still invoke job->driver->cancel() above, but if the
+     * job driver supports soft cancelling and the job is done, that
+     * should be a no-op, too.  We still call it so it can override
+     * @force.)
+     */
+    if (force || !job->deferred_to_main_loop) {
+        job->cancelled = true;
+        /* To prevent 'force == false' overriding a previous 'force == true' */
+        job->force_cancel |= force;
+    }
 }
 
 static void job_completed_txn_abort(Job *job)
@@ -963,7 +973,14 @@ void job_cancel(Job *job, bool force)
     if (!job_started(job)) {
         job_completed(job);
     } else if (job->deferred_to_main_loop) {
-        job_completed_txn_abort(job);
+        /*
+         * job_cancel_async() ignores soft-cancel requests for jobs
+         * that are already done (i.e. deferred to the main loop).  We
+         * have to check again whether the job is really cancelled.
+         */
+        if (job_is_cancelled(job)) {
+            job_completed_txn_abort(job);
+        }
     } else {
         job_enter(job);
     }
-- 
2.31.1


Re: [PATCH v5 07/13] job: Do not soft-cancel after a job is done
Posted by Eric Blake 4 years, 4 months ago
On Wed, Oct 06, 2021 at 05:19:34PM +0200, Hanna Reitz wrote:
> The only job that supports a soft cancel mode is the mirror job, and in
> such a case it resets its .cancelled field before it leaves its .run()
> function, so it does not really count as cancelled.
> 
> However, it is possible to cancel the job after .run() returns and
> before job_exit() (which is run in the main loop) is executed.  Then,
> .cancelled would still be true and the job would count as cancelled.
> This does not seem to be in the interest of the mirror job, so adjust
> job_cancel_async() to not set .cancelled in such a case, and
> job_cancel() to not invoke job_completed_txn_abort().
> 
> Signed-off-by: Hanna Reitz <hreitz@redhat.com>
> ---
>  job.c | 25 +++++++++++++++++++++----
>  1 file changed, 21 insertions(+), 4 deletions(-)
>

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


Re: [PATCH v5 07/13] job: Do not soft-cancel after a job is done
Posted by Vladimir Sementsov-Ogievskiy 4 years, 4 months ago
10/6/21 18:19, Hanna Reitz wrote:
> The only job that supports a soft cancel mode is the mirror job, and in
> such a case it resets its .cancelled field before it leaves its .run()
> function, so it does not really count as cancelled.
> 
> However, it is possible to cancel the job after .run() returns and
> before job_exit() (which is run in the main loop) is executed.  Then,
> .cancelled would still be true and the job would count as cancelled.
> This does not seem to be in the interest of the mirror job, so adjust
> job_cancel_async() to not set .cancelled in such a case, and
> job_cancel() to not invoke job_completed_txn_abort().
> 
> Signed-off-by: Hanna Reitz<hreitz@redhat.com>


Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

-- 
Best regards,
Vladimir