Commit 4aac001f authored by Pavel Begunkov's avatar Pavel Begunkov Committed by Jens Axboe
Browse files

io_uring/mock: add cmd using vectored regbufs



There is a command api allowing to import vectored registered buffers,
add a new mock command that uses the feature and simply copies the
specified registered buffer into user space or vice versa.

Signed-off-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/229a113fd7de6b27dbef9567f7c0bf4475c9017d.1750599274.git.asml.silence@gmail.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 3a0ae385
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -3,6 +3,12 @@

#include <linux/types.h>

enum {
	IORING_MOCK_FEAT_CMD_COPY,

	IORING_MOCK_FEAT_END,
};

struct io_uring_mock_probe {
	__u64		features;
	__u64		__resv[9];
@@ -19,4 +25,12 @@ enum {
	IORING_MOCK_MGR_CMD_CREATE,
};

enum {
	IORING_MOCK_CMD_COPY_REGBUF,
};

enum {
	IORING_MOCK_COPY_FROM			= 1,
};

#endif
+69 −1
Original line number Diff line number Diff line
@@ -9,8 +9,76 @@
#include <linux/io_uring_types.h>
#include <uapi/linux/io_uring/mock_file.h>

#define IO_VALID_COPY_CMD_FLAGS		IORING_MOCK_COPY_FROM

static int io_copy_regbuf(struct iov_iter *reg_iter, void __user *ubuf)
{
	size_t ret, copied = 0;
	size_t buflen = PAGE_SIZE;
	void *tmp_buf;

	tmp_buf = kzalloc(buflen, GFP_KERNEL);
	if (!tmp_buf)
		return -ENOMEM;

	while (iov_iter_count(reg_iter)) {
		size_t len = min(iov_iter_count(reg_iter), buflen);

		if (iov_iter_rw(reg_iter) == ITER_SOURCE) {
			ret = copy_from_iter(tmp_buf, len, reg_iter);
			if (ret <= 0)
				break;
			if (copy_to_user(ubuf, tmp_buf, ret))
				break;
		} else {
			if (copy_from_user(tmp_buf, ubuf, len))
				break;
			ret = copy_to_iter(tmp_buf, len, reg_iter);
			if (ret <= 0)
				break;
		}
		ubuf += ret;
		copied += ret;
	}

	kfree(tmp_buf);
	return copied;
}

static int io_cmd_copy_regbuf(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
	const struct io_uring_sqe *sqe = cmd->sqe;
	const struct iovec __user *iovec;
	unsigned flags, iovec_len;
	struct iov_iter iter;
	void __user *ubuf;
	int dir, ret;

	ubuf = u64_to_user_ptr(READ_ONCE(sqe->addr3));
	iovec = u64_to_user_ptr(READ_ONCE(sqe->addr));
	iovec_len = READ_ONCE(sqe->len);
	flags = READ_ONCE(sqe->file_index);

	if (unlikely(sqe->ioprio || sqe->__pad1))
		return -EINVAL;
	if (flags & ~IO_VALID_COPY_CMD_FLAGS)
		return -EINVAL;

	dir = (flags & IORING_MOCK_COPY_FROM) ? ITER_SOURCE : ITER_DEST;
	ret = io_uring_cmd_import_fixed_vec(cmd, iovec, iovec_len, dir, &iter,
					    issue_flags);
	if (ret)
		return ret;
	ret = io_copy_regbuf(&iter, ubuf);
	return ret ? ret : -EFAULT;
}

static int io_mock_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
	switch (cmd->cmd_op) {
	case IORING_MOCK_CMD_COPY_REGBUF:
		return io_cmd_copy_regbuf(cmd, issue_flags);
	}
	return -ENOTSUPP;
}

@@ -91,7 +159,7 @@ static int io_probe_mock(struct io_uring_cmd *cmd)
	if (!mem_is_zero(&mp, sizeof(mp)))
		return -EINVAL;

	mp.features = 0;
	mp.features = IORING_MOCK_FEAT_END;

	if (copy_to_user(uarg, &mp, uarg_size))
		return -EFAULT;