1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2014 SUSE Linux. All Rights Reserved.
4 *
5 * Started by Jan Kara <jack@suse.cz>
6 *
7 * DESCRIPTION
8 * Check that fanotify overflow event is properly generated
9 *
10 * ALGORITHM
11 * Generate enough events without reading them and check that overflow
12 * event is generated.
13 */
14 #define _GNU_SOURCE
15 #include "config.h"
16
17 #include <stdio.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/syscall.h>
24 #include "tst_test.h"
25 #include "fanotify.h"
26
27 #if defined(HAVE_SYS_FANOTIFY_H)
28 #include <sys/fanotify.h>
29
30 #define MOUNT_PATH "fs_mnt"
31
32 /* Currently this is fixed in kernel... */
33 #define MAX_EVENTS 16384
34
35 #define BUF_SIZE 256
36 static char fname[BUF_SIZE];
37 static int fd, fd_notify;
38
39 struct fanotify_event_metadata event;
40
test01(void)41 void test01(void)
42 {
43 int i;
44 int len;
45
46 /*
47 * generate events
48 */
49 for (i = 0; i < MAX_EVENTS + 1; i++) {
50 sprintf(fname, MOUNT_PATH"/fname_%d", i);
51 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0644);
52 SAFE_CLOSE(fd);
53 }
54
55 while (1) {
56 /*
57 * get list on events
58 */
59 len = read(fd_notify, &event, sizeof(event));
60 if (len < 0) {
61 if (errno == -EAGAIN) {
62 tst_res(TFAIL, "Overflow event not "
63 "generated!\n");
64 break;
65 }
66 tst_brk(TBROK | TERRNO,
67 "read of notification event failed");
68 break;
69 }
70 if (event.fd != FAN_NOFD)
71 close(event.fd);
72
73 /*
74 * check events
75 */
76 if (event.mask != FAN_OPEN &&
77 event.mask != FAN_Q_OVERFLOW) {
78 tst_res(TFAIL,
79 "got event: mask=%llx (expected %llx)"
80 "pid=%u fd=%d",
81 (unsigned long long)event.mask,
82 (unsigned long long)FAN_OPEN,
83 (unsigned)event.pid, event.fd);
84 break;
85 }
86 if (event.mask == FAN_Q_OVERFLOW) {
87 if (event.fd != FAN_NOFD) {
88 tst_res(TFAIL,
89 "invalid overflow event: "
90 "mask=%llx pid=%u fd=%d",
91 (unsigned long long)event.mask,
92 (unsigned)event.pid,
93 event.fd);
94 break;
95 }
96 tst_res(TPASS,
97 "got event: mask=%llx pid=%u fd=%d",
98 (unsigned long long)event.mask,
99 (unsigned)event.pid, event.fd);
100 break;
101 }
102 }
103 }
104
setup(void)105 static void setup(void)
106 {
107 fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF | FAN_NONBLOCK,
108 O_RDONLY);
109
110 if (fanotify_mark(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN,
111 AT_FDCWD, MOUNT_PATH) < 0) {
112 tst_brk(TBROK | TERRNO,
113 "fanotify_mark (%d, FAN_MARK_MOUNT | FAN_MARK_ADD, "
114 "FAN_OPEN, AT_FDCWD, \".\") failed",
115 fd_notify);
116 }
117 }
118
cleanup(void)119 static void cleanup(void)
120 {
121 if (fd_notify > 0)
122 SAFE_CLOSE(fd_notify);
123 }
124
125 static struct tst_test test = {
126 .test_all = test01,
127 .setup = setup,
128 .cleanup = cleanup,
129 .needs_root = 1,
130 .mount_device = 1,
131 .mntpoint = MOUNT_PATH,
132 };
133 #else
134 TST_TEST_TCONF("system doesn't have required fanotify support");
135 #endif
136