1 /*
2 * Copyright (c) 2015 SUSE Linux. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * Started by Jan Kara <jack@suse.cz>
20 *
21 * DESCRIPTION
22 * Test for inotify mark destruction race.
23 *
24 * Kernels prior to 4.2 have a race when inode is being deleted while
25 * inotify group watching that inode is being torn down. When the race is
26 * hit, the kernel crashes or loops.
27 *
28 * The problem has been fixed by commit:
29 * 8f2f3eb59dff "fsnotify: fix oops in fsnotify_clear_marks_by_group_flags()".
30 */
31
32 #include "config.h"
33
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <time.h>
39 #include <signal.h>
40 #include <sys/time.h>
41 #include <sys/wait.h>
42 #include <sys/syscall.h>
43
44 #include "tst_test.h"
45 #include "inotify.h"
46
47 #if defined(HAVE_SYS_INOTIFY_H)
48 #include <sys/inotify.h>
49
50 /* Number of test loops to run the test for */
51 #define TEARDOWNS 400
52
53 /* Number of files to test (must be > 1) */
54 #define FILES 5
55
56 char names[FILES][PATH_MAX];
57
setup(void)58 static void setup(void)
59 {
60 int i;
61
62 for (i = 0; i < FILES; i++)
63 sprintf(names[i], "fname_%d", i);
64 }
65
verify_inotify(void)66 static void verify_inotify(void)
67 {
68 int inotify_fd, fd;
69 pid_t pid;
70 int i, tests;
71
72 pid = SAFE_FORK();
73 if (pid == 0) {
74 while (1) {
75 for (i = 0; i < FILES; i++) {
76 fd = SAFE_OPEN(names[i], O_CREAT | O_RDWR, 0600);
77 SAFE_CLOSE(fd);
78 }
79 for (i = 0; i < FILES; i++)
80 SAFE_UNLINK(names[i]);
81 }
82 }
83
84 for (tests = 0; tests < TEARDOWNS; tests++) {
85 inotify_fd = myinotify_init1(O_NONBLOCK);
86 if (inotify_fd < 0)
87 tst_brk(TBROK | TERRNO, "inotify_init failed");
88
89 for (i = 0; i < FILES; i++) {
90 /*
91 * Both failure and success are fine since
92 * files are being deleted in parallel - this
93 * is what provokes the race we want to test
94 * for...
95 */
96 myinotify_add_watch(inotify_fd, names[i], IN_MODIFY);
97 }
98 SAFE_CLOSE(inotify_fd);
99 }
100 /* We survived for given time - test succeeded */
101 tst_res(TPASS, "kernel survived inotify beating");
102
103 /* Kill the child creating / deleting files and wait for it */
104 SAFE_KILL(pid, SIGKILL);
105 SAFE_WAIT(NULL);
106 }
107
108 static struct tst_test test = {
109 .timeout = 600,
110 .needs_tmpdir = 1,
111 .forks_child = 1,
112 .setup = setup,
113 .test_all = verify_inotify,
114 };
115
116 #else
117 TST_TEST_TCONF("system doesn't have required inotify support");
118 #endif
119