Skip to content

Commit b16e920

Browse files
committed
io_uring/rsrc: allow cloning at an offset
Right now buffer cloning is an all-or-nothing kind of thing - either the whole table is cloned from a source to a destination ring, or nothing at all. However, it's not always desired to clone the whole thing. Allow for the application to specify a source and destination offset, and a number of buffers to clone. If the destination offset is non-zero, then allocate sparse nodes upfront. Signed-off-by: Jens Axboe <[email protected]>
1 parent d50f94d commit b16e920

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

include/uapi/linux/io_uring.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,10 @@ enum {
719719
struct io_uring_clone_buffers {
720720
__u32 src_fd;
721721
__u32 flags;
722-
__u32 pad[6];
722+
__u32 src_off;
723+
__u32 dst_off;
724+
__u32 nr;
725+
__u32 pad[3];
723726
};
724727

725728
struct io_uring_buf {

io_uring/rsrc.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -927,10 +927,11 @@ int io_import_fixed(int ddir, struct iov_iter *iter,
927927
return 0;
928928
}
929929

930-
static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx)
930+
static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx,
931+
struct io_uring_clone_buffers *arg)
931932
{
933+
int i, ret, nbufs, off, nr;
932934
struct io_rsrc_data data;
933-
int i, ret, nbufs;
934935

935936
/*
936937
* Drop our own lock here. We'll setup the data we need and reference
@@ -943,11 +944,29 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
943944
nbufs = src_ctx->buf_table.nr;
944945
if (!nbufs)
945946
goto out_unlock;
946-
ret = io_rsrc_data_alloc(&data, nbufs);
947+
ret = -EINVAL;
948+
if (!arg->nr)
949+
arg->nr = nbufs;
950+
else if (arg->nr > nbufs)
951+
goto out_unlock;
952+
ret = -EOVERFLOW;
953+
if (check_add_overflow(arg->nr, arg->src_off, &off))
954+
goto out_unlock;
955+
if (off > nbufs)
956+
goto out_unlock;
957+
if (check_add_overflow(arg->nr, arg->dst_off, &off))
958+
goto out_unlock;
959+
ret = -EINVAL;
960+
if (off > IORING_MAX_REG_BUFFERS)
961+
goto out_unlock;
962+
ret = io_rsrc_data_alloc(&data, off);
947963
if (ret)
948964
goto out_unlock;
949965

950-
for (i = 0; i < nbufs; i++) {
966+
off = arg->dst_off;
967+
i = arg->src_off;
968+
nr = arg->nr;
969+
while (nr--) {
951970
struct io_rsrc_node *dst_node, *src_node;
952971

953972
src_node = io_rsrc_node_lookup(&src_ctx->buf_table, i);
@@ -963,7 +982,8 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
963982
refcount_inc(&src_node->buf->refs);
964983
dst_node->buf = src_node->buf;
965984
}
966-
data.nodes[i] = dst_node;
985+
data.nodes[off++] = dst_node;
986+
i++;
967987
}
968988

969989
/* Have a ref on the bufs now, drop src lock and re-grab our own lock */
@@ -1018,7 +1038,7 @@ int io_register_clone_buffers(struct io_ring_ctx *ctx, void __user *arg)
10181038
file = io_uring_register_get_file(buf.src_fd, registered_src);
10191039
if (IS_ERR(file))
10201040
return PTR_ERR(file);
1021-
ret = io_clone_buffers(ctx, file->private_data);
1041+
ret = io_clone_buffers(ctx, file->private_data, &buf);
10221042
if (!registered_src)
10231043
fput(file);
10241044
return ret;

0 commit comments

Comments
 (0)