1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4 *
5 * Description:
6 * Basic io_pgetevents() test to check various failures.
7 */
8#include "time64_variants.h"
9#include "tst_test.h"
10#include "tst_timer.h"
11#include "lapi/io_pgetevents.h"
12
13#ifdef HAVE_LIBAIO
14static sigset_t sigmask;
15static struct io_event events[1];
16static io_context_t ctx, invalid_ctx = 0;
17static int fd, ctx_initialized;
18
19static struct tst_ts to;
20static void *bad_addr;
21
22static struct tcase {
23	char *name;
24	io_context_t *ctx;
25	long min_nr;
26	long max_nr;
27	struct io_event *events;
28	struct tst_ts *timeout;
29	sigset_t *sigmask;
30	int exp_errno;
31} tcases[] = {
32	{"invalid ctx", &invalid_ctx, 1, 1, events, &to, &sigmask, EINVAL},
33	{"invalid min_nr", &ctx, -1, 1, events, &to, &sigmask, EINVAL},
34	{"invalid max_nr", &ctx, 1, -1, events, &to, &sigmask, EINVAL},
35	{"invalid events", &ctx, 1, 1, NULL, &to, &sigmask, EFAULT},
36	{"invalid timeout", &ctx, 1, 1, events, NULL, &sigmask, EFAULT},
37	{"invalid sigmask", &ctx, 1, 1, events, &to, NULL, EFAULT},
38};
39
40static struct time64_variants variants[] = {
41#if (__NR_io_pgetevents != __LTP__NR_INVALID_SYSCALL)
42	{ .io_pgetevents = sys_io_pgetevents, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
43#endif
44
45#if (__NR_io_pgetevents_time64 != __LTP__NR_INVALID_SYSCALL)
46	{ .io_pgetevents = sys_io_pgetevents_time64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
47#endif
48};
49
50static void setup(void)
51{
52	struct time64_variants *tv = &variants[tst_variant];
53	struct iocb cb, *cbs[1];
54	char data[4096];
55	int ret;
56
57	tst_res(TINFO, "Testing variant: %s", tv->desc);
58	bad_addr = tst_get_bad_addr(NULL);
59	to = tst_ts_from_ns(tv->ts_type, 10000);
60
61	cbs[0] = &cb;
62
63	sigemptyset(&sigmask);
64
65	fd = SAFE_OPEN("io_pgetevents_file", O_RDWR | O_CREAT, 0644);
66	io_prep_pwrite(&cb, fd, data, 4096, 0);
67
68	TEST(io_setup(1, &ctx));
69	if (TST_RET == -ENOSYS)
70		tst_brk(TCONF | TRERRNO, "io_setup(): AIO not supported by kernel");
71	if (TST_RET < 0)
72		tst_brk(TBROK | TRERRNO, "io_setup() failed");
73
74	ctx_initialized = 1;
75
76	ret = io_submit(ctx, 1, cbs);
77	if (ret != 1)
78		tst_brk(TBROK | TERRNO, "io_submit() failed");
79}
80
81static void cleanup(void)
82{
83	if (ctx_initialized) {
84		if (io_destroy(ctx) < 0)
85			tst_res(TWARN | TERRNO, "io_destroy() failed");
86	}
87
88	if (fd > 0)
89		SAFE_CLOSE(fd);
90}
91
92static void run(unsigned int n)
93{
94	struct time64_variants *tv = &variants[tst_variant];
95	struct tcase *tc = &tcases[n];
96	void *const to = tc->timeout ? tst_ts_get(tc->timeout) : bad_addr;
97	sigset_t *const sigmask = tc->sigmask ? tc->sigmask : bad_addr;
98
99	TEST(tv->io_pgetevents(*tc->ctx, tc->min_nr, tc->max_nr, tc->events, to,
100			       sigmask));
101
102	if (TST_RET == 1) {
103		tst_res(TFAIL, "%s: io_pgetevents() passed unexpectedly",
104			tc->name);
105		return;
106	}
107
108	if (tc->exp_errno != TST_ERR) {
109		tst_res(TFAIL | TTERRNO, "%s: io_pgetevents() should fail with %s",
110			tc->name, tst_strerrno(tc->exp_errno));
111		return;
112	}
113
114	tst_res(TPASS | TTERRNO, "%s: io_pgetevents() failed as expected",
115		tc->name);
116}
117
118static struct tst_test test = {
119	.min_kver = "4.18",
120	.needs_tmpdir = 1,
121	.tcnt = ARRAY_SIZE(tcases),
122	.test = run,
123	.test_variants = ARRAY_SIZE(variants),
124	.setup = setup,
125	.cleanup = cleanup,
126};
127
128#else
129TST_TEST_TCONF("test requires libaio and it's development packages");
130#endif
131