xref: /netbsd-src/sys/miscfs/genfs/genfs_vnops.c (revision 8ac07aec990b9d2e483062509d0a9fa5b4f57cf2)
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