Commit 3fb1bd68 authored by Jens Axboe's avatar Jens Axboe

io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT

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: 87f80d62 ("io_uring: handle connect -EINPROGRESS like -EAGAIN")
Link: https://github.com/axboe/liburing/issues/671Reported-by: default avatarAidan Sun <aidansun05@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent b7a81775
...@@ -46,6 +46,7 @@ struct io_connect { ...@@ -46,6 +46,7 @@ struct io_connect {
struct file *file; struct file *file;
struct sockaddr __user *addr; struct sockaddr __user *addr;
int addr_len; int addr_len;
bool in_progress;
}; };
struct io_sr_msg { struct io_sr_msg {
...@@ -1386,6 +1387,7 @@ int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) ...@@ -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 = u64_to_user_ptr(READ_ONCE(sqe->addr));
conn->addr_len = READ_ONCE(sqe->addr2); conn->addr_len = READ_ONCE(sqe->addr2);
conn->in_progress = false;
return 0; return 0;
} }
...@@ -1397,6 +1399,16 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags) ...@@ -1397,6 +1399,16 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
int ret; int ret;
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK; 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)) { if (req_has_async_data(req)) {
io = req->async_data; io = req->async_data;
} else { } else {
...@@ -1413,6 +1425,9 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags) ...@@ -1413,6 +1425,9 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
ret = __sys_connect_file(req->file, &io->address, ret = __sys_connect_file(req->file, &io->address,
connect->addr_len, file_flags); connect->addr_len, file_flags);
if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) { if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
if (ret == -EINPROGRESS) {
connect->in_progress = true;
} else {
if (req_has_async_data(req)) if (req_has_async_data(req))
return -EAGAIN; return -EAGAIN;
if (io_alloc_async_data(req)) { if (io_alloc_async_data(req)) {
...@@ -1420,6 +1435,7 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags) ...@@ -1420,6 +1435,7 @@ int io_connect(struct io_kiocb *req, unsigned int issue_flags)
goto out; goto out;
} }
memcpy(req->async_data, &__io, sizeof(__io)); memcpy(req->async_data, &__io, sizeof(__io));
}
return -EAGAIN; return -EAGAIN;
} }
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment