io-wq: add support for uncancellable work
authorJens Axboe <axboe@kernel.dk>
Thu, 12 Dec 2019 02:29:43 +0000 (19:29 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 21 Jan 2020 00:01:53 +0000 (17:01 -0700)
Not all work can be cancelled, some of it we may need to guarantee
that it runs to completion. Allow the caller to set IO_WQ_WORK_NO_CANCEL
on work that must not be cancelled. Note that the caller work function
must also check for IO_WQ_WORK_NO_CANCEL on work that is marked
IO_WQ_WORK_CANCEL.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c

index 5147d2213b019f9b80841a0e14a1709ba719bf69..79eae29983caf5b63c22275756883dbbbd1397cb 100644 (file)
@@ -456,6 +456,10 @@ next:
                }
                if (!worker->creds)
                        worker->creds = override_creds(wq->creds);
+               /*
+                * OK to set IO_WQ_WORK_CANCEL even for uncancellable work,
+                * the worker function will do the right thing.
+                */
                if (test_bit(IO_WQ_BIT_CANCEL, &wq->state))
                        work->flags |= IO_WQ_WORK_CANCEL;
                if (worker->mm)
@@ -828,6 +832,7 @@ static bool io_work_cancel(struct io_worker *worker, void *cancel_data)
         */
        spin_lock_irqsave(&worker->lock, flags);
        if (worker->cur_work &&
+           !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL) &&
            data->cancel(worker->cur_work, data->caller_data)) {
                send_sig(SIGINT, worker->task, 1);
                ret = true;
@@ -902,7 +907,8 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
                return false;
 
        spin_lock_irqsave(&worker->lock, flags);
-       if (worker->cur_work == work) {
+       if (worker->cur_work == work &&
+           !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL)) {
                send_sig(SIGINT, worker->task, 1);
                ret = true;
        }
index 3f5e356de98050f67503336cfac1db64f455230d..04d60ad38dfc9db3d14f563dd58382ff28e614cb 100644 (file)
@@ -12,6 +12,7 @@ enum {
        IO_WQ_WORK_UNBOUND      = 32,
        IO_WQ_WORK_INTERNAL     = 64,
        IO_WQ_WORK_CB           = 128,
+       IO_WQ_WORK_NO_CANCEL    = 256,
 
        IO_WQ_HASH_SHIFT        = 24,   /* upper 8 bits are used for hash key */
 };
index 34cbce622fcd25418c4b23ad1e00ad754afb1bed..fe227650efd66c14343bd28b7f235b08eeb399f2 100644 (file)
@@ -3460,8 +3460,11 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
        struct io_kiocb *nxt = NULL;
        int ret = 0;
 
-       if (work->flags & IO_WQ_WORK_CANCEL)
+       /* if NO_CANCEL is set, we must still run the work */
+       if ((work->flags & (IO_WQ_WORK_CANCEL|IO_WQ_WORK_NO_CANCEL)) ==
+                               IO_WQ_WORK_CANCEL) {
                ret = -ECANCELED;
+       }
 
        if (!ret) {
                req->has_user = (work->flags & IO_WQ_WORK_HAS_MM) != 0;