io-wq: cancel task_work on exit only targeting the current 'wq'
authorJens Axboe <axboe@kernel.dk>
Fri, 2 Apr 2021 01:57:07 +0000 (19:57 -0600)
committerJens Axboe <axboe@kernel.dk>
Mon, 12 Apr 2021 01:30:25 +0000 (19:30 -0600)
With using task_work_cancel(), we're potentially canceling task_work
that isn't related to this specific io_wq. Use the newly added
task_work_cancel_match() to ensure that we only remove and cancel work
items that are specific to this io_wq.

Fixes: 685fe7feedb9 ("io-wq: eliminate the need for a manager thread")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io-wq.c

index 8ba4cca..5551272 100644 (file)
@@ -986,6 +986,16 @@ err_wq:
        return ERR_PTR(ret);
 }
 
+static bool io_task_work_match(struct callback_head *cb, void *data)
+{
+       struct create_worker_data *cwd;
+
+       if (cb->func != create_worker_cb)
+               return false;
+       cwd = container_of(cb, struct create_worker_data, work);
+       return cwd->wqe->wq == data;
+}
+
 static void io_wq_exit_workers(struct io_wq *wq)
 {
        struct callback_head *cb;
@@ -996,7 +1006,7 @@ static void io_wq_exit_workers(struct io_wq *wq)
        if (!wq->task)
                return;
 
-       while ((cb = task_work_cancel(wq->task, create_worker_cb)) != NULL) {
+       while ((cb = task_work_cancel_match(wq->task, io_task_work_match, wq)) != NULL) {
                struct create_worker_data *cwd;
 
                cwd = container_of(cb, struct create_worker_data, work);