All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files
@ 2025-05-30  8:38 Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 1/6] " Pavel Begunkov
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

io_uring commands provide an ioctl style interface for files to
implement file specific operations. io_uring provides many features and
advanced api to commands, and it's getting hard to test as it requires
specific files/devices.

Add basic infrastucture for creating special mock files that will be
implementing the cmd api and using various io_uring features we want to
test. It'll also be useful to test some more obscure read/write/polling
edge cases in the future, which was initially suggested by Chase.

v3: fix memleak, + release fop callback

v2: add rw support with basic options
    implement features not as bitmask but sequence number

Pavel Begunkov (6):
  io_uring/mock: add basic infra for test mock files
  io_uring/mock: add cmd using vectored regbufs
  io_uring/mock: add sync read/write
  io_uring/mock: allow to choose FMODE_NOWAIT
  io_uring/mock: support for async read/write
  io_uring: add trivial poll handler

 init/Kconfig         |  11 ++
 io_uring/Makefile    |   1 +
 io_uring/mock_file.c | 354 +++++++++++++++++++++++++++++++++++++++++++
 io_uring/mock_file.h |  47 ++++++
 4 files changed, 413 insertions(+)
 create mode 100644 io_uring/mock_file.c
 create mode 100644 io_uring/mock_file.h

-- 
2.49.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  2025-05-30 11:31   ` Jens Axboe
  2025-05-30  8:38 ` [PATCH v3 2/6] io_uring/mock: add cmd using vectored regbufs Pavel Begunkov
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

io_uring commands provide an ioctl style interface for files to
implement file specific operations. io_uring provides many features and
advanced api to commands, and it's getting hard to test as it requires
specific files/devices.

Add basic infrastucture for creating special mock files that will be
implementing the cmd api and using various io_uring features we want to
test. It'll also be useful to test some more obscure read/write/polling
edge cases in the future.

Suggested-by: chase xd <sl1589472800@gmail.com>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 init/Kconfig         |  11 ++++
 io_uring/Makefile    |   1 +
 io_uring/mock_file.c | 139 +++++++++++++++++++++++++++++++++++++++++++
 io_uring/mock_file.h |  22 +++++++
 4 files changed, 173 insertions(+)
 create mode 100644 io_uring/mock_file.c
 create mode 100644 io_uring/mock_file.h

diff --git a/init/Kconfig b/init/Kconfig
index 63f5974b9fa6..856b37c2de8d 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1774,6 +1774,17 @@ config GCOV_PROFILE_URING
 	  the io_uring subsystem, hence this should only be enabled for
 	  specific test purposes.
 
+config IO_URING_MOCK_FILE
+	tristate "Enable io_uring mock files (Experimental)" if EXPERT
+	default n
+	depends on IO_URING
+	help
+	  Enable mock files for io_uring subststem testing. The ABI might
+	  still change, so it's still experimental and should only be enabled
+	  for specific test purposes.
+
+	  If unsure, say N.
+
 config ADVISE_SYSCALLS
 	bool "Enable madvise/fadvise syscalls" if EXPERT
 	default y
diff --git a/io_uring/Makefile b/io_uring/Makefile
index d97c6b51d584..b3f1bd492804 100644
--- a/io_uring/Makefile
+++ b/io_uring/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_EPOLL)		+= epoll.o
 obj-$(CONFIG_NET_RX_BUSY_POLL)	+= napi.o
 obj-$(CONFIG_NET) += net.o cmd_net.o
 obj-$(CONFIG_PROC_FS) += fdinfo.o
