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 #ifdef HAVE_LIBAIO
41 
42 #define AIO_MAXIO 32
43 #define AIO_BLKSIZE (64*1024)
44 
45 static int alignment = 512;
46 static int wait_count = 0;
47 
48 /*
49  * write work done
50  */
work_done(io_context_t ctx,struct iocb * iocb,long res,long res2)51 static 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  */
io_wait_run(io_context_t ctx,struct timespec * to)69 int 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 
io_tio(char * pathname,int flag,int n,int operation)91 int 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 
test_main(void)195 int 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 #endif
241