diff mbox series

io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT

Message ID 225ba417-7a82-59e0-6339-37cfd0ad4f7d@kernel.dk (mailing list archive)
State New
Headers show
Series io_uring/net: handle -EINPROGRESS correct for IORING_OP_CONNECT | expand

Commit Message

Jens Axboe Oct. 5, 2022, 2:34 a.m. UTC
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: 87f80d623c6c ("io_uring: handle connect -EINPROGRESS like -EAGAIN")
Link: https://github.com/axboe/liburing/issues/671
Signed-off-by: Jens Axboe <axboe@kernel.dk>

---
diff mbox series

Patch

diff --git a/io_uring/net.c b/io_uring/net.c
index 6b69eff6887e..2b6d55e365cb 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -46,6 +46,7 @@  struct io_connect {
 	struct file			*file;
 	struct sockaddr __user		*addr;
 	int				addr_len;
+	bool				in_progress;
 };
 
 struct io_sr_msg {
@@ -1382,6 +1383,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;
 }
 
@@ -1404,11 +1406,25 @@  int io_connect(struct io_kiocb *req, unsigned int issue_flags)
 		io = &__io;
 	}
 
+	if (connect->in_progress) {
+		struct socket *socket;
+
+		socket = sock_from_file(req->file);
+		if (unlikely(!socket)) {
+			ret = -EBADF;
+			goto out;
+		}
+		ret = sock_error(socket->sk);
+		goto out;
+	}
+
 	file_flags = force_nonblock ? O_NONBLOCK : 0;
 
 	ret = __sys_connect_file(req->file, &io->address,
 					connect->addr_len, file_flags);
 	if ((ret == -EAGAIN || ret == -EINPROGRESS) && force_nonblock) {
+		if (ret == -EINPROGRESS)
+			connect->in_progress = true;
 		if (req_has_async_data(req))
 			return -EAGAIN;
 		if (io_alloc_async_data(req)) {