Skip to content

Commit b6ffe53

Browse files
joannekoongaxboe
authored andcommitted
io_uring/kbuf: add buffer ring pinning/unpinning
Add kernel APIs to pin and unpin buffer rings, preventing userspace from unregistering a buffer ring while it is pinned by the kernel. This provides a mechanism for kernel subsystems to safely access buffer ring contents while ensuring the buffer ring remains valid. A pinned buffer ring cannot be unregistered until explicitly unpinned. On the userspace side, trying to unregister a pinned buffer will return -EBUSY. This is a preparatory change for upcoming fuse usage of kernel-managed buffer rings. It is necessary for fuse to pin the buffer ring because fuse may need to select a buffer in atomic contexts, which it can only do so by using the underlying buffer list pointer. Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Link: https://patch.msgid.link/20260306003224.3620942-4-joannelkoong@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent bf4a6eb commit b6ffe53

3 files changed

Lines changed: 77 additions & 0 deletions

File tree

include/linux/io_uring/cmd.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ struct io_br_sel io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd,
9191
bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
9292
struct io_br_sel *sel, unsigned int issue_flags);
9393

94+
int io_uring_buf_ring_pin(struct io_uring_cmd *cmd, unsigned buf_group,
95+
unsigned issue_flags, struct io_buffer_list **out_bl);
96+
int io_uring_buf_ring_unpin(struct io_uring_cmd *cmd, unsigned buf_group,
97+
unsigned issue_flags);
9498
#else
9599
static inline int
96100
io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
@@ -133,6 +137,19 @@ static inline bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
133137
{
134138
return true;
135139
}
140+
static inline int io_uring_buf_ring_pin(struct io_uring_cmd *cmd,
141+
unsigned buf_group,
142+
unsigned issue_flags,
143+
struct io_buffer_list **bl)
144+
{
145+
return -EOPNOTSUPP;
146+
}
147+
static inline int io_uring_buf_ring_unpin(struct io_uring_cmd *cmd,
148+
unsigned buf_group,
149+
unsigned issue_flags)
150+
{
151+
return -EOPNOTSUPP;
152+
}
136153
#endif
137154

138155
static inline struct io_uring_cmd *io_uring_cmd_from_tw(struct io_tw_req tw_req)

io_uring/kbuf.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/poll.h>
1010
#include <linux/vmalloc.h>
1111
#include <linux/io_uring.h>
12+
#include <linux/io_uring/cmd.h>
1213

1314
#include <uapi/linux/io_uring.h>
1415

@@ -246,6 +247,58 @@ struct io_br_sel io_buffer_select(struct io_kiocb *req, size_t *len,
246247
return sel;
247248
}
248249

250+
int io_uring_buf_ring_pin(struct io_uring_cmd *cmd, unsigned buf_group,
251+
unsigned issue_flags, struct io_buffer_list **out_bl)
252+
{
253+
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
254+
struct io_buffer_list *bl;
255+
int ret = -EINVAL;
256+
257+
io_ring_submit_lock(ctx, issue_flags);
258+
259+
bl = io_buffer_get_list(ctx, buf_group);
260+
if (!bl || !(bl->flags & IOBL_BUF_RING))
261+
goto err;
262+
263+
if (unlikely(bl->flags & IOBL_PINNED)) {
264+
ret = -EALREADY;
265+
goto err;
266+
}
267+
268+
bl->flags |= IOBL_PINNED;
269+
ret = 0;
270+
*out_bl = bl;
271+
err:
272+
io_ring_submit_unlock(ctx, issue_flags);
273+
return ret;
274+
}
275+
EXPORT_SYMBOL_GPL(io_uring_buf_ring_pin);
276+
277+
int io_uring_buf_ring_unpin(struct io_uring_cmd *cmd, unsigned buf_group,
278+
unsigned issue_flags)
279+
{
280+
struct io_ring_ctx *ctx = cmd_to_io_kiocb(cmd)->ctx;
281+
struct io_buffer_list *bl;
282+
unsigned int required_flags;
283+
int ret = -EINVAL;
284+
285+
io_ring_submit_lock(ctx, issue_flags);
286+
287+
bl = io_buffer_get_list(ctx, buf_group);
288+
if (!bl)
289+
goto err;
290+
291+
required_flags = IOBL_BUF_RING | IOBL_PINNED;
292+
if ((bl->flags & required_flags) == required_flags) {
293+
bl->flags &= ~IOBL_PINNED;
294+
ret = 0;
295+
}
296+
err:
297+
io_ring_submit_unlock(ctx, issue_flags);
298+
return ret;
299+
}
300+
EXPORT_SYMBOL_GPL(io_uring_buf_ring_unpin);
301+
249302
/* cap it at a reasonable 256, will be one page even for 4K */
250303
#define PEEK_MAX_IMPORT 256
251304

@@ -777,6 +830,8 @@ int io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
777830
return -ENOENT;
778831
if (!(bl->flags & IOBL_BUF_RING))
779832
return -EINVAL;
833+
if (bl->flags & IOBL_PINNED)
834+
return -EBUSY;
780835

781836
scoped_guard(mutex, &ctx->mmap_lock)
782837
xa_erase(&ctx->io_bl_xa, bl->bgid);

io_uring/kbuf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ enum {
1212
IOBL_INC = 2,
1313
/* buffers are kernel managed */
1414
IOBL_KERNEL_MANAGED = 4,
15+
/*
16+
* buffer ring is pinned and cannot be unregistered by userspace until
17+
* it has been unpinned
18+
*/
19+
IOBL_PINNED = 8,
1520
};
1621

1722
struct io_buffer_list {

0 commit comments

Comments
 (0)