1 /* gcc -g -Wall -O2 aiodio_sparse.c -o aiodio_sparse -laio */
4 * From http://developer.osdl.org/daniel/AIO/TESTS/aiodio_sparse.c
5 * With patch from https://bugzilla.redhat.com/attachment.cgi?id=142124
6 * (Bug https://bugzilla.redhat.com/show_bug.cgi?id=217098)
12 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/mount.h>
30 * aiodio_sparse - issue async O_DIRECT writes to holes is a file while
31 * concurrently reading the file and checking that the read never reads
35 unsigned char *check_zero(unsigned char *buf, int size)
43 fprintf(stderr, "non one buffer at buf[%ld] => 0x%02x,%02x,%02x,%02x\n",
44 (long)(buf - p), (unsigned int)buf[0],
45 size > 1 ? (unsigned int)buf[1] : 0,
46 size > 2 ? (unsigned int)buf[2] : 0,
47 size > 3 ? (unsigned int)buf[3] : 0);
49 fprintf(stderr, "buf %p, p %p\n", buf, p);
55 return 0; /* all zeros */
58 volatile int got_signal;
61 sig_term_func(int i, siginfo_t *si, void *p)
64 fprintf(stderr, "sig(%d, %p, %p)\n", i, si, p);
69 * do async DIO writes to a sparse file
71 void aiodio_sparse(char *filename, int align, int writesize, int startoffset, int filesize,
72 int num_aio, int step, int sparse, int direct, int keep)
78 static struct sigaction s;
82 struct io_event event;
85 s.sa_sigaction = sig_term_func;
86 s.sa_flags = SA_SIGINFO;
87 sigaction(SIGTERM, &s, 0);
89 if ((num_aio * step) > filesize) {
90 num_aio = filesize / step;
92 memset(&myctx, 0, sizeof(myctx));
93 io_queue_init(num_aio, &myctx);
95 iocbs = (struct iocb **)calloc(num_aio, sizeof(struct iocb *));
96 for (i = 0; i < num_aio; i++) {
97 if ((iocbs[i] = (struct iocb *)calloc(1, sizeof(struct iocb))) == 0) {
98 perror("cannot malloc iocb");
103 fd = open(filename, direct|O_WRONLY|O_CREAT, 0666);
106 perror("cannot create file");
111 ftruncate(fd, filesize);
114 * allocate the iocbs array and iocbs with buffers
116 offset = startoffset;
117 for (i = 0; i < num_aio; i++) {
120 w = posix_memalign(&bufptr, align, writesize);
122 fprintf(stderr, "cannot malloc aligned memory: %s\n",
128 memset(bufptr, 1, writesize);
129 io_prep_pwrite(iocbs[i], fd, bufptr, writesize, offset);
134 * start the 1st num_aio write requests
136 w = io_submit(myctx, num_aio, iocbs);
138 fprintf(stderr, "io_submit failed: %s\n",
145 fprintf(stderr, "io_submit() return %d\n", w);
148 * As AIO requests finish, keep issuing more AIO until done.
150 aio_inflight = num_aio;
152 fprintf(stderr, "aiodio_sparse: %d i/o in flight\n", aio_inflight);
153 while (offset < filesize) {
158 fprintf(stderr, "aiodio_sparse: offset %lld filesize %d inflight %d\n",
159 (long long)offset, filesize, aio_inflight);
161 if ((n = io_getevents(myctx, 1, 1, &event, 0)) != 1) {
163 fprintf(stderr, "io_getevents() returned %d\n", n);
167 fprintf(stderr, "aiodio_sparse: io_getevent() returned %d\n", n);
170 break; /* told to stop */
172 * check if write succeeded.
175 if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) {
177 "AIO write offset %lld expected %ld got %ld\n",
178 iocbp->u.c.offset, iocbp->u.c.nbytes,
183 fprintf(stderr, "aiodio_sparse: io_getevent() res %ld res2 %ld\n",
184 event.res, event.res2);
186 /* start next write */
187 io_prep_pwrite(iocbp, fd, iocbp->u.c.buf, writesize, offset);
189 w = io_submit(myctx, 1, &iocbp);
191 fprintf(stderr, "io_submit failed at offset %lld: %s\n",
197 fprintf(stderr, "io_submit() return %d\n", w);
202 * wait for AIO requests in flight.
204 while (aio_inflight > 0) {
208 n = io_getevents(myctx, 1, 1, &event, 0);
210 fprintf(stderr, "io_getevents failed: %s\n",
216 * check if write succeeded.
219 if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) {
221 "AIO write offset %lld expected %ld got %ld\n",
222 iocbp->u.c.offset, iocbp->u.c.nbytes,
227 fprintf(stderr, "AIO DIO write done\n");
229 if ((fd = open(filename, O_RDONLY)) < 0)
232 bufptr = malloc(writesize);
233 for (offset = startoffset; offset < filesize; offset += step) {
234 unsigned char *badbuf;
237 fprintf(stderr, "seek to %lld and read %d\n",
238 (long long) offset, writesize);
239 lseek(fd, offset, SEEK_SET);
240 if (read(fd, bufptr, writesize) < writesize) {
241 fprintf(stderr, "short read() at offset %lld\n",
245 if ((badbuf = check_zero(bufptr, writesize))) {
246 fprintf(stderr, "non-one read at offset %lld\n",
247 (long long)(offset + badbuf - (unsigned char*)bufptr));
248 fprintf(stderr, "*** WARNING *** %s has not been unlinked; if you don't rm it manually first, it may influence the next run\n", filename);
256 fprintf(stderr, "*** WARNING *** You requested %s not to be unlinked; if you don't rm it manually first, it may influence the next run\n", filename);
259 void dirty_freeblocks(char *filename, int size)
264 char filename2[PATH_MAX];
267 size = ((size + pg - 1) / pg) * pg;
268 sprintf(filename2, "%s.xx.%d", filename, getpid());
269 fd = open(filename2, O_CREAT|O_RDWR, 0666);
271 perror("cannot open file");
275 p = mmap(0, size, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
276 if (p == MAP_FAILED) {
277 perror("cannot mmap");
280 memset(p, 0xaa, size);
281 msync(p, size, MS_SYNC);
287 static long get_logical_block_size(char *filename)
291 int logical_block_size;
293 fd = open(filename, O_RDONLY);
297 ret = ioctl(fd, BLKSSZGET, &logical_block_size);
301 return logical_block_size;
306 fprintf(stderr, "usage: dio_sparse [-n step] [-s filesize]"
307 " [-w writesize] [-o startoffset] [-r readsize] filename\n");
312 * Scale value by kilo, mega, or giga.
314 long long scale_by_kmg(long long value, char scale)
338 * aiodio_sparse [-r readsize] [-w writesize] [-o startoffset] [-n step] [-a align] [-i num_aio] filename
341 int main(int argc, char **argv)
343 char filename[PATH_MAX];
345 int readsize = 65536;
346 int writesize = 65536;
348 int filesize = 100*1024*1024;
350 int step = 5*1024*1024;
351 int c, direct = O_DIRECT, keep = 0, sparse = 1;
353 extern int optind, optopt, opterr;
355 while ((c = getopt(argc, argv, "dr:w:n:o:a:s:i:DkS")) != -1) {
371 num_aio = atoi(optarg);
374 alignment = strtol(optarg, &endp, 0);
375 alignment = (int)scale_by_kmg((long long)alignment,
379 readsize = strtol(optarg, &endp, 0);
380 readsize = (int)scale_by_kmg((long long)readsize, *endp);
383 writesize = strtol(optarg, &endp, 0);
384 writesize = (int)scale_by_kmg((long long)writesize, *endp);
387 filesize = strtol(optarg, &endp, 0);
388 filesize = (int)scale_by_kmg((long long)filesize, *endp);
391 step = strtol(optarg, &endp, 0);
392 step = (int)scale_by_kmg((long long)step, *endp);
395 startoffset = strtol(optarg, &endp, 0);
396 startoffset = (int)scale_by_kmg((long long)startoffset, *endp);
404 strncpy(filename, argv[argc-1], PATH_MAX);
405 filename[PATH_MAX - 1] = '\0';
408 alignment = get_logical_block_size(filename);
410 * Create some dirty free blocks by allocating, writing, syncing,
411 * and then unlinking and freeing.
413 dirty_freeblocks(filename, filesize);
416 * Parent write to a hole in a file using async direct i/o
419 aiodio_sparse(filename, alignment, writesize, startoffset, filesize, num_aio, step, sparse, direct, keep);