1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
4 * 2004 Open Source Development Lab
6 * Copy file by using a async I/O state machine.
7 * 1. Start read request
8 * 2. When read completes turn it into a write request
9 * 3. When write completes decrement counter and free resources
11 * Usage: aiocp [-b blksize] -n [num_aio] [-w] [-z] [-s filesize]
12 * [-f DIRECT|TRUNC|CREAT|SYNC|LARGEFILE] src dest
16 * version of copy command using async i/o
17 * From: Stephen Hemminger <shemminger@osdl.org>
18 * Modified by Daniel McNeil <daniel@osdl.org> for testing aio.
19 * - added -a alignment
20 * - added -b blksize option
21 * _ added -s size option
22 * - added -f open_flag option
23 * - added -w (no write) option (reads from source only)
24 * - added -n (num aio) option
25 * - added -z (zero dest) opton (writes zeros to dest only)
26 * - added -D delay_ms option
27 * - 2/2004 Marty Ridgeway (mridge@us.ibm.com) Changes to adapt to LTP
36 #include <sys/types.h>
38 #include <sys/param.h>
42 #include <sys/select.h>
46 #define AIO_BLKSIZE (64*1024)
49 static int aio_blksize = AIO_BLKSIZE;
50 static int aio_maxio = AIO_MAXIO;
52 static int busy = 0; // # of I/O's in flight
53 static int tocopy = 0; // # of blocks left to copy
54 static int srcfd; // source fd
55 static int dstfd = -1; // destination file descriptor
56 static const char *dstname = NULL;
57 static const char *srcname = NULL;
58 static int source_open_flag = O_RDONLY; /* open flags on source file */
59 static int dest_open_flag = O_WRONLY; /* open flags on dest file */
60 static int no_write; /* do not write */
61 static int zero; /* write zero's only */
64 static int count_io_q_waits; /* how many time io_queue_wait called */
66 struct iocb **iocb_free; /* array of pointers to iocb */
67 int iocb_free_count; /* current free count */
68 int alignment = 512; /* buffer alignment */
70 struct timeval delay; /* delay between i/o */
72 int init_iocb(int n, int iosize)
77 if ((iocb_free = malloc(n * sizeof(struct iocb *))) == 0) {
81 for (i = 0; i < n; i++) {
82 if (!(iocb_free[i] = (struct iocb *) malloc(sizeof(struct iocb))))
84 if (posix_memalign(&buf, alignment, iosize))
87 printf("buf allocated at 0x%p, align:%d\n",
92 * We are writing zero's to dstfd
94 memset(buf, 0, iosize);
96 io_prep_pread(iocb_free[i], -1, buf, iosize, 0);
102 struct iocb *alloc_iocb()
104 if (!iocb_free_count)
106 return iocb_free[--iocb_free_count];
109 void free_iocb(struct iocb *io)
111 iocb_free[iocb_free_count++] = io;
115 * io_wait_run() - wait for an io_event and then call the callback.
117 int io_wait_run(io_context_t ctx, struct timespec *to)
119 struct io_event events[aio_maxio];
124 * get up to aio_maxio events at a time.
126 ret = n = io_getevents(ctx, 1, aio_maxio, events, to);
129 * Call the callback functions for each event.
131 for (ep = events; n-- > 0; ep++) {
132 io_callback_t cb = (io_callback_t)ep->data;
133 struct iocb *iocb = (struct iocb *)ep->obj;
135 cb(ctx, iocb, ep->res, ep->res2);
140 /* Fatal error handler */
141 static void io_error(const char *func, int rc)
144 fprintf(stderr, "AIO not in this kernel\n");
146 fprintf(stderr, "%s: %s\n", func, strerror(-rc));
148 fprintf(stderr, "%s: error %d\n", func, rc);
152 if (dstname && dest_open_flag & O_CREAT)
158 * Write complete callback.
159 * Adjust counts and free resources
161 static void wr_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
164 io_error("aio write", res2);
166 if (res != iocb->u.c.nbytes) {
167 fprintf(stderr, "write missed bytes expect %lu got %ld\n",
168 iocb->u.c.nbytes, res2);
175 fprintf(stderr, "w");
179 * Read complete callback.
180 * Change read iocb into a write iocb and start it.
182 static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
184 /* library needs accessors to look at iocb? */
185 int iosize = iocb->u.c.nbytes;
186 char *buf = iocb->u.c.buf;
187 off_t offset = iocb->u.c.offset;
190 io_error("aio read", res2);
192 fprintf(stderr, "read missing bytes expect %lu got %ld\n",
193 iocb->u.c.nbytes, res);
198 /* turn read into write */
204 io_prep_pwrite(iocb, dstfd, buf, iosize, offset);
205 io_set_callback(iocb, wr_done);
206 if (1 != (res = io_submit(ctx, 1, &iocb)))
207 io_error("io_submit write", res);
210 fprintf(stderr, "r");
212 printf("%d", iosize);
218 "Usage: aiocp [-a align] [-s size] [-b blksize] [-n num_io]"
219 " [-f open_flag] SOURCE DEST\n"
220 "This copies from SOURCE to DEST using AIO.\n\n"
221 "Usage: aiocp [options] -w SOURCE\n"
222 "This does sequential AIO reads (no writes).\n\n"
223 "Usage: aiocp [options] -z DEST\n"
224 "This does sequential AIO writes of zeros.\n");
230 * Scale value by kilo, mega, or giga.
232 long long scale_by_kmg(long long value, char scale)
254 int main(int argc, char *const *argv)
257 off_t length = 0, offset = 0;
261 extern int optind, opterr, optopt;
263 while ((c = getopt(argc, argv, "a:b:df:n:s:wzD:")) != -1) {
267 case 'a': /* alignment of data buffer */
268 alignment = strtol(optarg, &endp, 0);
269 alignment = (long)scale_by_kmg((long long)alignment,
272 case 'f': /* use these open flags */
273 if (strcmp(optarg, "LARGEFILE") == 0 ||
274 strcmp(optarg, "O_LARGEFILE") == 0) {
275 source_open_flag |= O_LARGEFILE;
276 dest_open_flag |= O_LARGEFILE;
277 } else if (strcmp(optarg, "TRUNC") == 0 ||
278 strcmp(optarg, "O_TRUNC") == 0) {
279 dest_open_flag |= O_TRUNC;
280 } else if (strcmp(optarg, "SYNC") == 0 ||
281 strcmp(optarg, "O_SYNC") == 0) {
282 dest_open_flag |= O_SYNC | O_NONBLOCK;
283 } else if (strcmp(optarg, "DIRECT") == 0 ||
284 strcmp(optarg, "O_DIRECT") == 0) {
285 source_open_flag |= O_DIRECT;
286 dest_open_flag |= O_DIRECT;
287 } else if (strncmp(optarg, "CREAT", 5) == 0 ||
288 strncmp(optarg, "O_CREAT", 5) == 0) {
289 dest_open_flag |= O_CREAT;
296 delay.tv_usec = atoi(optarg);
298 case 'b': /* block size */
299 aio_blksize = strtol(optarg, &endp, 0);
300 aio_blksize = (long)scale_by_kmg((long long)aio_blksize, *endp);
303 case 'n': /* num io */
304 aio_maxio = strtol(optarg, &endp, 0);
306 case 's': /* size to transfer */
307 length = strtoll(optarg, &endp, 0);
308 length = scale_by_kmg(length, *endp);
310 case 'w': /* no write */
313 case 'z': /* write zero's */
330 source_open_flag |= O_DIRECT;
331 dest_open_flag |= O_DIRECT;
334 srcname = "junkdata";
339 if ((srcfd = open(srcname = *argv, source_open_flag)) < 0) {
341 if ((srcfd = open(srcname, source_open_flag)) < 0) {
348 if (fstat(srcfd, &st) < 0) {
358 * We are either copying or writing zeros to dstname
364 if ((dstfd = open(dstname = *argv, dest_open_flag, 0666)) < 0) {
366 if ((dstfd = open(dstname, dest_open_flag, 0666)) < 0) {
373 * get size of dest, if we are zeroing it.
374 * TODO: handle devices.
376 if (fstat(dstfd, &st) < 0) {
385 /* initialize state machine */
386 memset(&myctx, 0, sizeof(myctx));
387 io_queue_init(aio_maxio, &myctx);
388 tocopy = howmany(length, aio_blksize);
389 if (init_iocb(aio_maxio, aio_blksize) < 0) {
390 fprintf(stderr, "Error allocating the i/o buffers\n");
396 /* Submit as many reads as once as possible upto aio_maxio */
397 int n = MIN(MIN(aio_maxio - busy, aio_maxio),
398 howmany(length - offset, aio_blksize));
402 for (i = 0; i < n; i++) {
403 struct iocb *io = alloc_iocb();
404 int iosize = MIN(length - offset, aio_blksize);
408 * We are writing zero's to dstfd
410 io_prep_pwrite(io, dstfd, io->u.c.buf,
412 io_set_callback(io, wr_done);
414 io_prep_pread(io, srcfd, io->u.c.buf,
416 io_set_callback(io, rd_done);
422 rc = io_submit(myctx, n, ioq);
424 io_error("io_submit", rc);
428 printf("io_submit(%d) busy:%d\n", n, busy);
430 struct timeval t = delay;
431 (void)select(0,0,0,0,&t);
436 * We have submitted all the i/o requests. Wait for at least one to complete
437 * and call the callbacks.
440 rc = io_wait_run(myctx, 0);
442 io_error("io_wait_run", rc);
445 printf("io_wait_run: rc == %d\n", rc);
446 printf("busy:%d aio_maxio:%d tocopy:%d\n",
447 busy, aio_maxio, tocopy);
460 * [alanm@toolbox ~/MOT3]$ ../taio -d kernel-source-2.4.8-0.4g.ppc.rpm abc
461 * rrrrrrrrrrrrrrrwwwrwrrwwrrwrwwrrwrwrwwrrwrwrrrrwwrwwwrrwrrrwwwwwwwwwwwwwwwww
462 * rrrrrrrrrrrrrrwwwrrwrwrwrwrrwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrwwwwrwrwwrwrwrwr
463 * wrrrrrrrwwwwwwwwwwwwwrrrwrrrwrrwrwwwwwwwwwwrrrrwwrwrrrrrrrrrrrwwwwwwwwwwwrww
464 * wwwrrrrrrrrwwrrrwwrwrwrwwwrrrrrrrwwwrrwwwrrwrwwwwwwwwrrrrrrrwwwrrrrrrrwwwwww
465 * wwwwwwwrwrrrrrrrrwrrwrrwrrwrwrrrwrrrwrrrwrwwwwwwwwwwwwwwwwwwrrrwwwrrrrrrrrrr
466 * rrwrrrrrrwrrwwwwwwwwwwwwwwwwrwwwrrwrwwrrrrrrrrrrrrrrrrrrrwwwwwwwwwwwwwwwwwww
467 * rrrrrwrrwrwrwrrwrrrwwwwwwwwrrrrwrrrwrwwrwrrrwrrwrrrrwwwwwwwrwrwwwwrwwrrrwrrr
468 * rrrwwwwwwwrrrrwwrrrrrrrrrrrrwrwrrrrwwwwwwwwwwwwwwrwrrrrwwwwrwrrrrwrwwwrrrwww
469 * rwwrrrrrrrwrrrrrrrrrrrrwwwwrrrwwwrwrrwwwwwwwwwwwwwwwwwwwwwrrrrrrrwwwwwwwrw