1 /*
2  * Copyright (C) 2012-2021 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * This code is a complete clean re-write of the stress tool by
19  * Colin Ian King <colin.king@canonical.com> and attempts to be
20  * backwardly compatible with the stress tool by Amos Waterland
21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
22  * functionality.
23  */
24 #include "stress-ng.h"
25 
26 static const stress_help_t help[] = {
27 	{ NULL,	"fanotify N",	  "start N workers exercising fanotify events" },
28 	{ NULL,	"fanotify-ops N", "stop fanotify workers after N bogo operations" },
29 	{ NULL,	NULL,		  NULL }
30 };
31 
32 #if defined(HAVE_MNTENT_H) &&		\
33     defined(HAVE_SYS_SELECT_H) && 	\
34     defined(HAVE_SYS_FANOTIFY_H) &&	\
35     defined(HAVE_FANOTIFY)
36 
37 #define MAX_MNTS	(4096)
38 
39 #define BUFFER_SIZE	(4096)
40 
41 /* fanotify stats */
42 typedef struct {
43 	uint64_t	open;
44 	uint64_t	close_write;
45 	uint64_t	close_nowrite;
46 	uint64_t	access;
47 	uint64_t	modify;
48 } stress_fanotify_account_t;
49 
50 #endif
51 
52 #if defined(HAVE_FANOTIFY) &&	\
53     defined(HAVE_SYS_SELECT_H)
54 
55 static const unsigned int fan_stress_settings[] = {
56 #if defined(FAN_ACCESS)
57 	FAN_ACCESS,
58 #endif
59 #if defined(FAN_ACCESS_PERM)
60 	FAN_ACCESS_PERM,
61 #endif
62 #if defined(FAN_ATTRIB)
63 	FAN_ATTRIB,
64 #endif
65 #if defined(FAN_CLOSE)
66 	FAN_CLOSE,
67 #endif
68 #if defined(FAN_CLOSE_NOWRITE)
69 	FAN_CLOSE_NOWRITE,
70 #endif
71 #if defined(FAN_CLOSE_WRITE)
72 	FAN_CLOSE_WRITE,
73 #endif
74 #if defined(FAN_CREATE)
75 	FAN_CREATE,
76 #endif
77 #if defined(FAN_DELETE)
78 	FAN_DELETE,
79 #endif
80 #if defined(FAN_DELETE_SELF)
81 	FAN_DELETE_SELF,
82 #endif
83 #if defined(FAN_DIR_MODIFY)
84 	FAN_DIR_MODIFY,
85 #endif
86 #if defined(FAN_EVENT_ON_CHILD)
87 	FAN_EVENT_ON_CHILD,
88 #endif
89 #if defined(FAN_MODIFY)
90 	FAN_MODIFY,
91 #endif
92 #if defined(FAN_MOVE)
93 	FAN_MOVE,
94 #endif
95 #if defined(FAN_MOVED_FROM)
96 	FAN_MOVED_FROM,
97 #endif
98 #if defined(FAN_MOVE_SELF)
99 	FAN_MOVE_SELF,
100 #endif
101 #if defined(FAN_MOVED_TO)
102 	FAN_MOVED_TO,
103 #endif
104 #if defined(FAN_ONDIR)
105 	FAN_ONDIR,
106 #endif
107 #if defined(FAN_OPEN)
108 	FAN_OPEN,
109 #endif
110 #if defined(FAN_OPEN_EXEC)
111 	FAN_OPEN_EXEC,
112 #endif
113 #if defined(FAN_OPEN_EXEC_PERM)
114 	FAN_OPEN_EXEC_PERM,
115 #endif
116 #if defined(FAN_OPEN_PERM)
117 	FAN_OPEN_PERM,
118 #endif
119 #if defined(FAN_Q_OVERFLOW)
120 	FAN_Q_OVERFLOW,
121 #endif
122 #if defined(FAN_FS_ERROR)
123 	FAN_FS_ERROR,
124 #endif
125 	0
126 };
127 
128 static const unsigned int init_flags[] =
129 {
130 #if defined(FAN_CLASS_CONTENT)
131 	FAN_CLASS_CONTENT,
132 #endif
133 #if defined(FAN_CLASS_PRE_CONTENT)
134 	FAN_CLASS_PRE_CONTENT,
135 #endif
136 #if defined(FAN_UNLIMITED_QUEUE)
137 	FAN_UNLIMITED_QUEUE,
138 #endif
139 #if defined(FAN_UNLIMITED_MARKS)
140 	FAN_UNLIMITED_MARKS,
141 #endif
142 #if defined(FAN_CLOEXEC)
143 	FAN_CLOEXEC,
144 #endif
145 #if defined(FAN_NONBLOCK)
146 	FAN_NONBLOCK,
147 #endif
148 #if defined(FAN_ENABLE_AUDIT)
149 	FAN_ENABLE_AUDIT,
150 #endif
151 #if defined(FAN_REPORT_NAME)
152 	FAN_REPORT_NAME,
153 #endif
154 #if defined(FAN_REPORT_DIR_FID)
155 	FAN_REPORT_DIR_FID,
156 #endif
157 #if defined(FAN_REPORT_PIDFD)
158 	FAN_REPORT_PIDFD,
159 #endif
160 };
161 
162 static char *mnts[MAX_MNTS];
163 static int n_mnts;
164 
165 /*
166  *  stress_fanotify_supported()
167  *      check if we can run this as root
168  */
stress_fanotify_supported(const char * name)169 static int stress_fanotify_supported(const char *name)
170 {
171 	int fan_fd;
172 	static const char skipped[] =
173 		"stressor will be skipped, ";
174 	static const char noperm[] =
175 		"stressor needs to be running with CAP_SYS_ADMIN "
176 		"rights";
177 	static const char noresource[] =
178 		": no resources (out of descriptors or memory)";
179 	static const char nosyscall[] =
180 		": system call not supported";
181 
182 	if (!stress_check_capability(SHIM_CAP_SYS_ADMIN)) {
183 		pr_inf_skip("%s %s%s\n", name, skipped, noperm);
184 		return -1;
185 	}
186 	fan_fd = fanotify_init(0, 0);
187 	if (fan_fd < 0) {
188 		int rc = -1;
189 
190 		switch (errno) {
191 		case EPERM:
192 			pr_inf_skip("%s %s%s\n", name, skipped, noperm);
193 			break;
194 		case EMFILE:
195 		case ENOMEM:
196 			pr_inf_skip("%s %s%s\n", name, skipped, noresource);
197 			break;
198 		case ENOSYS:
199 			pr_inf_skip("%s %s%s\n", name, skipped, nosyscall);
200 			break;
201 		default:
202 			rc = 0;
203 			break;
204 		}
205 		return rc;
206 	}
207 	(void)close(fan_fd);
208 
209 	return 0;
210 }
211 
212 /*
213  *  fanotify_event_init_invalid_call()
214  *	perform init call and close fd if call succeeded (which should
215  *	not happen).
216  */
fanotify_event_init_invalid_call(unsigned int flags,unsigned int event_f_flags)217 static void fanotify_event_init_invalid_call(unsigned int flags, unsigned int event_f_flags)
218 {
219 	int fan_fd;
220 
221 	fan_fd = fanotify_init(flags, event_f_flags);
222 	if (fan_fd >= 0)
223 		(void)close(fan_fd);
224 }
225 
226 #define FANOTIFY_CLASS_BITS
227 
228 /*
229  *  fanotify_event_init_invalid()
230  *  exercise invalid ways to call fanotify_init to
231  *  get more kernel coverage
232  */
fanotify_event_init_invalid(void)233 static void fanotify_event_init_invalid(void)
234 {
235 	fanotify_event_init_invalid_call(0U, ~0U);
236 	fanotify_event_init_invalid_call(~0U, ~0U);
237 	fanotify_event_init_invalid_call(~0U, 0U);
238 
239 #if defined(FAN_CLASS_NOTIF) &&		\
240     defined(FAN_CLASS_CONTENT) && 	\
241     defined(FAN_CLASS_PRE_CONTENT)
242 	fanotify_event_init_invalid_call(FAN_CLASS_NOTIF |
243 					 FAN_CLASS_CONTENT |
244 					 FAN_CLASS_PRE_CONTENT, ~0U);
245 #endif
246 }
247 
248 /*
249  *  test_fanotify_mark()
250  *     tests fanotify_mark syscall
251  */
test_fanotify_mark(const char * name,char * mounts[])252 static int test_fanotify_mark(const char *name, char *mounts[])
253 {
254 	int ret_fd, ret;
255 #if defined(FAN_MARK_INODE)
256 	const int bad_fd = stress_get_bad_fd();
257 #endif
258 
259 	ret_fd = fanotify_init(0, 0);
260 	if (ret_fd < 0) {
261 		pr_err("%s: cannot initialize fanotify, errno=%d (%s)\n",
262 			name, errno, strerror(errno));
263 		return -1;
264 	}
265 
266 	/* Exercise fanotify_mark with invalid mask */
267 #if defined(FAN_MARK_MOUNT)
268 	ret = fanotify_mark(ret_fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
269 			~0U, AT_FDCWD, mounts[0]);
270 	(void)ret;
271 #endif
272 
273 	/* Exercise fanotify_mark with invalid flag */
274 	ret = fanotify_mark(ret_fd, ~0U, FAN_ACCESS, AT_FDCWD, mounts[0]);
275 	(void)ret;
276 
277 	/* Exercise fanotify_mark on bad fd */
278 #if defined(FAN_MARK_INODE)
279 	ret = fanotify_mark(bad_fd, FAN_MARK_ADD | FAN_MARK_INODE,
280 		FAN_ACCESS, AT_FDCWD, mounts[0]);
281 	(void)ret;
282 #endif
283 
284 	/* Exercise fanotify_mark by passing two operations simultaneously */
285 	ret = fanotify_mark(ret_fd, FAN_MARK_REMOVE | FAN_MARK_ADD,
286 		FAN_ACCESS, AT_FDCWD, mounts[0]);
287 	(void)ret;
288 
289 	/* Exercise valid fanotify_mark to increase kernel coverage */
290 #if defined(FAN_MARK_INODE)
291 	ret = fanotify_mark(ret_fd, FAN_MARK_ADD | FAN_MARK_INODE,
292 		FAN_ACCESS, AT_FDCWD, mounts[0]);
293 	(void)ret;
294 #endif
295 
296 #if defined(FAN_MARK_IGNORED_MASK)
297 	ret = fanotify_mark(ret_fd, FAN_MARK_ADD | FAN_MARK_IGNORED_MASK,
298 		FAN_ACCESS, AT_FDCWD, mounts[0]);
299 	(void)ret;
300 #endif
301 
302 	/* Exercise other invalid combinations of flags */
303 	ret = fanotify_mark(ret_fd, FAN_MARK_REMOVE,
304 		0, AT_FDCWD, mnts[0]);
305 	(void)ret;
306 
307 #if defined(FAN_MARK_ONLYDIR)
308 	ret = fanotify_mark(ret_fd, FAN_MARK_FLUSH | FAN_MARK_ONLYDIR,
309 		FAN_ACCESS, AT_FDCWD, mnts[0]);
310 	(void)ret;
311 #endif
312 
313 	(void)close(ret_fd);
314 
315 	return 0;
316 }
317 
318 /*
319  *  fanotify_event_init()
320  *	initialize fanotify
321  */
fanotify_event_init(const char * name,char * mounts[],const int flags)322 static int fanotify_event_init(const char *name, char *mounts[], const int flags)
323 {
324 	int fan_fd, count = 0, i;
325 
326 	fan_fd = fanotify_init(flags, 0);
327 	if (fan_fd < 0) {
328 		pr_err("%s: cannot initialize fanotify, errno=%d (%s)\n",
329 			name, errno, strerror(errno));
330 		return -1;
331 	}
332 
333 	/*
334 	 *  Gather all mounted file systems and monitor them
335 	 */
336 	for (i = 0; i < n_mnts; i++) {
337 		size_t j;
338 #if defined(FAN_MARK_MOUNT) || defined(FAN_MARK_FILESYSTEM)
339 		int ret;
340 #endif
341 
342 		for (j = 0; j < SIZEOF_ARRAY(fan_stress_settings); j++) {
343 #if defined(FAN_MARK_MOUNT)
344 			ret = fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
345 				fan_stress_settings[j], AT_FDCWD, mounts[i]);
346 			if (ret == 0)
347 				count++;
348 #endif
349 
350 #if defined(FAN_MARK_FILESYSTEM)
351 			ret = fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_FILESYSTEM,
352 				fan_stress_settings[j], AT_FDCWD, mounts[i]);
353 			if (ret == 0)
354 				count++;
355 #endif
356 		}
357 	}
358 
359 	/* This really should not happen, / is always mounted */
360 	if (!count) {	/* cppcheck-suppress knownConditionTrueFalse */
361 		pr_err("%s: no mount points could be monitored\n",
362 			name);
363 		(void)close(fan_fd);
364 		return -1;
365 	}
366 	return fan_fd;
367 }
368 
369 /*
370  *  fanotify_event_clear()
371  *	exercise remove and flush fanotify_marking
372  */
fanotify_event_clear(const int fan_fd)373 static void fanotify_event_clear(const int fan_fd)
374 {
375 #if defined(FAN_MARK_REMOVE)
376 	int i;
377 
378 	/*
379 	 *  Gather all mounted file systems and monitor them
380 	 */
381 	for (i = 0; i < n_mnts; i++) {
382 		size_t j;
383 #if defined(FAN_MARK_MOUNT) || defined(FAN_MARK_FILESYSTEM)
384 		int ret;
385 #endif
386 
387 		for (j = 0; j < SIZEOF_ARRAY(fan_stress_settings); j++) {
388 #if defined(FAN_MARK_MOUNT)
389 			ret = fanotify_mark(fan_fd, FAN_MARK_REMOVE | FAN_MARK_MOUNT,
390 				fan_stress_settings[j], AT_FDCWD, mnts[i]);
391 			(void)ret;
392 #endif
393 
394 #if defined(FAN_MARK_FILESYSTEM)
395 			ret = fanotify_mark(fan_fd, FAN_MARK_REMOVE | FAN_MARK_FILESYSTEM,
396 				fan_stress_settings[j], AT_FDCWD, mnts[i]);
397 			(void)ret;
398 #endif
399 		}
400 #if defined(FAN_MARK_FLUSH) &&	\
401     defined(FAN_MARK_MOUNT)
402 		ret = fanotify_mark(fan_fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
403 				0, AT_FDCWD, mnts[i]);
404 		(void)ret;
405 #endif
406 #if defined(FAN_MARK_FLUSH) &&	\
407     defined(FAN_MARK_FILESYSTEM)
408 		ret = fanotify_mark(fan_fd, FAN_MARK_FLUSH | FAN_MARK_FILESYSTEM,
409 				0, AT_FDCWD, mnts[i]);
410 		(void)ret;
411 #endif
412 	}
413 #endif
414 }
415 
416 /*
417  *  stress_fanotify_init_exercise()
418  *	exercise fanotify_init with specified flags
419  */
stress_fanotify_init_exercise(const unsigned int flags)420 static void stress_fanotify_init_exercise(const unsigned int flags)
421 {
422 	int ret_fd;
423 
424 	ret_fd = fanotify_init(flags, 0);
425 	if (ret_fd != -1)
426 		(void)close(ret_fd);
427 }
428 
stress_fanotify_read_events(const stress_args_t * args,const int fan_fd,void * buffer,const size_t buffer_size,stress_fanotify_account_t * account)429 static void stress_fanotify_read_events(
430 	const stress_args_t *args,
431 	const int fan_fd,
432 	void *buffer,
433 	const size_t buffer_size,
434 	stress_fanotify_account_t *account)
435 {
436 	ssize_t len;
437 	struct fanotify_event_metadata *metadata;
438 
439 	len = read(fan_fd, (void *)buffer, buffer_size);
440 	if (len <= 0)
441 		return;
442 
443 	metadata = (struct fanotify_event_metadata *)buffer;
444 
445 	while (FAN_EVENT_OK(metadata, len)) {
446 		if (!keep_stressing_flag())
447 			break;
448 		if ((metadata->fd != FAN_NOFD) && (metadata->fd >= 0)) {
449 #if defined(FAN_OPEN)
450 			if (metadata->mask & FAN_OPEN)
451 				account->open++;
452 #endif
453 #if defined(FAN_CLOSE_WRITE)
454 			if (metadata->mask & FAN_CLOSE_WRITE)
455 				account->close_write++;
456 #endif
457 #if defined(FAN_CLOSE_NOWRITE)
458 			if (metadata->mask & FAN_CLOSE_NOWRITE)
459 				account->close_nowrite++;
460 #endif
461 #if defined(FAN_ACCESS)
462 			if (metadata->mask & FAN_ACCESS)
463 				account->access++;
464 #endif
465 #if defined(FAN_MODIFY)
466 			if (metadata->mask & FAN_MODIFY)
467 				account->modify++;
468 #endif
469 			inc_counter(args);
470 			(void)close(metadata->fd);
471 		}
472 		metadata = FAN_EVENT_NEXT(metadata, len);
473 	}
474 }
475 
476 /*
477  *  stress_fanotify()
478  *	stress fanotify
479  */
stress_fanotify(const stress_args_t * args)480 static int stress_fanotify(const stress_args_t *args)
481 {
482 	char pathname[PATH_MAX - 16], filename[PATH_MAX];
483 	int ret, pid, rc = EXIT_SUCCESS;
484 	stress_fanotify_account_t account;
485 
486 	(void)memset(&account, 0, sizeof(account));
487 
488 	stress_temp_dir_args(args, pathname, sizeof(pathname));
489 	(void)stress_mk_filename(filename, sizeof(filename), pathname, "fanotify_file");
490 	ret = stress_temp_dir_mk_args(args);
491 	if (ret < 0)
492 		return exit_status(-ret);
493 
494 	stress_set_proc_state(args->name, STRESS_STATE_RUN);
495 
496 	pid = fork();
497 
498 	/* do all mount points */
499 	(void)memset(mnts, 0, sizeof(mnts));
500 
501 	n_mnts = stress_mount_get(mnts, MAX_MNTS);
502 	if (n_mnts < 1) {
503 		pr_err("%s: cannot get mount point information\n", args->name);
504 		rc = EXIT_NO_RESOURCE;
505 		goto tidy;
506 	}
507 
508 	if (pid < 0) {
509 		pr_err("%s: fork failed: errno=%d (%s)\n",
510 			args->name, errno, strerror(errno));
511 		rc = EXIT_NO_RESOURCE;
512 		goto tidy;
513 	} else if (pid == 0) {
514 		/* Child */
515 
516 		(void)sched_settings_apply(true);
517 
518 		do {
519 			int fd;
520 			ssize_t n;
521 			char buffer[64];
522 
523 			/* Force FAN_CLOSE_NOWRITE */
524 			fd = creat(filename, S_IRUSR | S_IWUSR);
525 			if (fd < 0) {
526 				pr_fail("%s: creat %s failed, errno=%d (%s)\n",
527 					args->name, filename, errno, strerror(errno));
528 				(void)kill(args->ppid, SIGALRM);
529 				_exit(EXIT_FAILURE);
530 			}
531 			(void)close(fd);
532 
533 			/* Force FAN_CLOSE_WRITE */
534 			fd = open(filename, O_WRONLY, S_IRUSR | S_IWUSR);
535 			if (fd < 0) {
536 				pr_fail("%s: open %s O_WRONLY failed, errno=%d (%s)\n",
537 					args->name, filename, errno, strerror(errno));
538 				(void)kill(args->ppid, SIGALRM);
539 				_exit(EXIT_FAILURE);
540 			}
541 			n = write(fd, "test", 4);
542 			(void)n;
543 			(void)close(fd);
544 
545 			/* Force FAN_ACCESS */
546 			fd = open(filename, O_RDONLY, S_IRUSR | S_IWUSR);
547 			if (fd < 0) {
548 				pr_fail("%s: open %s O_RDONLY failed, errno=%d (%s)\n",
549 					args->name, filename, errno, strerror(errno));
550 				(void)kill(args->ppid, SIGALRM);
551 				_exit(EXIT_FAILURE);
552 			}
553 			n = read(fd, buffer, sizeof(buffer));
554 			(void)n;
555 			(void)close(fd);
556 
557 			/* Force remove */
558 			(void)unlink(filename);
559 		} while (keep_stressing(args));
560 
561 		_exit(EXIT_SUCCESS);
562 	} else {
563 		void *buffer;
564 		int fan_fd1, max_fd;
565 #if defined(FAN_CLASS_NOTIF) &&		\
566     defined(FAN_REPORT_DFID_NAME)
567 		int fan_fd2;
568 #endif
569 
570 		fanotify_event_init_invalid();
571 
572 		ret = posix_memalign(&buffer, BUFFER_SIZE, BUFFER_SIZE);
573 		if ((ret != 0) || (buffer == NULL)) {
574 			pr_err("%s: posix_memalign: cannot allocate 4K "
575 				"aligned buffer\n", args->name);
576 			rc = EXIT_NO_RESOURCE;
577 			goto tidy;
578 		}
579 
580 		fan_fd1 = fanotify_event_init(args->name, mnts, 0);
581 		if (fan_fd1 < 0) {
582 			free(buffer);
583 			rc = EXIT_FAILURE;
584 			goto tidy;
585 		}
586 
587 #if defined(FAN_CLASS_NOTIF) &&		\
588     defined(FAN_REPORT_DFID_NAME)
589 		fan_fd2 = fanotify_event_init(args->name, mnts, FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME);
590 		if (fan_fd2 < 0) {
591 			fan_fd2 = -1;
592 		}
593 		max_fd = STRESS_MAXIMUM(fan_fd1, fan_fd2);
594 #else
595 		max_fd = fan_fd1;
596 #endif
597 
598 		ret = test_fanotify_mark(args->name, mnts);
599 		if (ret < 0) {
600 			free(buffer);
601 			rc = EXIT_FAILURE;
602 			goto tidy;
603 		}
604 
605 		do {
606 			fd_set rfds;
607 			size_t i;
608 
609 			FD_ZERO(&rfds);
610 			FD_SET(fan_fd1, &rfds);
611 #if defined(FAN_CLASS_NOTIF) &&		\
612     defined(FAN_REPORT_DFID_NAME)
613 			if (fan_fd2 >= 0)
614 				FD_SET(fan_fd2, &rfds);
615 #endif
616 			ret = select(max_fd + 1, &rfds, NULL, NULL, NULL);
617 			if (ret == -1) {
618 				if (errno == EINTR)
619 					continue;
620 				pr_fail("%s: select failed, errno=%d (%s)\n",
621 					args->name, errno, strerror(errno));
622 				continue;
623 			}
624 			if (ret == 0)
625 				continue;
626 
627 #if defined(FIONREAD)
628 			{
629 				int isz;
630 
631 				/*
632 				 *  Force kernel to determine number
633 				 *  of bytes that are ready to be read
634 				 *  for some extra stress
635 				 */
636 				ret = ioctl(fan_fd1, FIONREAD, &isz);
637 				(void)ret;
638 			}
639 #endif
640 			if (FD_ISSET(fan_fd1, &rfds))
641 				stress_fanotify_read_events(args, fan_fd1, buffer, BUFFER_SIZE, &account);
642 #if defined(FAN_CLASS_NOTIF) &&		\
643     defined(FAN_REPORT_DFID_NAME)
644 			if ((fan_fd2 >= 0) && FD_ISSET(fan_fd2, &rfds))
645 				stress_fanotify_read_events(args, fan_fd2, buffer, BUFFER_SIZE, &account);
646 #endif
647 
648 			/*
649 			 * Exercise fanotify_init with all possible values
650 			 * of flag argument to increase kernel coverage
651 			 */
652 			for (i = 0; i < SIZEOF_ARRAY(init_flags); i++) {
653 				stress_fanotify_init_exercise(init_flags[i]);
654 			}
655 		} while (keep_stressing(args));
656 
657 		free(buffer);
658 		fanotify_event_clear(fan_fd1);
659 		(void)close(fan_fd1);
660 #if defined(FAN_CLASS_NOTIF) &&		\
661     defined(FAN_REPORT_DFID_NAME)
662 		if (fan_fd2 >= 0) {
663 			fanotify_event_clear(fan_fd2);
664 			(void)close(fan_fd2);
665 		}
666 #endif
667 		pr_inf("%s: "
668 			"%" PRIu64 " open, "
669 			"%" PRIu64 " close write, "
670 			"%" PRIu64 " close nowrite, "
671 			"%" PRIu64 " access, "
672 			"%" PRIu64 " modify\n",
673 			args->name,
674 			account.open,
675 			account.close_write,
676 			account.close_nowrite,
677 			account.access,
678 			account.modify);
679 	}
680 tidy:
681 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
682 
683 	if (pid > 0) {
684 		int status;
685 
686 		(void)kill(pid, SIGKILL);
687 		(void)shim_waitpid(pid, &status, 0);
688 	}
689 	(void)unlink(filename);
690 	(void)stress_temp_dir_rm_args(args);
691 	stress_mount_free(mnts, n_mnts);
692 
693 	return rc;
694 }
695 
696 stressor_info_t stress_fanotify_info = {
697 	.stressor = stress_fanotify,
698 	.supported = stress_fanotify_supported,
699 	.class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS,
700 	.help = help
701 };
702 #else
703 stressor_info_t stress_fanotify_info = {
704 	.stressor = stress_not_implemented,
705 	.class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS,
706 	.help = help
707 };
708 #endif
709