1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2014 SUSE Linux. All Rights Reserved.
4 * Author: Jan Kara <jack@suse.cz>
5 *
6 * DESCRIPTION
7 * Check that inotify overflow event is properly generated
8 *
9 * ALGORITHM
10 * Generate enough events without reading them and check that overflow
11 * event is generated.
12 */
13 #include "config.h"
14
15 #include <stdio.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <sys/syscall.h>
22 #include "tst_test.h"
23 #include "inotify.h"
24
25 #if defined(HAVE_SYS_INOTIFY_H)
26 #include <sys/inotify.h>
27
28 /* size of the event structure, not counting name */
29 #define EVENT_SIZE (sizeof(struct inotify_event))
30 #define EVENT_BUF_LEN (EVENT_SIZE * 16)
31
32 #define BUF_SIZE 256
33 static char fname[BUF_SIZE];
34 static char buf[BUF_SIZE];
35 static int fd, fd_notify;
36 static int wd;
37 static int max_events;
38
39 static char event_buf[EVENT_BUF_LEN];
40
verify_inotify(void)41 void verify_inotify(void)
42 {
43 int i;
44 int len, stop;
45
46 /*
47 * generate events
48 */
49 fd = SAFE_OPEN(fname, O_RDWR);
50
51 for (i = 0; i < max_events; i++) {
52 SAFE_LSEEK(fd, 0, SEEK_SET);
53 SAFE_READ(1, fd, buf, BUF_SIZE);
54 SAFE_LSEEK(fd, 0, SEEK_SET);
55 SAFE_WRITE(1, fd, buf, BUF_SIZE);
56 }
57
58 SAFE_CLOSE(fd);
59
60 stop = 0;
61 while (!stop) {
62 /*
63 * get list on events
64 */
65 len = read(fd_notify, event_buf, EVENT_BUF_LEN);
66 if (len < 0) {
67 tst_brk(TBROK | TERRNO,
68 "read(%d, buf, %zu) failed",
69 fd_notify, EVENT_BUF_LEN);
70 }
71
72 /*
73 * check events
74 */
75 i = 0;
76 while (i < len) {
77 struct inotify_event *event;
78
79 event = (struct inotify_event *)&event_buf[i];
80 if (event->mask != IN_ACCESS &&
81 event->mask != IN_MODIFY &&
82 event->mask != IN_OPEN &&
83 event->mask != IN_Q_OVERFLOW) {
84 tst_res(TFAIL,
85 "get event: wd=%d mask=%x "
86 "cookie=%u (expected 0) len=%u",
87 event->wd, event->mask,
88 event->cookie, event->len);
89 stop = 1;
90 break;
91 }
92 if (event->mask == IN_Q_OVERFLOW) {
93 if (event->len != 0 ||
94 event->cookie != 0 ||
95 event->wd != -1) {
96 tst_res(TFAIL,
97 "invalid overflow event: "
98 "wd=%d mask=%x "
99 "cookie=%u len=%u",
100 event->wd, event->mask,
101 event->cookie,
102 event->len);
103 stop = 1;
104 break;
105 }
106 if ((int)(i + EVENT_SIZE) != len) {
107 tst_res(TFAIL,
108 "overflow event is not last");
109 stop = 1;
110 break;
111 }
112 tst_res(TPASS, "get event: wd=%d "
113 "mask=%x cookie=%u len=%u",
114 event->wd, event->mask,
115 event->cookie, event->len);
116 stop = 1;
117 break;
118 }
119 i += EVENT_SIZE + event->len;
120 }
121 }
122 }
123
setup(void)124 static void setup(void)
125 {
126 sprintf(fname, "tfile_%d", getpid());
127 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
128 SAFE_WRITE(1, fd, buf, BUF_SIZE);
129 SAFE_CLOSE(fd);
130
131 fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK);
132
133 wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, fname, IN_ALL_EVENTS);
134
135 SAFE_FILE_SCANF("/proc/sys/fs/inotify/max_queued_events",
136 "%d", &max_events);
137 }
138
cleanup(void)139 static void cleanup(void)
140 {
141 if (fd_notify > 0 && myinotify_rm_watch(fd_notify, wd) == -1) {
142 tst_res(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
143 fd_notify, wd);
144 }
145
146 if (fd_notify > 0)
147 SAFE_CLOSE(fd_notify);
148 }
149
150 static struct tst_test test = {
151 .needs_tmpdir = 1,
152 .setup = setup,
153 .cleanup = cleanup,
154 .test_all = verify_inotify,
155 };
156
157 #else
158 TST_TEST_TCONF("system doesn't have required inotify support");
159 #endif
160