xref: /csrg-svn/sys/miscfs/nullfs/null_vnops.c (revision 54893)
154753Sjohnh /*
254753Sjohnh  * Copyright (c) 1992 The Regents of the University of California
354753Sjohnh  * All rights reserved.
454753Sjohnh  *
554766Sjohnh  * This code is derived from the null layer of
6*54893Sheideman  * John Heidemann from the UCLA Ficus project and
7*54893Sheideman  * Jan-Simon Pendry's loopback file system.
854753Sjohnh  *
954753Sjohnh  * %sccs.include.redist.c%
1054753Sjohnh  *
11*54893Sheideman  *	@(#)null_vnops.c	1.4 (Berkeley) 07/10/92
1254766Sjohnh  *
1354766Sjohnh  * Ancestors:
1454753Sjohnh  *	@(#)lofs_vnops.c	1.2 (Berkeley) 6/18/92
1554766Sjohnh  *	$Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1654766Sjohnh  *	...and...
1754766Sjohnh  *	@(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
1854753Sjohnh  */
1954753Sjohnh 
2054753Sjohnh /*
2154766Sjohnh  * Null Layer
2254766Sjohnh  *
2354766Sjohnh  * The null layer duplicates a portion of the file system
2454766Sjohnh  * name space under a new name.  In this respect, it is
2554766Sjohnh  * similar to the loopback file system.  It differs from
2654766Sjohnh  * the loopback fs in two respects:  it is implemented using
27*54893Sheideman  * a bypass operation, and it's "null-node"s stack above
2854766Sjohnh  * all lower-layer vnodes, not just over directory vnodes.
2954766Sjohnh  *
3054766Sjohnh  * The null layer is the minimum file system layer,
3154766Sjohnh  * simply bypassing all possible operations to the lower layer
3254766Sjohnh  * for processing there.  All but vop_getattr, _inactive, _reclaim,
3354766Sjohnh  * and _print are bypassed.
3454766Sjohnh  *
3554766Sjohnh  * Vop_getattr is not bypassed so that we can change the fsid being
3654766Sjohnh  * returned.  Vop_{inactive,reclaim} are bypassed so that
3754766Sjohnh  * they can handle freeing null-layer specific data.
3854766Sjohnh  * Vop_print is not bypassed for debugging.
3954766Sjohnh  *
40*54893Sheideman  *
41*54893Sheideman  * INVOKING OPERATIONS ON LOWER LAYERS
42*54893Sheideman  *
4354766Sjohnh  * NEEDSWORK: Describe methods to invoke operations on the lower layer
4454766Sjohnh  * (bypass vs. VOP).
45*54893Sheideman  *
46*54893Sheideman  *
47*54893Sheideman  * CREATING NEW FILESYSTEM LAYERS
48*54893Sheideman  *
49*54893Sheideman  * One of the easiest ways to construct new file system layers is to make
50*54893Sheideman  * a copy of the null layer, rename all files and variables, and
51*54893Sheideman  * then begin modifing the copy.  Sed can be used to easily rename
52*54893Sheideman  * all variables.
53*54893Sheideman  *
5454753Sjohnh  */
5554753Sjohnh 
5654753Sjohnh #include <sys/param.h>
5754753Sjohnh #include <sys/systm.h>
5854753Sjohnh #include <sys/proc.h>
5954753Sjohnh #include <sys/time.h>
6054753Sjohnh #include <sys/types.h>
6154753Sjohnh #include <sys/vnode.h>
6254753Sjohnh #include <sys/mount.h>
6354753Sjohnh #include <sys/namei.h>
6454753Sjohnh #include <sys/malloc.h>
6554753Sjohnh #include <sys/buf.h>
66*54893Sheideman #include <nullfs/null.h>
6754753Sjohnh 
6854753Sjohnh 
6954766Sjohnh int null_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
7054753Sjohnh 
7154753Sjohnh /*
7254766Sjohnh  * This is the 10-Apr-92 bypass routine.
7354766Sjohnh  *    This version has been optimized for speed, throwing away some
7454766Sjohnh  * safety checks.  It should still always work, but it's not as
7554766Sjohnh  * robust to programmer errors.
7654766Sjohnh  *    Define SAFETY to include some error checking code.
7754766Sjohnh  *
7854766Sjohnh  * In general, we map all vnodes going down and unmap them on the way back.
7954766Sjohnh  * As an exception to this, vnodes can be marked "unmapped" by setting
8054766Sjohnh  * the Nth bit in operation's vdesc_flags.
8154766Sjohnh  *
8254766Sjohnh  * Also, some BSD vnode operations have the side effect of vrele'ing
8354766Sjohnh  * their arguments.  With stacking, the reference counts are held
8454766Sjohnh  * by the upper node, not the lower one, so we must handle these
8554766Sjohnh  * side-effects here.  This is not of concern in Sun-derived systems
8654766Sjohnh  * since there are no such side-effects.
8754766Sjohnh  *
8854766Sjohnh  * This makes the following assumptions:
8954766Sjohnh  * - only one returned vpp
9054766Sjohnh  * - no INOUT vpp's (Sun's vop_open has one of these)
9154766Sjohnh  * - the vnode operation vector of the first vnode should be used
9254766Sjohnh  *   to determine what implementation of the op should be invoked
9354766Sjohnh  * - all mapped vnodes are of our vnode-type (NEEDSWORK:
9454766Sjohnh  *   problems on rmdir'ing mount points and renaming?)
9554766Sjohnh  */
9654766Sjohnh int
9754766Sjohnh null_bypass(ap)
98*54893Sheideman 	struct vop_generic_args *ap;
9954753Sjohnh {
100*54893Sheideman 	extern int (**null_vnodeop_p)();  /* not extern, really "forward" */
101*54893Sheideman 	register struct vnode **this_vp_p;
10254753Sjohnh 	int error;
10354766Sjohnh 	struct vnode *old_vps[VDESC_MAX_VPS];
10454766Sjohnh 	struct vnode **vps_p[VDESC_MAX_VPS];
10554766Sjohnh 	struct vnode ***vppp;
10654766Sjohnh 	struct vnodeop_desc *descp = ap->a_desc;
107*54893Sheideman 	int reles, i;
10854753Sjohnh 
10954766Sjohnh 	if (null_bug_bypass)
11054766Sjohnh 		printf ("null_bypass: %s\n", descp->vdesc_name);
11154753Sjohnh 
11254766Sjohnh #ifdef SAFETY
11354753Sjohnh 	/*
11454766Sjohnh 	 * We require at least one vp.
11554753Sjohnh 	 */
11654766Sjohnh 	if (descp->vdesc_vp_offsets==NULL ||
11754766Sjohnh 	    descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET)
11854766Sjohnh 		panic ("null_bypass: no vp's in map.\n");
11954753Sjohnh #endif
12054753Sjohnh 
12154753Sjohnh 	/*
12254766Sjohnh 	 * Map the vnodes going in.
12354766Sjohnh 	 * Later, we'll invoke the operation based on
12454766Sjohnh 	 * the first mapped vnode's operation vector.
12554753Sjohnh 	 */
126*54893Sheideman 	reles = descp->vdesc_flags;
127*54893Sheideman 	for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
12854766Sjohnh 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
12954766Sjohnh 			break;   /* bail out at end of list */
13054766Sjohnh 		vps_p[i] = this_vp_p =
13154766Sjohnh 			VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
132*54893Sheideman 		/*
133*54893Sheideman 		 * We're not guaranteed that any but the first vnode
134*54893Sheideman 		 * are of our type.  Check for and don't map any
135*54893Sheideman 		 * that aren't.
136*54893Sheideman 		 */
137*54893Sheideman 		if ((*this_vp_p)->v_op != null_vnodeop_p) {
138*54893Sheideman 			old_vps[i] = NULL;
139*54893Sheideman 		} else {
140*54893Sheideman 			old_vps[i] = *this_vp_p;
141*54893Sheideman 			*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
142*54893Sheideman 			if (reles & 1)
143*54893Sheideman 				VREF(*this_vp_p);
144*54893Sheideman 		};
14554766Sjohnh 
14654766Sjohnh 	};
14754753Sjohnh 
14854753Sjohnh 	/*
14954766Sjohnh 	 * Call the operation on the lower layer
15054766Sjohnh 	 * with the modified argument structure.
15154753Sjohnh 	 */
15254766Sjohnh 	error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
15354753Sjohnh 
15454753Sjohnh 	/*
15554766Sjohnh 	 * Maintain the illusion of call-by-value
15654766Sjohnh 	 * by restoring vnodes in the argument structure
15754766Sjohnh 	 * to their original value.
15854753Sjohnh 	 */
159*54893Sheideman 	reles = descp->vdesc_flags;
160*54893Sheideman 	for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
16154766Sjohnh 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
16254766Sjohnh 			break;   /* bail out at end of list */
163*54893Sheideman 		if (old_vps[i]) {
164*54893Sheideman 			*(vps_p[i]) = old_vps[i];
165*54893Sheideman 			if (reles & 1)
166*54893Sheideman 				vrele(*(vps_p[i]));
167*54893Sheideman 		};
16854766Sjohnh 	};
16954766Sjohnh 
17054753Sjohnh 	/*
17154766Sjohnh 	 * Map the possible out-going vpp.
17254753Sjohnh 	 */
17354766Sjohnh 	if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
17454766Sjohnh 	    !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
17554766Sjohnh 	    !error) {
17654766Sjohnh 		vppp=VOPARG_OFFSETTO(struct vnode***,
17754766Sjohnh 				 descp->vdesc_vpp_offset,ap);
178*54893Sheideman 		error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp);
17954766Sjohnh 	};
18054753Sjohnh 
18154766Sjohnh 	return (error);
18254753Sjohnh }
18354753Sjohnh 
18454753Sjohnh 
18554753Sjohnh /*
18654766Sjohnh  *  We handle getattr to change the fsid.
18754753Sjohnh  */
18854766Sjohnh int
18954766Sjohnh null_getattr(ap)
190*54893Sheideman 	struct vop_getattr_args *ap;
19154753Sjohnh {
19254753Sjohnh 	int error;
19354766Sjohnh 	if (error=null_bypass(ap))
19454766Sjohnh 		return error;
19554766Sjohnh 	/* Requires that arguments be restored. */
19654766Sjohnh 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
19754766Sjohnh 	return 0;
19854766Sjohnh }
19954753Sjohnh 
20054753Sjohnh 
20154766Sjohnh int
20254754Sjohnh null_inactive (ap)
20354753Sjohnh 	struct vop_inactive_args *ap;
20454753Sjohnh {
20554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
206*54893Sheideman 	printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
20754753Sjohnh #endif
20854766Sjohnh 	/*
20954766Sjohnh 	 * Do nothing (and _don't_ bypass).
21054766Sjohnh 	 * Wait to vrele lowervp until reclaim,
21154766Sjohnh 	 * so that until then our null_node is in the
21254766Sjohnh 	 * cache and reusable.
21354766Sjohnh 	 *
21454766Sjohnh 	 * NEEDSWORK: Someday, consider inactive'ing
21554766Sjohnh 	 * the lowervp and then trying to reactivate it
21654766Sjohnh 	 * like they do in the name lookup cache code.
21754766Sjohnh 	 * That's too much work for now.
21854766Sjohnh 	 */
21954766Sjohnh 	return 0;
22054753Sjohnh }
22154753Sjohnh 
22254754Sjohnh null_reclaim (ap)
22354753Sjohnh 	struct vop_reclaim_args *ap;
22454753Sjohnh {
22554753Sjohnh 	struct vnode *targetvp;
22654754Sjohnh #ifdef NULLFS_DIAGNOSTIC
227*54893Sheideman 	printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
22854753Sjohnh #endif
229*54893Sheideman 	remque(VTONULL(ap->a_vp));	     /* NEEDSWORK: What? */
230*54893Sheideman 	vrele (NULLVPTOLOWERVP(ap->a_vp));   /* release lower layer */
23154753Sjohnh 	FREE(ap->a_vp->v_data, M_TEMP);
23254753Sjohnh 	ap->a_vp->v_data = 0;
23354753Sjohnh 	return (0);
23454753Sjohnh }
23554753Sjohnh 
23654754Sjohnh null_bmap (ap)
23754753Sjohnh 	struct vop_bmap_args *ap;
23854753Sjohnh {
23954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
240*54893Sheideman 	printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
24154753Sjohnh #endif
24254753Sjohnh 
243*54893Sheideman 	return VOP_BMAP(NULLVPTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
24454753Sjohnh }
24554753Sjohnh 
24654754Sjohnh null_strategy (ap)
24754753Sjohnh 	struct vop_strategy_args *ap;
24854753Sjohnh {
24954753Sjohnh 	int error;
25054766Sjohnh 	struct vnode *savedvp;
25154753Sjohnh 
25254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
253*54893Sheideman 	printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLVPTOLOWERVP(ap->a_bp->b_vp));
25454753Sjohnh #endif
25554753Sjohnh 
25654766Sjohnh 	savedvp = ap->a_bp->b_vp;
25754753Sjohnh 
25854753Sjohnh 	error = VOP_STRATEGY(ap->a_bp);
25954753Sjohnh 
26054766Sjohnh 	ap->a_bp->b_vp = savedvp;
26154753Sjohnh 
26254766Sjohnh 	return error;
26354753Sjohnh }
26454753Sjohnh 
26554766Sjohnh 
26654766Sjohnh int
26754754Sjohnh null_print (ap)
26854753Sjohnh 	struct vop_print_args *ap;
26954753Sjohnh {
27054766Sjohnh 	register struct vnode *vp = ap->a_vp;
271*54893Sheideman 	printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp));
27254766Sjohnh 	return 0;
27354753Sjohnh }
27454753Sjohnh 
27554753Sjohnh 
27654753Sjohnh /*
27754766Sjohnh  * Global vfs data structures
27854753Sjohnh  */
27954753Sjohnh /*
28054766Sjohnh  * NEEDSWORK: strategy,bmap are hand coded currently.  They should
28154766Sjohnh  * go away with a merged buffer/block cache.
28254766Sjohnh  *
28354753Sjohnh  */
28454766Sjohnh int (**null_vnodeop_p)();
285*54893Sheideman struct vnodeopv_entry_desc null_vnodeop_entries[] = {
28654766Sjohnh 	{ &vop_default_desc, null_bypass },
28754753Sjohnh 
28854766Sjohnh 	{ &vop_getattr_desc, null_getattr },
28954766Sjohnh 	{ &vop_inactive_desc, null_inactive },
29054766Sjohnh 	{ &vop_reclaim_desc, null_reclaim },
29154766Sjohnh 	{ &vop_print_desc, null_print },
29254753Sjohnh 
29354766Sjohnh 	{ &vop_bmap_desc, null_bmap },
29454766Sjohnh 	{ &vop_strategy_desc, null_strategy },
29554753Sjohnh 
29654753Sjohnh 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
29754753Sjohnh };
298*54893Sheideman struct vnodeopv_desc null_vnodeop_opv_desc =
299*54893Sheideman 	{ &null_vnodeop_p, null_vnodeop_entries };
300