diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c index 49c52284ecdd..c833e776320d 100644 --- a/io_uring/sqpoll.c +++ b/io_uring/sqpoll.c @@ -433,6 +433,12 @@ static int io_sq_thread(void *data) if (io_sq_tw_pending()) io_sq_tw(UINT_MAX); + /* + * Cancelation drops sqd->lock while it waits, and a ring could attach + * to a thread that is on its way out. A fatal signal doesn't set the + * bit, so set it here for io_sq_offload_create() to see. + */ + set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state); io_uring_cancel_generic(true, sqd); rcu_assign_pointer(sqd->thread, NULL); put_task_struct(current); @@ -502,7 +508,10 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx, list_add(&ctx->sqd_list, &sqd->ctx_list); io_sqd_update_thread_idle(sqd); /* don't attach to a dying SQPOLL thread, would be racy */ - ret = (attached && !sqd->thread) ? -ENXIO : 0; + ret = 0; + if (attached && (!sqd->thread || + test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state))) + ret = -ENXIO; io_sq_thread_unpark(sqd); if (ret < 0)