Skip to content

Commit 713b982

Browse files
isilenceaxboe
authored andcommitted
io-wq: fix cancellation on create-worker failure
WARNING: CPU: 0 PID: 10392 at fs/io_uring.c:1151 req_ref_put_and_test fs/io_uring.c:1151 [inline] WARNING: CPU: 0 PID: 10392 at fs/io_uring.c:1151 req_ref_put_and_test fs/io_uring.c:1146 [inline] WARNING: CPU: 0 PID: 10392 at fs/io_uring.c:1151 io_req_complete_post+0xf5b/0x1190 fs/io_uring.c:1794 Modules linked in: Call Trace: tctx_task_work+0x1e5/0x570 fs/io_uring.c:2158 task_work_run+0xe0/0x1a0 kernel/task_work.c:164 tracehook_notify_signal include/linux/tracehook.h:212 [inline] handle_signal_work kernel/entry/common.c:146 [inline] exit_to_user_mode_loop kernel/entry/common.c:172 [inline] exit_to_user_mode_prepare+0x232/0x2a0 kernel/entry/common.c:209 __syscall_exit_to_user_mode_work kernel/entry/common.c:291 [inline] syscall_exit_to_user_mode+0x19/0x60 kernel/entry/common.c:302 do_syscall_64+0x42/0xb0 arch/x86/entry/common.c:86 entry_SYSCALL_64_after_hwframe+0x44/0xae When io_wqe_enqueue() -> io_wqe_create_worker() fails, we can't just call io_run_cancel() to clean up the request, it's already enqueued via io_wqe_insert_work() and will be executed either by some other worker during cancellation (e.g. in io_wq_put_and_exit()). Reported-by: Hao Sun <[email protected]> Fixes: 3146cba ("io-wq: make worker creation resilient against signals") Signed-off-by: Pavel Begunkov <[email protected]> Link: https://lore.kernel.org/r/93b9de0fcf657affab0acfd675d4abcd273ee863.1631092071.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <[email protected]>
1 parent 626bf91 commit 713b982

File tree

1 file changed

+20
-9
lines changed

1 file changed

+20
-9
lines changed

fs/io-wq.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,11 @@ static void io_wqe_insert_work(struct io_wqe *wqe, struct io_wq_work *work)
832832
wq_list_add_after(&work->list, &tail->list, &acct->work_list);
833833
}
834834

835+
static bool io_wq_work_match_item(struct io_wq_work *work, void *data)
836+
{
837+
return work == data;
838+
}
839+
835840
static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
836841
{
837842
struct io_wqe_acct *acct = io_work_get_acct(wqe, work);
@@ -844,7 +849,6 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
844849
*/
845850
if (test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state) ||
846851
(work->flags & IO_WQ_WORK_CANCEL)) {
847-
run_cancel:
848852
io_run_cancel(work, wqe);
849853
return;
850854
}
@@ -864,15 +868,22 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
864868
bool did_create;
865869

866870
did_create = io_wqe_create_worker(wqe, acct);
867-
if (unlikely(!did_create)) {
868-
raw_spin_lock(&wqe->lock);
869-
/* fatal condition, failed to create the first worker */
870-
if (!acct->nr_workers) {
871-
raw_spin_unlock(&wqe->lock);
872-
goto run_cancel;
873-
}
874-
raw_spin_unlock(&wqe->lock);
871+
if (likely(did_create))
872+
return;
873+
874+
raw_spin_lock(&wqe->lock);
875+
/* fatal condition, failed to create the first worker */
876+
if (!acct->nr_workers) {
877+
struct io_cb_cancel_data match = {
878+
.fn = io_wq_work_match_item,
879+
.data = work,
880+
.cancel_all = false,
881+
};
882+
883+
if (io_acct_cancel_pending_work(wqe, acct, &match))
884+
raw_spin_lock(&wqe->lock);
875885
}
886+
raw_spin_unlock(&wqe->lock);
876887
}
877888
}
878889

0 commit comments

Comments
 (0)