• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
spin_dio(int fd)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 
spin_buffered(int fd)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 
alarm_handler(int signum)89 static void alarm_handler(int signum)
90 {
91 }
92 
main(int argc,char ** argv)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