1 /* Tests for interrupting VFS calls - by D.C. van Moolenbroek */
2 #include <stdio.h>
3 #include <sys/time.h>
4 #include <sys/wait.h>
5 #include <sys/socket.h>
6 #include <sys/utsname.h>
7 #include <sys/syslimits.h>
8 #include <netinet/in.h>
9 #include <signal.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <util.h>
14
15 #define ITERATIONS 1
16
17 #include "common.h"
18
19 /*
20 * This signal handler does nothing. It just needs to be triggered, so that
21 * PM will tell VFS to unpause this process.
22 */
dummy_handler(int sig)23 static void dummy_handler(int sig)
24 {
25 /* Nothing. */
26 }
27
28 /*
29 * Interrupt a select(2) call.
30 */
31 static void
test76a(void)32 test76a(void)
33 {
34 struct sigaction act, oact;
35 struct itimerval it;
36 struct sockaddr_in sin;
37 struct timeval tv;
38 fd_set set;
39 int tfd[2], pfd[2], sfd, maxfd;
40
41 subtest = 1;
42
43 act.sa_handler = dummy_handler;
44 sigfillset(&act.sa_mask);
45 act.sa_flags = 0;
46 if (sigaction(SIGALRM, &act, &oact) < 0) e(1);
47
48 memset(&it, 0, sizeof(it));
49 it.it_value.tv_sec = 0;
50 it.it_value.tv_usec = 100000;
51 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(2);
52
53 /* First try without any file descriptors. */
54 tv.tv_sec = 1;
55 tv.tv_usec = 0;
56 if (select(0, NULL, NULL, NULL, &tv) >= 0) e(3);
57 if (errno != EINTR) e(4);
58
59 /* Then try with different types of file descriptors, all blocking. */
60 if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(5);
61
62 FD_ZERO(&set);
63 FD_SET(tfd[0], &set); /* reading from the PTY master should block */
64 maxfd = tfd[0];
65
66 if (pipe(pfd) < 0) e(6);
67 FD_SET(pfd[0], &set); /* reading from an empty pipe should block */
68 if (maxfd < pfd[0]) maxfd = pfd[0];
69
70 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(7);
71
72 memset(&sin, 0, sizeof(sin));
73 sin.sin_family = AF_INET;
74 /* Binding to an arbitrary port is fine. */
75 if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(8);
76
77 if (listen(sfd, 1) < 0) e(9);
78
79 FD_SET(sfd, &set); /* reading from a listening socket should block */
80 if (maxfd < sfd) maxfd = sfd;
81
82 memset(&it, 0, sizeof(it));
83 it.it_value.tv_sec = 0;
84 it.it_value.tv_usec = 100000;
85 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
86
87 tv.tv_sec = 1;
88 tv.tv_usec = 0;
89 if (select(maxfd + 1, &set, NULL, NULL, &tv) >= 0) e(11);
90 if (errno != EINTR) e(12);
91
92 if (close(tfd[0]) < 0) e(13);
93 if (close(tfd[1]) < 0) e(14);
94 if (close(pfd[0]) < 0) e(15);
95 if (close(pfd[1]) < 0) e(16);
96 if (close(sfd) < 0) e(17);
97
98 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(18);
99 }
100
101 /*
102 * Interrupt reads and writes to a pipe. POSIX states that if the operation
103 * was partially successful, the number of bytes written so far should be
104 * returned; otherwise, the we should get the normal EINTR.
105 */
106 static void
test76b(void)107 test76b(void)
108 {
109 struct sigaction act, oact;
110 struct itimerval it;
111 char *buf;
112 int pfd[2];
113
114 subtest = 2;
115
116 if ((buf = malloc(PIPE_BUF * 2)) == NULL) e(1);
117
118 if (pipe(pfd) < 0) e(2);
119
120 act.sa_handler = dummy_handler;
121 sigfillset(&act.sa_mask);
122 act.sa_flags = 0;
123 if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
124
125 memset(&it, 0, sizeof(it));
126 it.it_value.tv_sec = 0;
127 it.it_value.tv_usec = 100000;
128 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
129
130 /*
131 * This write is too large for the pipe, so it will block until the
132 * signal arrives. When being interrupted, it should return the pipe
133 * size, as that is the part that has been filled successfully so far.
134 */
135 if (write(pfd[1], buf, PIPE_BUF * 2) != PIPE_BUF) e(5);
136
137 /*
138 * Since the write partially succeeded, we should be able to read all
139 * we wrote so far, without blocking.
140 */
141 if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(6);
142
143 /* We should now be able to fill the pipe up to its full size again. */
144 if (write(pfd[1], buf, PIPE_BUF) != PIPE_BUF) e(7);
145
146 memset(&it, 0, sizeof(it));
147 it.it_value.tv_sec = 0;
148 it.it_value.tv_usec = 100000;
149 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(8);
150
151 /* Now interrupt a write attempt on a full pipe. */
152 if (write(pfd[1], buf, 1) >= 0) e(9);
153 if (errno != EINTR) e(10);
154
155 /* Empty the pipe again. */
156 if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(11);
157
158 memset(&it, 0, sizeof(it));
159 it.it_value.tv_sec = 0;
160 it.it_value.tv_usec = 100000;
161 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(12);
162
163 /* Now interrupt a read on an empty pipe. */
164 if (read(pfd[0], buf, PIPE_BUF) >= 0) e(13);
165 if (errno != EINTR) e(14);
166
167 if (close(pfd[0]) < 0) e(15);
168 if (close(pfd[1]) < 0) e(16);
169
170 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(17);
171
172 free(buf);
173 }
174
175 /*
176 * Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call
177 * on a TCP socket - the accept procedure is (currently) implemented using
178 * ioctl(2) calls.
179 */
180 static void
test76c(void)181 test76c(void)
182 {
183 struct sigaction act, oact;
184 struct itimerval it;
185 struct sockaddr_in sin;
186 socklen_t len;
187 int sfd;
188
189 subtest = 3;
190
191 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(1);
192
193 memset(&sin, 0, sizeof(sin));
194 sin.sin_family = AF_INET;
195 /* Binding to an arbitrary port is fine. */
196 if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(2);
197
198 if (listen(sfd, 1) < 0) e(3);
199
200 act.sa_handler = dummy_handler;
201 sigfillset(&act.sa_mask);
202 act.sa_flags = 0;
203 if (sigaction(SIGALRM, &act, &oact) < 0) e(4);
204
205 memset(&it, 0, sizeof(it));
206 it.it_value.tv_sec = 0;
207 it.it_value.tv_usec = 100000;
208 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(5);
209
210 /* This will block until the timer fires. */
211 len = sizeof(sin);
212 if (accept(sfd, (struct sockaddr *)&sin, &len) >= 0) e(6);
213 if (errno != EINTR) e(7);
214
215 if (close(sfd) < 0) e(8);
216
217 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(9);
218 }
219
220 /*
221 * Try to trigger semi-concurrent processing of normal system calls and
222 * postponed PM requests for a single process within VFS.
223 */
224 static void
test76d(void)225 test76d(void)
226 {
227 struct utsname name;
228 struct sigaction act, oact;
229 struct itimerval it;
230 int r, fd, pfd[2], count, status;
231 time_t stime, etime, runtime = 30 /*seconds*/;
232 char buf[3], *pbuf;
233
234 subtest = 4;
235
236 /* This test would kill wimpy platforms such as ARM. */
237 if (uname(&name) < 0) e(1);
238 if (!strcmp(name.machine, "arm")) return;
239
240 act.sa_handler = dummy_handler;
241 sigfillset(&act.sa_mask);
242 act.sa_flags = 0;
243 if (sigaction(SIGALRM, &act, &oact) < 0) e(2);
244
245 if (pipe(pfd) < 0) e(3);
246
247 /* Pre-fill the pipe. */
248 if ((pbuf = malloc(PIPE_BUF - 1)) == NULL) e(4);
249
250 if (write(pfd[1], pbuf, PIPE_BUF - 1) != PIPE_BUF - 1) e(5);
251
252 free(pbuf);
253
254 switch (fork()) {
255 case 0:
256 if (close(pfd[1]) < 0) e(6);
257
258 /* Read from the pipe, but more slowly than the writer. */
259 while ((r = read(pfd[0], buf, 2)) != 0)
260 if (r < 0) e(7);
261
262 exit(0);
263 case -1:
264 e(8);
265 default:
266 break;
267 }
268
269 switch (fork()) {
270 case 0:
271 if (close(pfd[0]) < 0) e(9);
272
273 time(&stime);
274
275 /* Start an alarm mayhem. */
276 it.it_value.tv_sec = 0;
277 it.it_value.tv_usec = 1;
278 it.it_interval.tv_sec = 0;
279 it.it_interval.tv_usec = 1;
280 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
281
282 /*
283 * Then start writing to the pipe, in such a way that the
284 * write operation will be suspended in every so many cases.
285 */
286 do {
287 if (write(pfd[1], buf, 3) < 0 && errno != EINTR)
288 e(11);
289
290 time(&etime);
291 } while ((int)(etime - stime) < runtime);
292
293 exit(0);
294 case -1:
295 e(12);
296 default:
297 break;
298 }
299
300 if (close(pfd[0]) < 0) e(13);
301 if (close(pfd[1]) < 0) e(14);
302
303 /*
304 * First give the two processes a while to run regularly. Then start
305 * creating additional noise to keep the VFS worker threads busy.
306 */
307 runtime /= 2;
308
309 sleep(runtime);
310
311 /*
312 * As of writing, VFS has less than 20 worker threads. Create more
313 * processes than that.
314 */
315 for (count = 2; count < 20; count++) {
316 switch (fork()) {
317 case 0:
318 time(&stime);
319
320 do {
321 /*
322 * Opening a character device blocks the
323 * calling thread, hopefully causing work to be
324 * queued. Sadly, in practice, the high
325 * priorities of system processes prevent this
326 * case from occurring frequently. It works
327 * better with a driver that has a priority
328 * below that of of user processes.
329 */
330 if ((fd = open("/dev/null", O_WRONLY)) < 0)
331 e(15);
332
333 close(fd);
334
335 time(&etime);
336 } while ((int)(etime - stime) < runtime);
337
338 exit(0);
339 case -1:
340 e(16);
341 default:
342 break;
343 }
344 }
345
346 /* Wait for all children to shut down. */
347 while (count-- > 0) {
348 if (wait(&status) <= 0) e(17);
349 if (!WIFEXITED(status)) e(18);
350 if (WEXITSTATUS(status) != 0) e(19);
351 }
352
353 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(20);
354 }
355
356 /*
357 * Try to get a nonblocking select(2) call to be interrupted by a signal.
358 * In the future, VFS should prevent this from happening at all; for now, we
359 * just want to make sure it does not result in disaster when it does happen.
360 */
361 static void
test76e(void)362 test76e(void)
363 {
364 struct utsname name;
365 struct sigaction act, oact;
366 struct itimerval it;
367 struct timeval tv;
368 fd_set set;
369 int tfd[2], left;
370
371 subtest = 5;
372
373 /* This test would kill wimpy platforms such as ARM. */
374 if (uname(&name) < 0) e(1);
375 if (!strcmp(name.machine, "arm")) return;
376
377 if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(2);
378
379 act.sa_handler = dummy_handler;
380 sigfillset(&act.sa_mask);
381 act.sa_flags = 0;
382 if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
383
384 /*
385 * Start an alarm mayhem. We have to try to get a signal in between
386 * VFS sending a select request to TTY, and TTY replying to VFS with
387 * initial results.
388 */
389 it.it_value.tv_sec = 0;
390 it.it_value.tv_usec = 1;
391 it.it_interval.tv_sec = 0;
392 it.it_interval.tv_usec = 1;
393 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
394
395 /*
396 * Now issue nonblocking selects until we get interrupted, or until
397 * we have gone through a hardcoded maximum of attempts.
398 */
399 left = 100000;
400 do {
401 if (--left == 0) break;
402
403 FD_ZERO(&set);
404 FD_SET(tfd[0], &set); /* reading from master should block */
405
406 tv.tv_sec = 0;
407 tv.tv_usec = 0;
408 } while (select(2, &set, NULL, NULL, &tv) >= 0);
409
410 if (left > 0 && errno != EINTR) e(5);
411
412 it.it_value.tv_sec = 0;
413 it.it_value.tv_usec = 0;
414 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(6);
415
416 /* The call failed, so the set must be unmodified. */
417 if (left > 0 && !FD_SET(tfd[0], &set)) e(7);
418
419 if (close(tfd[0]) < 0) e(8);
420 if (close(tfd[1]) < 0) e(9);
421
422 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(10);
423 }
424
425 int
main(int argc,char ** argv)426 main(int argc, char **argv)
427 {
428 int i, m;
429
430 start(76);
431
432 if (argc == 2)
433 m = atoi(argv[1]);
434 else
435 m = 0xFF;
436
437 for (i = 0; i < ITERATIONS; i++) {
438 if (m & 0x01) test76a();
439 if (m & 0x02) test76b();
440 if (m & 0x04) test76c();
441 if (m & 0x08) test76d();
442 if (m & 0x10) test76e();
443 }
444
445 quit();
446 }
447