Skip to content

Commit

Permalink
io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT
Browse files Browse the repository at this point in the history
We treat EINPROGRESS like EAGAIN, but if we're retrying post getting
EINPROGRESS, then we just need to check the socket for errors and
terminate the request.

This was exposed on a bluetooth connection request which ends up
taking a while and hitting EINPROGRESS, and yields a CQE result of
-EBADFD because we're retrying a connect on a socket that is now
connected.

Cc: stable@vger.kernel.org
Fixes: 87f80d6 ("io_uring: handle connect -EINPROGRESS like -EAGAIN")
Link: axboe/liburing#671
Reported-by: Aidan Sun <aidansun05@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
axboe committed Oct 12, 2022
1 parent b7a8177 commit 3fb1bd6
Showing 1 changed file with 22 additions and 6 deletions.
28 changes: 22 additions & 6 deletions io_uring/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct io_connect {
struct file *file;
struct sockaddr __user *addr;
int addr_len;
bool in_progress;
};

struct io_sr_msg {
Expand Down Expand Up @@ -1386,6 +1387,7 @@ int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)

conn->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
conn->addr_len = READ_ONCE(sqe->addr2);
conn->in_progress = false;
return 0;
}

Expand All @@ -1397,6 +1399,16 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
int ret;
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;

if (connect->in_progress) {
struct socket *socket;

ret = -ENOTSOCK;
socket = sock_from_file(req->file);
if (socket)
ret = sock_error(socket->sk);
goto out;
}

if (req_has_async_data(req)) {
io = req->async_data;
} else {
Expand All @@ -1413,13 +1425,17 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
ret = __sys_connect_file(req->file, &io->address,
connect->addr_len, file_flags);
if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
if (req_has_async_data(req))
return -EAGAIN;
if (io_alloc_async_data(req)) {
ret = -ENOMEM;
goto out;
if (ret == -EINPROGRESS) {
connect->in_progress = true;
} else {
if (req_has_async_data(req))
return -EAGAIN;
if (io_alloc_async_data(req)) {
ret = -ENOMEM;
goto out;
}
memcpy(req->async_data, &__io, sizeof(__io));
}
memcpy(req->async_data, &__io, sizeof(__io));
return -EAGAIN;
}
if (ret == -ERESTARTSYS)
Expand Down

0 comments on commit 3fb1bd6

Please sign in to comment.