io-wq: perform both unstarted and started work cancelations in one go
authorJens Axboe <axboe@kernel.dk>
Wed, 19 Jan 2022 02:22:32 +0000 (19:22 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 19 Jan 2022 02:27:59 +0000 (19:27 -0700)
Rather than split these into two separate lookups and matches, combine
them into one loop. This will become important when we can guarantee
that we don't have a window where a pending work item isn't discoverable
in either state.

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

index a92fbdc..db15018 100644 (file)
@@ -1072,27 +1072,25 @@ enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
         * First check pending list, if we're lucky we can just remove it
         * from there. CANCEL_OK means that the work is returned as-new,
         * no completion will be posted for it.
-        */
-       for_each_node(node) {
-               struct io_wqe *wqe = wq->wqes[node];
-
-               raw_spin_lock(&wqe->lock);
-               io_wqe_cancel_pending_work(wqe, &match);
-               raw_spin_unlock(&wqe->lock);
-               if (match.nr_pending && !match.cancel_all)
-                       return IO_WQ_CANCEL_OK;
-       }
-
-       /*
-        * Now check if a free (going busy) or busy worker has the work
+        *
+        * Then check if a free (going busy) or busy worker has the work
         * currently running. If we find it there, we'll return CANCEL_RUNNING
         * as an indication that we attempt to signal cancellation. The
         * completion will run normally in this case.
+        *
+        * Do both of these while holding the wqe->lock, to ensure that
+        * we'll find a work item regardless of state.
         */
        for_each_node(node) {
                struct io_wqe *wqe = wq->wqes[node];
 
                raw_spin_lock(&wqe->lock);
+               io_wqe_cancel_pending_work(wqe, &match);
+               if (match.nr_pending && !match.cancel_all) {
+                       raw_spin_unlock(&wqe->lock);
+                       return IO_WQ_CANCEL_OK;
+               }
+
                io_wqe_cancel_running_work(wqe, &match);
                raw_spin_unlock(&wqe->lock);
                if (match.nr_running && !match.cancel_all)