+obj-$(CONFIG_IO_URING_MOCK_FILE) += mock_file.o
diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
new file mode 100644
index 000000000000..e8ec0aeddbae
--- /dev/null
+++ b/io_uring/mock_file.c
@@ -0,0 +1,139 @@
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/anon_inodes.h>
+
+#include <linux/io_uring/cmd.h>
+#include <linux/io_uring_types.h>
+#include "mock_file.h"
+
+static int io_mock_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+	return -ENOTSUPP;
+}
+
+static const struct file_operations io_mock_fops = {
+	.owner		= THIS_MODULE,
+	.uring_cmd	= io_mock_cmd,
+};
+
+static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+	const struct io_uring_sqe *sqe = cmd->sqe;
+	struct io_uring_mock_create mc, __user *uarg;
+	struct file *file = NULL;
+	size_t uarg_size;
+	int fd, ret;
+
+	uarg = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	uarg_size = READ_ONCE(sqe->len);
+
+	if (sqe->ioprio || sqe->__pad1 || sqe->addr3 || sqe->file_index)
+		return -EINVAL;
+	if (uarg_size != sizeof(mc))
+		return -EINVAL;
+
+	memset(&mc, 0, sizeof(mc));
+	if (copy_from_user(&mc, uarg, uarg_size))
+		return -EFAULT;
+	if (!mem_is_zero(mc.__resv, sizeof(mc.__resv)) || mc.flags)
+		return -EINVAL;
+
+	fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+	if (fd < 0)
+		return fd;
+
+	file = anon_inode_create_getfile("[io_uring_mock]", &io_mock_fops,
+					 NULL, O_RDWR | O_CLOEXEC, NULL);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto fail;
+	}
+
+	mc.out_fd = fd;
+	if (copy_to_user(uarg, &mc, uarg_size)) {
+		fput(file);
+		ret = -EFAULT;
+		goto fail;
+	}
+
+	fd_install(fd, file);
+	return 0;
+fail:
+	put_unused_fd(fd);
+	return ret;
+}
+
+static int io_probe_mock(struct io_uring_cmd *cmd)
+{
+	const struct io_uring_sqe *sqe = cmd->sqe;
+	struct io_uring_mock_probe mp, __user *uarg;
+	size_t uarg_size;
+
+	uarg = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	uarg_size = READ_ONCE(sqe->len);
+
+	if (sqe->ioprio || sqe->__pad1 || sqe->addr3 || sqe->file_index ||
+	    uarg_size != sizeof(mp))
+		return -EINVAL;
+
+	memset(&mp, 0, sizeof(mp));
+	if (copy_from_user(&mp, uarg, uarg_size))
+		return -EFAULT;
+	if (!mem_is_zero(&mp, sizeof(mp)))
+		return -EINVAL;
+
+	mp.features = 0;
+
+	if (copy_to_user(uarg, &mp, uarg_size))
+		return -EFAULT;
+	return 0;
+}
+
+static int iou_mock_mgr_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+	switch (cmd->cmd_op) {
+	case IORING_MOCK_MGR_CMD_PROBE:
+		return io_probe_mock(cmd);
+	case IORING_MOCK_MGR_CMD_CREATE:
+		return io_create_mock_file(cmd, issue_flags);
+	}
+	return -EOPNOTSUPP;
+}
+
+static const struct file_operations iou_mock_dev_fops = {
+	.owner		= THIS_MODULE,
+	.uring_cmd	= iou_mock_mgr_cmd,
+};
+
+static struct miscdevice iou_mock_miscdev = {
+	.minor			= MISC_DYNAMIC_MINOR,
+	.name			= "io_uring_mock",
+	.fops			= &iou_mock_dev_fops,
+};
+
+static int __init io_mock_init(void)
+{
+	int ret;
+
+	ret = misc_register(&iou_mock_miscdev);
+	if (ret < 0) {
+		pr_err("Could not initialize io_uring mock device\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void __exit io_mock_exit(void)
+{
+	misc_deregister(&iou_mock_miscdev);
+}
+
+module_init(io_mock_init)
+module_exit(io_mock_exit)
+
+MODULE_AUTHOR("Pavel Begunkov <asml.silence@gmail.com>");
+MODULE_DESCRIPTION("io_uring mock file");
+MODULE_LICENSE("GPL");
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
new file mode 100644
index 000000000000..8b00045480cd
--- /dev/null
+++ b/io_uring/mock_file.h
@@ -0,0 +1,22 @@
+#ifndef IOU_MOCK_H
+#define IOU_MOCK_H
+
+#include <linux/types.h>
+
+struct io_uring_mock_probe {
+	__u64		features;
+	__u64		__resv[9];
+};
+
+struct io_uring_mock_create {
+	__u32		out_fd;
+	__u32		flags;
+	__u64		__resv[15];
+};
+
+enum {
+	IORING_MOCK_MGR_CMD_PROBE,
+	IORING_MOCK_MGR_CMD_CREATE,
+};
+
+#endif
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/6] io_uring/mock: add cmd using vectored regbufs
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 1/6] " Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 3/6] io_uring/mock: add sync read/write Pavel Begunkov
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

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: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/mock_file.c | 70 +++++++++++++++++++++++++++++++++++++++++++-
 io_uring/mock_file.h | 14 +++++++++
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
index e8ec0aeddbae..6d6100052a26 100644
--- a/io_uring/mock_file.c
+++ b/io_uring/mock_file.c
@@ -9,8 +9,76 @@
 #include <linux/io_uring_types.h>
 #include "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;
 }
 
