All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH liburing v2 0/5] Add basic test for nvme uring passthrough commands
       [not found] <CGME20220726105812epcas5p4a2946262206548f67e238845e23a122c@epcas5p4.samsung.com>
@ 2022-07-26 10:52 ` Ankit Kumar
       [not found]   ` <CGME20220726105813epcas5p44c4058c9d3e9332ef939dbbb9a052738@epcas5p4.samsung.com>
                     ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

Hi Jens,

This patchset adds a way to test NVMe uring passthrough commands with
nvme-ns character device. The uring passthrough was introduced with 5.19
io_uring.

To send nvme uring passthrough commands we require helpers to fetch NVMe
char device (/dev/ngXnY) specific fields such as namespace id, lba size etc.
 
How to run:
./test/io_uring_passthrough.t /dev/ng0n1

The test covers write/read with verify for sqthread poll, vectored / nonvectored
and fixed IO buffers, which can be extended in future. As of now iopoll is not
supported for passthrough commands, there is a test for such case.

There was no reviewer for v1, can you please have a look at the changes.

v1 -> v2
 - Rebase on top of latest master

Ankit Kumar (5):
  configure: check for nvme uring command support
  io_uring.h: sync sqe entry with 5.20 io_uring
  nvme: add nvme opcodes, structures and helper functions
  test: add io_uring passthrough test
  test/io_uring_passthrough: add test case for poll IO

 configure                       |  20 ++
 src/include/liburing/io_uring.h |  17 +-
 test/Makefile                   |   1 +
 test/io_uring_passthrough.c     | 395 ++++++++++++++++++++++++++++++++
 test/nvme.h                     | 168 ++++++++++++++
 5 files changed, 599 insertions(+), 2 deletions(-)
 create mode 100644 test/io_uring_passthrough.c
 create mode 100644 test/nvme.h

-- 
2.17.1


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

* [PATCH liburing v2 1/5] configure: check for nvme uring command support
       [not found]   ` <CGME20220726105813epcas5p44c4058c9d3e9332ef939dbbb9a052738@epcas5p4.samsung.com>
@ 2022-07-26 10:52     ` Ankit Kumar
  0 siblings, 0 replies; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

Modify configure to check availability of nvme_uring_cmd.
The follow up patch will have uring passthrough tests.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
---
 configure | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/configure b/configure
index 43071dd..1b0cc50 100755
--- a/configure
+++ b/configure
@@ -367,6 +367,23 @@ if compile_prog "" "" "has_ucontext"; then
 fi
 print_config "has_ucontext" "$has_ucontext"
 
+##########################################
+# Check NVME_URING_CMD support
+nvme_uring_cmd="no"
+cat > $TMPC << EOF
+#include <linux/nvme_ioctl.h>
+int main(void)
+{
+  struct nvme_uring_cmd *cmd;
+
+  return sizeof(struct nvme_uring_cmd);
+}
+EOF
+if compile_prog "" "" "nvme uring cmd"; then
+  nvme_uring_cmd="yes"
+fi
+print_config "NVMe uring command support" "$nvme_uring_cmd"
+
 #############################################################################
 if test "$liburing_nolibc" = "yes"; then
   output_sym "CONFIG_NOLIBC"
@@ -402,6 +419,9 @@ fi
 if test "$array_bounds" = "yes"; then
   output_sym "CONFIG_HAVE_ARRAY_BOUNDS"
 fi
+if test "$nvme_uring_cmd" = "yes"; then
+  output_sym "CONFIG_HAVE_NVME_URING"
+fi
 
 echo "CC=$cc" >> $config_host_mak
 print_config "CC" "$cc"
-- 
2.17.1


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

* [PATCH liburing v2 2/5] io_uring.h: sync sqe entry with 5.20 io_uring
       [not found]   ` <CGME20220726105814epcas5p4b454a04c6f7befa23788b5a6bf3031c3@epcas5p4.samsung.com>
@ 2022-07-26 10:52     ` Ankit Kumar
  0 siblings, 0 replies; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

Add a few missing fields which was added for uring command

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
---
 src/include/liburing/io_uring.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/include/liburing/io_uring.h b/src/include/liburing/io_uring.h
