diff --git a/io_uring/cancel.c b/io_uring/cancel.c index 6f7a6cf356c2..79b5c133319b 100644 --- a/io_uring/cancel.c +++ b/io_uring/cancel.c @@ -703,7 +703,16 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd) } if (loop) { + /* + * A request that runs in io-wq and doesn't end makes + * each round come here. Don't hold sqd->lock for that + * long either. + */ + if (sqd) + mutex_unlock(&sqd->lock); cond_resched(); + if (sqd) + mutex_lock(&sqd->lock); continue; } @@ -741,7 +750,18 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd) if (state & TASK_INTERRUPTIBLE) timeout = MAX_SCHEDULE_TIMEOUT; + /* + * A zero-copy notification can't be canceled, and a + * peer that doesn't read keeps it pending. Don't hold + * sqd->lock while waiting for it, or whoever wants the + * lock sleeps as long. No ring is used across this, + * the next round walks ->ctx_list anew. + */ + if (sqd) + mutex_unlock(&sqd->lock); schedule_timeout(timeout); + if (sqd) + mutex_lock(&sqd->lock); } end_wait: finish_wait(&tctx->wait, &wait);