1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) Crackerjack Project., 2007
4  * Copyright (c) 2011-2017 Cyril Hrubis <chrubis@suse.cz>
5  */
6 
7 /* Porting from Crackerjack to LTP is done
8    by Masatake YAMATO <yamato@redhat.com> */
9 
10 #include <errno.h>
11 #include <string.h>
12 #include <fcntl.h>
13 
14 #include "config.h"
15 #include "tst_test.h"
16 
17 #ifdef HAVE_LIBAIO
18 #include <libaio.h>
19 
20 static io_context_t ctx;
21 static io_context_t invalid_ctx;
22 
23 static struct iocb iocb;
24 static struct iocb *iocbs[] = {&iocb};
25 
26 static struct iocb inv_fd_iocb;
27 static struct iocb *inv_fd_iocbs[] = {&inv_fd_iocb};
28 
29 static int rdonly_fd;
30 static struct iocb rdonly_fd_iocb;
31 static struct iocb *rdonly_fd_iocbs[] = {&rdonly_fd_iocb};
32 
33 static int wronly_fd;
34 static struct iocb wronly_fd_iocb;
35 static struct iocb *wronly_fd_iocbs[] = {&wronly_fd_iocb};
36 
37 static struct iocb zero_buf_iocb;
38 static struct iocb *zero_buf_iocbs[] = {&zero_buf_iocb};
39 
40 static struct iocb *zero_iocbs[1];
41 
42 static char buf[100];
43 
44 static struct tcase {
45 	io_context_t *ctx;
46 	long nr;
47 	struct iocb **iocbs;
48 	int exp_errno;
49 	const char *desc;
50 } tcases[] = {
51 	/* Invalid ctx */
52 	{&invalid_ctx, 1, iocbs, -EINVAL, "invalid ctx"},
53 	/* Invalid nr */
54 	{&ctx, -1, iocbs, -EINVAL, "invalid nr"},
55 	/* Invalid pointer */
56 	{&ctx, 1, (void*)-1, -EFAULT, "invalid iocbpp pointer"},
57 	{&ctx, 1, zero_iocbs, -EFAULT, "NULL iocb pointers"},
58 	/* Invalid fd */
59 	{&ctx, 1, inv_fd_iocbs, -EBADF, "invalid fd"},
60 	{&ctx, 1, rdonly_fd_iocbs, -EBADF, "readonly fd for write"},
61 	{&ctx, 1, wronly_fd_iocbs, -EBADF, "writeonly fd for read"},
62 	/* No-op but should work fine */
63 	{&ctx, 1, zero_buf_iocbs, 1, "zero buf size"},
64 	{&ctx, 0, NULL, 0, "zero nr"},
65 };
66 
setup(void)67 static void setup(void)
68 {
69 	int rval;
70 
71 	rval = io_setup(1, &ctx);
72 	if (rval)
73 		tst_brk(TBROK | TERRNO, "io_setup() returned %d", rval);
74 
75 	io_prep_pread(&inv_fd_iocb, -1, buf, sizeof(buf), 0);
76 
77 	rdonly_fd = SAFE_OPEN("rdonly_file", O_RDONLY | O_CREAT, 0777);
78 	io_prep_pwrite(&rdonly_fd_iocb, rdonly_fd, buf, sizeof(buf), 0);
79 
80 	io_prep_pread(&zero_buf_iocb, rdonly_fd, buf, 0, 0);
81 
82 	wronly_fd = SAFE_OPEN("wronly_file", O_WRONLY | O_CREAT, 0777);
83 	io_prep_pread(&wronly_fd_iocb, wronly_fd, buf, sizeof(buf), 0);
84 }
85 
cleanup(void)86 static void cleanup(void)
87 {
88 	if (rdonly_fd > 0)
89 		SAFE_CLOSE(rdonly_fd);
90 
91 	if (wronly_fd > 0)
92 		SAFE_CLOSE(wronly_fd);
93 }
94 
errno_name(int err)95 static const char *errno_name(int err)
96 {
97 	if (err <= 0)
98 		return tst_strerrno(-err);
99 
100 	return "SUCCESS";
101 }
102 
verify_io_submit(unsigned int n)103 static void verify_io_submit(unsigned int n)
104 {
105 	struct tcase *t = &tcases[n];
106 	int ret;
107 
108 	ret = io_submit(*t->ctx, t->nr, t->iocbs);
109 
110 	if (ret == t->exp_errno) {
111 		tst_res(TPASS, "io_submit() with %s failed with %s",
112 			t->desc, errno_name(t->exp_errno));
113 		return;
114 	}
115 
116 	tst_res(TFAIL, "io_submit() returned %i(%s), expected %s(%i)",
117 		ret, ret < 0 ? tst_strerrno(-ret) : "SUCCESS",
118 		errno_name(t->exp_errno), t->exp_errno);
119 }
120 
121 static struct tst_test test = {
122 	.setup = setup,
123 	.cleanup = cleanup,
124 	.test = verify_io_submit,
125 	.tcnt = ARRAY_SIZE(tcases),
126 	.needs_tmpdir = 1,
127 };
128 
129 #else
130 	TST_TEST_TCONF("test requires libaio and it's development packages");
131 #endif
132