index 3953807..c923f5c 100644
--- a/src/include/liburing/io_uring.h
+++ b/src/include/liburing/io_uring.h
@@ -26,6 +26,10 @@ struct io_uring_sqe {
 	union {
 		__u64	off;	/* offset into file */
 		__u64	addr2;
+		struct {
+			__u32	cmd_op;
+			__u32	__pad1;
+		};
 	};
 	union {
 		__u64	addr;	/* pointer to buffer or iovecs */
@@ -69,8 +73,17 @@ struct io_uring_sqe {
 			__u16	addr_len;
 		};
 	};
-	__u64	addr3;
-	__u64	__pad2[1];
+	union {
+		struct {
+			__u64	addr3;
+			__u64	__pad2[1];
+		};
+		/*
+		 * If the ring is initialized with IORING_SETUP_SQE128, then
+		 * this field is used for 80 bytes of arbitrary command data
+		 */
+		__u8	cmd[0];
+	};
 };
 
 /*
-- 
2.17.1


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

* [PATCH liburing v2 3/5] nvme: add nvme opcodes, structures and helper functions
       [not found]   ` <CGME20220726105815epcas5p2e19ff2fe748cfeb69517124370de3b7f@epcas5p2.samsung.com>
@ 2022-07-26 10:52     ` Ankit Kumar
  2022-07-27 18:24       ` Jens Axboe
  0 siblings, 1 reply; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

Add bare minimum structures and helper functions required for
io_uring passthrough commands. This will enable the follow up
patch to add tests for nvme-ns generic character device.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
---
 test/nvme.h | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 test/nvme.h

diff --git a/test/nvme.h b/test/nvme.h
new file mode 100644
index 0000000..866a7e6
--- /dev/null
+++ b/test/nvme.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: Helpers for NVMe uring passthrough commands
+ */
+#ifndef LIBURING_NVME_H
+#define LIBURING_NVME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/ioctl.h>
+#include <linux/nvme_ioctl.h>
+
+/*
+ * If the uapi headers installed on the system lacks nvme uring command
+ * support, use the local version to prevent compilation issues.
+ */
+#ifndef CONFIG_HAVE_NVME_URING
+struct nvme_uring_cmd {
+	__u8	opcode;
+	__u8	flags;
+	__u16	rsvd1;
+	__u32	nsid;
+	__u32	cdw2;
+	__u32	cdw3;
+	__u64	metadata;
+	__u64	addr;
+	__u32	metadata_len;
+	__u32	data_len;
+	__u32	cdw10;
+	__u32	cdw11;
+	__u32	cdw12;
+	__u32	cdw13;
+	__u32	cdw14;
+	__u32	cdw15;
+	__u32	timeout_ms;
+	__u32   rsvd2;
+};
+
+#define NVME_URING_CMD_IO	_IOWR('N', 0x80, struct nvme_uring_cmd)
+#define NVME_URING_CMD_IO_VEC	_IOWR('N', 0x81, struct nvme_uring_cmd)
+#endif /* CONFIG_HAVE_NVME_URING */
+
+#define NVME_DEFAULT_IOCTL_TIMEOUT 0
+#define NVME_IDENTIFY_DATA_SIZE 4096
+#define NVME_IDENTIFY_CSI_SHIFT 24
+#define NVME_IDENTIFY_CNS_NS 0
+#define NVME_CSI_NVM 0
+
+enum nvme_admin_opcode {
+	nvme_admin_identify		= 0x06,
+};
+
+enum nvme_io_opcode {
+	nvme_cmd_write			= 0x01,
+	nvme_cmd_read			= 0x02,
+};
+
+int nsid;
+__u32 lba_shift;
+
+struct nvme_lbaf {
+	__le16			ms;
+	__u8			ds;
+	__u8			rp;
+};
+
+struct nvme_id_ns {
+	__le64			nsze;
+	__le64			ncap;
+	__le64			nuse;
+	__u8			nsfeat;
+	__u8			nlbaf;
+	__u8			flbas;
+	__u8			mc;
+	__u8			dpc;
+	__u8			dps;
+	__u8			nmic;
+	__u8			rescap;
+	__u8			fpi;
+	__u8			dlfeat;
+	__le16			nawun;
+	__le16			nawupf;
+	__le16			nacwu;
+	__le16			nabsn;
+	__le16			nabo;
+	__le16			nabspf;
+	__le16			noiob;
+	__u8			nvmcap[16];
+	__le16			npwg;
+	__le16			npwa;
+	__le16			npdg;
+	__le16			npda;
+	__le16			nows;
+	__le16			mssrl;
+	__le32			mcl;
+	__u8			msrc;
+	__u8			rsvd81[11];
+	__le32			anagrpid;
+	__u8			rsvd96[3];
+	__u8			nsattr;
+	__le16			nvmsetid;
+	__le16			endgid;
+	__u8			nguid[16];
+	__u8			eui64[8];
+	struct nvme_lbaf	lbaf[16];
+	__u8			rsvd192[192];
+	__u8			vs[3712];
+};
+
+static inline int ilog2(uint32_t i)
+{
+	int log = -1;
+
+	while (i) {
+		i >>= 1;
+		log++;
+	}
+	return log;
+}
+
+int fio_nvme_get_info(const char *file)
+{
+	struct nvme_id_ns ns;
+	int fd, err;
+	__u32 lba_size;
+
+	fd = open(file, O_RDONLY);
+	if (fd < 0)
+		return -errno;
+
+	nsid = ioctl(fd, NVME_IOCTL_ID);
+	if (nsid < 0) {
+		fprintf(stderr, "failed to fetch namespace-id\n");
+		close(fd);
+		return -errno;
+	}
+
+	struct nvme_passthru_cmd cmd = {
+		.opcode         = nvme_admin_identify,
+		.nsid           = nsid,
+		.addr           = (__u64)(uintptr_t)&ns,
+		.data_len       = NVME_IDENTIFY_DATA_SIZE,
+		.cdw10          = NVME_IDENTIFY_CNS_NS,
+		.cdw11          = NVME_CSI_NVM << NVME_IDENTIFY_CSI_SHIFT,
+		.timeout_ms     = NVME_DEFAULT_IOCTL_TIMEOUT,
+	};
+
+	err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+	if (err) {
+		fprintf(stderr, "failed to fetch identify namespace\n");
+		close(fd);
+		return err;
+	}
+
+	lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
+	lba_shift = ilog2(lba_size);
+
+	close(fd);
+	return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.17.1


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

* [PATCH liburing v2 4/5] test: add io_uring passthrough test
       [not found]   ` <CGME20220726105816epcas5p3365fed54f9ba20518dd8019a50c6c27c@epcas5p3.samsung.com>
@ 2022-07-26 10:52     ` Ankit Kumar
  2022-07-27 18:04       ` Kanchan Joshi
  2022-07-27 18:26       ` Jens Axboe
  0 siblings, 2 replies; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

Add a way to test uring passthrough commands, which was added
with 5.19 kernel. This requires nvme-ns character device (/dev/ngXnY)
as filename argument. It runs a combination of read/write tests with
sqthread poll, vectored and non-vectored commands, fixed I/O buffers.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
---
 test/Makefile               |   1 +
 test/io_uring_passthrough.c | 319 ++++++++++++++++++++++++++++++++++++
 2 files changed, 320 insertions(+)
 create mode 100644 test/io_uring_passthrough.c

diff --git a/test/Makefile b/test/Makefile
index a36ddb3..418c11c 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -90,6 +90,7 @@ test_srcs := \
 	io-cancel.c \
 	iopoll.c \
 	io_uring_enter.c \
+	io_uring_passthrough.c \
 	io_uring_register.c \
 	io_uring_setup.c \
 	lfs-openat.c \
diff --git a/test/io_uring_passthrough.c b/test/io_uring_passthrough.c
new file mode 100644
index 0000000..2e2b806
--- /dev/null
+++ b/test/io_uring_passthrough.c
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: basic read/write tests for io_uring passthrough commands
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers.h"
+#include "liburing.h"
+#include "nvme.h"
+
+#define FILE_SIZE	(256 * 1024)
+#define BS		8192
+#define BUFFERS		(FILE_SIZE / BS)
+
+static struct iovec *vecs;
+
+/*
+ * Each offset in the file has the ((test_case / 2) * FILE_SIZE)
+ * + (offset / sizeof(int)) stored for every
+ * sizeof(int) address.
+ */
+static int verify_buf(int tc, void *buf, off_t off)
+{
+	int i, u_in_buf = BS / sizeof(unsigned int);
+	unsigned int *ptr;
+
+	off /= sizeof(unsigned int);
+	off += (tc / 2) * FILE_SIZE;
+	ptr = buf;
+	for (i = 0; i < u_in_buf; i++) {
+		if (off != *ptr) {
+			fprintf(stderr, "Found %u, wanted %lu\n", *ptr, off);
+			return 1;
+		}
+		ptr++;
+		off++;
+	}
+
+	return 0;
+}
+
+static int fill_pattern(int tc)
+{
+	unsigned int val, *ptr;
+	int i, j;
+	int u_in_buf = BS / sizeof(val);
+
+	val = (tc / 2) * FILE_SIZE;
+	for (i = 0; i < BUFFERS; i++) {
+		ptr = vecs[i].iov_base;
+		for (j = 0; j < u_in_buf; j++) {
+			*ptr = val;
+			val++;
+			ptr++;
+		}
+	}
+
+	return 0;
+}
+
+static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
+		     int sqthread, int fixed, int nonvec)
+{
+	struct io_uring_sqe *sqe;
+	struct io_uring_cqe *cqe;
+	struct nvme_uring_cmd *cmd;
+	int open_flags;
+	int do_fixed;
+	int i, ret, fd = -1;
+	off_t offset;
+	__u64 slba;
+	__u32 nlb;
+
+#ifdef VERBOSE
+	fprintf(stdout, "%s: start %d/%d/%d/%d: ", __FUNCTION__, read,
+							sqthread, fixed,
+							nonvec);
+#endif
+	if (read)
+		open_flags = O_RDONLY;
+	else
+		open_flags = O_WRONLY;
+
+	if (fixed) {
+		ret = t_register_buffers(ring, vecs, BUFFERS);
+		if (ret == T_SETUP_SKIP)
+			return 0;
+		if (ret != T_SETUP_OK) {
+			fprintf(stderr, "buffer reg failed: %d\n", ret);
+			goto err;
+		}
+	}
+
+	fd = open(file, open_flags);
+	if (fd < 0) {
+		perror("file open");
+		goto err;
+	}
+
+	if (sqthread) {
+		ret = io_uring_register_files(ring, &fd, 1);
+		if (ret) {
+			fprintf(stderr, "file reg failed: %d\n", ret);
+			goto err;
+		}
+	}
+
+	if (!read)
+		fill_pattern(tc);
+
+	offset = 0;
+	for (i = 0; i < BUFFERS; i++) {
+		sqe = io_uring_get_sqe(ring);
+		if (!sqe) {
+			fprintf(stderr, "sqe get failed\n");
+			goto err;
+		}
+		if (read) {
+			int use_fd = fd;
+
+			do_fixed = fixed;
+
+			if (sqthread)
+				use_fd = 0;
+			if (fixed && (i & 1))
+				do_fixed = 0;
+			if (do_fixed) {
+				io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
+								vecs[i].iov_len,
+								offset, i);
+				sqe->cmd_op = NVME_URING_CMD_IO;
+			} else if (nonvec) {
+				io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
+							vecs[i].iov_len, offset);
+				sqe->cmd_op = NVME_URING_CMD_IO;
+			} else {
+				io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
+								offset);
+				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
+			}
+		} else {
+			int use_fd = fd;
+
+			do_fixed = fixed;
+
+			if (sqthread)
+				use_fd = 0;
+			if (fixed && (i & 1))
+				do_fixed = 0;
+			if (do_fixed) {
+				io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
+								vecs[i].iov_len,
+								offset, i);
+				sqe->cmd_op = NVME_URING_CMD_IO;
+			} else if (nonvec) {
+				io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
+							vecs[i].iov_len, offset);
+				sqe->cmd_op = NVME_URING_CMD_IO;
+			} else {
+				io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
+								offset);
+				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
+			}
+		}
+		sqe->opcode = IORING_OP_URING_CMD;
+		sqe->user_data = ((uint64_t)offset << 32) | i;
+		if (sqthread)
+			sqe->flags |= IOSQE_FIXED_FILE;
+
+		/* 80 bytes for NVMe uring passthrough command */
+		cmd = (struct nvme_uring_cmd *)sqe->cmd;
+		memset(cmd, 0, sizeof(struct nvme_uring_cmd));
+
+		cmd->opcode = read ? nvme_cmd_read : nvme_cmd_write;
+
+		slba = offset >> lba_shift;
+		nlb = (BS >> lba_shift) - 1;
+
+		/* cdw10 and cdw11 represent starting lba */
+		cmd->cdw10 = slba & 0xffffffff;
+		cmd->cdw11 = slba >> 32;
+		/* cdw12 represent number of lba's for read/write */
+		cmd->cdw12 = nlb;
+		if (do_fixed || nonvec) {
+			cmd->addr = (__u64)(uintptr_t)vecs[i].iov_base;
+			cmd->data_len = vecs[i].iov_len;
+		} else {
+			cmd->addr = (__u64)(uintptr_t)&vecs[i];
+			cmd->data_len = 1;
+		}
+		cmd->nsid = nsid;
+
+		offset += BS;
+	}
+
+	ret = io_uring_submit(ring);
+	if (ret != BUFFERS) {
+		fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
+		goto err;
+	}
+
+	for (i = 0; i < BUFFERS; i++) {
+		ret = io_uring_wait_cqe(ring, &cqe);
+		if (ret) {
+			fprintf(stderr, "wait_cqe=%d\n", ret);
+			goto err;
+		}
+		if (cqe->res != 0) {
+			fprintf(stderr, "cqe res %d, wanted 0\n", cqe->res);
+			goto err;
+		}
+		io_uring_cqe_seen(ring, cqe);
+		if (read) {
+			int index = cqe->user_data & 0xffffffff;
+			void *buf = vecs[index].iov_base;
+			off_t voff = cqe->user_data >> 32;
+
+			if (verify_buf(tc, buf, voff))
+				goto err;
+		}
+	}
+
+	if (fixed) {
+		ret = io_uring_unregister_buffers(ring);
+		if (ret) {
+			fprintf(stderr, "buffer unreg failed: %d\n", ret);
+			goto err;
+		}
+	}
+	if (sqthread) {
+		ret = io_uring_unregister_files(ring);
+		if (ret) {
+			fprintf(stderr, "file unreg failed: %d\n", ret);
+			goto err;
+		}
+	}
+
+	close(fd);
+#ifdef VERBOSE
+	fprintf(stdout, "PASS\n");
+#endif
+	return 0;
+err:
+#ifdef VERBOSE
+	fprintf(stderr, "FAILED\n");
+#endif
+	if (fd != -1)
+		close(fd);
+	return 1;
+}
+
+static int test_io(const char *file, int tc, int read, int sqthread,
+		   int fixed, int nonvec)
+{
+	struct io_uring ring;
+	int ret, ring_flags = 0;
+
+	ring_flags |= IORING_SETUP_SQE128;
+	ring_flags |= IORING_SETUP_CQE32;
+
+	if (sqthread)
+		ring_flags |= IORING_SETUP_SQPOLL;
+
+	ret = t_create_ring(64, &ring, ring_flags);
+	if (ret == T_SETUP_SKIP)
+		return 0;
+	if (ret != T_SETUP_OK) {
+		fprintf(stderr, "ring create failed: %d\n", ret);
+		return 1;
+	}
+
+	ret = __test_io(file, &ring, tc, read, sqthread, fixed, nonvec);
+	io_uring_queue_exit(&ring);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int i, ret;
+	char *fname;
+
+	if (argc < 2) {
+		printf("%s: requires NVMe character device\n", argv[0]);
+		return T_EXIT_SKIP;
+	}
+
+	fname = argv[1];
+	ret = fio_nvme_get_info(fname);
+
+	if (ret) {
+		fprintf(stderr, "failed to fetch device info: %d\n", ret);
+		goto err;
+	}
+
+	vecs = t_create_buffers(BUFFERS, BS);
+
+	for (i = 0; i < 16; i++) {
+		int read = (i & 1) != 0;
+		int sqthread = (i & 2) != 0;
+		int fixed = (i & 4) != 0;
+		int nonvec = (i & 8) != 0;
+
+		ret = test_io(fname, i, read, sqthread, fixed, nonvec);
+		if (ret) {
+			fprintf(stderr, "test_io failed %d/%d/%d/%d\n",
+				read, sqthread, fixed, nonvec);
+			goto err;
+		}
+	}
+
+	return T_EXIT_PASS;
+err:
+	return T_EXIT_FAIL;
+}
-- 
2.17.1


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

