xref: /csrg-svn/sys/miscfs/nullfs/null_vnops.c (revision 54893)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California
3  * All rights reserved.
4  *
5  * This code is derived from the null layer of
6  * John Heidemann from the UCLA Ficus project and
7  * Jan-Simon Pendry's loopback file system.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)null_vnops.c	1.4 (Berkeley) 07/10/92
12  *
13  * Ancestors:
14  *	@(#)lofs_vnops.c	1.2 (Berkeley) 6/18/92
15  *	$Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
16  *	...and...
17  *	@(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
18  */
19 
20 /*
21  * Null Layer
22  *
23  * The null layer duplicates a portion of the file system
24  * name space under a new name.  In this respect, it is
25  * similar to the loopback file system.  It differs from
26  * the loopback fs in two respects:  it is implemented using
27  * a bypass operation, and it's "null-node"s stack above
28  * all lower-layer vnodes, not just over directory vnodes.
29  *
30  * The null layer is the minimum file system layer,
31  * simply bypassing all possible operations to the lower layer
32  * for processing there.  All but vop_getattr, _inactive, _reclaim,
33  * and _print are bypassed.
34  *
35  * Vop_getattr is not bypassed so that we can change the fsid being
36  * returned.  Vop_{inactive,reclaim} are bypassed so that
37  * they can handle freeing null-layer specific data.
38  * Vop_print is not bypassed for debugging.
39  *
40  *
41  * INVOKING OPERATIONS ON LOWER LAYERS
42  *
43  * NEEDSWORK: Describe methods to invoke operations on the lower layer
44  * (bypass vs. VOP).
45  *
46  *
47  * CREATING NEW FILESYSTEM LAYERS
48  *
49  * One of the easiest ways to construct new file system layers is to make
50  * a copy of the null layer, rename all files and variables, and
51  * then begin modifing the copy.  Sed can be used to easily rename
52  * all variables.
53  *
54  */
55 
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/proc.h>
59 #include <sys/time.h>
60 #include <sys/types.h>
61 #include <sys/vnode.h>
62 #include <sys/mount.h>
63 #include <sys/namei.h>
64 #include <sys/malloc.h>
65 #include <sys/buf.h>
66 #include <nullfs/null.h>
67 
68 
69 int null_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
70 
71 /*
72  * This is the 10-Apr-92 bypass routine.
73  *    This version has been optimized for speed, throwing away some
74  * safety checks.  It should still always work, but it's not as
75  * robust to programmer errors.
76  *    Define SAFETY to include some error checking code.
77  *
78  * In general, we map all vnodes going down and unmap them on the way back.
79  * As an exception to this, vnodes can be marked "unmapped" by setting
80  * the Nth bit in operation's vdesc_flags.
81  *
82  * Also, some BSD vnode operations have the side effect of vrele'ing
83  * their arguments.  With stacking, the reference counts are held
84  * by the upper node, not the lower one, so we must handle these
85  * side-effects here.  This is not of concern in Sun-derived systems
86  * since there are no such side-effects.
87  *
88  * This makes the following assumptions:
89  * - only one returned vpp
90  * - no INOUT vpp's (Sun's vop_open has one of these)
91  * - the vnode operation vector of the first vnode should be used
92  *   to determine what implementation of the op should be invoked
93  * - all mapped vnodes are of our vnode-type (NEEDSWORK:
94  *   problems on rmdir'ing mount points and renaming?)
95  */
96 int
97 null_bypass(ap)
98 	struct vop_generic_args *ap;
99 {
100 	extern int (**null_vnodeop_p)();  /* not extern, really "forward" */
101 	register struct vnode **this_vp_p;
102 	int error;
103 	struct vnode *old_vps[VDESC_MAX_VPS];
104 	struct vnode **vps_p[VDESC_MAX_VPS];
105 	struct vnode ***vppp;
106 	struct vnodeop_desc *descp = ap->a_desc;
107 	int reles, i;
108 
109 	if (null_bug_bypass)
110 		printf ("null_bypass: %s\n", descp->vdesc_name);
111 
112 #ifdef SAFETY
113 	/*
114 	 * We require at least one vp.
115 	 */
116 	if (descp->vdesc_vp_offsets==NULL ||
117 	    descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET)
118 		panic ("null_bypass: no vp's in map.\n");
119 #endif
120 
121 	/*
122 	 * Map the vnodes going in.
123 	 * Later, we'll invoke the operation based on
124 	 * the first mapped vnode's operation vector.
125 	 */
126 	reles = descp->vdesc_flags;
127 	for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
128 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
129 			break;   /* bail out at end of list */
130 		vps_p[i] = this_vp_p =
131 			VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
132 		/*
133 		 * We're not guaranteed that any but the first vnode
134 		 * are of our type.  Check for and don't map any
135 		 * that aren't.
136 		 */
137 		if ((*this_vp_p)->v_op != null_vnodeop_p) {
138 			old_vps[i] = NULL;
139 		} else {
140 			old_vps[i] = *this_vp_p;
141 			*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
142 			if (reles & 1)
143 				VREF(*this_vp_p);
144 		};
145 
146 	};
147 
148 	/*
149 	 * Call the operation on the lower layer
150 	 * with the modified argument structure.
151 	 */
152 	error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
153 
154 	/*
155 	 * Maintain the illusion of call-by-value
156 	 * by restoring vnodes in the argument structure
157 	 * to their original value.
158 	 */
159 	reles = descp->vdesc_flags;
160 	for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
161 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
162 			break;   /* bail out at end of list */
163 		if (old_vps[i]) {
164 			*(vps_p[i]) = old_vps[i];
165 			if (reles & 1)
166 				vrele(*(vps_p[i]));
167 		};
168 	};
169 
170 	/*
171 	 * Map the possible out-going vpp.
172 	 */
173 	if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
174 	    !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
175 	    !error) {
176 		vppp=VOPARG_OFFSETTO(struct vnode***,
177 				 descp->vdesc_vpp_offset,ap);
178 		error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp);
179 	};
180 
181 	return (error);
182 }
183 
184 
185 /*
186  *  We handle getattr to change the fsid.
187  */
188 int
189 null_getattr(ap)
190 	struct vop_getattr_args *ap;
191 {
192 	int error;
193 	if (error=null_bypass(ap))
194 		return error;
195 	/* Requires that arguments be restored. */
196 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
197 	return 0;
198 }
199 
200 
201 int
202 null_inactive (ap)
203 	struct vop_inactive_args *ap;
204 {
205 #ifdef NULLFS_DIAGNOSTIC
206 	printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
207 #endif
208 	/*
209 	 * Do nothing (and _don't_ bypass).
210 	 * Wait to vrele lowervp until reclaim,
211 	 * so that until then our null_node is in the
212 	 * cache and reusable.
213 	 *
214 	 * NEEDSWORK: Someday, consider inactive'ing
215 	 * the lowervp and then trying to reactivate it
216 	 * like they do in the name lookup cache code.
217 	 * That's too much work for now.
218 	 */
219 	return 0;
220 }
221 
222 null_reclaim (ap)
223 	struct vop_reclaim_args *ap;
224 {
225 	struct vnode *targetvp;
226 #ifdef NULLFS_DIAGNOSTIC
227 	printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
228 #endif
229 	remque(VTONULL(ap->a_vp));	     /* NEEDSWORK: What? */
230 	vrele (NULLVPTOLOWERVP(ap->a_vp));   /* release lower layer */
231 	FREE(ap->a_vp->v_data, M_TEMP);
232 	ap->a_vp->v_data = 0;
233 	return (0);
234 }
235 
236 null_bmap (ap)
237 	struct vop_bmap_args *ap;
238 {
239 #ifdef NULLFS_DIAGNOSTIC
240 	printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp));
241 #endif
242 
243 	return VOP_BMAP(NULLVPTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
244 }
245 
246 null_strategy (ap)
247 	struct vop_strategy_args *ap;
248 {
249 	int error;
250 	struct vnode *savedvp;
251 
252 #ifdef NULLFS_DIAGNOSTIC
253 	printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLVPTOLOWERVP(ap->a_bp->b_vp));
254 #endif
255 
256 	savedvp = ap->a_bp->b_vp;
257 
258 	error = VOP_STRATEGY(ap->a_bp);
259 
260 	ap->a_bp->b_vp = savedvp;
261 
262 	return error;
263 }
264 
265 
266 int
267 null_print (ap)
268 	struct vop_print_args *ap;
269 {
270 	register struct vnode *vp = ap->a_vp;
271 	printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp));
272 	return 0;
273 }
274 
275 
276 /*
277  * Global vfs data structures
278  */
279 /*
280  * NEEDSWORK: strategy,bmap are hand coded currently.  They should
281  * go away with a merged buffer/block cache.
282  *
283  */
284 int (**null_vnodeop_p)();
285 struct vnodeopv_entry_desc null_vnodeop_entries[] = {
286 	{ &vop_default_desc, null_bypass },
287 
288 	{ &vop_getattr_desc, null_getattr },
289 	{ &vop_inactive_desc, null_inactive },
290 	{ &vop_reclaim_desc, null_reclaim },
291 	{ &vop_print_desc, null_print },
292 
293 	{ &vop_bmap_desc, null_bmap },
294 	{ &vop_strategy_desc, null_strategy },
295 
296 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
297 };
298 struct vnodeopv_desc null_vnodeop_opv_desc =
299 	{ &null_vnodeop_p, null_vnodeop_entries };
300