xref: /freebsd/tests/sys/kqueue/libkqueue/vnode.c (revision e17f5b1d)
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  * $FreeBSD$
17  */
18 
19 #include "common.h"
20 
21 int vnode_fd;
22 
23 static void
24 test_kevent_vnode_add(void)
25 {
26     const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
27     const char *testfile = "./kqueue-test.tmp";
28     struct kevent kev;
29 
30     test_begin(test_id);
31 
32     system("touch ./kqueue-test.tmp");
33     vnode_fd = open(testfile, O_RDONLY);
34     if (vnode_fd < 0)
35         err(1, "open of %s", testfile);
36     else
37         printf("vnode_fd = %d\n", vnode_fd);
38 
39     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
40             NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
41     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
42         err(1, "%s", test_id);
43 
44     success();
45 }
46 
47 static void
48 test_kevent_vnode_note_delete(void)
49 {
50     const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
51     struct kevent kev;
52 
53     test_begin(test_id);
54 
55     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
56     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
57         err(1, "%s", test_id);
58 
59     if (unlink("./kqueue-test.tmp") < 0)
60         err(1, "unlink");
61 
62     kevent_cmp(&kev, kevent_get(kqfd));
63 
64     success();
65 }
66 
67 static void
68 test_kevent_vnode_note_write(void)
69 {
70     const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
71     struct kevent kev;
72 
73     test_begin(test_id);
74 
75     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
76     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
77         err(1, "%s", test_id);
78 
79     if (system("echo hello >> ./kqueue-test.tmp") < 0)
80         err(1, "system");
81 
82     /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
83     /* BSD kqueue removes EV_ENABLE */
84     kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
85     kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
86     kevent_cmp(&kev, kevent_get(kqfd));
87 
88     success();
89 }
90 
91 static void
92 test_kevent_vnode_note_attrib(void)
93 {
94     const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
95     struct kevent kev;
96     int nfds;
97 
98     test_begin(test_id);
99 
100     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
101     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
102         err(1, "%s", test_id);
103 
104     if (system("touch ./kqueue-test.tmp") < 0)
105         err(1, "system");
106 
107     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
108     if (nfds < 1)
109         err(1, "%s", test_id);
110     if (kev.ident != (uintptr_t)vnode_fd ||
111             kev.filter != EVFILT_VNODE ||
112             kev.fflags != NOTE_ATTRIB)
113         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
114                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
115 
116     success();
117 }
118 
119 static void
120 test_kevent_vnode_note_rename(void)
121 {
122     const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
123     struct kevent kev;
124     int nfds;
125 
126     test_begin(test_id);
127 
128     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
129     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
130         err(1, "%s", test_id);
131 
132     if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0)
133         err(1, "system");
134 
135     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
136     if (nfds < 1)
137         err(1, "%s", test_id);
138     if (kev.ident != (uintptr_t)vnode_fd ||
139             kev.filter != EVFILT_VNODE ||
140             kev.fflags != NOTE_RENAME)
141         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
142                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
143 
144     if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0)
145         err(1, "system");
146 
147     success();
148 }
149 
150 static void
151 test_kevent_vnode_del(void)
152 {
153     const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
154     struct kevent kev;
155 
156     test_begin(test_id);
157 
158     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
159     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
160         err(1, "%s", test_id);
161 
162     success();
163 }
164 
165 static void
166 test_kevent_vnode_disable_and_enable(void)
167 {
168     const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
169     struct kevent kev;
170     int nfds;
171 
172     test_begin(test_id);
173 
174     test_no_kevents();
175 
176     /* Add the watch and immediately disable it */
177     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
178     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
179         err(1, "%s", test_id);
180     kev.flags = EV_DISABLE;
181     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
182         err(1, "%s", test_id);
183 
184     /* Confirm that the watch is disabled */
185     if (system("touch ./kqueue-test.tmp") < 0)
186         err(1, "system");
187     test_no_kevents();
188 
189     /* Re-enable and check again */
190     kev.flags = EV_ENABLE;
191     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
192         err(1, "%s", test_id);
193     if (system("touch ./kqueue-test.tmp") < 0)
194         err(1, "system");
195     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
196     if (nfds < 1)
197         err(1, "%s", test_id);
198     if (kev.ident != (uintptr_t)vnode_fd ||
199             kev.filter != EVFILT_VNODE ||
200             kev.fflags != NOTE_ATTRIB)
201         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
202                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
203 
204     success();
205 }
206 
207 #if HAVE_EV_DISPATCH
208 static void
209 test_kevent_vnode_dispatch(void)
210 {
211     const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
212     struct kevent kev;
213     int nfds;
214 
215     test_begin(test_id);
216 
217     test_no_kevents();
218 
219     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
220     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
221         err(1, "%s", test_id);
222 
223     if (system("touch ./kqueue-test.tmp") < 0)
224         err(1, "system");
225 
226     nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
227     if (nfds < 1)
228         err(1, "%s", test_id);
229     if (kev.ident != (uintptr_t)vnode_fd ||
230             kev.filter != EVFILT_VNODE ||
231             kev.fflags != NOTE_ATTRIB)
232         err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
233                 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
234 
235     /* Confirm that the watch is disabled automatically */
236     puts("-- checking that watch is disabled");
237     if (system("touch ./kqueue-test.tmp") < 0)
238         err(1, "system");
239     test_no_kevents();
240 
241     /* Delete the watch */
242     EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
243     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
244         err(1, "remove watch failed: %s", test_id);
245 
246     success();
247 }
248 #endif 	/* HAVE_EV_DISPATCH */
249 
250 void
251 test_evfilt_vnode(void)
252 {
253     kqfd = kqueue();
254     test_kevent_vnode_add();
255     test_kevent_vnode_del();
256     test_kevent_vnode_disable_and_enable();
257 #if HAVE_EV_DISPATCH
258     test_kevent_vnode_dispatch();
259 #endif
260     test_kevent_vnode_note_write();
261     test_kevent_vnode_note_attrib();
262     test_kevent_vnode_note_rename();
263     test_kevent_vnode_note_delete();
264     close(kqfd);
265 }
266