xref: /aosp_15_r20/external/ltp/testcases/kernel/io/aio/aio02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) International Business Machines Corp., 2003
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) Linux Test Project, 2004-2019
5*49cdfc7eSAndroid Build Coastguard Worker  *
6*49cdfc7eSAndroid Build Coastguard Worker  *  AUTHORS
7*49cdfc7eSAndroid Build Coastguard Worker  *   Kai Zhao ([email protected])
8*49cdfc7eSAndroid Build Coastguard Worker  */
9*49cdfc7eSAndroid Build Coastguard Worker 
10*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
11*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
12*49cdfc7eSAndroid Build Coastguard Worker 
13*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_LIBAIO
14*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
15*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
16*49cdfc7eSAndroid Build Coastguard Worker #include <libaio.h>
17*49cdfc7eSAndroid Build Coastguard Worker 
18*49cdfc7eSAndroid Build Coastguard Worker #define AIO_MAXIO 32
19*49cdfc7eSAndroid Build Coastguard Worker #define AIO_BLKSIZE (64*1024)
20*49cdfc7eSAndroid Build Coastguard Worker 
21*49cdfc7eSAndroid Build Coastguard Worker static int wait_count;
22*49cdfc7eSAndroid Build Coastguard Worker 
23*49cdfc7eSAndroid Build Coastguard Worker #define DESC_FLAGS_OPR(x, y) .desc = (x == IO_CMD_PWRITE ? "WRITE: " #y: "READ : " #y), \
24*49cdfc7eSAndroid Build Coastguard Worker 	.flags = y, .operation = x
25*49cdfc7eSAndroid Build Coastguard Worker 
26*49cdfc7eSAndroid Build Coastguard Worker struct testcase {
27*49cdfc7eSAndroid Build Coastguard Worker 	const char *desc;
28*49cdfc7eSAndroid Build Coastguard Worker 	int flags;
29*49cdfc7eSAndroid Build Coastguard Worker 	int operation;
30*49cdfc7eSAndroid Build Coastguard Worker } testcases[] = {
31*49cdfc7eSAndroid Build Coastguard Worker 	{
32*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PWRITE, O_WRONLY | O_TRUNC | O_DIRECT | O_LARGEFILE | O_CREAT),
33*49cdfc7eSAndroid Build Coastguard Worker 	},
34*49cdfc7eSAndroid Build Coastguard Worker 	{
35*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDONLY | O_DIRECT | O_LARGEFILE),
36*49cdfc7eSAndroid Build Coastguard Worker 	},
37*49cdfc7eSAndroid Build Coastguard Worker 	{
38*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PWRITE, O_RDWR | O_TRUNC),
39*49cdfc7eSAndroid Build Coastguard Worker 	},
40*49cdfc7eSAndroid Build Coastguard Worker 	{
41*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDWR),
42*49cdfc7eSAndroid Build Coastguard Worker 	},
43*49cdfc7eSAndroid Build Coastguard Worker 	{
44*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PWRITE, O_WRONLY | O_TRUNC),
45*49cdfc7eSAndroid Build Coastguard Worker 	},
46*49cdfc7eSAndroid Build Coastguard Worker 	{
47*49cdfc7eSAndroid Build Coastguard Worker 		DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDONLY),
48*49cdfc7eSAndroid Build Coastguard Worker 	},
49*49cdfc7eSAndroid Build Coastguard Worker };
50*49cdfc7eSAndroid Build Coastguard Worker 
51*49cdfc7eSAndroid Build Coastguard Worker /*
52*49cdfc7eSAndroid Build Coastguard Worker  * Fatal error handler
53*49cdfc7eSAndroid Build Coastguard Worker  */
io_error(const char * func,int rc)54*49cdfc7eSAndroid Build Coastguard Worker static void io_error(const char *func, int rc)
55*49cdfc7eSAndroid Build Coastguard Worker {
56*49cdfc7eSAndroid Build Coastguard Worker 	if (rc == -ENOSYS)
57*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TCONF, "AIO not in this kernel");
58*49cdfc7eSAndroid Build Coastguard Worker 	else if (rc < 0)
59*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TFAIL, "%s: %s", func, strerror(-rc));
60*49cdfc7eSAndroid Build Coastguard Worker 	else
61*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TFAIL, "%s: error %d", func, rc);
62*49cdfc7eSAndroid Build Coastguard Worker }
63*49cdfc7eSAndroid Build Coastguard Worker 
64*49cdfc7eSAndroid Build Coastguard Worker /*
65*49cdfc7eSAndroid Build Coastguard Worker  * write work done
66*49cdfc7eSAndroid Build Coastguard Worker  */
work_done(io_context_t ctx,struct iocb * iocb,long res,long res2)67*49cdfc7eSAndroid Build Coastguard Worker static void work_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
68*49cdfc7eSAndroid Build Coastguard Worker {
69*49cdfc7eSAndroid Build Coastguard Worker 	(void) ctx;  // silence compiler warning (-Wunused)
70*49cdfc7eSAndroid Build Coastguard Worker 
71*49cdfc7eSAndroid Build Coastguard Worker 	if (res2 != 0)
72*49cdfc7eSAndroid Build Coastguard Worker 		io_error("aio write", res2);
73*49cdfc7eSAndroid Build Coastguard Worker 
74*49cdfc7eSAndroid Build Coastguard Worker 	if (res != (long)iocb->u.c.nbytes)
75*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TFAIL, "write missed bytes expect %lu got %ld",
76*49cdfc7eSAndroid Build Coastguard Worker 			iocb->u.c.nbytes, res);
77*49cdfc7eSAndroid Build Coastguard Worker 
78*49cdfc7eSAndroid Build Coastguard Worker 	wait_count--;
79*49cdfc7eSAndroid Build Coastguard Worker }
80*49cdfc7eSAndroid Build Coastguard Worker 
81*49cdfc7eSAndroid Build Coastguard Worker /*
82*49cdfc7eSAndroid Build Coastguard Worker  * io_wait_run() - wait for an io_event and then call the callback.
83*49cdfc7eSAndroid Build Coastguard Worker  */
io_wait_run(io_context_t ctx,struct timespec * to)84*49cdfc7eSAndroid Build Coastguard Worker static int io_wait_run(io_context_t ctx, struct timespec *to)
85*49cdfc7eSAndroid Build Coastguard Worker {
86*49cdfc7eSAndroid Build Coastguard Worker 	struct io_event events[AIO_MAXIO];
87*49cdfc7eSAndroid Build Coastguard Worker 	struct io_event *ep;
88*49cdfc7eSAndroid Build Coastguard Worker 	int ret, n;
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	/*
91*49cdfc7eSAndroid Build Coastguard Worker 	 * get up to aio_maxio events at a time.
92*49cdfc7eSAndroid Build Coastguard Worker 	 */
93*49cdfc7eSAndroid Build Coastguard Worker 	ret = n = io_getevents(ctx, 1, AIO_MAXIO, events, to);
94*49cdfc7eSAndroid Build Coastguard Worker 
95*49cdfc7eSAndroid Build Coastguard Worker 	/*
96*49cdfc7eSAndroid Build Coastguard Worker 	 * Call the callback functions for each event.
97*49cdfc7eSAndroid Build Coastguard Worker 	 */
98*49cdfc7eSAndroid Build Coastguard Worker 	for (ep = events; n-- > 0; ep++) {
99*49cdfc7eSAndroid Build Coastguard Worker 		io_callback_t cb = (io_callback_t) ep->data;
100*49cdfc7eSAndroid Build Coastguard Worker 		struct iocb *iocb = ep->obj;
101*49cdfc7eSAndroid Build Coastguard Worker 		cb(ctx, iocb, ep->res, ep->res2);
102*49cdfc7eSAndroid Build Coastguard Worker 	}
103*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
104*49cdfc7eSAndroid Build Coastguard Worker }
105*49cdfc7eSAndroid Build Coastguard Worker 
io_tio(char * pathname,int flag,int operation)106*49cdfc7eSAndroid Build Coastguard Worker static int io_tio(char *pathname, int flag, int operation)
107*49cdfc7eSAndroid Build Coastguard Worker {
108*49cdfc7eSAndroid Build Coastguard Worker 	int res, fd = 0, i = 0;
109*49cdfc7eSAndroid Build Coastguard Worker 	void *bufptr = NULL;
110*49cdfc7eSAndroid Build Coastguard Worker 	off_t offset = 0;
111*49cdfc7eSAndroid Build Coastguard Worker 	struct timespec timeout;
112*49cdfc7eSAndroid Build Coastguard Worker 	struct stat fi_stat;
113*49cdfc7eSAndroid Build Coastguard Worker 	size_t alignment;
114*49cdfc7eSAndroid Build Coastguard Worker 
115*49cdfc7eSAndroid Build Coastguard Worker 	io_context_t myctx;
116*49cdfc7eSAndroid Build Coastguard Worker 	struct iocb iocb_array[AIO_MAXIO];
117*49cdfc7eSAndroid Build Coastguard Worker 	struct iocb *iocbps[AIO_MAXIO];
118*49cdfc7eSAndroid Build Coastguard Worker 
119*49cdfc7eSAndroid Build Coastguard Worker 	fd = SAFE_OPEN(pathname, flag, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
120*49cdfc7eSAndroid Build Coastguard Worker 
121*49cdfc7eSAndroid Build Coastguard Worker 	/* determine the alignment from the blksize of the underlying device */
122*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FSTAT(fd, &fi_stat);
123*49cdfc7eSAndroid Build Coastguard Worker 	alignment = fi_stat.st_blksize;
124*49cdfc7eSAndroid Build Coastguard Worker 
125*49cdfc7eSAndroid Build Coastguard Worker 	res = io_queue_init(AIO_MAXIO, &myctx);
126*49cdfc7eSAndroid Build Coastguard Worker 
127*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < AIO_MAXIO; i++) {
128*49cdfc7eSAndroid Build Coastguard Worker 
129*49cdfc7eSAndroid Build Coastguard Worker 		switch (operation) {
130*49cdfc7eSAndroid Build Coastguard Worker 		case IO_CMD_PWRITE:
131*49cdfc7eSAndroid Build Coastguard Worker 			if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) {
132*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk(TBROK | TERRNO, "posix_memalign failed");
133*49cdfc7eSAndroid Build Coastguard Worker 				return -1;
134*49cdfc7eSAndroid Build Coastguard Worker 			}
135*49cdfc7eSAndroid Build Coastguard Worker 			memset(bufptr, 0, AIO_BLKSIZE);
136*49cdfc7eSAndroid Build Coastguard Worker 
137*49cdfc7eSAndroid Build Coastguard Worker 			io_prep_pwrite(&iocb_array[i], fd, bufptr,
138*49cdfc7eSAndroid Build Coastguard Worker 					   AIO_BLKSIZE, offset);
139*49cdfc7eSAndroid Build Coastguard Worker 			io_set_callback(&iocb_array[i], work_done);
140*49cdfc7eSAndroid Build Coastguard Worker 			iocbps[i] = &iocb_array[i];
141*49cdfc7eSAndroid Build Coastguard Worker 			offset += AIO_BLKSIZE;
142*49cdfc7eSAndroid Build Coastguard Worker 
143*49cdfc7eSAndroid Build Coastguard Worker 			break;
144*49cdfc7eSAndroid Build Coastguard Worker 		case IO_CMD_PREAD:
145*49cdfc7eSAndroid Build Coastguard Worker 			if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) {
146*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk(TBROK | TERRNO, "posix_memalign failed");
147*49cdfc7eSAndroid Build Coastguard Worker 				return -1;
148*49cdfc7eSAndroid Build Coastguard Worker 			}
149*49cdfc7eSAndroid Build Coastguard Worker 			memset(bufptr, 0, AIO_BLKSIZE);
150*49cdfc7eSAndroid Build Coastguard Worker 
151*49cdfc7eSAndroid Build Coastguard Worker 			io_prep_pread(&iocb_array[i], fd, bufptr,
152*49cdfc7eSAndroid Build Coastguard Worker 					  AIO_BLKSIZE, offset);
153*49cdfc7eSAndroid Build Coastguard Worker 			io_set_callback(&iocb_array[i], work_done);
154*49cdfc7eSAndroid Build Coastguard Worker 			iocbps[i] = &iocb_array[i];
155*49cdfc7eSAndroid Build Coastguard Worker 			offset += AIO_BLKSIZE;
156*49cdfc7eSAndroid Build Coastguard Worker 			break;
157*49cdfc7eSAndroid Build Coastguard Worker 		default:
158*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL, "Command failed; opcode returned: %d", operation);
159*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
160*49cdfc7eSAndroid Build Coastguard Worker 			break;
161*49cdfc7eSAndroid Build Coastguard Worker 		}
162*49cdfc7eSAndroid Build Coastguard Worker 	}
163*49cdfc7eSAndroid Build Coastguard Worker 
164*49cdfc7eSAndroid Build Coastguard Worker 	do {
165*49cdfc7eSAndroid Build Coastguard Worker 		res = io_submit(myctx, AIO_MAXIO, iocbps);
166*49cdfc7eSAndroid Build Coastguard Worker 	} while (res == -EAGAIN);
167*49cdfc7eSAndroid Build Coastguard Worker 
168*49cdfc7eSAndroid Build Coastguard Worker 	if (res < 0)
169*49cdfc7eSAndroid Build Coastguard Worker 		io_error("io_submit tio", res);
170*49cdfc7eSAndroid Build Coastguard Worker 
171*49cdfc7eSAndroid Build Coastguard Worker 	/*
172*49cdfc7eSAndroid Build Coastguard Worker 	 * We have submitted all the i/o requests. Wait for them to complete and
173*49cdfc7eSAndroid Build Coastguard Worker 	 * call the callbacks.
174*49cdfc7eSAndroid Build Coastguard Worker 	 */
175*49cdfc7eSAndroid Build Coastguard Worker 	wait_count = AIO_MAXIO;
176*49cdfc7eSAndroid Build Coastguard Worker 
177*49cdfc7eSAndroid Build Coastguard Worker 	timeout.tv_sec = 30;
178*49cdfc7eSAndroid Build Coastguard Worker 	timeout.tv_nsec = 0;
179*49cdfc7eSAndroid Build Coastguard Worker 
180*49cdfc7eSAndroid Build Coastguard Worker 	switch (operation) {
181*49cdfc7eSAndroid Build Coastguard Worker 	case IO_CMD_PREAD:
182*49cdfc7eSAndroid Build Coastguard Worker 	case IO_CMD_PWRITE:
183*49cdfc7eSAndroid Build Coastguard Worker 		{
184*49cdfc7eSAndroid Build Coastguard Worker 			while (wait_count) {
185*49cdfc7eSAndroid Build Coastguard Worker 				res = io_wait_run(myctx, &timeout);
186*49cdfc7eSAndroid Build Coastguard Worker 				if (res < 0)
187*49cdfc7eSAndroid Build Coastguard Worker 					io_error("io_wait_run", res);
188*49cdfc7eSAndroid Build Coastguard Worker 			}
189*49cdfc7eSAndroid Build Coastguard Worker 		}
190*49cdfc7eSAndroid Build Coastguard Worker 		break;
191*49cdfc7eSAndroid Build Coastguard Worker 	}
192*49cdfc7eSAndroid Build Coastguard Worker 
193*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd);
194*49cdfc7eSAndroid Build Coastguard Worker 
195*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < AIO_MAXIO; i++)
196*49cdfc7eSAndroid Build Coastguard Worker 		if (iocb_array[i].u.c.buf != NULL)
197*49cdfc7eSAndroid Build Coastguard Worker 			free(iocb_array[i].u.c.buf);
198*49cdfc7eSAndroid Build Coastguard Worker 
199*49cdfc7eSAndroid Build Coastguard Worker 	io_queue_release(myctx);
200*49cdfc7eSAndroid Build Coastguard Worker 
201*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
202*49cdfc7eSAndroid Build Coastguard Worker }
203*49cdfc7eSAndroid Build Coastguard Worker 
test_io(unsigned int n)204*49cdfc7eSAndroid Build Coastguard Worker static void test_io(unsigned int n)
205*49cdfc7eSAndroid Build Coastguard Worker {
206*49cdfc7eSAndroid Build Coastguard Worker 	int status, new_flags;
207*49cdfc7eSAndroid Build Coastguard Worker 	struct testcase *tc = testcases + n;
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker 	new_flags = tc->flags;
210*49cdfc7eSAndroid Build Coastguard Worker 
211*49cdfc7eSAndroid Build Coastguard Worker 	if ((tst_fs_type(".") == TST_TMPFS_MAGIC) && (tc->flags & O_DIRECT)) {
212*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Drop O_DIRECT flag for tmpfs");
213*49cdfc7eSAndroid Build Coastguard Worker 		new_flags &= ~O_DIRECT;
214*49cdfc7eSAndroid Build Coastguard Worker 	}
215*49cdfc7eSAndroid Build Coastguard Worker 
216*49cdfc7eSAndroid Build Coastguard Worker 	status = io_tio("file", new_flags, tc->operation);
217*49cdfc7eSAndroid Build Coastguard Worker 	if (status)
218*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "%s, status = %d", tc->desc, status);
219*49cdfc7eSAndroid Build Coastguard Worker 	else
220*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "%s", tc->desc);
221*49cdfc7eSAndroid Build Coastguard Worker }
222*49cdfc7eSAndroid Build Coastguard Worker 
223*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
224*49cdfc7eSAndroid Build Coastguard Worker 	.needs_tmpdir = 1,
225*49cdfc7eSAndroid Build Coastguard Worker 	.test = test_io,
226*49cdfc7eSAndroid Build Coastguard Worker 	.tcnt = ARRAY_SIZE(testcases),
227*49cdfc7eSAndroid Build Coastguard Worker };
228*49cdfc7eSAndroid Build Coastguard Worker 
229*49cdfc7eSAndroid Build Coastguard Worker #else
230*49cdfc7eSAndroid Build Coastguard Worker TST_TEST_TCONF("test requires libaio and its development packages");
231*49cdfc7eSAndroid Build Coastguard Worker #endif
232