Home | History | Annotate | Download | only in src
      1 #define _XOPEN_SOURCE 500 /* pwrite */
      2 #include <unistd.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <sys/types.h>
      6 #include <sys/stat.h>
      7 #include <fcntl.h>
      8 #include <libaio.h>
      9 #include <errno.h>
     10 #include <time.h>
     11 #include <sys/types.h>
     12 #include <sys/wait.h>
     13 
     14 /*
     15  * DIO invalidates the read cache after it writes.  At one point it tried to
     16  * return EIO if this failed.  When called from AIO, though, this EIO return
     17  * would clobber EIOCBQUEUED and cause fs/aio.c and fs/direct-io.c to complete
     18  * an iocb twice.  This typically references freed memory from an interrupt
     19  * handler and oopses.
     20  *
     21  * This test hits the race after at most two minutes on a single spindle.  It
     22  * spins performing large dio writes.  It also spins racing buffered writes.
     23  * It assumes it's on ext3 using ordered writes.  The ordered write bhs can be
     24  * pinned by jbd as a transaction commits.  If invalidate_inode_pages2_range()
     25  * hits pages backed by those buffers ->releasepage will fail and it'll try to
     26  * return -EIO.
     27  */
     28 #ifndef O_DIRECT
     29 #define O_DIRECT         040000 /* direct disk access hint */
     30 #endif
     31 
     32 #define GINORMOUS (32 * 1024 * 1024)
     33 
     34 
     35 /* This test never survived to 180 seconds on a single spindle */
     36 #define SECONDS 200
     37 
     38 static unsigned char buf[GINORMOUS] __attribute((aligned (512)));
     39 
     40 #define fail(fmt , args...) do {\
     41 	printf(fmt , ##args);	\
     42 	exit(1);		\
     43 } while (0)
     44 
     45 void spin_dio(int fd)
     46 {
     47 	io_context_t ctx;
     48 	struct iocb iocb;
     49 	struct iocb *iocbs[1] = { &iocb };
     50 	struct io_event event;
     51 	int ret;
     52 
     53         io_prep_pwrite(&iocb, fd, buf, GINORMOUS, 0);
     54 
     55 	ret = io_queue_init(1, &ctx);
     56 	if (ret)
     57 		fail("io_queue_init returned %d", ret);
     58 
     59 	while (1) {
     60 		ret = io_submit(ctx, 1, iocbs);
     61 		if (ret != 1)
     62 			fail("io_submit returned %d instead of 1", ret);
     63 
     64 		ret = io_getevents(ctx, 1, 1, &event, NULL);
     65 		if (ret != 1)
     66 			fail("io_getevents returned %d instead of 1", ret);
     67 
     68 		if (event.res == -EIO) {
     69 			printf("invalidation returned -EIO, OK\n");
     70 			exit(0);
     71 		}
     72 
     73 		if (event.res != GINORMOUS)
     74 			fail("event res %ld\n", event.res);
     75 	}
     76 }
     77 
     78 void spin_buffered(int fd)
     79 {
     80 	int ret;
     81 
     82 	while (1) {
     83 		ret = pwrite(fd, buf, GINORMOUS, 0);
     84 		if (ret != GINORMOUS)
     85 			fail("buffered write returned %d", ret);
     86 	}
     87 }
     88 
     89 static void alarm_handler(int signum)
     90 {
     91 }
     92 
     93 int main(int argc, char **argv)
     94 {
     95 	pid_t buffered_pid;
     96 	pid_t dio_pid;
     97 	pid_t pid;
     98 	int fd;
     99 	int fd2;
    100 	int status;
    101 
    102 	if (argc != 2)
    103 		fail("only arg should be file name");
    104 
    105 	fd = open(argv[1], O_DIRECT|O_CREAT|O_RDWR, 0644);
    106 	if (fd < 0)
    107 		fail("open dio failed: %d\n", errno);
    108 
    109 	fd2 = open(argv[1], O_RDWR, 0644);
    110 	if (fd < 0)
    111 		fail("open failed: %d\n", errno);
    112 
    113 	buffered_pid = fork();
    114 	if (buffered_pid < 0)
    115 		fail("fork failed: %d\n", errno);
    116 
    117 	if (buffered_pid == 0) {
    118 		spin_buffered(fd2);
    119 		exit(0);
    120 	}
    121 
    122 	dio_pid = fork();
    123 	if (dio_pid < 0) {
    124 		kill(buffered_pid, SIGKILL);
    125 		fail("fork failed: %d\n", errno);
    126 	}
    127 
    128 	if (dio_pid == 0) {
    129 		spin_dio(fd);
    130 		exit(0);
    131 	}
    132 
    133 	signal(SIGALRM, alarm_handler);
    134 	alarm(SECONDS);
    135 
    136 	pid = wait(&status);
    137 	if (pid < 0 && errno == EINTR) {
    138 		/* if we timed out then we're done */
    139 		kill(buffered_pid, SIGKILL);
    140 		kill(dio_pid, SIGKILL);
    141 		printf("ran for %d seconds without error, passing\n", SECONDS);
    142 		exit(0);
    143 	}
    144 
    145 	if (pid == dio_pid)
    146 		kill(buffered_pid, SIGKILL);
    147 	else
    148 		kill(dio_pid, SIGKILL);
    149 
    150 	/*
    151 	 * pass on the child's pass/fail return code or fail if the child
    152 	 * didn't exit cleanly.
    153 	 */
    154 	exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
    155 }
    156