* [PATCH liburing v2 5/5] test/io_uring_passthrough: add test case for poll IO
       [not found]   ` <CGME20220726105817epcas5p450a87008879689894b187924a854d513@epcas5p4.samsung.com>
@ 2022-07-26 10:52     ` Ankit Kumar
  0 siblings, 0 replies; 10+ messages in thread
From: Ankit Kumar @ 2022-07-26 10:52 UTC (permalink / raw)
  To: axboe; +Cc: io-uring, joshi.k, Ankit Kumar

For uring passthrough add test case for poll IO completion.
If poll IO is not supported return success.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
---
 test/io_uring_passthrough.c | 76 +++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/test/io_uring_passthrough.c b/test/io_uring_passthrough.c
index 2e2b806..acb57f8 100644
--- a/test/io_uring_passthrough.c
+++ b/test/io_uring_passthrough.c
@@ -10,6 +10,7 @@
 
 #include "helpers.h"
 #include "liburing.h"
+#include "../src/syscall.h"
 #include "nvme.h"
 
 #define FILE_SIZE	(256 * 1024)
@@ -279,6 +280,75 @@ static int test_io(const char *file, int tc, int read, int sqthread,
 	return ret;
 }
 
+extern int __io_uring_flush_sq(struct io_uring *ring);
+
+/*
+ * if we are polling io_uring_submit needs to always enter the
+ * kernel to fetch events
+ */
+static int test_io_uring_submit_enters(const char *file)
+{
+	struct io_uring ring;
+	int fd, i, ret, ring_flags, open_flags;
+	unsigned head;
+	struct io_uring_cqe *cqe;
+
+	ring_flags = IORING_SETUP_IOPOLL;
+	ring_flags |= IORING_SETUP_SQE128;
+	ring_flags |= IORING_SETUP_CQE32;
+
+	ret = io_uring_queue_init(64, &ring, ring_flags);
+	if (ret) {
+		fprintf(stderr, "ring create failed: %d\n", ret);
+		return 1;
+	}
+
+	open_flags = O_WRONLY;
+	fd = open(file, open_flags);
+	if (fd < 0) {
+		perror("file open");
+		goto err;
+	}
+
+	for (i = 0; i < BUFFERS; i++) {
+		struct io_uring_sqe *sqe;
+		off_t offset = BS * (rand() % BUFFERS);
+
+		sqe = io_uring_get_sqe(&ring);
+		io_uring_prep_writev(sqe, fd, &vecs[i], 1, offset);
+		sqe->user_data = 1;
+	}
+
+	/* submit manually to avoid adding IORING_ENTER_GETEVENTS */
+	ret = __sys_io_uring_enter(ring.ring_fd, __io_uring_flush_sq(&ring), 0,
+						0, NULL);
+	if (ret < 0)
+		goto err;
+
+	for (i = 0; i < 500; i++) {
+		ret = io_uring_submit(&ring);
+		if (ret != 0) {
+			fprintf(stderr, "still had %d sqes to submit, this is unexpected", ret);
+			goto err;
+		}
+
+		io_uring_for_each_cqe(&ring, head, cqe) {
+			if (cqe->res == -EOPNOTSUPP)
+				fprintf(stdout, "doesn't support polled IO\n");
+			goto ok;
+		}
+		usleep(10000);
+	}
+err:
+	ret = 1;
+	if (fd != -1)
+		close(fd);
+
+ok:
+	io_uring_queue_exit(&ring);
+	return ret;
+}
+
 int main(int argc, char *argv[])
 {
 	int i, ret;
@@ -313,6 +383,12 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	ret = test_io_uring_submit_enters(fname);
+	if (ret) {
+		fprintf(stderr, "test_io_uring_submit_enters failed\n");
+		goto err;
+	}
+
 	return T_EXIT_PASS;
 err:
 	return T_EXIT_FAIL;
-- 
2.17.1


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

* Re: [PATCH liburing v2 4/5] test: add io_uring passthrough test
  2022-07-26 10:52     ` [PATCH liburing v2 4/5] test: add io_uring passthrough test Ankit Kumar
@ 2022-07-27 18:04       ` Kanchan Joshi
  2022-07-27 18:26       ` Jens Axboe
  1 sibling, 0 replies; 10+ messages in thread
From: Kanchan Joshi @ 2022-07-27 18:04 UTC (permalink / raw)
  To: Ankit Kumar; +Cc: axboe, io-uring

[-- Attachment #1: Type: text/plain, Size: 5420 bytes --]

On Tue, Jul 26, 2022 at 04:22:29PM +0530, Ankit Kumar wrote:
>Add a way to test uring passthrough commands, which was added
>with 5.19 kernel. This requires nvme-ns character device (/dev/ngXnY)
>as filename argument. It runs a combination of read/write tests with
>sqthread poll, vectored and non-vectored commands, fixed I/O buffers.
>
>Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
>---
> test/Makefile               |   1 +
> test/io_uring_passthrough.c | 319 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 320 insertions(+)
> create mode 100644 test/io_uring_passthrough.c
>
>diff --git a/test/Makefile b/test/Makefile
>index a36ddb3..418c11c 100644
>--- a/test/Makefile
>+++ b/test/Makefile
>@@ -90,6 +90,7 @@ test_srcs := \
> 	io-cancel.c \
> 	iopoll.c \
> 	io_uring_enter.c \
>+	io_uring_passthrough.c \
> 	io_uring_register.c \
> 	io_uring_setup.c \
> 	lfs-openat.c \
>diff --git a/test/io_uring_passthrough.c b/test/io_uring_passthrough.c
>new file mode 100644
>index 0000000..2e2b806
>--- /dev/null
>+++ b/test/io_uring_passthrough.c
>@@ -0,0 +1,319 @@
>+/* SPDX-License-Identifier: MIT */
>+/*
>+ * Description: basic read/write tests for io_uring passthrough commands
>+ */
>+#include <errno.h>
>+#include <stdio.h>
>+#include <unistd.h>
>+#include <stdlib.h>
>+#include <string.h>
>+
>+#include "helpers.h"
>+#include "liburing.h"
>+#include "nvme.h"
>+
>+#define FILE_SIZE	(256 * 1024)
>+#define BS		8192
>+#define BUFFERS		(FILE_SIZE / BS)
>+
>+static struct iovec *vecs;
>+
>+/*
>+ * Each offset in the file has the ((test_case / 2) * FILE_SIZE)
>+ * + (offset / sizeof(int)) stored for every
>+ * sizeof(int) address.
>+ */
>+static int verify_buf(int tc, void *buf, off_t off)
>+{
>+	int i, u_in_buf = BS / sizeof(unsigned int);
>+	unsigned int *ptr;
>+
>+	off /= sizeof(unsigned int);
>+	off += (tc / 2) * FILE_SIZE;
>+	ptr = buf;
>+	for (i = 0; i < u_in_buf; i++) {
>+		if (off != *ptr) {
>+			fprintf(stderr, "Found %u, wanted %lu\n", *ptr, off);
>+			return 1;
>+		}
>+		ptr++;
>+		off++;
>+	}
>+
>+	return 0;
>+}
>+
>+static int fill_pattern(int tc)
>+{
>+	unsigned int val, *ptr;
>+	int i, j;
>+	int u_in_buf = BS / sizeof(val);
>+
>+	val = (tc / 2) * FILE_SIZE;
>+	for (i = 0; i < BUFFERS; i++) {
>+		ptr = vecs[i].iov_base;
>+		for (j = 0; j < u_in_buf; j++) {
>+			*ptr = val;
>+			val++;
>+			ptr++;
>+		}
>+	}
>+
>+	return 0;
>+}
>+
>+static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
>+		     int sqthread, int fixed, int nonvec)
>+{
>+	struct io_uring_sqe *sqe;
>+	struct io_uring_cqe *cqe;
>+	struct nvme_uring_cmd *cmd;
>+	int open_flags;
>+	int do_fixed;
>+	int i, ret, fd = -1;
>+	off_t offset;
>+	__u64 slba;
>+	__u32 nlb;
>+
>+#ifdef VERBOSE
>+	fprintf(stdout, "%s: start %d/%d/%d/%d: ", __FUNCTION__, read,
>+							sqthread, fixed,
>+							nonvec);
>+#endif
>+	if (read)
>+		open_flags = O_RDONLY;
>+	else
>+		open_flags = O_WRONLY;
>+
>+	if (fixed) {
>+		ret = t_register_buffers(ring, vecs, BUFFERS);
>+		if (ret == T_SETUP_SKIP)
>+			return 0;
>+		if (ret != T_SETUP_OK) {
>+			fprintf(stderr, "buffer reg failed: %d\n", ret);
>+			goto err;
>+		}
>+	}
>+
>+	fd = open(file, open_flags);
>+	if (fd < 0) {
>+		perror("file open");
>+		goto err;
>+	}
>+
>+	if (sqthread) {
>+		ret = io_uring_register_files(ring, &fd, 1);
>+		if (ret) {
>+			fprintf(stderr, "file reg failed: %d\n", ret);
>+			goto err;
>+		}
>+	}
>+
>+	if (!read)
>+		fill_pattern(tc);
>+
>+	offset = 0;
>+	for (i = 0; i < BUFFERS; i++) {
>+		sqe = io_uring_get_sqe(ring);
>+		if (!sqe) {
>+			fprintf(stderr, "sqe get failed\n");
>+			goto err;
>+		}
>+		if (read) {
>+			int use_fd = fd;
>+
>+			do_fixed = fixed;
>+
>+			if (sqthread)
>+				use_fd = 0;
>+			if (fixed && (i & 1))
>+				do_fixed = 0;
>+			if (do_fixed) {
>+				io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
>+								vecs[i].iov_len,
>+								offset, i);
>+				sqe->cmd_op = NVME_URING_CMD_IO;
>+			} else if (nonvec) {
>+				io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
>+							vecs[i].iov_len, offset);
>+				sqe->cmd_op = NVME_URING_CMD_IO;
>+			} else {
>+				io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
>+								offset);
>+				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
>+			}
>+		} else {
>+			int use_fd = fd;
>+
>+			do_fixed = fixed;
>+
>+			if (sqthread)
>+				use_fd = 0;
>+			if (fixed && (i & 1))
>+				do_fixed = 0;
>+			if (do_fixed) {
>+				io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
>+								vecs[i].iov_len,
>+								offset, i);
>+				sqe->cmd_op = NVME_URING_CMD_IO;
>+			} else if (nonvec) {
>+				io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
>+							vecs[i].iov_len, offset);
>+				sqe->cmd_op = NVME_URING_CMD_IO;
>+			} else {
>+				io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
>+								offset);
>+				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
>+			}
>+		}
>+		sqe->opcode = IORING_OP_URING_CMD;
>+		sqe->user_data = ((uint64_t)offset << 32) | i;
>+		if (sqthread)
>+			sqe->flags |= IOSQE_FIXED_FILE;
>+
>+		/* 80 bytes for NVMe uring passthrough command */
>+		cmd = (struct nvme_uring_cmd *)sqe->cmd;
>+		memset(cmd, 0, sizeof(struct nvme_uring_cmd));

The above 80 bytes commment does not serve much purpose since
you are using sizeof(struct nvme_uring_cmd) anyway and do not use the
magic number. Moreover actual size is 72 bytes. But this is a nit and
things look fine to me, so -

Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



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

* Re: [PATCH liburing v2 3/5] nvme: add nvme opcodes, structures and helper functions
  2022-07-26 10:52     ` [PATCH liburing v2 3/5] nvme: add nvme opcodes, structures and helper functions Ankit Kumar
@ 2022-07-27 18:24       ` Jens Axboe
  0 siblings, 0 replies; 10+ messages in thread
From: Jens Axboe @ 2022-07-27 18:24 UTC (permalink / raw)
  To: Ankit Kumar; +Cc: io-uring, joshi.k

On 7/26/22 4:52 AM, Ankit Kumar wrote:
> Add bare minimum structures and helper functions required for
> io_uring passthrough commands. This will enable the follow up
> patch to add tests for nvme-ns generic character device.
> 
> Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
> ---
>  test/nvme.h | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 168 insertions(+)
>  create mode 100644 test/nvme.h
> 
> diff --git a/test/nvme.h b/test/nvme.h
> new file mode 100644
> index 0000000..866a7e6
> --- /dev/null
> +++ b/test/nvme.h
> @@ -0,0 +1,168 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Description: Helpers for NVMe uring passthrough commands
> + */
> +#ifndef LIBURING_NVME_H
> +#define LIBURING_NVME_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <sys/ioctl.h>
> +#include <linux/nvme_ioctl.h>
> +
> +/*
> + * If the uapi headers installed on the system lacks nvme uring command
> + * support, use the local version to prevent compilation issues.
> + */
> +#ifndef CONFIG_HAVE_NVME_URING
> +struct nvme_uring_cmd {
> +	__u8	opcode;
> +	__u8	flags;
> +	__u16	rsvd1;
> +	__u32	nsid;
> +	__u32	cdw2;
> +	__u32	cdw3;
> +	__u64	metadata;
> +	__u64	addr;
> +	__u32	metadata_len;
> +	__u32	data_len;
> +	__u32	cdw10;
> +	__u32	cdw11;
> +	__u32	cdw12;
> +	__u32	cdw13;
> +	__u32	cdw14;
> +	__u32	cdw15;
> +	__u32	timeout_ms;
> +	__u32   rsvd2;
> +};
> +
> +#define NVME_URING_CMD_IO	_IOWR('N', 0x80, struct nvme_uring_cmd)
> +#define NVME_URING_CMD_IO_VEC	_IOWR('N', 0x81, struct nvme_uring_cmd)
> +#endif /* CONFIG_HAVE_NVME_URING */
> +
> +#define NVME_DEFAULT_IOCTL_TIMEOUT 0
> +#define NVME_IDENTIFY_DATA_SIZE 4096
> +#define NVME_IDENTIFY_CSI_SHIFT 24
> +#define NVME_IDENTIFY_CNS_NS 0
> +#define NVME_CSI_NVM 0
> +
> +enum nvme_admin_opcode {
> +	nvme_admin_identify		= 0x06,
> +};
> +
> +enum nvme_io_opcode {
> +	nvme_cmd_write			= 0x01,
> +	nvme_cmd_read			= 0x02,
> +};
> +
> +int nsid;
> +__u32 lba_shift;
> +
> +struct nvme_lbaf {
> +	__le16			ms;
> +	__u8			ds;
> +	__u8			rp;
> +};
> +
> +struct nvme_id_ns {
> +	__le64			nsze;
> +	__le64			ncap;
> +	__le64			nuse;
> +	__u8			nsfeat;
> +	__u8			nlbaf;
> +	__u8			flbas;
> +	__u8			mc;
> +	__u8			dpc;
> +	__u8			dps;
> +	__u8			nmic;
> +	__u8			rescap;
> +	__u8			fpi;
> +	__u8			dlfeat;
> +	__le16			nawun;
> +	__le16			nawupf;
> +	__le16			nacwu;
> +	__le16			nabsn;
> +	__le16			nabo;
> +	__le16			nabspf;
> +	__le16			noiob;
> +	__u8			nvmcap[16];
> +	__le16			npwg;
> +	__le16			npwa;
> +	__le16			npdg;
> +	__le16			npda;
> +	__le16			nows;
> +	__le16			mssrl;
> +	__le32			mcl;
> +	__u8			msrc;
> +	__u8			rsvd81[11];
> +	__le32			anagrpid;
> +	__u8			rsvd96[3];
> +	__u8			nsattr;
> +	__le16			nvmsetid;
> +	__le16			endgid;
> +	__u8			nguid[16];
> +	__u8			eui64[8];
> +	struct nvme_lbaf	lbaf[16];
> +	__u8			rsvd192[192];
> +	__u8			vs[3712];
> +};
> +
> +static inline int ilog2(uint32_t i)
> +{
> +	int log = -1;
> +
> +	while (i) {
> +		i >>= 1;
> +		log++;
> +	}
> +	return log;
> +}
> +
> +int fio_nvme_get_info(const char *file)
> +{
> +	struct nvme_id_ns ns;
> +	int fd, err;
> +	__u32 lba_size;
> +
> +	fd = open(file, O_RDONLY);
> +	if (fd < 0)
> +		return -errno;
> +
> +	nsid = ioctl(fd, NVME_IOCTL_ID);
> +	if (nsid < 0) {
> +		fprintf(stderr, "failed to fetch namespace-id\n");
> +		close(fd);
> +		return -errno;
> +	}
> +
> +	struct nvme_passthru_cmd cmd = {
> +		.opcode         = nvme_admin_identify,
> +		.nsid           = nsid,
> +		.addr           = (__u64)(uintptr_t)&ns,
> +		.data_len       = NVME_IDENTIFY_DATA_SIZE,
> +		.cdw10          = NVME_IDENTIFY_CNS_NS,
> +		.cdw11          = NVME_CSI_NVM << NVME_IDENTIFY_CSI_SHIFT,
> +		.timeout_ms     = NVME_DEFAULT_IOCTL_TIMEOUT,
> +	};
> +
> +	err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
> +	if (err) {
> +		fprintf(stderr, "failed to fetch identify namespace\n");
> +		close(fd);
> +		return err;
> +	}
> +
> +	lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
> +	lba_shift = ilog2(lba_size);
> +
> +	close(fd);
> +	return 0;
> +}

Too much copy pasting I think? Probably should not prefix this one with
fio?

-- 
Jens Axboe


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

* Re: [PATCH liburing v2 4/5] test: add io_uring passthrough test
  2022-07-26 10:52     ` [PATCH liburing v2 4/5] test: add io_uring passthrough test Ankit Kumar
  2022-07-27 18:04       ` Kanchan Joshi
@ 2022-07-27 18:26       ` Jens Axboe
  1 sibling, 0 replies; 10+ messages in thread
From: Jens Axboe @ 2022-07-27 18:26 UTC (permalink / raw)
  To: Ankit Kumar; +Cc: io-uring, joshi.k

On 7/26/22 4:52 AM, Ankit Kumar wrote:
> Add a way to test uring passthrough commands, which was added
> with 5.19 kernel. This requires nvme-ns character device (/dev/ngXnY)
> as filename argument. It runs a combination of read/write tests with
> sqthread poll, vectored and non-vectored commands, fixed I/O buffers.
> 
> Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
> ---
>  test/Makefile               |   1 +
>  test/io_uring_passthrough.c | 319 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 320 insertions(+)
>  create mode 100644 test/io_uring_passthrough.c
> 
> diff --git a/test/Makefile b/test/Makefile
> index a36ddb3..418c11c 100644
> --- a/test/Makefile
> +++ b/test/Makefile
> @@ -90,6 +90,7 @@ test_srcs := \
>  	io-cancel.c \
>  	iopoll.c \
>  	io_uring_enter.c \
> +	io_uring_passthrough.c \
>  	io_uring_register.c \
>  	io_uring_setup.c \
>  	lfs-openat.c \
> diff --git a/test/io_uring_passthrough.c b/test/io_uring_passthrough.c
> new file mode 100644
> index 0000000..2e2b806
> --- /dev/null
> +++ b/test/io_uring_passthrough.c
> @@ -0,0 +1,319 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Description: basic read/write tests for io_uring passthrough commands
> + */
> +#include <errno.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "helpers.h"
> +#include "liburing.h"
> +#include "nvme.h"
> +
> +#define FILE_SIZE	(256 * 1024)
> +#define BS		8192
> +#define BUFFERS		(FILE_SIZE / BS)
> +
> +static struct iovec *vecs;
> +
> +/*
> + * Each offset in the file has the ((test_case / 2) * FILE_SIZE)
> + * + (offset / sizeof(int)) stored for every
> + * sizeof(int) address.
> + */
> +static int verify_buf(int tc, void *buf, off_t off)
> +{
> +	int i, u_in_buf = BS / sizeof(unsigned int);
> +	unsigned int *ptr;
> +
> +	off /= sizeof(unsigned int);
> +	off += (tc / 2) * FILE_SIZE;
> +	ptr = buf;
> +	for (i = 0; i < u_in_buf; i++) {
> +		if (off != *ptr) {
> +			fprintf(stderr, "Found %u, wanted %lu\n", *ptr, off);
> +			return 1;
> +		}
> +		ptr++;
> +		off++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int fill_pattern(int tc)
> +{
> +	unsigned int val, *ptr;
> +	int i, j;
> +	int u_in_buf = BS / sizeof(val);
> +
> +	val = (tc / 2) * FILE_SIZE;
> +	for (i = 0; i < BUFFERS; i++) {
> +		ptr = vecs[i].iov_base;
> +		for (j = 0; j < u_in_buf; j++) {
> +			*ptr = val;
> +			val++;
> +			ptr++;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int __test_io(const char *file, struct io_uring *ring, int tc, int read,
> +		     int sqthread, int fixed, int nonvec)
> +{
> +	struct io_uring_sqe *sqe;
> +	struct io_uring_cqe *cqe;
> +	struct nvme_uring_cmd *cmd;
> +	int open_flags;
> +	int do_fixed;
> +	int i, ret, fd = -1;
> +	off_t offset;
> +	__u64 slba;
> +	__u32 nlb;
> +
> +#ifdef VERBOSE
> +	fprintf(stdout, "%s: start %d/%d/%d/%d: ", __FUNCTION__, read,
> +							sqthread, fixed,
> +							nonvec);
> +#endif
> +	if (read)
> +		open_flags = O_RDONLY;
> +	else
> +		open_flags = O_WRONLY;
> +
> +	if (fixed) {
> +		ret = t_register_buffers(ring, vecs, BUFFERS);
> +		if (ret == T_SETUP_SKIP)
> +			return 0;
> +		if (ret != T_SETUP_OK) {
> +			fprintf(stderr, "buffer reg failed: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +
> +	fd = open(file, open_flags);
> +	if (fd < 0) {
> +		perror("file open");
> +		goto err;
> +	}
> +
> +	if (sqthread) {
> +		ret = io_uring_register_files(ring, &fd, 1);
> +		if (ret) {
> +			fprintf(stderr, "file reg failed: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +
> +	if (!read)
> +		fill_pattern(tc);
> +
> +	offset = 0;
> +	for (i = 0; i < BUFFERS; i++) {
> +		sqe = io_uring_get_sqe(ring);
> +		if (!sqe) {
> +			fprintf(stderr, "sqe get failed\n");
> +			goto err;
> +		}
> +		if (read) {
> +			int use_fd = fd;
> +
> +			do_fixed = fixed;
> +
> +			if (sqthread)
> +				use_fd = 0;
> +			if (fixed && (i & 1))
> +				do_fixed = 0;
> +			if (do_fixed) {
> +				io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
> +								vecs[i].iov_len,
> +								offset, i);
> +				sqe->cmd_op = NVME_URING_CMD_IO;
> +			} else if (nonvec) {
> +				io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
> +							vecs[i].iov_len, offset);
> +				sqe->cmd_op = NVME_URING_CMD_IO;
> +			} else {
> +				io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
> +								offset);
> +				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
> +			}
> +		} else {
> +			int use_fd = fd;
> +
> +			do_fixed = fixed;
> +
> +			if (sqthread)
> +				use_fd = 0;
> +			if (fixed && (i & 1))
> +				do_fixed = 0;
> +			if (do_fixed) {
> +				io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
> +								vecs[i].iov_len,
> +								offset, i);
> +				sqe->cmd_op = NVME_URING_CMD_IO;
> +			} else if (nonvec) {
> +				io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
> +							vecs[i].iov_len, offset);
> +				sqe->cmd_op = NVME_URING_CMD_IO;
> +			} else {
> +				io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
> +								offset);
> +				sqe->cmd_op = NVME_URING_CMD_IO_VEC;
> +			}
> +		}
> +		sqe->opcode = IORING_OP_URING_CMD;
> +		sqe->user_data = ((uint64_t)offset << 32) | i;
> +		if (sqthread)
> +			sqe->flags |= IOSQE_FIXED_FILE;
> +
> +		/* 80 bytes for NVMe uring passthrough command */
> +		cmd = (struct nvme_uring_cmd *)sqe->cmd;
> +		memset(cmd, 0, sizeof(struct nvme_uring_cmd));
> +
> +		cmd->opcode = read ? nvme_cmd_read : nvme_cmd_write;
> +
> +		slba = offset >> lba_shift;
> +		nlb = (BS >> lba_shift) - 1;
> +
> +		/* cdw10 and cdw11 represent starting lba */
> +		cmd->cdw10 = slba & 0xffffffff;
> +		cmd->cdw11 = slba >> 32;
> +		/* cdw12 represent number of lba's for read/write */
> +		cmd->cdw12 = nlb;
> +		if (do_fixed || nonvec) {
> +			cmd->addr = (__u64)(uintptr_t)vecs[i].iov_base;
> +			cmd->data_len = vecs[i].iov_len;
> +		} else {
> +			cmd->addr = (__u64)(uintptr_t)&vecs[i];
> +			cmd->data_len = 1;
> +		}
> +		cmd->nsid = nsid;
> +
> +		offset += BS;
> +	}
> +
> +	ret = io_uring_submit(ring);
> +	if (ret != BUFFERS) {
> +		fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
> +		goto err;
> +	}
> +
> +	for (i = 0; i < BUFFERS; i++) {
> +		ret = io_uring_wait_cqe(ring, &cqe);
> +		if (ret) {
> +			fprintf(stderr, "wait_cqe=%d\n", ret);
> +			goto err;
> +		}
> +		if (cqe->res != 0) {
> +			fprintf(stderr, "cqe res %d, wanted 0\n", cqe->res);
> +			goto err;
> +		}
> +		io_uring_cqe_seen(ring, cqe);
> +		if (read) {
> +			int index = cqe->user_data & 0xffffffff;
> +			void *buf = vecs[index].iov_base;
> +			off_t voff = cqe->user_data >> 32;
> +
> +			if (verify_buf(tc, buf, voff))
> +				goto err;
> +		}
> +	}
> +
> +	if (fixed) {
> +		ret = io_uring_unregister_buffers(ring);
> +		if (ret) {
> +			fprintf(stderr, "buffer unreg failed: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +	if (sqthread) {
> +		ret = io_uring_unregister_files(ring);
> +		if (ret) {
> +			fprintf(stderr, "file unreg failed: %d\n", ret);
> +			goto err;
> +		}
> +	}
> +
> +	close(fd);
> +#ifdef VERBOSE
> +	fprintf(stdout, "PASS\n");
> +#endif
> +	return 0;
> +err:
> +#ifdef VERBOSE
> +	fprintf(stderr, "FAILED\n");
> +#endif
> +	if (fd != -1)
> +		close(fd);
> +	return 1;
> +}
> +
> +static int test_io(const char *file, int tc, int read, int sqthread,
> +		   int fixed, int nonvec)
> +{
> +	struct io_uring ring;
> +	int ret, ring_flags = 0;
> +
> +	ring_flags |= IORING_SETUP_SQE128;
> +	ring_flags |= IORING_SETUP_CQE32;
> +
> +	if (sqthread)
> +		ring_flags |= IORING_SETUP_SQPOLL;
> +
> +	ret = t_create_ring(64, &ring, ring_flags);
> +	if (ret == T_SETUP_SKIP)
> +		return 0;
> +	if (ret != T_SETUP_OK) {
> +		fprintf(stderr, "ring create failed: %d\n", ret);
> +		return 1;
> +	}
> +
> +	ret = __test_io(file, &ring, tc, read, sqthread, fixed, nonvec);
> +	io_uring_queue_exit(&ring);
> +
> +	return ret;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int i, ret;
> +	char *fname;
> +
> +	if (argc < 2) {
> +		printf("%s: requires NVMe character device\n", argv[0]);
> +		return T_EXIT_SKIP;
> +	}
> +
> +	fname = argv[1];
> +	ret = fio_nvme_get_info(fname);
> +
> +	if (ret) {
> +		fprintf(stderr, "failed to fetch device info: %d\n", ret);
> +		goto err;
> +	}

If we can't open the device, then we should probably turn this into a
SKIP rather than a FAIL?

Same for if the argument passed isn't actually an nvme device, it should
just skip the test in that case rather than print errors.

-- 
Jens Axboe


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

* Re: [PATCH liburing v2 0/5] Add basic test for nvme uring passthrough commands
  2022-07-26 10:52 ` [PATCH liburing v2 0/5] Add basic test for nvme uring passthrough commands Ankit Kumar
                     ` (4 preceding siblings ...)
       [not found]   ` <CGME20220726105817epcas5p450a87008879689894b187924a854d513@epcas5p4.samsung.com>
@ 2022-07-27 18:27   ` Kanchan Joshi
  5 siblings, 0 replies; 10+ messages in thread
From: Kanchan Joshi @ 2022-07-27 18:27 UTC (permalink / raw)
  To: Ankit Kumar; +Cc: axboe, io-uring

[-- Attachment #1: Type: text/plain, Size: 1108 bytes --]

On Tue, Jul 26, 2022 at 04:22:25PM +0530, Ankit Kumar wrote:
>Hi Jens,
>
>This patchset adds a way to test NVMe uring passthrough commands with
>nvme-ns character device. The uring passthrough was introduced with 5.19
>io_uring.
>
>To send nvme uring passthrough commands we require helpers to fetch NVMe
>char device (/dev/ngXnY) specific fields such as namespace id, lba size etc.
>
>How to run:
>./test/io_uring_passthrough.t /dev/ng0n1
>
>The test covers write/read with verify for sqthread poll, vectored / nonvectored
>and fixed IO buffers, which can be extended in future. As of now iopoll is not
>supported for passthrough commands, there is a test for such case.

./test/io_uring_passthrough.t /dev/ng0n1
doesn't support polled IO                 

Not sure if iopoll test is bit premature, as above message will keep
coming until this is wired up in kernel-side.
Perhaps this is fine to test as in initial stages graceful no-support
error code was not coming from kernel. The above confirms that
kernel bails out fine now.

Things ran fine for me, so
Tested-by: Kanchan Joshi <joshi.k@samsung.com>

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



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

end of thread, other threads:[~2022-07-27 19:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20220726105812epcas5p4a2946262206548f67e238845e23a122c@epcas5p4.samsung.com>
2022-07-26 10:52 ` [PATCH liburing v2 0/5] Add basic test for nvme uring passthrough commands Ankit Kumar
     [not found]   ` <CGME20220726105813epcas5p44c4058c9d3e9332ef939dbbb9a052738@epcas5p4.samsung.com>
2022-07-26 10:52     ` [PATCH liburing v2 1/5] configure: check for nvme uring command support Ankit Kumar
     [not found]   ` <CGME20220726105814epcas5p4b454a04c6f7befa23788b5a6bf3031c3@epcas5p4.samsung.com>
2022-07-26 10:52     ` [PATCH liburing v2 2/5] io_uring.h: sync sqe entry with 5.20 io_uring Ankit Kumar
     [not found]   ` <CGME20220726105815epcas5p2e19ff2fe748cfeb69517124370de3b7f@epcas5p2.samsung.com>
2022-07-26 10:52     ` [PATCH liburing v2 3/5] nvme: add nvme opcodes, structures and helper functions Ankit Kumar
2022-07-27 18:24       ` Jens Axboe
     [not found]   ` <CGME20220726105816epcas5p3365fed54f9ba20518dd8019a50c6c27c@epcas5p3.samsung.com>
2022-07-26 10:52     ` [PATCH liburing v2 4/5] test: add io_uring passthrough test Ankit Kumar
2022-07-27 18:04       ` Kanchan Joshi
2022-07-27 18:26       ` Jens Axboe
     [not found]   ` <CGME20220726105817epcas5p450a87008879689894b187924a854d513@epcas5p4.samsung.com>
2022-07-26 10:52     ` [PATCH liburing v2 5/5] test/io_uring_passthrough: add test case for poll IO Ankit Kumar
2022-07-27 18:27   ` [PATCH liburing v2 0/5] Add basic test for nvme uring passthrough commands Kanchan Joshi

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.