genfs_vnops.c revision 1.166 1 /* $NetBSD: genfs_vnops.c,v 1.166 2008/04/19 11:49:54 hannken Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the NetBSD
18 * Foundation, Inc. and its contributors.
19 * 4. Neither the name of The NetBSD Foundation nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*
37 * Copyright (c) 1982, 1986, 1989, 1993
38 * The Regents of the University of California. All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.166 2008/04/19 11:49:54 hannken Exp $");
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/proc.h>
72 #include <sys/kernel.h>
73 #include <sys/mount.h>
74 #include <sys/namei.h>
75 #include <sys/vnode.h>
76 #include <sys/fcntl.h>
77 #include <sys/kmem.h>
78 #include <sys/poll.h>
79 #include <sys/mman.h>
80 #include <sys/file.h>
81 #include <sys/kauth.h>
82
83 #include <miscfs/genfs/genfs.h>
84 #include <miscfs/genfs/genfs_node.h>
85 #include <miscfs/specfs/specdev.h>
86
87 #include <uvm/uvm.h>
88 #include <uvm/uvm_pager.h>
89
90 static void filt_genfsdetach(struct knote *);
91 static int filt_genfsread(struct knote *, long);
92 static int filt_genfsvnode(struct knote *, long);
93
94 int
95 genfs_poll(void *v)
96 {
97 struct vop_poll_args /* {
98 struct vnode *a_vp;
99 int a_events;
100 struct lwp *a_l;
101 } */ *ap = v;
102
103 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
104 }
105
106 int
107 genfs_seek(void *v)
108 {
109 struct vop_seek_args /* {
110 struct vnode *a_vp;
111 off_t a_oldoff;
112 off_t a_newoff;
113 kauth_cred_t cred;
114 } */ *ap = v;
115
116 if (ap->a_newoff < 0)
117 return (EINVAL);
118
119 return (0);
120 }
121
122 int
123 genfs_abortop(void *v)
124 {
125 struct vop_abortop_args /* {
126 struct vnode *a_dvp;
127 struct componentname *a_cnp;
128 } */ *ap = v;
129
130 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
131 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
132 return (0);
133 }
134
135 int
136 genfs_fcntl(void *v)
137 {
138 struct vop_fcntl_args /* {
139 struct vnode *a_vp;
140 u_int a_command;
141 void *a_data;
142 int a_fflag;
143 kauth_cred_t a_cred;
144 struct lwp *a_l;
145 } */ *ap = v;
146
147 if (ap->a_command == F_SETFL)
148 return (0);
149 else
150 return (EOPNOTSUPP);
151 }
152
153 /*ARGSUSED*/
154 int
155 genfs_badop(void *v)
156 {
157
158 panic("genfs: bad op");
159 }
160
161 /*ARGSUSED*/
162 int
163 genfs_nullop(void *v)
164 {
165
166 return (0);
167 }
168
169 /*ARGSUSED*/
170 int
171 genfs_einval(void *v)
172 {
173
174 return (EINVAL);
175 }
176
177 /*
178 * Called when an fs doesn't support a particular vop.
179 * This takes care to vrele, vput, or vunlock passed in vnodes.
180 */
181 int
182 genfs_eopnotsupp(void *v)
183 {
184 struct vop_generic_args /*
185 struct vnodeop_desc *a_desc;
186 / * other random data follows, presumably * /
187 } */ *ap = v;
188 struct vnodeop_desc *desc = ap->a_desc;
189 struct vnode *vp, *vp_last = NULL;
190 int flags, i, j, offset;
191
192 flags = desc->vdesc_flags;
193 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
194 if ((offset = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
195 break; /* stop at end of list */
196 if ((j = flags & VDESC_VP0_WILLPUT)) {
197 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
198
199 /* Skip if NULL */
200 if (!vp)
201 continue;
202
203 switch (j) {
204 case VDESC_VP0_WILLPUT:
205 /* Check for dvp == vp cases */
206 if (vp == vp_last)
207 vrele(vp);
208 else {
209 vput(vp);
210 vp_last = vp;
211 }
212 break;
213 case VDESC_VP0_WILLUNLOCK:
214 VOP_UNLOCK(vp, 0);
215 break;
216 case VDESC_VP0_WILLRELE:
217 vrele(vp);
218 break;
219 }
220 }
221 }
222
223 return (EOPNOTSUPP);
224 }
225
226 /*ARGSUSED*/
227 int
228 genfs_ebadf(void *v)
229 {
230
231 return (EBADF);
232 }
233
234 /* ARGSUSED */
235 int
236 genfs_enoioctl(void *v)
237 {
238
239 return (EPASSTHROUGH);
240 }
241
242
243 /*
244 * Eliminate all activity associated with the requested vnode
245 * and with all vnodes aliased to the requested vnode.
246 */
247 int
248 genfs_revoke(void *v)
249 {
250 struct vop_revoke_args /* {
251 struct vnode *a_vp;
252 int a_flags;
253 } */ *ap = v;
254
255 #ifdef DIAGNOSTIC
256 if ((ap->a_flags & REVOKEALL) == 0)
257 panic("genfs_revoke: not revokeall");
258 #endif
259 vrevoke(ap->a_vp);
260 return (0);
261 }
262
263 /*
264 * Lock the node.
265 */
266 int
267 genfs_lock(void *v)
268 {
269 struct vop_lock_args /* {
270 struct vnode *a_vp;
271 int a_flags;
272 } */ *ap = v;
273 struct vnode *vp = ap->a_vp;
274 int flags = ap->a_flags;
275
276 if ((flags & LK_INTERLOCK) != 0) {
277 flags &= ~LK_INTERLOCK;
278 mutex_exit(&vp->v_interlock);
279 }
280
281 return (vlockmgr(vp->v_vnlock, flags));
282 }
283
284 /*
285 * Unlock the node.
286 */
287 int
288 genfs_unlock(void *v)
289 {
290 struct vop_unlock_args /* {
291 struct vnode *a_vp;
292 int a_flags;
293 } */ *ap = v;
294 struct vnode *vp = ap->a_vp;
295
296 KASSERT(ap->a_flags == 0);
297
298 return (vlockmgr(vp->v_vnlock, LK_RELEASE));
299 }
300
301 /*
302 * Return whether or not the node is locked.
303 */
304 int
305 genfs_islocked(void *v)
306 {
307 struct vop_islocked_args /* {
308 struct vnode *a_vp;
309 } */ *ap = v;
310 struct vnode *vp = ap->a_vp;
311
312 return (vlockstatus(vp->v_vnlock));
313 }
314
315 /*
316 * Stubs to use when there is no locking to be done on the underlying object.
317 */
318 int
319 genfs_nolock(void *v)
320 {
321 struct vop_lock_args /* {
322 struct vnode *a_vp;
323 int a_flags;
324 struct lwp *a_l;
325 } */ *ap = v;
326
327 /*
328 * Since we are not using the lock manager, we must clear
329 * the interlock here.
330 */
331 if (ap->a_flags & LK_INTERLOCK)
332 mutex_exit(&ap->a_vp->v_interlock);
333 return (0);
334 }
335
336 int
337 genfs_nounlock(void *v)
338 {
339
340 return (0);
341 }
342
343 int
344 genfs_noislocked(void *v)
345 {
346
347 return (0);
348 }
349
350 int
351 genfs_mmap(void *v)
352 {
353
354 return (0);
355 }
356
357 void
358 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
359 {
360 struct genfs_node *gp = VTOG(vp);
361
362 rw_init(&gp->g_glock);
363 gp->g_op = ops;
364 }
365
366 void
367 genfs_node_destroy(struct vnode *vp)
368 {
369 struct genfs_node *gp = VTOG(vp);
370
371 rw_destroy(&gp->g_glock);
372 }
373
374 void
375 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
376 {
377 int bsize;
378
379 bsize = 1 << vp->v_mount->mnt_fs_bshift;
380 *eobp = (size + bsize - 1) & ~(bsize - 1);
381 }
382
383 static void
384 filt_genfsdetach(struct knote *kn)
385 {
386 struct vnode *vp = (struct vnode *)kn->kn_hook;
387
388 mutex_enter(&vp->v_interlock);
389 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
390 mutex_exit(&vp->v_interlock);
391 }
392
393 static int
394 filt_genfsread(struct knote *kn, long hint)
395 {
396 struct vnode *vp = (struct vnode *)kn->kn_hook;
397 int rv;
398
399 /*
400 * filesystem is gone, so set the EOF flag and schedule
401 * the knote for deletion.
402 */
403 switch (hint) {
404 case NOTE_REVOKE:
405 KASSERT(mutex_owned(&vp->v_interlock));
406 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
407 return (1);
408 case 0:
409 mutex_enter(&vp->v_interlock);
410 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
411 rv = (kn->kn_data != 0);
412 mutex_exit(&vp->v_interlock);
413 return rv;
414 default:
415 KASSERT(mutex_owned(&vp->v_interlock));
416 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
417 return (kn->kn_data != 0);
418 }
419 }
420
421 static int
422 filt_genfsvnode(struct knote *kn, long hint)
423 {
424 struct vnode *vp = (struct vnode *)kn->kn_hook;
425 int fflags;
426
427 switch (hint) {
428 case NOTE_REVOKE:
429 KASSERT(mutex_owned(&vp->v_interlock));
430 kn->kn_flags |= EV_EOF;
431 if ((kn->kn_sfflags & hint) != 0)
432 kn->kn_fflags |= hint;
433 return (1);
434 case 0:
435 mutex_enter(&vp->v_interlock);
436 fflags = kn->kn_fflags;
437 mutex_exit(&vp->v_interlock);
438 break;
439 default:
440 KASSERT(mutex_owned(&vp->v_interlock));
441 if ((kn->kn_sfflags & hint) != 0)
442 kn->kn_fflags |= hint;
443 fflags = kn->kn_fflags;
444 break;
445 }
446
447 return (fflags != 0);
448 }
449
450 static const struct filterops genfsread_filtops =
451 { 1, NULL, filt_genfsdetach, filt_genfsread };
452 static const struct filterops genfsvnode_filtops =
453 { 1, NULL, filt_genfsdetach, filt_genfsvnode };
454
455 int
456 genfs_kqfilter(void *v)
457 {
458 struct vop_kqfilter_args /* {
459 struct vnode *a_vp;
460 struct knote *a_kn;
461 } */ *ap = v;
462 struct vnode *vp;
463 struct knote *kn;
464
465 vp = ap->a_vp;
466 kn = ap->a_kn;
467 switch (kn->kn_filter) {
468 case EVFILT_READ:
469 kn->kn_fop = &genfsread_filtops;
470 break;
471 case EVFILT_VNODE:
472 kn->kn_fop = &genfsvnode_filtops;
473 break;
474 default:
475 return (EINVAL);
476 }
477
478 kn->kn_hook = vp;
479
480 mutex_enter(&vp->v_interlock);
481 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
482 mutex_exit(&vp->v_interlock);
483
484 return (0);
485 }
486
487 void
488 genfs_node_wrlock(struct vnode *vp)
489 {
490 struct genfs_node *gp = VTOG(vp);
491
492 rw_enter(&gp->g_glock, RW_WRITER);
493 }
494
495 void
496 genfs_node_rdlock(struct vnode *vp)
497 {
498 struct genfs_node *gp = VTOG(vp);
499
500 rw_enter(&gp->g_glock, RW_READER);
501 }
502
503 void
504 genfs_node_unlock(struct vnode *vp)
505 {
506 struct genfs_node *gp = VTOG(vp);
507
508 rw_exit(&gp->g_glock);
509 }
510