There may be concurrent poll interruptions: async_wake() ->del wait entry ->add to tw list async_wake() ->del wait entry ->add to tw list This mess up the tw list, let's avoid it by adding a if check before delete wait entry: async_wake() ->if empty(wait entry) return ->del wait entry ->add to tw list async_wake() ->if empty(wait entry) return <------------will return here ->del wait entry ->add to tw list Fixes: 88e41cf928a6 ("io_uring: add multishot mode for IORING_OP_POLL_ADD") Signed-off-by: Hao Xu <haoxu@xxxxxxxxxxxxxxxxx> --- fs/io_uring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/io_uring.c b/fs/io_uring.c index 8317c360f7a4..d0b358b9b589 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -5245,6 +5245,8 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll, trace_io_uring_task_add(req->ctx, req->opcode, req->user_data, mask); + if (list_empty(&poll->wait.entry)) + return 0; list_del_init(&poll->wait.entry); req->result = mask; -- 2.24.4