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