@@ -85,7 +153,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;
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
index 8b00045480cd..8475dfd827e9 100644
--- a/io_uring/mock_file.h
+++ b/io_uring/mock_file.h
@@ -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
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/6] io_uring/mock: add sync read/write
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 1/6] " Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 2/6] io_uring/mock: add cmd using vectored regbufs Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 4/6] io_uring/mock: allow to choose FMODE_NOWAIT Pavel Begunkov
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

Add support for synchronous zero read/write for mock files.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/mock_file.c | 67 ++++++++++++++++++++++++++++++++++++++++----
 io_uring/mock_file.h |  4 ++-
 2 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
index 6d6100052a26..f606e1d03113 100644
--- a/io_uring/mock_file.c
+++ b/io_uring/mock_file.c
@@ -9,6 +9,10 @@
 #include <linux/io_uring_types.h>
 #include "mock_file.h"
 
+struct io_mock_file {
+	size_t size;
+};
+
 #define IO_VALID_COPY_CMD_FLAGS		IORING_MOCK_COPY_FROM
 
 static int io_copy_regbuf(struct iov_iter *reg_iter, void __user *ubuf)
@@ -82,18 +86,59 @@ static int io_mock_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 	return -ENOTSUPP;
 }
 
+static ssize_t io_mock_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+	struct io_mock_file *mf = iocb->ki_filp->private_data;
+	size_t len = iov_iter_count(to);
+
+	if (iocb->ki_pos + len > mf->size)
+		return -EINVAL;
+	return iov_iter_zero(len, to);
+}
+
+static ssize_t io_mock_write_iter(struct kiocb *iocb, struct iov_iter *from)
+{
+	struct io_mock_file *mf = iocb->ki_filp->private_data;
+	size_t len = iov_iter_count(from);
+
+	if (iocb->ki_pos + len > mf->size)
+		return -EINVAL;
+	iov_iter_advance(from, len);
+	return len;
+}
+
+static loff_t io_mock_llseek(struct file *file, loff_t offset, int whence)
+{
+	struct io_mock_file *mf = file->private_data;
+
+	return fixed_size_llseek(file, offset, whence, mf->size);
+}
+
+static int io_mock_release(struct inode *inode, struct file *file)
+{
+	struct io_mock_file *mf = file->private_data;
+
+	kfree(mf);
+	return 0;
+}
+
 static const struct file_operations io_mock_fops = {
 	.owner		= THIS_MODULE,
+	.release	= io_mock_release,
 	.uring_cmd	= io_mock_cmd,
+	.read_iter	= io_mock_read_iter,
+	.write_iter	= io_mock_write_iter,
+	.llseek		= io_mock_llseek,
 };
 
 static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flags)
 {
 	const struct io_uring_sqe *sqe = cmd->sqe;
 	struct io_uring_mock_create mc, __user *uarg;
+	struct io_mock_file *mf = NULL;
 	struct file *file = NULL;
 	size_t uarg_size;
-	int fd, ret;
+	int fd = -1, ret;
 
 	uarg = u64_to_user_ptr(READ_ONCE(sqe->addr));
 	uarg_size = READ_ONCE(sqe->len);
@@ -108,18 +153,28 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 		return -EFAULT;
 	if (!mem_is_zero(mc.__resv, sizeof(mc.__resv)) || mc.flags)
 		return -EINVAL;
+	if (mc.file_size > SZ_1G)
+		return -EINVAL;
+	mf = kzalloc(sizeof(*mf), GFP_KERNEL_ACCOUNT);
+	if (!mf)
+		return -ENOMEM;
 
-	fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+	ret = fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
 	if (fd < 0)
-		return fd;
+		goto fail;
 
+	mf->size = mc.file_size;
 	file = anon_inode_create_getfile("[io_uring_mock]", &io_mock_fops,
-					 NULL, O_RDWR | O_CLOEXEC, NULL);
+					 mf, O_RDWR | O_CLOEXEC, NULL);
 	if (IS_ERR(file)) {
 		ret = PTR_ERR(file);
 		goto fail;
 	}
 
+	file->f_mode |= FMODE_READ | FMODE_CAN_READ |
+			FMODE_WRITE | FMODE_CAN_WRITE |
+			FMODE_LSEEK;
+
 	mc.out_fd = fd;
 	if (copy_to_user(uarg, &mc, uarg_size)) {
 		fput(file);
@@ -130,7 +185,9 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 	fd_install(fd, file);
 	return 0;
 fail:
-	put_unused_fd(fd);
+	if (fd >= 0)
+		put_unused_fd(fd);
+	kfree(mf);
 	return ret;
 }
 
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
index 8475dfd827e9..dc6cc343410d 100644
--- a/io_uring/mock_file.h
+++ b/io_uring/mock_file.h
@@ -5,6 +5,7 @@
 
 enum {
 	IORING_MOCK_FEAT_CMD_COPY,
+	IORING_MOCK_FEAT_RW_ZERO,
 
 	IORING_MOCK_FEAT_END,
 };
