xref: /csrg-svn/sys/miscfs/nullfs/null_vnops.c (revision 54766)
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 of the UCLA Ficus project and
7  * the Jan-Simon Pendry's loopback file system.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)null_vnops.c	1.3 (Berkeley) 07/07/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-nodes" 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  * NEEDSWORK: Describe methods to invoke operations on the lower layer
41  * (bypass vs. VOP).
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/proc.h>
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <sys/vnode.h>
50 #include <sys/mount.h>
51 #include <sys/namei.h>
52 #include <sys/malloc.h>
53 #include <sys/buf.h>
54 #include <lofs/lofs.h>
55 
56 
57 int null_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
58 
59 /*
60  * This is the 10-Apr-92 bypass routine.
61  *    This version has been optimized for speed, throwing away some
62  * safety checks.  It should still always work, but it's not as
63  * robust to programmer errors.
64  *    Define SAFETY to include some error checking code.
65  *
66  * In general, we map all vnodes going down and unmap them on the way back.
67  * As an exception to this, vnodes can be marked "unmapped" by setting
68  * the Nth bit in operation's vdesc_flags.
69  *
70  * Also, some BSD vnode operations have the side effect of vrele'ing
71  * their arguments.  With stacking, the reference counts are held
72  * by the upper node, not the lower one, so we must handle these
73  * side-effects here.  This is not of concern in Sun-derived systems
74  * since there are no such side-effects.
75  *
76  * This makes the following assumptions:
77  * - only one returned vpp
78  * - no INOUT vpp's (Sun's vop_open has one of these)
79  * - the vnode operation vector of the first vnode should be used
80  *   to determine what implementation of the op should be invoked
81  * - all mapped vnodes are of our vnode-type (NEEDSWORK:
82  *   problems on rmdir'ing mount points and renaming?)
83  */
84 int
85 null_bypass(ap)
86 	struct nvop_generic_args *ap;
87 {
88 	register int this_vp_p;
89 	int error;
90 	struct vnode *old_vps[VDESC_MAX_VPS];
91 	struct vnode **vps_p[VDESC_MAX_VPS];
92 	struct vnode ***vppp;
93 	struct vnodeop_desc *descp = ap->a_desc;
94 	int maps, reles, i;
95 
96 	if (null_bug_bypass)
97 		printf ("null_bypass: %s\n", descp->vdesc_name);
98 
99 #ifdef SAFETY
100 	/*
101 	 * We require at least one vp.
102 	 */
103 	if (descp->vdesc_vp_offsets==NULL ||
104 	    descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET)
105 		panic ("null_bypass: no vp's in map.\n");
106 #endif
107 
108 	/*
109 	 * Map the vnodes going in.
110 	 * Later, we'll invoke the operation based on
111 	 * the first mapped vnode's operation vector.
112 	 */
113 	maps = descp->vdesc_flags;
114 	reles = descp->vdesc_rele_flags;
115 	for (i=0; i<VDESC_MAX_VPS; maps>>=1, reles>>=1, i++) {
116 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
117 			break;   /* bail out at end of list */
118 		if (maps & 1)   /* skip vps that aren't to be mapped */
119 			continue;
120 		vps_p[i] = this_vp_p =
121 			VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
122 		old_vps[i] = *this_vp_p;
123 		*(vps_p[i]) = NULLTOLOWERVP(VTONULLNODE(*this_vp_p));
124 		if (reles & 1)
125 			VREF(*this_vp_p);
126 
127 	};
128 
129 	/*
130 	 * Call the operation on the lower layer
131 	 * with the modified argument structure.
132 	 */
133 	error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
134 
135 	/*
136 	 * Maintain the illusion of call-by-value
137 	 * by restoring vnodes in the argument structure
138 	 * to their original value.
139 	 */
140 	maps = descp->vdesc_flags;
141 	reles = descp->vdesc_rele_flags;
142 	for (i=0; i<VDESC_MAX_VPS; maps>>=1, i++) {
143 		if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
144 			break;   /* bail out at end of list */
145 		if (maps & 1)   /* skip vps that aren't to be mapped */
146 			continue;
147 		*(vps_p[i]) = old_vps[i];
148 		if (reles & 1)
149 			vrele(*(vps_p[i]));
150 	};
151 
152 	/*
153 	 * Map the possible out-going vpp.
154 	 */
155 	if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
156 	    !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
157 	    !error) {
158 		vppp=VOPARG_OFFSETTO(struct vnode***,
159 				 descp->vdesc_vpp_offset,ap);
160 		error = make_null_node(old_vps[0]->v_mount, **vppp, *vppp);
161 	};
162 
163 	return (error);
164 }
165 
166 
167 /*
168  *  We handle getattr to change the fsid.
169  */
170 int
171 null_getattr(ap)
172 	struct nvop_getattr_args *ap;
173 {
174 	int error;
175 	if (error=null_bypass(ap))
176 		return error;
177 	/* Requires that arguments be restored. */
178 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
179 	return 0;
180 }
181 
182 
183 #if 0
184 null_rename (ap)
185 	struct vop_rename_args *ap;
186 {
187 	USES_VOP_RENAME;
188 	struct vnode *fvp, *tvp;
189 	struct vnode *tdvp;
190 #if 0
191 	struct vnode *fsvp, *tsvp;
192 #endif
193 	int error;
194 
195 #ifdef NULLFS_DIAGNOSTIC
196 	printf("null_rename(fdvp = %x->%x)\n", ap->a_fdvp, NULLTOLOWERVP(ap->a_fdvp));
197 	/*printf("null_rename(tdvp = %x->%x)\n", tndp->ni_dvp, NULLTOLOWERVP(tndp->ni_dvp));*/
198 #endif
199 
200 #ifdef NULLFS_DIAGNOSTIC
201 	printf("null_rename - switch source dvp\n");
202 #endif
203 	/*
204 	 * Switch source directory to point to lofsed vnode
205 	 */
206 	PUSHREF(fdvp, ap->a_fdvp);
207 	VREF(ap->a_fdvp);
208 
209 #ifdef NULLFS_DIAGNOSTIC
210 	printf("null_rename - switch source vp\n");
211 #endif
212 	/*
213 	 * And source object if it is lofsed...
214 	 */
215 	fvp = ap->a_fvp;
216 	if (fvp && fvp->v_op == null_vnodeop_p) {
217 		ap->a_fvp = NULLTOLOWERVP(fvp);
218 		VREF(ap->a_fvp);
219 	} else {
220 		fvp = 0;
221 	}
222 
223 #if 0
224 #ifdef NULLFS_DIAGNOSTIC
225 	printf("null_rename - switch source start vp\n");
226 #endif
227 	/*
228 	 * And source startdir object if it is lofsed...
229 	 */
230 	fsvp = fndp->ni_startdir;
231 	if (fsvp && fsvp->v_op == null_vnodeop_p) {
232 		fndp->ni_startdir = NULLTOLOWERVP(fsvp);
233 		VREF(fndp->ni_startdir);
234 	} else {
235 		fsvp = 0;
236 	}
237 #endif
238 
239 #ifdef NULLFS_DIAGNOSTIC
240 	printf("null_rename - switch target dvp\n");
241 #endif
242 	/*
243  	 * Switch target directory to point to lofsed vnode
244 	 */
245 	tdvp = ap->a_tdvp;
246 	if (tdvp && tdvp->v_op == null_vnodeop_p) {
247 		ap->a_tdvp = NULLTOLOWERVP(tdvp);
248 		VREF(ap->a_tdvp);
249 	} else {
250 		tdvp = 0;
251 	}
252 
253 #ifdef NULLFS_DIAGNOSTIC
254 	printf("null_rename - switch target vp\n");
255 #endif
256 	/*
257 	 * And target object if it is lofsed...
258 	 */
259 	tvp = ap->a_tvp;
260 	if (tvp && tvp->v_op == null_vnodeop_p) {
261 		ap->a_tvp = NULLTOLOWERVP(tvp);
262 		VREF(ap->a_tvp);
263 	} else {
264 		tvp = 0;
265 	}
266 
267 #if 0
268 #ifdef NULLFS_DIAGNOSTIC
269 	printf("null_rename - switch target start vp\n");
270 #endif
271 	/*
272 	 * And target startdir object if it is lofsed...
273 	 */
274 	tsvp = tndp->ni_startdir;
275 	if (tsvp && tsvp->v_op == null_vnodeop_p) {
276 		tndp->ni_startdir = NULLTOLOWERVP(fsvp);
277 		VREF(tndp->ni_startdir);
278 	} else {
279 		tsvp = 0;
280 	}
281 #endif
282 
283 #ifdef NULLFS_DIAGNOSTIC
284 	printf("null_rename - VOP_RENAME(%x, %x, %x, %x)\n",
285 		ap->a_fdvp, ap->a_fvp, ap->a_tdvp, ap->a_tvp);
286 	vprint("ap->a_fdvp", ap->a_fdvp);
287 	vprint("ap->a_fvp", ap->a_fvp);
288 	vprint("ap->a_tdvp", ap->a_tdvp);
289 	if (ap->a_tvp) vprint("ap->a_tvp", ap->a_tvp);
290 	DELAY(16000000);
291 #endif
292 
293 	error = VOP_RENAME(ap->a_fdvp, ap->a_fvp, ap->a_fcnp, ap->a_tdvp, ap->a_tvp, ap->a_tcnp);
294 
295 	/*
296 	 * Put everything back...
297 	 */
298 
299 #if 0
300 #ifdef NULLFS_DIAGNOSTIC
301 	printf("null_rename - restore target startdir\n");
302 #endif
303 
304 	if (tsvp) {
305 		if (tndp->ni_startdir)
306 			vrele(tndp->ni_startdir);
307 		tndp->ni_startdir = tsvp;
308 	}
309 #endif
310 
311 #ifdef NULLFS_DIAGNOSTIC
312 	printf("null_rename - restore target vp\n");
313 #endif
314 
315 	if (tvp) {
316 		ap->a_tvp = tvp;
317 		vrele(ap->a_tvp);
318 	}
319 
320 #ifdef NULLFS_DIAGNOSTIC
321 	printf("null_rename - restore target dvp\n");
322 #endif
323 
324 	if (tdvp) {
325 		ap->a_tdvp = tdvp;
326 		vrele(ap->a_tdvp);
327 	}
328 
329 #if 0
330 #ifdef NULLFS_DIAGNOSTIC
331 	printf("null_rename - restore source startdir\n");
332 #endif
333 
334 	if (fsvp) {
335 		if (fndp->ni_startdir)
336 			vrele(fndp->ni_startdir);
337 		fndp->ni_startdir = fsvp;
338 	}
339 #endif
340 
341 #ifdef NULLFS_DIAGNOSTIC
342 	printf("null_rename - restore source vp\n");
343 #endif
344 
345 
346 	if (fvp) {
347 		ap->a_fvp = fvp;
348 		vrele(ap->a_fvp);
349 	}
350 
351 #ifdef NULLFS_DIAGNOSTIC
352 	printf("null_rename - restore source dvp\n");
353 #endif
354 
355 	POP(fdvp, ap->a_fdvp);
356 	vrele(ap->a_fdvp);
357 
358 	return (error);
359 }
360 #endif
361 
362 
363 int
364 null_inactive (ap)
365 	struct vop_inactive_args *ap;
366 {
367 #ifdef NULLFS_DIAGNOSTIC
368 	printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
369 #endif
370 	/*
371 	 * Do nothing (and _don't_ bypass).
372 	 * Wait to vrele lowervp until reclaim,
373 	 * so that until then our null_node is in the
374 	 * cache and reusable.
375 	 *
376 	 * NEEDSWORK: Someday, consider inactive'ing
377 	 * the lowervp and then trying to reactivate it
378 	 * like they do in the name lookup cache code.
379 	 * That's too much work for now.
380 	 */
381 	return 0;
382 }
383 
384 null_reclaim (ap)
385 	struct vop_reclaim_args *ap;
386 {
387 	USES_VOP_RECLAIM;
388 	struct vnode *targetvp;
389 #ifdef NULLFS_DIAGNOSTIC
390 	printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
391 #endif
392 	remque(VTONULLNODE(ap->a_vp));   /* NEEDSWORK: What? */
393 	vrele (NULLTOLOWERVP(ap->a_vp));   /* release lower layer */
394 	FREE(ap->a_vp->v_data, M_TEMP);
395 	ap->a_vp->v_data = 0;
396 	return (0);
397 }
398 
399 null_bmap (ap)
400 	struct vop_bmap_args *ap;
401 {
402 	USES_VOP_BMAP;
403 #ifdef NULLFS_DIAGNOSTIC
404 	printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
405 #endif
406 
407 	return VOP_BMAP(NULLTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
408 }
409 
410 null_strategy (ap)
411 	struct vop_strategy_args *ap;
412 {
413 	USES_VOP_STRATEGY;
414 	int error;
415 	struct vnode *savedvp;
416 
417 #ifdef NULLFS_DIAGNOSTIC
418 	printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLTOLOWERVP(ap->a_bp->b_vp));
419 #endif
420 
421 	savedvp = ap->a_bp->b_vp;
422 
423 	error = VOP_STRATEGY(ap->a_bp);
424 
425 	ap->a_bp->b_vp = savedvp;
426 
427 	return error;
428 }
429 
430 
431 int
432 null_print (ap)
433 	struct vop_print_args *ap;
434 {
435 	register struct vnode *vp = ap->a_vp;
436 	printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLTOLOWERVP(vp));
437 	return 0;
438 }
439 
440 
441 /*
442  * Global vfs data structures
443  */
444 /*
445  * NEEDSWORK: strategy,bmap are hand coded currently.  They should
446  * go away with a merged buffer/block cache.
447  *
448  */
449 int (**null_vnodeop_p)();
450 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
451 	{ &vop_default_desc, null_bypass },
452 
453 	{ &vop_getattr_desc, null_getattr },
454 	{ &vop_inactive_desc, null_inactive },
455 	{ &vop_reclaim_desc, null_reclaim },
456 	{ &vop_print_desc, null_print },
457 
458 	{ &vop_bmap_desc, null_bmap },
459 	{ &vop_strategy_desc, null_strategy },
460 
461 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
462 };
463 struct vnodeopv_desc lofs_vnodeop_opv_desc =
464 	{ &null_vnodeop_p, lofs_vnodeop_entries };
465