int main(int argc, char **argv) { char *filename = "dio_sparse"; int pid[NUM_CHILDREN]; int num_children = 1; int i; long alignment = 512; int writesize = 65536; int filesize = 100 * 1024 * 1024; int offset = 0; int c; int children_errors = 0; int ret; while ((c = getopt(argc, argv, "dw:n:a:s:o:")) != -1) { char *endp; switch (c) { case 'd': debug++; break; case 'a': alignment = strtol(optarg, &endp, 0); alignment = scale_by_kmg(alignment, *endp); break; case 'w': writesize = strtol(optarg, &endp, 0); writesize = scale_by_kmg(writesize, *endp); break; case 's': filesize = strtol(optarg, &endp, 0); filesize = scale_by_kmg(filesize, *endp); break; case 'o': offset = strtol(optarg, &endp, 0); offset = scale_by_kmg(offset, *endp); break; case 'n': num_children = atoi(optarg); if (num_children > NUM_CHILDREN) { fprintf(stderr, "number of children limited to %d\n", NUM_CHILDREN); num_children = NUM_CHILDREN; } break; case '?': usage(); break; } } setup(); tst_resm(TINFO, "Dirtying free blocks"); dirty_freeblocks(filesize); fd = SAFE_OPEN(cleanup, filename, O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600); SAFE_FTRUNCATE(cleanup, fd, filesize); tst_resm(TINFO, "Starting I/O tests"); signal(SIGTERM, SIG_DFL); for (i = 0; i < num_children; i++) { switch (pid[i] = fork()) { case 0: SAFE_CLOSE(NULL, fd); read_sparse(filename, filesize); break; case -1: while (i-- > 0) kill(pid[i], SIGTERM); tst_brkm(TBROK | TERRNO, cleanup, "fork()"); default: continue; } } tst_sig(FORK, DEF_HANDLER, cleanup); ret = dio_sparse(fd, alignment, writesize, filesize, offset); tst_resm(TINFO, "Killing childrens(s)"); for (i = 0; i < num_children; i++) kill(pid[i], SIGTERM); for (i = 0; i < num_children; i++) { int status; pid_t p; p = waitpid(pid[i], &status, 0); if (p < 0) { tst_resm(TBROK | TERRNO, "waitpid()"); } else { if (WIFEXITED(status) && WEXITSTATUS(status) == 10) children_errors++; } } if (children_errors) tst_resm(TFAIL, "%i children(s) exited abnormally", children_errors); if (!children_errors && !ret) tst_resm(TPASS, "Test passed"); cleanup(); tst_exit(); }
int main(int argc, char *const *argv) { struct stat st; off_t length = 0, offset = 0; io_context_t myctx; int c; extern char *optarg; extern int optind, opterr, optopt; while ((c = getopt(argc, argv, "a:b:df:n:s:wzD:")) != -1) { char *endp; switch (c) { case 'a': /* alignment of data buffer */ alignment = strtol(optarg, &endp, 0); alignment = (long)scale_by_kmg((long long)alignment, *endp); break; case 'f': /* use these open flags */ if (strcmp(optarg, "LARGEFILE") == 0 || strcmp(optarg, "O_LARGEFILE") == 0) { source_open_flag |= O_LARGEFILE; dest_open_flag |= O_LARGEFILE; } else if (strcmp(optarg, "TRUNC") == 0 || strcmp(optarg, "O_TRUNC") == 0) { dest_open_flag |= O_TRUNC; } else if (strcmp(optarg, "SYNC") == 0 || strcmp(optarg, "O_SYNC") == 0) { dest_open_flag |= O_SYNC; } else if (strcmp(optarg, "DIRECT") == 0 || strcmp(optarg, "O_DIRECT") == 0) { source_open_flag |= O_DIRECT; dest_open_flag |= O_DIRECT; } else if (strncmp(optarg, "CREAT", 5) == 0 || strncmp(optarg, "O_CREAT", 5) == 0) { dest_open_flag |= O_CREAT; } break; case 'd': debug++; break; case 'D': delay.tv_usec = atoi(optarg); break; case 'b': /* block size */ aio_blksize = strtol(optarg, &endp, 0); aio_blksize = (long)scale_by_kmg((long long)aio_blksize, *endp); break; case 'n': /* num io */ aio_maxio = strtol(optarg, &endp, 0); break; case 's': /* size to transfer */ length = strtoll(optarg, &endp, 0); length = scale_by_kmg(length, *endp); break; case 'w': /* no write */ no_write = 1; break; case 'z': /* write zero's */ zero = 1; break; default: usage(); } } argc -= optind; argv += optind; #ifndef DEBUG if (argc < 1) { usage(); } #else source_open_flag |= O_DIRECT; dest_open_flag |= O_DIRECT; aio_blksize = 1; aio_maxio=1; srcname = "junkdata"; dstname = "ff2"; #endif if (!zero) { #ifndef DEBUG if ((srcfd = open(srcname = *argv, source_open_flag)) < 0) { #else if ((srcfd = open(srcname, source_open_flag)) < 0) { #endif perror(srcname); exit(1); } argv++; argc--; length = 1073741824; #if 0 if (fstat(srcfd, &st) < 0) { perror("fstat"); exit(1); } if (length == 0) length = st.st_size; #endif } if (!no_write) { /* * We are either copying or writing zeros to dstname */ #ifndef DEBUG if (argc < 1) { usage(); } if ((dstfd = open(dstname = *argv, dest_open_flag, 0666)) < 0) { #else if ((dstfd = open(dstname, dest_open_flag, 0666)) < 0) { #endif perror(dstname); exit(1); } if (zero) { /* * get size of dest, if we are zeroing it. * TODO: handle devices. */ if (fstat(dstfd, &st) < 0) { perror("fstat"); exit(1); } if (length == 0) length = st.st_size; } } /* initialize state machine */ memset(&myctx, 0, sizeof(myctx)); io_queue_init(aio_maxio, &myctx); tocopy = howmany(length, aio_blksize); if (init_iocb(aio_maxio, aio_blksize) < 0) { fprintf(stderr, "Error allocating the i/o buffers\n"); exit(1); } while (tocopy > 0) { int i, rc; /* Submit as many reads as once as possible upto aio_maxio */ int n = MIN(MIN(aio_maxio - busy, aio_maxio), howmany(length - offset, aio_blksize)); if (n > 0) { struct iocb *ioq[n]; for (i = 0; i < n; i++) { struct iocb *io = alloc_iocb(); int iosize = MIN(length - offset, aio_blksize); if (zero) { /* * We are writing zero's to dstfd */ io_prep_pwrite(io, dstfd, io->u.c.buf, iosize, offset); io_set_callback(io, wr_done); } else { io_prep_pread(io, srcfd, io->u.c.buf, iosize, offset); io_set_callback(io, rd_done); } ioq[i] = io; offset += iosize; } rc = io_submit(myctx, n, ioq); if (rc < 0) io_error("io_submit", rc); busy += n; if (debug > 1) printf("io_submit(%d) busy:%d\n", n, busy); if (delay.tv_usec) { struct timeval t = delay; (void)select(0,0,0,0,&t); } } /* * We have submitted all the i/o requests. Wait for at least one to complete * and call the callbacks. */ count_io_q_waits++; rc = io_wait_run(myctx, 0); if (rc < 0) io_error("io_wait_run", rc); if (debug > 1) { printf("io_wait_run: rc == %d\n", rc); printf("busy:%d aio_maxio:%d tocopy:%d\n", busy, aio_maxio, tocopy); } } if (srcfd != -1) close(srcfd); if (dstfd != -1) close(dstfd); exit(0); }