xref: /freebsd-13-stable/tests/sys/kqueue/libkqueue/vnode.c (revision 17da660ad5b3b9cd90e164dd4dbb9beaa7203054)
1 /*
2  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "common.h"
18 
19 int vnode_fd;
20 
21 static void
test_kevent_vnode_add(void)22 test_kevent_vnode_add(void)
23 {
24     const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
25     const char *testfile = "./kqueue-test.tmp";
26     struct kevent kev;
27 
28     test_begin(test_id);
29 
30     system("touch ./kqueue-test.tmp");
31     vnode_fd = open(testfile, O_RDONLY);
32     if (vnode_fd < 0)
33         err(1, "open of %s", testfile);
34     else
35         printf("vnode_fd = %d\n", vnode_fd);
36 
37     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
38             NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
39     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40         err(1, "%s", test_id);
41 
42     success();
43 }
44 
45 static void
test_kevent_vnode_note_delete(void)46 test_kevent_vnode_note_delete(void)
47 {
48     const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
49     struct kevent kev;
50 
51     test_begin(test_id);
52 
53     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
54     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
55         err(1, "%s", test_id);
56 
57     if (unlink("./kqueue-test.tmp") < 0)
58         err(1, "unlink");
59 
60     kevent_cmp(&kev, kevent_get(kqfd));
61 
62     success();
63 }
64 
65 static void
test_kevent_vnode_note_write(void)66 test_kevent_vnode_note_write(void)
67 {
68     const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
69     struct kevent kev;
70 
71     test_begin(test_id);
72 
73     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
74     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
75         err(1, "%s", test_id);
76 
77     if (system("echo hello >> ./kqueue-test.tmp") < 0)
78         err(1, "system");
79 
80     /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
81     /* BSD kqueue removes EV_ENABLE */
82     kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
83     kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
84     kevent_cmp(&kev, kevent_get(kqfd));
85 
86     success();
87 }
88 
89 static void
test_kevent_vnode_note_attrib(void)90 test_kevent_vnode_note_attrib(void)
91 {
92     const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
93     struct kevent kev;
94     int nfds;
95 
96     test_begin(test_id);
97 
98     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
99     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
100         err(1, "%s", test_id);
101 
102     if (system("touch ./kqueue-test.tmp") < 0)
103         err(1, "system");
104 
105     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
106     if (nfds < 1)
107         err(1, "%s", test_id);
108     if (kev.ident != (uintptr_t)vnode_fd ||
109             kev.filter != EVFILT_VNODE ||
110             kev.fflags != NOTE_ATTRIB)
111         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
112                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
113 
114     success();
115 }
116 
117 static void
test_kevent_vnode_note_rename(void)118 test_kevent_vnode_note_rename(void)
119 {
120     const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
121     struct kevent kev;
122     int nfds;
123 
124     test_begin(test_id);
125 
126     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
127     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
128         err(1, "%s", test_id);
129 
130     if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0)
131         err(1, "system");
132 
133     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
134     if (nfds < 1)
135         err(1, "%s", test_id);
136     if (kev.ident != (uintptr_t)vnode_fd ||
137             kev.filter != EVFILT_VNODE ||
138             kev.fflags != NOTE_RENAME)
139         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
140                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
141 
142     if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0)
143         err(1, "system");
144 
145     success();
146 }
147 
148 static void
test_kevent_vnode_del(void)149 test_kevent_vnode_del(void)
150 {
151     const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
152     struct kevent kev;
153 
154     test_begin(test_id);
155 
156     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
157     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
158         err(1, "%s", test_id);
159 
160     success();
161 }
162 
163 static void
test_kevent_vnode_disable_and_enable(void)164 test_kevent_vnode_disable_and_enable(void)
165 {
166     const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
167     struct kevent kev;
168     int nfds;
169 
170     test_begin(test_id);
171 
172     test_no_kevents();
173 
174     /* Add the watch and immediately disable it */
175     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
176     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
177         err(1, "%s", test_id);
178     kev.flags = EV_DISABLE;
179     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
180         err(1, "%s", test_id);
181 
182     /* Confirm that the watch is disabled */
183     if (system("touch ./kqueue-test.tmp") < 0)
184         err(1, "system");
185     test_no_kevents();
186 
187     /* Re-enable and check again */
188     kev.flags = EV_ENABLE;
189     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
190         err(1, "%s", test_id);
191     if (system("touch ./kqueue-test.tmp") < 0)
192         err(1, "system");
193     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
194     if (nfds < 1)
195         err(1, "%s", test_id);
196     if (kev.ident != (uintptr_t)vnode_fd ||
197             kev.filter != EVFILT_VNODE ||
198             kev.fflags != NOTE_ATTRIB)
199         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
200                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
201 
202     success();
203 }
204 
205 #if HAVE_EV_DISPATCH
206 static void
test_kevent_vnode_dispatch(void)207 test_kevent_vnode_dispatch(void)
208 {
209     const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
210     struct kevent kev;
211     int nfds;
212 
213     test_begin(test_id);
214 
215     test_no_kevents();
216 
217     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
218     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
219         err(1, "%s", test_id);
220 
221     if (system("touch ./kqueue-test.tmp") < 0)
222         err(1, "system");
223 
224     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
225     if (nfds < 1)
226         err(1, "%s", test_id);
227     if (kev.ident != (uintptr_t)vnode_fd ||
228             kev.filter != EVFILT_VNODE ||
229             kev.fflags != NOTE_ATTRIB)
230         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
231                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
232 
233     /* Confirm that the watch is disabled automatically */
234     puts("-- checking that watch is disabled");
235     if (system("touch ./kqueue-test.tmp") < 0)
236         err(1, "system");
237     test_no_kevents();
238 
239     /* Delete the watch */
240     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
241     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
242         err(1, "remove watch failed: %s", test_id);
243 
244     success();
245 }
246 #endif 	/* HAVE_EV_DISPATCH */
247 
248 void
test_evfilt_vnode(void)249 test_evfilt_vnode(void)
250 {
251     kqfd = kqueue();
252     test_kevent_vnode_add();
253     test_kevent_vnode_del();
254     test_kevent_vnode_disable_and_enable();
255 #if HAVE_EV_DISPATCH
256     test_kevent_vnode_dispatch();
257 #endif
258     test_kevent_vnode_note_write();
259     test_kevent_vnode_note_attrib();
260     test_kevent_vnode_note_rename();
261     test_kevent_vnode_note_delete();
262     close(kqfd);
263 }
264