This source file includes following definitions.
- nfs_kqpoll
- filt_nfsdetach
- filt_nfsread
- filt_nfsvnode
- nfs_kqfilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <sys/cdefs.h>
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/mount.h>
47 #include <sys/malloc.h>
48 #include <sys/vnode.h>
49 #include <sys/unistd.h>
50 #include <sys/file.h>
51 #include <sys/kthread.h>
52 #include <sys/rwlock.h>
53
54 #include <uvm/uvm_extern.h>
55 #include <uvm/uvm.h>
56
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
59 #include <nfs/nfs.h>
60 #include <nfs/nfsnode.h>
61 #include <nfs/nfs_var.h>
62
63 void nfs_kqpoll(void *);
64
65 void filt_nfsdetach(struct knote *);
66 int filt_nfsread(struct knote *, long);
67 int filt_nfsvnode(struct knote *, long);
68
69 struct kevq {
70 SLIST_ENTRY(kevq) kev_link;
71 struct vnode *vp;
72 u_int usecount;
73 u_int flags;
74 #define KEVQ_BUSY 0x01
75 #define KEVQ_WANT 0x02
76 struct timespec omtime;
77 struct timespec octime;
78 nlink_t onlink;
79 };
80 SLIST_HEAD(kevqlist, kevq);
81
82 struct rwlock nfskevq_lock = RWLOCK_INITIALIZER("nfskqlk");
83 struct proc *pnfskq;
84 struct kevqlist kevlist = SLIST_HEAD_INITIALIZER(kevlist);
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 void
102 nfs_kqpoll(void *arg)
103 {
104 struct kevq *ke;
105 struct vattr attr;
106 struct proc *p = pnfskq;
107 u_quad_t osize;
108 int error;
109
110 for(;;) {
111 rw_enter_write(&nfskevq_lock);
112 SLIST_FOREACH(ke, &kevlist, kev_link) {
113 struct nfsnode *np = VTONFS(ke->vp);
114
115 #ifdef DEBUG
116 printf("nfs_kqpoll on: ");
117 VOP_PRINT(ke->vp);
118 #endif
119
120 if (nfs_getattrcache(ke->vp, &attr) != ENOENT)
121 continue;
122
123
124
125
126
127 ke->flags |= KEVQ_BUSY;
128 rw_exit_write(&nfskevq_lock);
129
130
131 osize = np->n_size;
132
133 error = VOP_GETATTR(ke->vp, &attr, p->p_ucred, p);
134 if (error == ESTALE) {
135 np->n_attrstamp = 0;
136 VN_KNOTE(ke->vp, NOTE_DELETE);
137 goto next;
138 }
139
140
141
142 if (attr.va_size != osize) {
143 int extended = (attr.va_size > osize);
144 VN_KNOTE(ke->vp, NOTE_WRITE
145 | (extended ? NOTE_EXTEND : 0));
146 ke->omtime = attr.va_mtime;
147 } else if (attr.va_mtime.tv_sec != ke->omtime.tv_sec
148 || attr.va_mtime.tv_nsec != ke->omtime.tv_nsec) {
149 VN_KNOTE(ke->vp, NOTE_WRITE);
150 ke->omtime = attr.va_mtime;
151 }
152
153 if (attr.va_ctime.tv_sec != ke->octime.tv_sec
154 || attr.va_ctime.tv_nsec != ke->octime.tv_nsec) {
155 VN_KNOTE(ke->vp, NOTE_ATTRIB);
156 ke->octime = attr.va_ctime;
157 }
158
159 if (attr.va_nlink != ke->onlink) {
160 VN_KNOTE(ke->vp, NOTE_LINK);
161 ke->onlink = attr.va_nlink;
162 }
163
164 next:
165 rw_enter_write(&nfskevq_lock);
166 ke->flags &= ~KEVQ_BUSY;
167 if (ke->flags & KEVQ_WANT) {
168 ke->flags &= ~KEVQ_WANT;
169 wakeup(ke);
170 }
171 }
172
173 if (SLIST_EMPTY(&kevlist)) {
174
175 pnfskq = NULL;
176 rw_exit_write(&nfskevq_lock);
177 kthread_exit(0);
178 }
179 rw_exit_write(&nfskevq_lock);
180
181
182 tsleep(pnfskq, PSOCK, "nfskqpw", NFS_MINATTRTIMO * hz / 2);
183
184 }
185 }
186
187 void
188 filt_nfsdetach(struct knote *kn)
189 {
190 struct vnode *vp = (struct vnode *)kn->kn_hook;
191 struct kevq *ke;
192
193 SLIST_REMOVE(&vp->v_selectinfo.si_note, kn, knote, kn_selnext);
194
195
196 rw_enter_write(&nfskevq_lock);
197 SLIST_FOREACH(ke, &kevlist, kev_link) {
198 if (ke->vp == vp) {
199 while (ke->flags & KEVQ_BUSY) {
200 ke->flags |= KEVQ_WANT;
201 rw_exit_write(&nfskevq_lock);
202 (void) tsleep(ke, PSOCK, "nfskqdet", 0);
203 rw_enter_write(&nfskevq_lock);
204 }
205
206 if (ke->usecount > 1) {
207
208 ke->usecount--;
209 } else {
210
211 SLIST_REMOVE(&kevlist, ke, kevq, kev_link);
212 FREE(ke, M_KEVENT);
213 }
214 break;
215 }
216 }
217 rw_exit_write(&nfskevq_lock);
218 }
219
220 int
221 filt_nfsread(struct knote *kn, long hint)
222 {
223 struct vnode *vp = (struct vnode *)kn->kn_hook;
224 struct nfsnode *np = VTONFS(vp);
225
226
227
228
229
230 if (hint == NOTE_REVOKE) {
231 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
232 return (1);
233 }
234
235 kn->kn_data = np->n_size - kn->kn_fp->f_offset;
236 #ifdef DEBUG
237 printf("nfsread event. %d\n", kn->kn_data);
238 #endif
239 return (kn->kn_data != 0);
240 }
241
242 int
243 filt_nfsvnode(struct knote *kn, long hint)
244 {
245 if (kn->kn_sfflags & hint)
246 kn->kn_fflags |= hint;
247 if (hint == NOTE_REVOKE) {
248 kn->kn_flags |= EV_EOF;
249 return (1);
250 }
251 return (kn->kn_fflags != 0);
252 }
253
254 static const struct filterops nfsread_filtops =
255 { 1, NULL, filt_nfsdetach, filt_nfsread };
256 static const struct filterops nfsvnode_filtops =
257 { 1, NULL, filt_nfsdetach, filt_nfsvnode };
258
259 int
260 nfs_kqfilter(void *v)
261 {
262 struct vop_kqfilter_args *ap = v;
263 struct vnode *vp;
264 struct knote *kn;
265 struct kevq *ke;
266 int error = 0;
267 struct vattr attr;
268 struct proc *p = curproc;
269
270 vp = ap->a_vp;
271 kn = ap->a_kn;
272
273 #ifdef DEBUG
274 printf("nfs_kqfilter(%d) on: ", kn->kn_filter);
275 VOP_PRINT(vp);
276 #endif
277
278 switch (kn->kn_filter) {
279 case EVFILT_READ:
280 kn->kn_fop = &nfsread_filtops;
281 break;
282 case EVFILT_VNODE:
283 kn->kn_fop = &nfsvnode_filtops;
284 break;
285 default:
286 return (1);
287 }
288
289 kn->kn_hook = vp;
290
291
292
293
294
295
296
297
298
299
300 memset(&attr, 0, sizeof(attr));
301 (void) VOP_GETATTR(vp, &attr, p->p_ucred, p);
302
303 rw_enter_write(&nfskevq_lock);
304
305
306 if (!pnfskq) {
307 error = kthread_create(nfs_kqpoll, NULL, &pnfskq,
308 "nfskqpoll");
309 if (error)
310 goto out;
311 }
312
313 SLIST_FOREACH(ke, &kevlist, kev_link)
314 if (ke->vp == vp)
315 break;
316
317 if (ke) {
318
319 ke->usecount++;
320 } else {
321
322 MALLOC(ke, struct kevq *,
323 sizeof(struct kevq), M_KEVENT, M_WAITOK);
324 ke->vp = vp;
325 ke->usecount = 1;
326 ke->flags = 0;
327 ke->omtime = attr.va_mtime;
328 ke->octime = attr.va_ctime;
329 ke->onlink = attr.va_nlink;
330 SLIST_INSERT_HEAD(&kevlist, ke, kev_link);
331 }
332
333
334 wakeup(pnfskq);
335
336 SLIST_INSERT_HEAD(&vp->v_selectinfo.si_note, kn, kn_selnext);
337
338 out:
339 rw_exit_write(&nfskevq_lock);
340 return (error);
341 }