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