Currently cloning a buffer table will fail if the destination already has a table. But it should be possible to use it to replace existing elements. Add a IORING_REGISTER_DST_REPLACE cloning flag, which if set, will allow the destination to already having a buffer table. If that is the case, then entries designated by offset + nr buffers will be replaced if they already exist. Note that it's allowed to use IORING_REGISTER_DST_REPLACE and not have an existing table, in which case it'll work just like not having the flag set and an empty table - it'll just assign the newly created table for that case. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- include/uapi/linux/io_uring.h | 3 ++- io_uring/rsrc.c | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index cc8dbe78c126..ce58c4590de6 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -713,7 +713,8 @@ struct io_uring_clock_register { }; enum { - IORING_REGISTER_SRC_REGISTERED = 1, + IORING_REGISTER_SRC_REGISTERED = (1U << 0), + IORING_REGISTER_DST_REPLACE = (1U << 1), }; struct io_uring_clone_buffers { diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 4c149dc42fd7..9829c51105ed 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -990,9 +990,25 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx /* Have a ref on the bufs now, drop src lock and re-grab our own lock */ mutex_unlock(&src_ctx->uring_lock); mutex_lock(&ctx->uring_lock); - if (!ctx->buf_table.nr) { + + /* + * Not replacing, or replacing an empty table. Just install the + * new table. + */ + if (!(arg->flags & IORING_REGISTER_DST_REPLACE) || !ctx->buf_table.nr) { ctx->buf_table = data; return 0; + } else if (arg->flags & IORING_REGISTER_DST_REPLACE) { + /* put nodes in overlapping spots, if any */ + for (i = arg->src_off; i < arg->nr; i++) { + if (data.nodes[i] == rsrc_empty_node) + continue; + io_reset_rsrc_node(&ctx->buf_table, i); + ctx->buf_table.nodes[i] = data.nodes[i]; + data.nodes[i] = NULL; + } + io_rsrc_data_free(&data); + return 0; } mutex_unlock(&ctx->uring_lock); @@ -1026,12 +1042,12 @@ int io_register_clone_buffers(struct io_ring_ctx *ctx, void __user *arg) struct file *file; int ret; - if (ctx->buf_table.nr) - return -EBUSY; if (copy_from_user(&buf, arg, sizeof(buf))) return -EFAULT; - if (buf.flags & ~IORING_REGISTER_SRC_REGISTERED) + if (buf.flags & ~(IORING_REGISTER_SRC_REGISTERED|IORING_REGISTER_DST_REPLACE)) return -EINVAL; + if (!(buf.flags & IORING_REGISTER_DST_REPLACE) && ctx->buf_table.nr) + return -EBUSY; if (memchr_inv(buf.pad, 0, sizeof(buf.pad))) return -EINVAL; -- 2.45.2