@@ -17,7 +18,8 @@ struct io_uring_mock_probe {
 struct io_uring_mock_create {
 	__u32		out_fd;
 	__u32		flags;
-	__u64		__resv[15];
+	__u64		file_size;
+	__u64		__resv[14];
 };
 
 enum {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/6] io_uring/mock: allow to choose FMODE_NOWAIT
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
                   ` (2 preceding siblings ...)
  2025-05-30  8:38 ` [PATCH v3 3/6] io_uring/mock: add sync read/write Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 5/6] io_uring/mock: support for async read/write Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 6/6] io_uring: add trivial poll handler Pavel Begunkov
  5 siblings, 0 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

Add an option to choose whether the file supports FMODE_NOWAIT, that
changes the execution path io_uring request takes.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/mock_file.c | 8 +++++++-
 io_uring/mock_file.h | 5 +++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
index f606e1d03113..63c7d2f07f11 100644
--- a/io_uring/mock_file.c
+++ b/io_uring/mock_file.c
@@ -131,6 +131,8 @@ static const struct file_operations io_mock_fops = {
 	.llseek		= io_mock_llseek,
 };
 
+#define IO_VALID_CREATE_FLAGS (IORING_MOCK_CREATE_F_SUPPORT_NOWAIT)
+
 static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flags)
 {
 	const struct io_uring_sqe *sqe = cmd->sqe;
@@ -151,7 +153,9 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 	memset(&mc, 0, sizeof(mc));
 	if (copy_from_user(&mc, uarg, uarg_size))
 		return -EFAULT;
-	if (!mem_is_zero(mc.__resv, sizeof(mc.__resv)) || mc.flags)
+	if (!mem_is_zero(mc.__resv, sizeof(mc.__resv)))
+		return -EINVAL;
+	if (mc.flags & ~IO_VALID_CREATE_FLAGS)
 		return -EINVAL;
 	if (mc.file_size > SZ_1G)
 		return -EINVAL;
@@ -174,6 +178,8 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 	file->f_mode |= FMODE_READ | FMODE_CAN_READ |
 			FMODE_WRITE | FMODE_CAN_WRITE |
 			FMODE_LSEEK;
+	if (mc.flags & IORING_MOCK_CREATE_F_SUPPORT_NOWAIT)
+		file->f_mode |= FMODE_NOWAIT;
 
 	mc.out_fd = fd;
 	if (copy_to_user(uarg, &mc, uarg_size)) {
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
index dc6cc343410d..b2b669f7621f 100644
--- a/io_uring/mock_file.h
+++ b/io_uring/mock_file.h
@@ -6,6 +6,7 @@
 enum {
 	IORING_MOCK_FEAT_CMD_COPY,
 	IORING_MOCK_FEAT_RW_ZERO,
+	IORING_MOCK_FEAT_RW_NOWAIT,
 
 	IORING_MOCK_FEAT_END,
 };
@@ -15,6 +16,10 @@ struct io_uring_mock_probe {
 	__u64		__resv[9];
 };
 
+enum {
+	IORING_MOCK_CREATE_F_SUPPORT_NOWAIT			= 1,
+};
+
 struct io_uring_mock_create {
 	__u32		out_fd;
 	__u32		flags;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/6] io_uring/mock: support for async read/write
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
                   ` (3 preceding siblings ...)
  2025-05-30  8:38 ` [PATCH v3 4/6] io_uring/mock: allow to choose FMODE_NOWAIT Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  2025-05-30  8:38 ` [PATCH v3 6/6] io_uring: add trivial poll handler Pavel Begunkov
  5 siblings, 0 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

Let the user to specify a delay to read/write request. io_uring will
start a timer, return -EIOCBQUEUED and complete the request
asynchronously after the delay pass.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/mock_file.c | 59 +++++++++++++++++++++++++++++++++++++++++---
 io_uring/mock_file.h |  4 ++-
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
index 63c7d2f07f11..6130fa66c914 100644
--- a/io_uring/mock_file.c
+++ b/io_uring/mock_file.c
@@ -4,13 +4,22 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/anon_inodes.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
 
 #include <linux/io_uring/cmd.h>
 #include <linux/io_uring_types.h>
 #include "mock_file.h"
 
+struct io_mock_iocb {
+	struct kiocb		*iocb;
+	struct hrtimer		timer;
+	int			res;
+};
+
 struct io_mock_file {
-	size_t size;
+	size_t			size;
+	u64			rw_delay_ns;
 };
 
 #define IO_VALID_COPY_CMD_FLAGS		IORING_MOCK_COPY_FROM
@@ -86,14 +95,48 @@ static int io_mock_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 	return -ENOTSUPP;
 }
 
+static enum hrtimer_restart io_mock_rw_timer_expired(struct hrtimer *timer)
+{
+	struct io_mock_iocb *mio = container_of(timer, struct io_mock_iocb, timer);
+	struct kiocb *iocb = mio->iocb;
+
+	WRITE_ONCE(iocb->private, NULL);
+	iocb->ki_complete(iocb, mio->res);
+	kfree(mio);
+	return HRTIMER_NORESTART;
+}
+
+static ssize_t io_mock_delay_rw(struct kiocb *iocb, size_t len)
+{
+	struct io_mock_file *mf = iocb->ki_filp->private_data;
+	struct io_mock_iocb *mio;
+
+	mio = kzalloc(sizeof(*mio), GFP_KERNEL);
+	if (!mio)
+		return -ENOMEM;
+
+	mio->iocb = iocb;
+	mio->res = len;
+	hrtimer_setup(&mio->timer, io_mock_rw_timer_expired,
+		      CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hrtimer_start(&mio->timer, ns_to_ktime(mf->rw_delay_ns),
+		      HRTIMER_MODE_REL);
+	return -EIOCBQUEUED;
+}
+
 static ssize_t io_mock_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
 	struct io_mock_file *mf = iocb->ki_filp->private_data;
 	size_t len = iov_iter_count(to);
+	size_t nr_zeroed;
 
 	if (iocb->ki_pos + len > mf->size)
 		return -EINVAL;
-	return iov_iter_zero(len, to);
+	nr_zeroed = iov_iter_zero(len, to);
+	if (!mf->rw_delay_ns || nr_zeroed != len)
+		return nr_zeroed;
+
+	return io_mock_delay_rw(iocb, len);
 }
 
 static ssize_t io_mock_write_iter(struct kiocb *iocb, struct iov_iter *from)
@@ -103,8 +146,12 @@ static ssize_t io_mock_write_iter(struct kiocb *iocb, struct iov_iter *from)
 
 	if (iocb->ki_pos + len > mf->size)
 		return -EINVAL;
-	iov_iter_advance(from, len);
-	return len;
+	if (!mf->rw_delay_ns) {
+		iov_iter_advance(from, len);
+		return len;
+	}
+
+	return io_mock_delay_rw(iocb, len);
 }
 
 static loff_t io_mock_llseek(struct file *file, loff_t offset, int whence)
@@ -159,6 +206,9 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 		return -EINVAL;
 	if (mc.file_size > SZ_1G)
 		return -EINVAL;
+	if (mc.rw_delay_ns > NSEC_PER_SEC)
+		return -EINVAL;
+
 	mf = kzalloc(sizeof(*mf), GFP_KERNEL_ACCOUNT);
 	if (!mf)
 		return -ENOMEM;
@@ -168,6 +218,7 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 		goto fail;
 
 	mf->size = mc.file_size;
+	mf->rw_delay_ns = mc.rw_delay_ns;
 	file = anon_inode_create_getfile("[io_uring_mock]", &io_mock_fops,
 					 mf, O_RDWR | O_CLOEXEC, NULL);
 	if (IS_ERR(file)) {
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
index b2b669f7621f..0ca03562359f 100644
--- a/io_uring/mock_file.h
+++ b/io_uring/mock_file.h
@@ -7,6 +7,7 @@ enum {
 	IORING_MOCK_FEAT_CMD_COPY,
 	IORING_MOCK_FEAT_RW_ZERO,
 	IORING_MOCK_FEAT_RW_NOWAIT,
+	IORING_MOCK_FEAT_RW_ASYNC,
 
 	IORING_MOCK_FEAT_END,
 };
@@ -24,7 +25,8 @@ struct io_uring_mock_create {
 	__u32		out_fd;
 	__u32		flags;
 	__u64		file_size;
-	__u64		__resv[14];
+	__u64		rw_delay_ns;
+	__u64		__resv[13];
 };
 
 enum {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/6] io_uring: add trivial poll handler
  2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
                   ` (4 preceding siblings ...)
  2025-05-30  8:38 ` [PATCH v3 5/6] io_uring/mock: support for async read/write Pavel Begunkov
@ 2025-05-30  8:38 ` Pavel Begunkov
  5 siblings, 0 replies; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30  8:38 UTC (permalink / raw)
  To: io-uring; +Cc: asml.silence

Add a flag that enables polling on the mock file. For now it's trivially
says that there is always data available, it'll be extended in the
future.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 io_uring/mock_file.c | 37 +++++++++++++++++++++++++++++++++++--
 io_uring/mock_file.h |  2 ++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/io_uring/mock_file.c b/io_uring/mock_file.c
index 6130fa66c914..78438f99229e 100644
--- a/io_uring/mock_file.c
+++ b/io_uring/mock_file.c
@@ -6,6 +6,7 @@
 #include <linux/anon_inodes.h>
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
+#include <linux/poll.h>
 
 #include <linux/io_uring/cmd.h>
 #include <linux/io_uring_types.h>
@@ -20,6 +21,8 @@ struct io_mock_iocb {
 struct io_mock_file {
 	size_t			size;
 	u64			rw_delay_ns;
+	bool			pollable;
+	struct wait_queue_head	poll_wq;
 };
 
 #define IO_VALID_COPY_CMD_FLAGS		IORING_MOCK_COPY_FROM
@@ -161,6 +164,18 @@ static loff_t io_mock_llseek(struct file *file, loff_t offset, int whence)
 	return fixed_size_llseek(file, offset, whence, mf->size);
 }
 
+static __poll_t io_mock_poll(struct file *file, struct poll_table_struct *pt)
+{
+	struct io_mock_file *mf = file->private_data;
+	__poll_t mask = 0;
+
+	poll_wait(file, &mf->poll_wq, pt);
+
+	mask |= EPOLLOUT | EPOLLWRNORM;
+	mask |= EPOLLIN | EPOLLRDNORM;
+	return mask;
+}
+
 static int io_mock_release(struct inode *inode, struct file *file)
 {
 	struct io_mock_file *mf = file->private_data;
@@ -178,10 +193,22 @@ static const struct file_operations io_mock_fops = {
 	.llseek		= io_mock_llseek,
 };
 
-#define IO_VALID_CREATE_FLAGS (IORING_MOCK_CREATE_F_SUPPORT_NOWAIT)
+static const struct file_operations io_mock_poll_fops = {
+	.owner		= THIS_MODULE,
+	.release	= io_mock_release,
+	.uring_cmd	= io_mock_cmd,
+	.read_iter	= io_mock_read_iter,
+	.write_iter	= io_mock_write_iter,
+	.llseek		= io_mock_llseek,
+	.poll		= io_mock_poll,
+};
+
+#define IO_VALID_CREATE_FLAGS (IORING_MOCK_CREATE_F_SUPPORT_NOWAIT | \
+				IORING_MOCK_CREATE_F_POLL)
 
 static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flags)
 {
+	const struct file_operations *fops = &io_mock_fops;
 	const struct io_uring_sqe *sqe = cmd->sqe;
 	struct io_uring_mock_create mc, __user *uarg;
 	struct io_mock_file *mf = NULL;
@@ -217,9 +244,15 @@ static int io_create_mock_file(struct io_uring_cmd *cmd, unsigned int issue_flag
 	if (fd < 0)
 		goto fail;
 
+	init_waitqueue_head(&mf->poll_wq);
 	mf->size = mc.file_size;
 	mf->rw_delay_ns = mc.rw_delay_ns;
-	file = anon_inode_create_getfile("[io_uring_mock]", &io_mock_fops,
+	if (mc.flags & IORING_MOCK_CREATE_F_POLL) {
+		fops = &io_mock_poll_fops;
+		mf->pollable = true;
+	}
+
+	file = anon_inode_create_getfile("[io_uring_mock]", fops,
 					 mf, O_RDWR | O_CLOEXEC, NULL);
 	if (IS_ERR(file)) {
 		ret = PTR_ERR(file);
diff --git a/io_uring/mock_file.h b/io_uring/mock_file.h
index 0ca03562359f..30456ea71d54 100644
--- a/io_uring/mock_file.h
+++ b/io_uring/mock_file.h
@@ -8,6 +8,7 @@ enum {
 	IORING_MOCK_FEAT_RW_ZERO,
 	IORING_MOCK_FEAT_RW_NOWAIT,
 	IORING_MOCK_FEAT_RW_ASYNC,
+	IORING_MOCK_FEAT_POLL,
 
 	IORING_MOCK_FEAT_END,
 };
@@ -19,6 +20,7 @@ struct io_uring_mock_probe {
 
 enum {
 	IORING_MOCK_CREATE_F_SUPPORT_NOWAIT			= 1,
+	IORING_MOCK_CREATE_F_POLL				= 2,
 };
 
 struct io_uring_mock_create {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30  8:38 ` [PATCH v3 1/6] " Pavel Begunkov
@ 2025-05-30 11:31   ` Jens Axboe
  2025-05-30 11:45     ` Pavel Begunkov
  0 siblings, 1 reply; 12+ messages in thread
From: Jens Axboe @ 2025-05-30 11:31 UTC (permalink / raw)
  To: Pavel Begunkov, io-uring

On 5/30/25 2:38 AM, Pavel Begunkov wrote:
> io_uring commands provide an ioctl style interface for files to
> implement file specific operations. io_uring provides many features and
> advanced api to commands, and it's getting hard to test as it requires
> specific files/devices.
> 
> Add basic infrastucture for creating special mock files that will be
> implementing the cmd api and using various io_uring features we want to
> test. It'll also be useful to test some more obscure read/write/polling
> edge cases in the future.

Do we want to have the creation of a mock file be a privileged
operation?

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30 11:31   ` Jens Axboe
@ 2025-05-30 11:45     ` Pavel Begunkov
  2025-05-30 11:48       ` Jens Axboe
  0 siblings, 1 reply; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30 11:45 UTC (permalink / raw)
  To: Jens Axboe, io-uring

On 5/30/25 12:31, Jens Axboe wrote:
> On 5/30/25 2:38 AM, Pavel Begunkov wrote:
>> io_uring commands provide an ioctl style interface for files to
>> implement file specific operations. io_uring provides many features and
>> advanced api to commands, and it's getting hard to test as it requires
>> specific files/devices.
>>
>> Add basic infrastucture for creating special mock files that will be
>> implementing the cmd api and using various io_uring features we want to
>> test. It'll also be useful to test some more obscure read/write/polling
>> edge cases in the future.
> 
> Do we want to have the creation of a mock file be a privileged
> operation?

It doesn't do anything that would warrant that, maybe just yet.
Do you mean from the security perspective? i.e. making sure a
user can't exploit it if there is anything to be exploited.
I'd really hope nobody would compile this thing for non-test
kernels. Maybe I should make it dependent on lockdep to enforce
it.

-- 
Pavel Begunkov


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30 11:45     ` Pavel Begunkov
@ 2025-05-30 11:48       ` Jens Axboe
  2025-05-30 12:21         ` Pavel Begunkov
  0 siblings, 1 reply; 12+ messages in thread
From: Jens Axboe @ 2025-05-30 11:48 UTC (permalink / raw)
  To: Pavel Begunkov, io-uring

On 5/30/25 5:45 AM, Pavel Begunkov wrote:
> On 5/30/25 12:31, Jens Axboe wrote:
>> On 5/30/25 2:38 AM, Pavel Begunkov wrote:
>>> io_uring commands provide an ioctl style interface for files to
>>> implement file specific operations. io_uring provides many features and
>>> advanced api to commands, and it's getting hard to test as it requires
>>> specific files/devices.
>>>
>>> Add basic infrastucture for creating special mock files that will be
>>> implementing the cmd api and using various io_uring features we want to
>>> test. It'll also be useful to test some more obscure read/write/polling
>>> edge cases in the future.
>>
>> Do we want to have the creation of a mock file be a privileged
>> operation?
> 
> It doesn't do anything that would warrant that, maybe just yet.
> Do you mean from the security perspective? i.e. making sure a
> user can't exploit it if there is anything to be exploited.
> I'd really hope nobody would compile this thing for non-test
> kernels. Maybe I should make it dependent on lockdep to enforce
> it.

People do all sorts of weird stuff. I know it doesn't do anything
that warrants making it root only, but at least as root only, any
side effects will be limited to that. I think that'd be better than
making it forcibly depend on something unrelated (but debug'y) like
lockdep.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30 11:48       ` Jens Axboe
@ 2025-05-30 12:21         ` Pavel Begunkov
  2025-05-30 13:20           ` Jens Axboe
  0 siblings, 1 reply; 12+ messages in thread
From: Pavel Begunkov @ 2025-05-30 12:21 UTC (permalink / raw)
  To: Jens Axboe, io-uring

On 5/30/25 12:48, Jens Axboe wrote:
> On 5/30/25 5:45 AM, Pavel Begunkov wrote:
>> On 5/30/25 12:31, Jens Axboe wrote:
>>> On 5/30/25 2:38 AM, Pavel Begunkov wrote:
>>>> io_uring commands provide an ioctl style interface for files to
>>>> implement file specific operations. io_uring provides many features and
>>>> advanced api to commands, and it's getting hard to test as it requires
>>>> specific files/devices.
>>>>
>>>> Add basic infrastucture for creating special mock files that will be
>>>> implementing the cmd api and using various io_uring features we want to
>>>> test. It'll also be useful to test some more obscure read/write/polling
>>>> edge cases in the future.
>>>
>>> Do we want to have the creation of a mock file be a privileged
>>> operation?
>>
>> It doesn't do anything that would warrant that, maybe just yet.
>> Do you mean from the security perspective? i.e. making sure a
>> user can't exploit it if there is anything to be exploited.
>> I'd really hope nobody would compile this thing for non-test
>> kernels. Maybe I should make it dependent on lockdep to enforce
>> it.
> 
> People do all sorts of weird stuff. I know it doesn't do anything
> that warrants making it root only, but at least as root only, any
> side effects will be limited to that. I think that'd be better than
> making it forcibly depend on something unrelated (but debug'y) like
> lockdep.

I don't hate the CAP_ADMIN idea, I'll add it, but making it
dependent on something incompatible with production kernels is
the only way to ensure it's used in the intended way.

-- 
Pavel Begunkov


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/6] io_uring/mock: add basic infra for test mock files
  2025-05-30 12:21         ` Pavel Begunkov
@ 2025-05-30 13:20           ` Jens Axboe
  0 siblings, 0 replies; 12+ messages in thread
From: Jens Axboe @ 2025-05-30 13:20 UTC (permalink / raw)
  To: Pavel Begunkov, io-uring

On 5/30/25 6:21 AM, Pavel Begunkov wrote:
> On 5/30/25 12:48, Jens Axboe wrote:
>> On 5/30/25 5:45 AM, Pavel Begunkov wrote:
>>> On 5/30/25 12:31, Jens Axboe wrote:
>>>> On 5/30/25 2:38 AM, Pavel Begunkov wrote:
>>>>> io_uring commands provide an ioctl style interface for files to
>>>>> implement file specific operations. io_uring provides many features and
>>>>> advanced api to commands, and it's getting hard to test as it requires
>>>>> specific files/devices.
>>>>>
>>>>> Add basic infrastucture for creating special mock files that will be
>>>>> implementing the cmd api and using various io_uring features we want to
>>>>> test. It'll also be useful to test some more obscure read/write/polling
>>>>> edge cases in the future.
>>>>
>>>> Do we want to have the creation of a mock file be a privileged
>>>> operation?
>>>
>>> It doesn't do anything that would warrant that, maybe just yet.
>>> Do you mean from the security perspective? i.e. making sure a
>>> user can't exploit it if there is anything to be exploited.
>>> I'd really hope nobody would compile this thing for non-test
>>> kernels. Maybe I should make it dependent on lockdep to enforce
>>> it.
>>
>> People do all sorts of weird stuff. I know it doesn't do anything
>> that warrants making it root only, but at least as root only, any
>> side effects will be limited to that. I think that'd be better than
>> making it forcibly depend on something unrelated (but debug'y) like
>> lockdep.
> 
> I don't hate the CAP_ADMIN idea, I'll add it, but making it
> dependent on something incompatible with production kernels is
> the only way to ensure it's used in the intended way.

But any kind of dependency like lockdep will mean that I cannot run
testing without lockdep, or whatever else the dependency might be. I
think that'd be rather unfortunate, I tend to test with both a "stock"
kind of config, and a KASAN && PROVE_LOCKING setup.

So I really don't think we should limit ourselves that way, attempting
to stop a weird use case by adding artificial dependencies.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-05-30 13:20 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-30  8:38 [PATCH v3 0/6] io_uring/mock: add basic infra for test mock files Pavel Begunkov
2025-05-30  8:38 ` [PATCH v3 1/6] " Pavel Begunkov
2025-05-30 11:31   ` Jens Axboe
2025-05-30 11:45     ` Pavel Begunkov
2025-05-30 11:48       ` Jens Axboe
2025-05-30 12:21         ` Pavel Begunkov
2025-05-30 13:20           ` Jens Axboe
2025-05-30  8:38 ` [PATCH v3 2/6] io_uring/mock: add cmd using vectored regbufs Pavel Begunkov
2025-05-30  8:38 ` [PATCH v3 3/6] io_uring/mock: add sync read/write Pavel Begunkov
2025-05-30  8:38 ` [PATCH v3 4/6] io_uring/mock: allow to choose FMODE_NOWAIT Pavel Begunkov
2025-05-30  8:38 ` [PATCH v3 5/6] io_uring/mock: support for async read/write Pavel Begunkov
2025-05-30  8:38 ` [PATCH v3 6/6] io_uring: add trivial poll handler Pavel Begunkov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.