Joseph reports following deadlock:
CPU0: ... io_kill_linked_timeout // &ctx->completion_lock io_commit_cqring __io_queue_deferred __io_queue_async_work io_wq_enqueue io_wqe_enqueue // &wqe->lock
CPU1: ... __io_uring_files_cancel io_wq_cancel_cb io_wqe_cancel_pending_work // &wqe->lock io_cancel_task_cb // &ctx->completion_lock
Only __io_queue_deferred() calls queue_async_work() while holding ctx->completion_lock, enqueue drained requests via io_req_task_queue() instead.
Cc: stable@vger.kernel.org # 5.9+ Reported-by: Joseph Qi joseph.qi@linux.alibaba.com Signed-off-by: Pavel Begunkov asml.silence@gmail.com --- fs/io_uring.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index bb0270eeb8cb..c218deaf73a9 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1026,6 +1026,7 @@ static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec, const struct iovec *fast_iov, struct iov_iter *iter, bool force); static void io_req_drop_files(struct io_kiocb *req); +static void io_req_task_queue(struct io_kiocb *req);
static struct kmem_cache *req_cachep;
@@ -1634,18 +1635,11 @@ static void __io_queue_deferred(struct io_ring_ctx *ctx) do { struct io_defer_entry *de = list_first_entry(&ctx->defer_list, struct io_defer_entry, list); - struct io_kiocb *link;
if (req_need_defer(de->req, de->seq)) break; list_del_init(&de->list); - /* punt-init is done before queueing for defer */ - link = __io_queue_async_work(de->req); - if (link) { - __io_queue_linked_timeout(link); - /* drop submission reference */ - io_put_req_deferred(link, 1); - } + io_req_task_queue(de->req); kfree(de); } while (!list_empty(&ctx->defer_list)); }
On 26/01/2021 23:35, Pavel Begunkov wrote:
Joseph reports following deadlock:
CPU0: ... io_kill_linked_timeout // &ctx->completion_lock io_commit_cqring __io_queue_deferred __io_queue_async_work io_wq_enqueue io_wqe_enqueue // &wqe->lock
CPU1: ... __io_uring_files_cancel io_wq_cancel_cb io_wqe_cancel_pending_work // &wqe->lock io_cancel_task_cb // &ctx->completion_lock
Only __io_queue_deferred() calls queue_async_work() while holding ctx->completion_lock, enqueue drained requests via io_req_task_queue() instead.
Joseph, can you try it out? would much appreciate
Cc: stable@vger.kernel.org # 5.9+ Reported-by: Joseph Qi joseph.qi@linux.alibaba.com Signed-off-by: Pavel Begunkov asml.silence@gmail.com
fs/io_uring.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index bb0270eeb8cb..c218deaf73a9 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1026,6 +1026,7 @@ static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec, const struct iovec *fast_iov, struct iov_iter *iter, bool force); static void io_req_drop_files(struct io_kiocb *req); +static void io_req_task_queue(struct io_kiocb *req); static struct kmem_cache *req_cachep; @@ -1634,18 +1635,11 @@ static void __io_queue_deferred(struct io_ring_ctx *ctx) do { struct io_defer_entry *de = list_first_entry(&ctx->defer_list, struct io_defer_entry, list);
struct io_kiocb *link;
if (req_need_defer(de->req, de->seq)) break; list_del_init(&de->list);
/* punt-init is done before queueing for defer */
link = __io_queue_async_work(de->req);
if (link) {
__io_queue_linked_timeout(link);
/* drop submission reference */
io_put_req_deferred(link, 1);
}
kfree(de); } while (!list_empty(&ctx->defer_list));io_req_task_queue(de->req);
}
linux-stable-mirror@lists.linaro.org