io_uring/net: only retry recv bundle for a full transfer io_uring-6.15 io_uring-6.15-20250522
authorJens Axboe <axboe@kernel.dk>
Thu, 22 May 2025 00:51:49 +0000 (18:51 -0600)
committerJens Axboe <axboe@kernel.dk>
Thu, 22 May 2025 01:24:18 +0000 (19:24 -0600)
If a shorter than assumed transfer was seen, a partial buffer will have
been filled. For that case it isn't sane to attempt to fill more into
the bundle before posting a completion, as that will cause a gap in
the received data.

Check if the iterator has hit zero and only allow to continue a bundle
operation if that is the case.

Also ensure that for putting finished buffers, only the current transfer
is accounted. Otherwise too many buffers may be put for a short transfer.

Link: https://github.com/axboe/liburing/issues/1409
Cc: stable@vger.kernel.org
Fixes: 7c71a0af81ba ("io_uring/net: improve recv bundles")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/net.c

index 24040bc3916a1bebf33f7da891bfe85d5abfa0e7..27f37fa2ef7936786932f4a8edb6d8c14478bae6 100644 (file)
@@ -827,18 +827,24 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
                cflags |= IORING_CQE_F_SOCK_NONEMPTY;
 
        if (sr->flags & IORING_RECVSEND_BUNDLE) {
-               cflags |= io_put_kbufs(req, *ret, io_bundle_nbufs(kmsg, *ret),
+               size_t this_ret = *ret - sr->done_io;
+
+               cflags |= io_put_kbufs(req, *ret, io_bundle_nbufs(kmsg, this_ret),
                                      issue_flags);
                if (sr->retry)
                        cflags = req->cqe.flags | (cflags & CQE_F_MASK);
                /* bundle with no more immediate buffers, we're done */
                if (req->flags & REQ_F_BL_EMPTY)
                        goto finish;
-               /* if more is available, retry and append to this one */
-               if (!sr->retry && kmsg->msg.msg_inq > 0 && *ret > 0) {
+               /*
+                * If more is available AND it was a full transfer, retry and
+                * append to this one
+                */
+               if (!sr->retry && kmsg->msg.msg_inq > 0 && this_ret > 0 &&
+                   !iov_iter_count(&kmsg->msg.msg_iter)) {
                        req->cqe.flags = cflags & ~CQE_F_MASK;
                        sr->len = kmsg->msg.msg_inq;
-                       sr->done_io += *ret;
+                       sr->done_io += this_ret;
                        sr->retry = true;
                        return false;
                }