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