[LTP] [RFC] [PATCH 1/2] io_uring: Test IORING READ and WRITE operations
Cyril Hrubis
chrubis@suse.cz
Thu Mar 19 17:49:43 CET 2026
Hi!
> # 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 749db17db..9382ae413 100644
> --- a/testcases/kernel/syscalls/io_uring/.gitignore
> +++ b/testcases/kernel/syscalls/io_uring/.gitignore
> @@ -1,2 +1,3 @@
> /io_uring01
> /io_uring02
> +/io_uring03
> diff --git a/testcases/kernel/syscalls/io_uring/io_uring03.c b/testcases/kernel/syscalls/io_uring/io_uring03.c
> new file mode 100644
> index 000000000..53d4feae5
> --- /dev/null
> +++ b/testcases/kernel/syscalls/io_uring/io_uring03.c
> @@ -0,0 +1,145 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 IBM
> + * Author: Sachin Sant <sachinp@linux.ibm.com>
> + *
> + * Test IORING_OP_READ and IORING_OP_WRITE operations.
> + *
> + * This test validates basic read and write operations using io_uring.
> + * It tests:
> + * 1. IORING_OP_WRITE - Writing data to a file
> + * 2. IORING_OP_READ - Reading data from a file
> + * 3. Data integrity verification
> + */
The second half of the comment should be doc comment (starts with /*\)
so that it's picked up by the documentation parser and exported into the
online documentation.
> +#include "io_uring_common.h"
> +
> +#define TEST_FILE "io_uring_test_file"
> +#define QUEUE_DEPTH 2
> +#define BLOCK_SZ 4096
> +
> +static char write_buf[BLOCK_SZ];
> +static char read_buf[BLOCK_SZ];
> +static struct io_uring_submit s;
> +static sigset_t sig;
> +
> +static void test_write_read(void)
> +{
> + int fd;
> + size_t i;
> +
> + /* Prepare write buffer with pattern */
There a lot of comments like this that are commenting the
obvious. Comments that comment obvious does not add any value and
shouldn't be added.
> + for (i = 0; i < BLOCK_SZ; i++)
> + write_buf[i] = 'A' + (i % 26);
This should be done only once in the test setup.
> + /* Open file for writing */
> + fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
> +
> + /* Test IORING_OP_WRITE */
> + tst_res(TINFO, "Testing IORING_OP_WRITE");
> + io_uring_submit_sqe(&s, fd, IORING_OP_WRITE, write_buf, BLOCK_SZ, 0);
> + if (io_uring_wait_cqe(&s, BLOCK_SZ, IORING_OP_WRITE, &sig) == 0)
> + tst_res(TPASS, "IORING_OP_WRITE completed successfully");
> +
> + /* Sync to ensure data is written */
> + SAFE_FSYNC(fd);
> +
> + /* Test IORING_OP_READ */
> + tst_res(TINFO, "Testing IORING_OP_READ");
> + memset(read_buf, 0, BLOCK_SZ);
> + io_uring_submit_sqe(&s, fd, IORING_OP_READ, read_buf, BLOCK_SZ, 0);
> +
> + if (io_uring_wait_cqe(&s, BLOCK_SZ, IORING_OP_READ, &sig) == 0)
> + tst_res(TPASS, "IORING_OP_READ completed successfully");
> +
> + /* Verify data integrity */
> + if (memcmp(write_buf, read_buf, BLOCK_SZ) == 0) {
> + tst_res(TPASS, "Data integrity verified");
> + } else {
> + tst_res(TFAIL, "Data mismatch after read");
> + for (i = 0; i < BLOCK_SZ && i < 64; i++) {
> + if (write_buf[i] != read_buf[i]) {
> + tst_res(TINFO, "First mismatch at offset %zu: "
> + "wrote 0x%02x, read 0x%02x",
> + i, write_buf[i], read_buf[i]);
> + break;
> + }
> + }
> + }
This should really be put into a function and used in both test cases.
> + SAFE_CLOSE(fd);
> +}
> +
> +static void test_partial_io(void)
> +{
> + int fd;
> + size_t half = BLOCK_SZ / 2;
> + size_t i;
> +
> + tst_res(TINFO, "Testing partial I/O operations");
> +
> + /* Prepare buffer */
> + for (i = 0; i < BLOCK_SZ; i++)
> + write_buf[i] = 'a' + (i % 26);
> +
> + fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT | O_TRUNC, 0644);
> +
> + /* Write first half */
> + io_uring_submit_sqe(&s, fd, IORING_OP_WRITE, write_buf, half, 0);
> + if (io_uring_wait_cqe(&s, half, IORING_OP_WRITE, &sig) == 0)
> + tst_res(TPASS, "Partial write (first half) succeeded");
> +
> + /* Write second half */
> + io_uring_submit_sqe(&s, fd, IORING_OP_WRITE, write_buf + half,
> + half, half);
> + if (io_uring_wait_cqe(&s, half, IORING_OP_WRITE, &sig) == 0)
> + tst_res(TPASS, "Partial write (second half) succeeded");
> +
> + SAFE_FSYNC(fd);
> +
> + /* Read back in one operation */
> + memset(read_buf, 0, BLOCK_SZ);
> + io_uring_submit_sqe(&s, fd, IORING_OP_READ, read_buf, BLOCK_SZ, 0);
> + if (io_uring_wait_cqe(&s, BLOCK_SZ, IORING_OP_READ, &sig) == 0)
> + tst_res(TPASS, "Full read after partial writes succeeded");
> +
> + /* Verify */
> + if (memcmp(write_buf, read_buf, BLOCK_SZ) == 0)
> + tst_res(TPASS, "Partial I/O data integrity verified");
> + else
> + tst_res(TFAIL, "Partial I/O data mismatch");
> +
> + SAFE_CLOSE(fd);
> +}
> +
> +static void run(void)
> +{
> + io_uring_setup_queue(&s, QUEUE_DEPTH);
> + test_write_read();
> + test_partial_io();
> + io_uring_cleanup_queue(&s, QUEUE_DEPTH);
> +}
> +
> +static void setup(void)
> +{
> + io_uring_setup_supported_by_kernel();
> + sigemptyset(&sig);
> + memset(&s, 0, sizeof(s));
> +}
> +
> +static struct tst_test test = {
> + .test_all = run,
> + .setup = setup,
> + .needs_tmpdir = 1,
> + .save_restore = (const struct tst_path_val[]) {
> + {"/proc/sys/kernel/io_uring_disabled", "0",
> + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO},
> + {}
> + },
> + .tags = (const struct tst_tag[]) {
> + {"linux-git", "5d17b4a4b48c"},
This commit does not appear to exist in linux kernel git tree.
> + {"linux-git", "2b188cc1bb85"},
And this is a commit that added io_uring. Commit hashes in tests are
used only for cases where the test is a regression test for some bug and
point to a commit that fixed the problem.
> + {}
> + }
> +};
> diff --git a/testcases/kernel/syscalls/io_uring/io_uring_common.h b/testcases/kernel/syscalls/io_uring/io_uring_common.h
Since you are pulling the common code into header it would be nice to
convert the io_uring01.c so that it uses the common header as well.
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list