io_uring/kbuf: Allow the full buffer id space for provided buffers
authorGabriel Krisman Bertazi <krisman@suse.de>
Thu, 5 Oct 2023 00:05:30 +0000 (20:05 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:59:11 +0000 (11:59 +0100)
[ Upstream commit f74c746e476b9dad51448b9a9421aae72b60e25f ]

nbufs tracks the number of buffers and not the last bgid. In 16-bit, we
have 2^16 valid buffers, but the check mistakenly rejects the last
bid. Let's fix it to make the interface consistent with the
documentation.

Fixes: ddf0322db79c ("io_uring: add IORING_OP_PROVIDE_BUFFERS")
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
Link: https://lore.kernel.org/r/20231005000531.30800-3-krisman@suse.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
io_uring/kbuf.c

index 74a4f96..f6e5ae0 100644 (file)
 
 #define BGID_ARRAY     64
 
+/* BIDs are addressed by a 16-bit field in a CQE */
+#define MAX_BIDS_PER_BGID (1 << 16)
+
 struct io_provide_buf {
        struct file                     *file;
        __u64                           addr;
        __u32                           len;
        __u32                           bgid;
-       __u16                           nbufs;
+       __u32                           nbufs;
        __u16                           bid;
 };
 
@@ -289,7 +292,7 @@ int io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                return -EINVAL;
 
        tmp = READ_ONCE(sqe->fd);
-       if (!tmp || tmp > USHRT_MAX)
+       if (!tmp || tmp > MAX_BIDS_PER_BGID)
                return -EINVAL;
 
        memset(p, 0, sizeof(*p));
@@ -332,7 +335,7 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
                return -EINVAL;
 
        tmp = READ_ONCE(sqe->fd);
-       if (!tmp || tmp > USHRT_MAX)
+       if (!tmp || tmp > MAX_BIDS_PER_BGID)
                return -E2BIG;
        p->nbufs = tmp;
        p->addr = READ_ONCE(sqe->addr);
@@ -352,7 +355,7 @@ int io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
        tmp = READ_ONCE(sqe->off);
        if (tmp > USHRT_MAX)
                return -E2BIG;
-       if (tmp + p->nbufs > USHRT_MAX)
+       if (tmp + p->nbufs > MAX_BIDS_PER_BGID)
                return -EINVAL;
        p->bid = tmp;
        return 0;