1/*************************************************************************************
2*
3*  Copyright (c) International Business Machines  Corp., 2003
4*
5*  This program is free software;  you can redistribute it and/or modify
6*  it under the terms of the GNU General Public License as published by
7*  the Free Software Foundation; either version 2 of the License, or
8*  (at your option) any later version.
9*
10*  This program is distributed in the hope that it will be useful,
11*  but WITHOUT ANY WARRANTY;  without even the implied warranty of
12*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13*  the GNU General Public License for more details.
14*
15*  You should have received a copy of the GNU General Public License
16*  along with this program;  if not, write to the Free Software
17*  Foundation,
18*
19*  FILE        : aio_tio
20*  USAGE       : ./aio_tio
21*
22*  DESCRIPTION : This program will test Asynchronous I/O for 2.5 Kernel infrastructure
23*  REQUIREMENTS:
24*                1) libaio-0.3.92 or up for 2.5 kernal
25*                2) glibc 2.1.91 or up
26*  HISTORY     :
27*      11/03/2003 Kai Zhao (ltcd3@cn.ibm.com)
28*
29*  CODE COVERAGE:
30*                 68.3% - fs/aio.c
31*
32************************************************************************************/
33
34#include "config.h"
35#include "common.h"
36#include "test.h"
37#include <string.h>
38#include <errno.h>
39
40#if HAVE_LIBAIO_H
41
42#define AIO_MAXIO 32
43#define AIO_BLKSIZE (64*1024)
44
45static int alignment = 512;
46static int wait_count = 0;
47
48/*
49 * write work done
50 */
51static void work_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
52{
53
54	if (res2 != 0) {
55		io_error("aio write", res2);
56	}
57
58	if (res != iocb->u.c.nbytes) {
59		fprintf(stderr, "write missed bytes expect %lu got %ld\n",
60			iocb->u.c.nbytes, res2);
61		exit(1);
62	}
63	wait_count--;
64}
65
66/*
67 * io_wait_run() - wait for an io_event and then call the callback.
68 */
69int io_wait_run(io_context_t ctx, struct timespec *to)
70{
71	struct io_event events[AIO_MAXIO];
72	struct io_event *ep;
73	int ret, n;
74
75	/*
76	 * get up to aio_maxio events at a time.
77	 */
78	ret = n = io_getevents(ctx, 1, AIO_MAXIO, events, to);
79
80	/*
81	 * Call the callback functions for each event.
82	 */
83	for (ep = events; n-- > 0; ep++) {
84		io_callback_t cb = (io_callback_t) ep->data;
85		struct iocb *iocb = ep->obj;
86		cb(ctx, iocb, ep->res, ep->res2);
87	}
88	return ret;
89}
90
91int io_tio(char *pathname, int flag, int n, int operation)
92{
93	int res, fd = 0, i = 0;
94	void *bufptr = NULL;
95	off_t offset = 0;
96	struct timespec timeout;
97
98	io_context_t myctx;
99	struct iocb iocb_array[AIO_MAXIO];
100	struct iocb *iocbps[AIO_MAXIO];
101
102	fd = open(pathname, flag, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
103	if (fd <= 0) {
104		printf("open for %s failed: %s\n", pathname, strerror(errno));
105		return -1;
106	}
107
108	res = io_queue_init(n, &myctx);
109	//printf (" res = %d \n", res);
110
111	for (i = 0; i < AIO_MAXIO; i++) {
112
113		switch (operation) {
114		case IO_CMD_PWRITE:
115			if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) {
116				perror(" posix_memalign failed ");
117				return -1;
118			}
119			memset(bufptr, 0, AIO_BLKSIZE);
120
121			io_prep_pwrite(&iocb_array[i], fd, bufptr,
122				       AIO_BLKSIZE, offset);
123			io_set_callback(&iocb_array[i], work_done);
124			iocbps[i] = &iocb_array[i];
125			offset += AIO_BLKSIZE;
126
127			break;
128		case IO_CMD_PREAD:
129			if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) {
130				perror(" posix_memalign failed ");
131				return -1;
132			}
133			memset(bufptr, 0, AIO_BLKSIZE);
134
135			io_prep_pread(&iocb_array[i], fd, bufptr,
136				      AIO_BLKSIZE, offset);
137			io_set_callback(&iocb_array[i], work_done);
138			iocbps[i] = &iocb_array[i];
139			offset += AIO_BLKSIZE;
140			break;
141		case IO_CMD_POLL:
142		case IO_CMD_NOOP:
143			break;
144		default:
145			tst_resm(TFAIL,
146				 "Command failed; opcode returned: %d\n",
147				 operation);
148			return -1;
149			break;
150		}
151	}
152
153	do {
154		res = io_submit(myctx, AIO_MAXIO, iocbps);
155	} while (res == -EAGAIN);
156	if (res < 0) {
157		io_error("io_submit tio", res);
158	}
159
160	/*
161	 * We have submitted all the i/o requests. Wait for at least one to complete
162	 * and call the callbacks.
163	 */
164	wait_count = AIO_MAXIO;
165
166	timeout.tv_sec = 30;
167	timeout.tv_nsec = 0;
168
169	switch (operation) {
170	case IO_CMD_PREAD:
171	case IO_CMD_PWRITE:
172		{
173			while (wait_count) {
174				res = io_wait_run(myctx, &timeout);
175				if (res < 0)
176					io_error("io_wait_run", res);
177			}
178		}
179		break;
180	}
181
182	close(fd);
183
184	for (i = 0; i < AIO_MAXIO; i++) {
185		if (iocb_array[i].u.c.buf != NULL) {
186			free(iocb_array[i].u.c.buf);
187		}
188	}
189
190	io_queue_release(myctx);
191
192	return 0;
193}
194
195int test_main(void)
196{
197	int status = 0;
198
199	tst_resm(TINFO, "Running test 1\n");
200	status = io_tio("file1",
201			O_TRUNC | O_DIRECT | O_WRONLY | O_CREAT | O_LARGEFILE,
202			AIO_MAXIO, IO_CMD_PWRITE);
203	if (status) {
204		return status;
205	}
206
207	tst_resm(TINFO, "Running test 2\n");
208	status = io_tio("file1", O_RDONLY | O_DIRECT | O_LARGEFILE,
209			AIO_MAXIO, IO_CMD_PREAD);
210	if (status) {
211		return status;
212	}
213
214	tst_resm(TINFO, "Running test 3\n");
215	status = io_tio("file1", O_TRUNC | O_RDWR, AIO_MAXIO, IO_CMD_PWRITE);
216	if (status) {
217		return status;
218	}
219
220	tst_resm(TINFO, "Running test 4\n");
221	status = io_tio("file1", O_RDWR, AIO_MAXIO, IO_CMD_PREAD);
222	if (status) {
223		return status;
224	}
225
226	tst_resm(TINFO, "Running test 5\n");
227	status = io_tio("file1", O_TRUNC | O_WRONLY, AIO_MAXIO, IO_CMD_PWRITE);
228	if (status) {
229		return status;
230	}
231
232	tst_resm(TINFO, "Running test 6 \n");
233	status = io_tio("file1", O_RDONLY, AIO_MAXIO, IO_CMD_PREAD);
234	if (status) {
235		return status;
236	}
237
238	return status;
239}
240
241#endif
242