]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
io_uring/poll: fix POLLERR handling
authorPavel Begunkov <asml.silence@gmail.com>
Wed, 16 Jul 2025 16:20:17 +0000 (17:20 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 24 Jul 2025 06:53:12 +0000 (08:53 +0200)
commit c7cafd5b81cc07fb402e3068d134c21e60ea688c upstream.

8c8492ca64e7 ("io_uring/net: don't retry connect operation on EPOLLERR")
is a little dirty hack that
1) wrongfully assumes that POLLERR equals to a failed request, which
breaks all POLLERR users, e.g. all error queue recv interfaces.
2) deviates the connection request behaviour from connect(2), and
3) racy and solved at a wrong level.

Nothing can be done with 2) now, and 3) is beyond the scope of the
patch. At least solve 1) by moving the hack out of generic poll handling
into io_connect().

Cc: stable@vger.kernel.org
Fixes: 8c8492ca64e79 ("io_uring/net: don't retry connect operation on EPOLLERR")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/3dc89036388d602ebd84c28e5042e457bdfc952b.1752682444.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
io_uring/net.c
io_uring/poll.c

index 4948a67bbac4805f6de92d5b1505cd7570ef9075..e455f051e62ef7c53b437c8ed18873350264bc78 100644 (file)
@@ -1537,9 +1537,11 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
                io = &__io;
        }
 
-       if (unlikely(req->flags & REQ_F_FAIL)) {
-               ret = -ECONNRESET;
-               goto out;
+       if (connect->in_progress) {
+               struct poll_table_struct pt = { ._key = EPOLLERR };
+
+               if (vfs_poll(req->file, &pt) & EPOLLERR)
+                       goto get_sock_err;
        }
 
        file_flags = force_nonblock ? O_NONBLOCK : 0;
@@ -1571,8 +1573,10 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
                 * which means the previous result is good. For both of these,
                 * grab the sock_error() and use that for the completion.
                 */
-               if (ret == -EBADFD || ret == -EISCONN)
+               if (ret == -EBADFD || ret == -EISCONN) {
+get_sock_err:
                        ret = sock_error(sock_from_file(req->file)->sk);
+               }
        }
        if (ret == -ERESTARTSYS)
                ret = -EINTR;
index 2390bf5f1710b41c5dce163ef194c55d8307eac4..65935ec8de89c4a8c30977e68b2950f41f8de65a 100644 (file)
@@ -308,8 +308,6 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
                                return IOU_POLL_REISSUE;
                        }
                }
-               if (unlikely(req->cqe.res & EPOLLERR))
-                       req_set_fail(req);
                if (req->apoll_events & EPOLLONESHOT)
                        return IOU_POLL_DONE;