* [LTP] [PATCH v4] io_uring: Add test for READV and WRITEV operations
@ 2026-04-16 6:23 Sachin Sant
2026-04-16 8:02 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 2+ messages in thread
From: Sachin Sant @ 2026-04-16 6:23 UTC (permalink / raw)
To: ltp
Add a test to validate vectored read and write operations using io_uring.
1. IORING_OP_WRITEV - Writing data using multiple buffers (scatter)
2. IORING_OP_READV - Reading data into multiple buffers (gather)
3. Data integrity verification across multiple iovecs
4. Edge cases with different iovec configurations including zero
buffer length
Additionally merge io_uring_init_buffer_pattern() into unified
init_iovec_buffers() function that supports both rotating and
simple character patterns
Signed-off-by: Sachin Sant <sachinp@linux.ibm.com>
---
V4 changes:
- Updated commit message to remove references to non-existent function
- Removed extra blank line before test_writev_readv()
- Link to v3 https://lore.kernel.org/ltp/20260416042531.81093-1-sachinp@linux.ibm.com/T/
V3 changes (2/3 io_uring04 only):
- 1/3 and 3/3 from the patch series already merged.
- Merged prepare_read_buffers() and clear_iovec_buffers() into
single clear_iovec_buffers() function
- Merged io_uring_init_buffer_pattern() into unified
init_iovec_buffers() function that supports both rotating and
simple character patterns
- Removed io_uring_init_buffer_pattern() from io_uring_common.h as it's
only used in io_uring04.c
- Link to V2: https://lore.kernel.org/ltp/b4653e3f-ac9b-4a24-8d3f-51677c488e8c@linux.ibm.com/T/
V2 changes:
- Use guarded buffer(including iovec) allocation
- Move setup/cleanup code from run to appropriate path
- Add a function to map the OP to the enum name
- Define and use generic cleanup functions
- Add a buffer size 0 in the middle of the iovec
- Simplify setup_io_uring_test to use common code.
- Link to V1: https://lore.kernel.org/ltp/20260320124742.75946-1-sachinp@linux.ibm.com/T/#t
Changes after RFC patch series:
- Addressed review comments
- Refactored io_uring01 test to use common code
- Removed git tags
- Link to RFC: https://lore.kernel.org/ltp/20260318110328.52031-1-sachinp@linux.ibm.com/T/#t
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/io_uring/.gitignore | 1 +
.../kernel/syscalls/io_uring/io_uring04.c | 221 ++++++++++++++++++
.../syscalls/io_uring/io_uring_common.h | 13 --
4 files changed, 223 insertions(+), 13 deletions(-)
create mode 100644 testcases/kernel/syscalls/io_uring/io_uring04.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 5025b259f..aa7a91d97 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1901,6 +1901,7 @@ membarrier01 membarrier01
io_uring01 io_uring01
io_uring02 io_uring02
io_uring03 io_uring03
+io_uring04 io_uring04
# Tests below may cause kernel memory leak
perf_event_open03 perf_event_open03
diff --git a/testcases/kernel/syscalls/io_uring/.gitignore b/testcases/kernel/syscalls/io_uring/.gitignore
index 9382ae413..36cd24662 100644
--- a/testcases/kernel/syscalls/io_uring/.gitignore
+++ b/testcases/kernel/syscalls/io_uring/.gitignore
@@ -1,3 +1,4 @@
/io_uring01
/io_uring02
/io_uring03
+/io_uring04
diff --git a/testcases/kernel/syscalls/io_uring/io_uring04.c b/testcases/kernel/syscalls/io_uring/io_uring04.c
new file mode 100644
index 000000000..7ff0b194f
--- /dev/null
+++ b/testcases/kernel/syscalls/io_uring/io_uring04.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 IBM
+ * Author: Sachin Sant <sachinp@linux.ibm.com>
+ */
+/*\
+ * Test IORING_OP_READV and IORING_OP_WRITEV operations.
+ *
+ * This test validates vectored read and write operations using io_uring.
+ * It tests:
+ * 1. IORING_OP_WRITEV - Writing data using multiple buffers (scatter)
+ * 2. IORING_OP_READV - Reading data into multiple buffers (gather)
+ * 3. Data integrity verification across multiple iovecs
+ * 4. Edge cases with different iovec configurations
+ */
+
+#include "io_uring_common.h"
+
+#define TEST_FILE "io_uring_test_file"
+#define QUEUE_DEPTH 2
+#define NUM_VECS 4
+#define VEC_SIZE 1024
+#define VAR_BUF1_SIZE 512
+#define VAR_BUF2_SIZE 1024
+#define VAR_BUF3_SIZE 256
+
+static struct iovec *write_iovs, *read_iovs;
+static struct iovec *var_write_iovs, *var_read_iovs;
+static struct io_uring_submit s;
+static sigset_t sig;
+
+/*
+ * Initialize iovec buffers with pattern
+ * @iovs: array of iovec structures
+ * @nvecs: number of iovecs
+ * @base_char: base character for pattern
+ * @use_rotating: if true, use rotating pattern; if false, use simple repeat
+ */
+static void init_iovec_buffers(struct iovec *iovs, int nvecs,
+ char base_char, int use_rotating)
+{
+ int i;
+ size_t j;
+ char *buf;
+
+ for (i = 0; i < nvecs; i++) {
+ if (iovs[i].iov_len == 0)
+ continue;
+
+ buf = (char *)iovs[i].iov_base;
+ if (use_rotating) {
+ /* Each vector has a different rotating pattern */
+ for (j = 0; j < iovs[i].iov_len; j++)
+ buf[j] = base_char + i + (j % 26);
+ } else {
+ for (j = 0; j < iovs[i].iov_len; j++)
+ buf[j] = base_char + i;
+ }
+ }
+}
+
+static void clear_iovec_buffers(struct iovec *iovs, int nvecs)
+{
+ int i;
+
+ for (i = 0; i < nvecs; i++)
+ memset(iovs[i].iov_base, 0, iovs[i].iov_len);
+}
+
+static void verify_iovec_data(struct iovec *write_iovs, struct iovec *read_iovs,
+ int nvecs, const char *test_name)
+{
+ int i;
+ size_t j;
+
+ for (i = 0; i < nvecs; i++) {
+ if (write_iovs[i].iov_len != read_iovs[i].iov_len) {
+ tst_res(TFAIL, "%s: iovec %d length mismatch: write=%zu read=%zu",
+ test_name, i, write_iovs[i].iov_len, read_iovs[i].iov_len);
+ return;
+ }
+
+ if (memcmp(write_iovs[i].iov_base, read_iovs[i].iov_base,
+ write_iovs[i].iov_len) != 0) {
+ tst_res(TFAIL, "%s: data mismatch in vector %d", test_name, i);
+ for (j = 0; j < write_iovs[i].iov_len && j < 64; j++) {
+ char *wbuf = (char *)write_iovs[i].iov_base;
+ char *rbuf = (char *)read_iovs[i].iov_base;
+ if (wbuf[j] != rbuf[j]) {
+ tst_res(TINFO, "Vector %d: first mismatch at "
+ "offset %zu: wrote 0x%02x, read 0x%02x",
+ i, j, wbuf[j], rbuf[j]);
+ break;
+ }
+ }
+ return;
+ }
+ }
+
+ tst_res(TPASS, "%s: data integrity verified across %d vectors",
+ test_name, nvecs);
+}
+
+static void test_writev_readv(void)
+{
+ int fd;
+ int total_size = NUM_VECS * VEC_SIZE;
+
+ tst_res(TINFO, "Testing IORING_OP_WRITEV and IORING_OP_READV");
+
+ fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
+
+ tst_res(TINFO, "Writing %d bytes using %d vectors", total_size, NUM_VECS);
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_WRITEV, write_iovs, NUM_VECS,
+ 0, total_size, &sig);
+
+ SAFE_FSYNC(fd);
+
+ tst_res(TINFO, "Reading %d bytes using %d vectors", total_size, NUM_VECS);
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_READV, read_iovs, NUM_VECS,
+ 0, total_size, &sig);
+
+ verify_iovec_data(write_iovs, read_iovs, NUM_VECS, "Basic vectored I/O");
+
+ SAFE_CLOSE(fd);
+}
+
+static void test_partial_vectors(void)
+{
+ int fd;
+ int half_size = 2 * VEC_SIZE;
+
+ tst_res(TINFO, "Testing partial vector operations");
+
+ fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
+
+ /* Write first half using first 2 vectors at offset 0 */
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_WRITEV, write_iovs, 2, 0,
+ half_size, &sig);
+
+ /* Write second half using next 2 vectors at offset half_size */
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_WRITEV, &write_iovs[2], 2,
+ half_size, half_size, &sig);
+
+ SAFE_FSYNC(fd);
+
+ /* Read back entire file using all 4 vectors */
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_READV, read_iovs, NUM_VECS, 0,
+ NUM_VECS * VEC_SIZE, &sig);
+
+ verify_iovec_data(write_iovs, read_iovs, NUM_VECS, "Partial vector I/O");
+
+ SAFE_CLOSE(fd);
+}
+
+static void test_varying_sizes(void)
+{
+ int fd;
+ int expected_size = VAR_BUF1_SIZE + VAR_BUF2_SIZE + VAR_BUF3_SIZE;
+
+ tst_res(TINFO, "Testing vectors with varying sizes including zero-length buffer");
+
+ init_iovec_buffers(var_write_iovs, 4, 'X', 0);
+
+ clear_iovec_buffers(var_read_iovs, 4);
+
+ fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
+
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_WRITEV, var_write_iovs, 4, 0,
+ expected_size, &sig);
+
+ SAFE_FSYNC(fd);
+
+ io_uring_do_vec_io_op(&s, fd, IORING_OP_READV, var_read_iovs, 4, 0,
+ expected_size, &sig);
+
+ verify_iovec_data(var_write_iovs, var_read_iovs, 4, "Varying size vector I/O with zero-length buffer");
+
+ SAFE_CLOSE(fd);
+}
+
+static void run(void)
+{
+ test_writev_readv();
+ test_partial_vectors();
+ test_varying_sizes();
+}
+
+static void setup(void)
+{
+ io_uring_setup_supported_by_kernel();
+ sigemptyset(&sig);
+ memset(&s, 0, sizeof(s));
+ io_uring_setup_queue(&s, QUEUE_DEPTH, 0);
+ init_iovec_buffers(write_iovs, NUM_VECS, 'A', 1);
+ clear_iovec_buffers(read_iovs, NUM_VECS);
+}
+
+static void cleanup(void)
+{
+ io_uring_cleanup_queue(&s, QUEUE_DEPTH);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_tmpdir = 1,
+ .bufs = (struct tst_buffers []) {
+ {&write_iovs, .iov_sizes = (int[]){VEC_SIZE, VEC_SIZE, VEC_SIZE, VEC_SIZE, -1}},
+ {&read_iovs, .iov_sizes = (int[]){VEC_SIZE, VEC_SIZE, VEC_SIZE, VEC_SIZE, -1}},
+ {&var_write_iovs, .iov_sizes = (int[]){VAR_BUF1_SIZE, 0, VAR_BUF2_SIZE, VAR_BUF3_SIZE, -1}},
+ {&var_read_iovs, .iov_sizes = (int[]){VAR_BUF1_SIZE, 0, VAR_BUF2_SIZE, VAR_BUF3_SIZE, -1}},
+ {}
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {"/proc/sys/kernel/io_uring_disabled", "0",
+ TST_SR_SKIP_MISSING | TST_SR_TCONF_RO},
+ {}
+ }
+};
diff --git a/testcases/kernel/syscalls/io_uring/io_uring_common.h b/testcases/kernel/syscalls/io_uring/io_uring_common.h
index aa31339fb..7816b55dc 100644
--- a/testcases/kernel/syscalls/io_uring/io_uring_common.h
+++ b/testcases/kernel/syscalls/io_uring/io_uring_common.h
@@ -230,19 +230,6 @@ static inline void io_uring_wait_cqe(struct io_uring_submit *s,
*cring->head = head + 1;
}
-/*
- * Initialize buffer with a repeating character pattern
- * Useful for creating test data with predictable patterns
- */
-static inline void io_uring_init_buffer_pattern(char *buf, size_t size,
- char pattern)
-{
- size_t i;
-
- for (i = 0; i < size; i++)
- buf[i] = pattern;
-}
-
/*
* Submit and wait for a non-vectored I/O operation
* Combines io_uring_submit_sqe() and io_uring_wait_cqe() with result reporting
--
2.39.1
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [LTP] io_uring: Add test for READV and WRITEV operations
2026-04-16 6:23 [LTP] [PATCH v4] io_uring: Add test for READV and WRITEV operations Sachin Sant
@ 2026-04-16 8:02 ` linuxtestproject.agent
0 siblings, 0 replies; 2+ messages in thread
From: linuxtestproject.agent @ 2026-04-16 8:02 UTC (permalink / raw)
To: Sachin Sant; +Cc: ltp
Hi Sachin,
On Thu, 16 Apr 2026, Sachin Sant wrote:
> io_uring: Add test for READV and WRITEV operations
> Additionally merge io_uring_init_buffer_pattern() into unified
> init_iovec_buffers() function that supports both rotating and
> simple character patterns
This mixes two logical changes in one commit. io_uring_init_buffer_pattern()
was unused by any existing test; its removal should be a separate preceding
commit, e.g. "io_uring: remove unused io_uring_init_buffer_pattern()".
[...]
> +static void setup(void)
> +{
> + io_uring_setup_supported_by_kernel();
> + sigemptyset(&sig);
> + memset(&s, 0, sizeof(s));
> + io_uring_setup_queue(&s, QUEUE_DEPTH, 0);
> + init_iovec_buffers(write_iovs, NUM_VECS, 'A', 1);
> + clear_iovec_buffers(read_iovs, NUM_VECS);
> +}
read_iovs is modified by READV in run() but only cleared in setup(). With
-i, the second iteration starts with stale data. Add
clear_iovec_buffers(read_iovs, NUM_VECS) at the top of run().
---
Note:
Our agent completed the review of the patch. The full review can be
found at: https://patchwork.ozlabs.org/project/ltp/list/?series=500082
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-04-16 8:03 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-16 6:23 [LTP] [PATCH v4] io_uring: Add test for READV and WRITEV operations Sachin Sant
2026-04-16 8:02 ` [LTP] " linuxtestproject.agent
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox