xref: /netbsd-src/sys/miscfs/genfs/genfs_vnops.c (revision 267197ec1eebfcb9810ea27a89625b6ddf68e3e7)
1 /*	$NetBSD: genfs_vnops.c,v 1.164 2008/02/05 14:19:53 ad 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.164 2008/02/05 14:19:53 ad 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 #include <sys/fstrans.h>
83 
84 #include <miscfs/genfs/genfs.h>
85 #include <miscfs/genfs/genfs_node.h>
86 #include <miscfs/specfs/specdev.h>
87 
88 #include <uvm/uvm.h>
89 #include <uvm/uvm_pager.h>
90 
91 static void filt_genfsdetach(struct knote *);
92 static int filt_genfsread(struct knote *, long);
93 static int filt_genfsvnode(struct knote *, long);
94 
95 int
96 genfs_poll(void *v)
97 {
98 	struct vop_poll_args /* {
99 		struct vnode *a_vp;
100 		int a_events;
101 		struct lwp *a_l;
102 	} */ *ap = v;
103 
104 	return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
105 }
106 
107 int
108 genfs_seek(void *v)
109 {
110 	struct vop_seek_args /* {
111 		struct vnode *a_vp;
112 		off_t a_oldoff;
113 		off_t a_newoff;
114 		kauth_cred_t cred;
115 	} */ *ap = v;
116 
117 	if (ap->a_newoff < 0)
118 		return (EINVAL);
119 
120 	return (0);
121 }
122 
123 int
124 genfs_abortop(void *v)
125 {
126 	struct vop_abortop_args /* {
127 		struct vnode *a_dvp;
128 		struct componentname *a_cnp;
129 	} */ *ap = v;
130 
131 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
132 		PNBUF_PUT(ap->a_cnp->cn_pnbuf);
133 	return (0);
134 }
135 
136 int
137 genfs_fcntl(void *v)
138 {
139 	struct vop_fcntl_args /* {
140 		struct vnode *a_vp;
141 		u_int a_command;
142 		void *a_data;
143 		int a_fflag;
144 		kauth_cred_t a_cred;
145 		struct lwp *a_l;
146 	} */ *ap = v;
147 
148 	if (ap->a_command == F_SETFL)
149 		return (0);
150 	else
151 		return (EOPNOTSUPP);
152 }
153 
154 /*ARGSUSED*/
155 int
156 genfs_badop(void *v)
157 {
158 
159 	panic("genfs: bad op");
160 }
161 
162 /*ARGSUSED*/
163 int
164 genfs_nullop(void *v)
165 {
166 
167 	return (0);
168 }
169 
170 /*ARGSUSED*/
171 int
172 genfs_einval(void *v)
173 {
174 
175 	return (EINVAL);
176 }
177 
178 /*
179  * Called when an fs doesn't support a particular vop.
180  * This takes care to vrele, vput, or vunlock passed in vnodes.
181  */
182 int
183 genfs_eopnotsupp(void *v)
184 {
185 	struct vop_generic_args /*
186 		struct vnodeop_desc *a_desc;
187 		/ * other random data follows, presumably * /
188 	} */ *ap = v;
189 	struct vnodeop_desc *desc = ap->a_desc;
190 	struct vnode *vp, *vp_last = NULL;
191 	int flags, i, j, offset;
192 
193 	flags = desc->vdesc_flags;
194 	for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
195 		if ((offset = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
196 			break;	/* stop at end of list */
197 		if ((j = flags & VDESC_VP0_WILLPUT)) {
198 			vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
199 
200 			/* Skip if NULL */
201 			if (!vp)
202 				continue;
203 
204 			switch (j) {
205 			case VDESC_VP0_WILLPUT:
206 				/* Check for dvp == vp cases */
207 				if (vp == vp_last)
208 					vrele(vp);
209 				else {
210 					vput(vp);
211 					vp_last = vp;
212 				}
213 				break;
214 			case VDESC_VP0_WILLUNLOCK:
215 				VOP_UNLOCK(vp, 0);
216 				break;
217 			case VDESC_VP0_WILLRELE:
218 				vrele(vp);
219 				break;
220 			}
221 		}
222 	}
223 
224 	return (EOPNOTSUPP);
225 }
226 
227 /*ARGSUSED*/
228 int
229 genfs_ebadf(void *v)
230 {
231 
232 	return (EBADF);
233 }
234 
235 /* ARGSUSED */
236 int
237 genfs_enoioctl(void *v)
238 {
239 
240 	return (EPASSTHROUGH);
241 }
242 
243 
244 /*
245  * Eliminate all activity associated with the requested vnode
246  * and with all vnodes aliased to the requested vnode.
247  */
248 int
249 genfs_revoke(void *v)
250 {
251 	struct vop_revoke_args /* {
252 		struct vnode *a_vp;
253 		int a_flags;
254 	} */ *ap = v;
255 
256 #ifdef DIAGNOSTIC
257 	if ((ap->a_flags & REVOKEALL) == 0)
258 		panic("genfs_revoke: not revokeall");
259 #endif
260 	vrevoke(ap->a_vp);
261 	return (0);
262 }
263 
264 /*
265  * Lock the node.
266  */
267 int
268 genfs_lock(void *v)
269 {
270 	struct vop_lock_args /* {
271 		struct vnode *a_vp;
272 		int a_flags;
273 	} */ *ap = v;
274 	struct vnode *vp = ap->a_vp;
275 	int flags = ap->a_flags;
276 
277 	if ((flags & LK_INTERLOCK) != 0) {
278 		flags &= ~LK_INTERLOCK;
279 		mutex_exit(&vp->v_interlock);
280 	}
281 
282 	return (vlockmgr(vp->v_vnlock, flags));
283 }
284 
285 /*
286  * Unlock the node.
287  */
288 int
289 genfs_unlock(void *v)
290 {
291 	struct vop_unlock_args /* {
292 		struct vnode *a_vp;
293 		int a_flags;
294 	} */ *ap = v;
295 	struct vnode *vp = ap->a_vp;
296 
297 	KASSERT(ap->a_flags == 0);
298 
299 	return (vlockmgr(vp->v_vnlock, LK_RELEASE));
300 }
301 
302 /*
303  * Return whether or not the node is locked.
304  */
305 int
306 genfs_islocked(void *v)
307 {
308 	struct vop_islocked_args /* {
309 		struct vnode *a_vp;
310 	} */ *ap = v;
311 	struct vnode *vp = ap->a_vp;
312 
313 	return (vlockstatus(vp->v_vnlock));
314 }
315 
316 /*
317  * Stubs to use when there is no locking to be done on the underlying object.
318  */
319 int
320 genfs_nolock(void *v)
321 {
322 	struct vop_lock_args /* {
323 		struct vnode *a_vp;
324 		int a_flags;
325 		struct lwp *a_l;
326 	} */ *ap = v;
327 
328 	/*
329 	 * Since we are not using the lock manager, we must clear
330 	 * the interlock here.
331 	 */
332 	if (ap->a_flags & LK_INTERLOCK)
333 		mutex_exit(&ap->a_vp->v_interlock);
334 	return (0);
335 }
336 
337 int
338 genfs_nounlock(void *v)
339 {
340 
341 	return (0);
342 }
343 
344 int
345 genfs_noislocked(void *v)
346 {
347 
348 	return (0);
349 }
350 
351 int
352 genfs_mmap(void *v)
353 {
354 
355 	return (0);
356 }
357 
358 void
359 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
360 {
361 	struct genfs_node *gp = VTOG(vp);
362 
363 	rw_init(&gp->g_glock);
364 	gp->g_op = ops;
365 }
366 
367 void
368 genfs_node_destroy(struct vnode *vp)
369 {
370 	struct genfs_node *gp = VTOG(vp);
371 
372 	rw_destroy(&gp->g_glock);
373 }
374 
375 void
376 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
377 {
378 	int bsize;
379 
380 	bsize = 1 << vp->v_mount->mnt_fs_bshift;
381 	*eobp = (size + bsize - 1) & ~(bsize - 1);
382 }
383 
384 static void
385 filt_genfsdetach(struct knote *kn)
386 {
387 	struct vnode *vp = (struct vnode *)kn->kn_hook;
388 
389 	mutex_enter(&vp->v_interlock);
390 	SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
391 	mutex_exit(&vp->v_interlock);
392 }
393 
394 static int
395 filt_genfsread(struct knote *kn, long hint)
396 {
397 	struct vnode *vp = (struct vnode *)kn->kn_hook;
398 	int rv;
399 
400 	/*
401 	 * filesystem is gone, so set the EOF flag and schedule
402 	 * the knote for deletion.
403 	 */
404 	switch (hint) {
405 	case NOTE_REVOKE:
406 		KASSERT(mutex_owned(&vp->v_interlock));
407 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
408 		return (1);
409 	case 0:
410 		mutex_enter(&vp->v_interlock);
411 		kn->kn_data = vp->v_size - kn->kn_fp->f_offset;
412 		rv = (kn->kn_data != 0);
413 		mutex_exit(&vp->v_interlock);
414 		return rv;
415 	default:
416 		KASSERT(mutex_owned(&vp->v_interlock));
417 		kn->kn_data = vp->v_size - kn->kn_fp->f_offset;
418 		return (kn->kn_data != 0);
419 	}
420 }
421 
422 static int
423 filt_genfsvnode(struct knote *kn, long hint)
424 {
425 	struct vnode *vp = (struct vnode *)kn->kn_hook;
426 	int fflags;
427 
428 	switch (hint) {
429 	case NOTE_REVOKE:
430 		KASSERT(mutex_owned(&vp->v_interlock));
431 		kn->kn_flags |= EV_EOF;
432 		if ((kn->kn_sfflags & hint) != 0)
433 			kn->kn_fflags |= hint;
434 		return (1);
435 	case 0:
436 		mutex_enter(&vp->v_interlock);
437 		fflags = kn->kn_fflags;
438 		mutex_exit(&vp->v_interlock);
439 		break;
440 	default:
441 		KASSERT(mutex_owned(&vp->v_interlock));
442 		if ((kn->kn_sfflags & hint) != 0)
443 			kn->kn_fflags |= hint;
444 		fflags = kn->kn_fflags;
445 		break;
446 	}
447 
448 	return (kn->kn_fflags != 0);
449 }
450 
451 static const struct filterops genfsread_filtops =
452 	{ 1, NULL, filt_genfsdetach, filt_genfsread };
453 static const struct filterops genfsvnode_filtops =
454 	{ 1, NULL, filt_genfsdetach, filt_genfsvnode };
455 
456 int
457 genfs_kqfilter(void *v)
458 {
459 	struct vop_kqfilter_args /* {
460 		struct vnode	*a_vp;
461 		struct knote	*a_kn;
462 	} */ *ap = v;
463 	struct vnode *vp;
464 	struct knote *kn;
465 
466 	vp = ap->a_vp;
467 	kn = ap->a_kn;
468 	switch (kn->kn_filter) {
469 	case EVFILT_READ:
470 		kn->kn_fop = &genfsread_filtops;
471 		break;
472 	case EVFILT_VNODE:
473 		kn->kn_fop = &genfsvnode_filtops;
474 		break;
475 	default:
476 		return (EINVAL);
477 	}
478 
479 	kn->kn_hook = vp;
480 
481 	mutex_enter(&vp->v_interlock);
482 	SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
483 	mutex_exit(&vp->v_interlock);
484 
485 	return (0);
486 }
487 
488 void
489 genfs_node_wrlock(struct vnode *vp)
490 {
491 	struct genfs_node *gp = VTOG(vp);
492 
493 	rw_enter(&gp->g_glock, RW_WRITER);
494 }
495 
496 void
497 genfs_node_rdlock(struct vnode *vp)
498 {
499 	struct genfs_node *gp = VTOG(vp);
500 
501 	rw_enter(&gp->g_glock, RW_READER);
502 }
503 
504 void
505 genfs_node_unlock(struct vnode *vp)
506 {
507 	struct genfs_node *gp = VTOG(vp);
508 
509 	rw_exit(&gp->g_glock);
510 }
511