Re: [LTP] [PATCH v4] io_submit04: Add test case for RWF_NOWAIT flag

Wei Gao via ltp
2026-03-05T04:42:13Z

On Wed, Feb 18, 2026 at 01:21:46PM +0100, Andrea Cervesato wrote:
> Hi!
>
> On Wed Jan 7, 2026 at 7:10 AM CET, Wei Gao wrote:
> > Fixes: #467
> > Signed-off-by: Wei Gao <wegao@suse.com>
> > ---
>
> > +
> > +#ifndef HAVE_STRUCT_IOCB_AIO_RW_FLAGS
> > +typedef struct iocb_fallback iocb;
>
> Why not just define here the iocb, instead of having iocb_fallback
> defined before?
This way can avoid complie failure on old system such as:
https://github.com/coolgw/ltp/actions/runs/22699554704/job/65813365426
make[4]: *** [io_submit04] Error 1
make[4]: *** Waiting for unfinished jobs....
../../../../include/mk/rules.mk:48: recipe for target 'io_submit04' failed
CC testcases/kernel/syscalls/io_submit/io_submit01
CC testcases/kernel/syscalls/io_submit/io_submit02
CC testcases/kernel/syscalls/io_submit/io_submit03
make[3]: *** [all] Error 2
../../../include/mk/generic_trunk_target.inc:92: recipe for target 'all' failed
make[2]: *** [all] Error 2
../../include/mk/generic_trunk_target.inc:92: recipe for target 'all' failed
make[1]: *** [all] Error 2
../include/mk/generic_trunk_target.inc:92: recipe for target 'all' failed
make[1]: Leaving directory '/__w/ltp/ltp/testcases'
Makefile:85: recipe for target 'testcases-all' failed
make: *** [testcases-all] Error 2
Error: Process completed with exit code 2

This kind of fallback also mentioned/used in following patch:
https://patchwork.ozlabs.org/project/ltp/patch/20251211015915.1086-1-wegao@suse.com/

>
> > +#else
> > +typedef struct iocb iocb;
>
> And this would not be needed then.
>
> > +#endif
> > +
> > +#endif /* LAPI_AIO_ABI_H__ */
> > diff --git a/runtest/syscalls b/runtest/syscalls
> > index a1ef7548b..18182a2d6 100644
> > --- a/runtest/syscalls
> > +++ b/runtest/syscalls
> > @@ -696,6 +696,7 @@ io_setup02 io_setup02
> > io_submit01 io_submit01
> > io_submit02 io_submit02
> > io_submit03 io_submit03
> > +io_submit04 io_submit04
> >
> > keyctl01 keyctl01
> > keyctl02 keyctl02
> > diff --git a/testcases/kernel/syscalls/io_submit/.gitignore b/testcases/kernel/syscalls/io_submit/.gitignore
> > index 60b07970a..abe962e1c 100644
> > --- a/testcases/kernel/syscalls/io_submit/.gitignore
> > +++ b/testcases/kernel/syscalls/io_submit/.gitignore
> > @@ -1,3 +1,4 @@
> > /io_submit01
> > /io_submit02
> > /io_submit03
> > +/io_submit04
> > diff --git a/testcases/kernel/syscalls/io_submit/io_submit04.c b/testcases/kernel/syscalls/io_submit/io_submit04.c
> > new file mode 100644
> > index 000000000..d085d3238
> > --- /dev/null
> > +++ b/testcases/kernel/syscalls/io_submit/io_submit04.c
> > @@ -0,0 +1,94 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (c) 2025 Wei Gao <wegao@suse.com>
> > + */
> > +
> > +/*\
> > + * Test RWF_NOWAIT support in io_submit(), verifying that an
> > + * asynchronous read operation on a blocking resource (empty pipe)
> > + * will cause -EAGAIN. This is done by checking that io_getevents()
> > + * syscall returns immediately and io_event.res is equal to -EAGAIN.
> > + */
> > +
> > +#include "config.h"
> > +#include "tst_test.h"
> > +#include "lapi/syscalls.h"
> > +#include "lapi/aio_abi.h"
> > +
> > +
>
> nit: double blank-line is not needed.
>
> > +#define BUF_SIZE 100
> > +
> > +static int fd[2];
>
> fd should be initialized to -1 and compared to this value in the
> cleanup() before closing. zero is a valid value for file descriptors
> (stdin).
>
> > +
> > +static aio_context_t ctx;
> > +static char *buf;
> > +static iocb *cb;
> > +static iocb **iocbs;
> > +
> > +static void setup(void)
> > +{
> > + TST_EXP_PASS_SILENT(tst_syscall(__NR_io_setup, 1, &ctx));
>
> We need to break the test here if io_setup fails. Silently failing it
> will keep test running.
>
> > + SAFE_PIPE(fd);
> > +
> > + cb->aio_fildes = fd[0];
> > + cb->aio_lio_opcode = IOCB_CMD_PREAD;
> > + cb->aio_buf = (uint64_t)buf;
> > + cb->aio_offset = 0;
> > + cb->aio_nbytes = BUF_SIZE;
> > + cb->aio_rw_flags = RWF_NOWAIT;
> > +
> > + iocbs[0] = cb;
> > +}
> > +
> > +static void cleanup(void)
> > +{
> > + if (fd[0])
> > + SAFE_CLOSE(fd[0]);
> > +
> > + if (fd[1])
> > + SAFE_CLOSE(fd[1]);
> > +
> > + if (ctx)
> > + if (tst_syscall(__NR_io_destroy, ctx))
> > + tst_brk(TBROK | TERRNO, "io_destroy() failed");
> > +}
> > +
> > +static void run(void)
> > +{
> > + struct io_event evbuf;
> > + struct timespec timeout = { .tv_sec = 1 };
> > + long nr = 1;
> > +
> > + TEST(tst_syscall(__NR_io_submit, ctx, nr, iocbs));
> > +
> > + if (TST_RET == -1 && errno == EOPNOTSUPP) {
> > + tst_brk(TCONF, "RWF_NOWAIT not supported by kernel");
> > + } else if (TST_RET != nr) {
> > + tst_brk(TBROK | TTERRNO, "io_submit() returns %ld, expected %ld",
> > + TST_RET, nr);
> > + }
> > +
> > + tst_syscall(__NR_io_getevents, ctx, 1, 1, &evbuf, &timeout);
>
> Return value is ignored.
>
> > +
> > + if (evbuf.res == -EAGAIN)
> > + tst_res(TPASS, "io_getevents() returned EAGAIN on read event");
> > + else
> > + tst_res(TFAIL | TTERRNO, "io_getevents() returned with %s instead of EAGAIN",
>
> TTERRNO is not needed.
>
> > + strerror(-evbuf.res));
> > +}
> > +
> > +static struct tst_test test = {
> > + .test_all = run,
> > + .setup = setup,
> > + .cleanup = cleanup,
> > + .needs_kconfigs = (const char *[]) {
> > + "CONFIG_AIO=y",
> > + NULL
> > + },
> > + .bufs = (struct tst_buffers []) {
> > + {&buf, .size = BUF_SIZE},
> > + {&cb, .size = sizeof(iocb)},
> > + {&iocbs, .size = sizeof(iocb *)},
> > + {},
> > + }
> > +};
>
>
>
>
> --
> Andrea Cervesato
> SUSE QE Automation Engineer Linux
> andrea.cervesato@suse.com
>