1 /*
2  * Copyright (c) 1992 The Regents of the University of California
3  * Copyright (c) 1990, 1992 Jan-Simon Pendry
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)lofs_vnops.c	7.2 (Berkeley) 07/15/92
12  *
13  * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
14  */
15 
16 /*
17  * Loopback Filesystem
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/proc.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/vnode.h>
26 #include <sys/mount.h>
27 #include <sys/namei.h>
28 #include <sys/malloc.h>
29 #include <sys/buf.h>
30 #include <miscfs/lofs/lofs.h>
31 
32 /*
33  * Basic strategy: as usual, do as little work as possible.
34  * Nothing is ever locked in the lofs'ed filesystem, all
35  * locks are held in the underlying filesystems.
36  */
37 
38 /*
39  * Save a vnode and replace with
40  * the lofs'ed one
41  */
42 #define PUSHREF(v, nd) \
43 { \
44 	struct { struct vnode *vnp; } v; \
45 	v.vnp = (nd); \
46 	(nd) = LOFSVP(v.vnp)
47 
48 /*
49  * Undo the PUSHREF
50  */
51 #define POP(v, nd) \
52 	\
53 	(nd) = v.vnp; \
54 }
55 
56 
57 /*
58  * vp is the current namei directory
59  * ndp is the name to locate in that directory...
60  */
61 lofs_lookup(ap)
62 	struct vop_lookup_args /* {
63 		struct vnode * a_dvp;
64 		struct vnode ** a_vpp;
65 		struct componentname * a_cnp;
66 	} */ *ap;
67 {
68 	struct vnode *dvp = ap->a_dvp;
69 	struct vnode *newvp;
70 	struct vnode *targetdvp;
71 	int error;
72 	int flag = ap->a_cnp->cn_nameiop /*& OPMASK*/;
73 
74 #ifdef LOFS_DIAGNOSTIC
75 	printf("lofs_lookup(ap->a_dvp = %x->%x, \"%s\", op = %d)\n",
76 		dvp, LOFSVP(dvp), ap->a_cnp->cn_nameptr, flag);
77 #endif
78 
79 	/*
80 	 * (ap->a_dvp) was locked when passed in, and it will be replaced
81 	 * with the target vnode, BUT that will already have been
82 	 * locked when (ap->a_dvp) was locked [see lofs_lock].  all that
83 	 * must be done here is to keep track of reference counts.
84 	 */
85 	targetdvp = LOFSVP(dvp);
86 	/*VREF(targetdvp);*/
87 #ifdef LOFS_DIAGNOSTIC
88 	vprint("lofs VOP_LOOKUP", targetdvp);
89 #endif
90 
91 	/*
92 	 * Call lookup on the looped vnode
93 	 */
94 	error = VOP_LOOKUP(targetdvp, &newvp, ap->a_cnp);
95 	/*vrele(targetdvp);*/
96 
97 	if (error) {
98 		*ap->a_vpp = NULLVP;
99 #ifdef LOFS_DIAGNOSTIC
100 		printf("lofs_lookup(%x->%x) = %d\n", dvp, LOFSVP(dvp), error);
101 #endif
102 		return (error);
103 	}
104 #ifdef LOFS_DIAGNOSTIC
105 	printf("lofs_lookup(%x->%x) = OK\n", dvp, LOFSVP(dvp));
106 #endif
107 
108 	*ap->a_vpp = newvp;
109 
110 	/*
111 	 * If we just found a directory then make
112 	 * a loopback node for it and return the loopback
113 	 * instead of the real vnode.  Otherwise simply
114 	 * return the aliased directory and vnode.
115 	 */
116 	if (newvp && newvp->v_type == VDIR && flag == LOOKUP) {
117 #ifdef LOFS_DIAGNOSTIC
118 		printf("lofs_lookup: found VDIR\n");
119 #endif
120 		/*
121 		 * At this point, newvp is the vnode to be looped.
122 		 * Activate a loopback and return the looped vnode.
123 		 */
124 		return (make_lofs(dvp->v_mount, ap->a_vpp));
125 	}
126 
127 #ifdef LOFS_DIAGNOSTIC
128 	printf("lofs_lookup: not VDIR\n");
129 #endif
130 
131 	return (0);
132 }
133 
134 /*
135  * this = ni_dvp
136  * ni_dvp references the locked directory.
137  * ni_vp is NULL.
138  */
139 lofs_mknod(ap)
140 	struct vop_mknod_args /* {
141 		struct vnode *a_dvp;
142 		struct vnode **a_vpp;
143 		struct componentname *a_cnp;
144 		struct vattr *a_vap;
145 	} */ *ap;
146 {
147 	int error;
148 
149 #ifdef LOFS_DIAGNOSTIC
150 	printf("lofs_mknod(vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
151 #endif
152 
153 	PUSHREF(xdvp, ap->a_dvp);
154 	VREF(ap->a_dvp);
155 
156 	error = VOP_MKNOD(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
157 
158 	POP(xdvp, ap->a_dvp);
159 	vrele(ap->a_dvp);
160 
161 	return (error);
162 }
163 
164 /*
165  * this = ni_dvp;
166  * ni_dvp references the locked directory
167  * ni_vp is NULL.
168  */
169 lofs_create(ap)
170 	struct vop_create_args /* {
171 		struct vnode *a_dvp;
172 		struct vnode **a_vpp;
173 		struct componentname *a_cnp;
174 		struct vattr *a_vap;
175 	} */ *ap;
176 {
177 	int error;
178 
179 #ifdef LOFS_DIAGNOSTIC
180 	printf("lofs_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
181 #endif
182 
183 	PUSHREF(xdvp, ap->a_dvp);
184 	VREF(ap->a_dvp);
185 
186 	error = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
187 
188 	POP(xdvp, ap->a_dvp);
189 	vrele(ap->a_dvp);
190 
191 #ifdef LOFS_DIAGNOSTIC
192 	printf("lofs_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
193 #endif
194 
195 	return (error);
196 }
197 
198 lofs_open(ap)
199 	struct vop_open_args /* {
200 		struct vnode *a_vp;
201 		int  a_mode;
202 		struct ucred *a_cred;
203 		struct proc *a_p;
204 	} */ *ap;
205 {
206 
207 #ifdef LOFS_DIAGNOSTIC
208 	printf("lofs_open(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
209 #endif
210 
211 	return VOP_OPEN(LOFSVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
212 }
213 
214 lofs_close(ap)
215 	struct vop_close_args /* {
216 		struct vnode *a_vp;
217 		int  a_fflag;
218 		struct ucred *a_cred;
219 		struct proc *a_p;
220 	} */ *ap;
221 {
222 
223 #ifdef LOFS_DIAGNOSTIC
224 	printf("lofs_close(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
225 #endif
226 
227 	return VOP_CLOSE(LOFSVP(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p);
228 }
229 
230 lofs_access(ap)
231 	struct vop_access_args /* {
232 		struct vnode *a_vp;
233 		int  a_mode;
234 		struct ucred *a_cred;
235 		struct proc *a_p;
236 	} */ *ap;
237 {
238 
239 #ifdef LOFS_DIAGNOSTIC
240 	printf("lofs_access(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
241 #endif
242 
243 	return VOP_ACCESS(LOFSVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
244 }
245 
246 lofs_getattr(ap)
247 	struct vop_getattr_args /* {
248 		struct vnode *a_vp;
249 		struct vattr *a_vap;
250 		struct ucred *a_cred;
251 		struct proc *a_p;
252 	} */ *ap;
253 {
254 	int error;
255 
256 #ifdef LOFS_DIAGNOSTIC
257 	printf("lofs_getattr(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
258 #endif
259 
260 	/*
261 	 * Get the stats from the underlying filesystem
262 	 */
263 	error = VOP_GETATTR(LOFSVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_p);
264 	if (error)
265 		return (error);
266 	/*
267 	 * and replace the fsid field with the loopback number
268 	 * to preserve the namespace.
269 	 */
270 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
271 	return (0);
272 }
273 
274 lofs_setattr(ap)
275 	struct vop_setattr_args /* {
276 		struct vnode *a_vp;
277 		struct vattr *a_vap;
278 		struct ucred *a_cred;
279 		struct proc *a_p;
280 	} */ *ap;
281 {
282 
283 #ifdef LOFS_DIAGNOSTIC
284 	printf("lofs_setattr(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
285 #endif
286 
287 	return VOP_SETATTR(LOFSVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_p);
288 }
289 
290 lofs_read(ap)
291 	struct vop_read_args /* {
292 		struct vnode *a_vp;
293 		struct uio *a_uio;
294 		int  a_ioflag;
295 		struct ucred *a_cred;
296 	} */ *ap;
297 {
298 
299 #ifdef LOFS_DIAGNOSTIC
300 	printf("lofs_read(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
301 #endif
302 
303 	return VOP_READ(LOFSVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
304 }
305 
306 lofs_write(ap)
307 	struct vop_write_args /* {
308 		struct vnode *a_vp;
309 		struct uio *a_uio;
310 		int  a_ioflag;
311 		struct ucred *a_cred;
312 	} */ *ap;
313 {
314 
315 #ifdef LOFS_DIAGNOSTIC
316 	printf("lofs_write(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
317 #endif
318 
319 	return VOP_WRITE(LOFSVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
320 }
321 
322 lofs_ioctl(ap)
323 	struct vop_ioctl_args /* {
324 		struct vnode *a_vp;
325 		int  a_command;
326 		caddr_t  a_data;
327 		int  a_fflag;
328 		struct ucred *a_cred;
329 		struct proc *a_p;
330 	} */ *ap;
331 {
332 
333 #ifdef LOFS_DIAGNOSTIC
334 	printf("lofs_ioctl(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
335 #endif
336 
337 	return VOP_IOCTL(LOFSVP(ap->a_vp), ap->a_command, ap->a_data, ap->a_fflag, ap->a_cred, ap->a_p);
338 }
339 
340 lofs_select(ap)
341 	struct vop_select_args /* {
342 		struct vnode *a_vp;
343 		int  a_which;
344 		int  a_fflags;
345 		struct ucred *a_cred;
346 		struct proc *a_p;
347 	} */ *ap;
348 {
349 
350 #ifdef LOFS_DIAGNOSTIC
351 	printf("lofs_select(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
352 #endif
353 
354 	return VOP_SELECT(LOFSVP(ap->a_vp), ap->a_which, ap->a_fflags, ap->a_cred, ap->a_p);
355 }
356 
357 lofs_mmap(ap)
358 	struct vop_mmap_args /* {
359 		struct vnode *a_vp;
360 		int  a_fflags;
361 		struct ucred *a_cred;
362 		struct proc *a_p;
363 	} */ *ap;
364 {
365 
366 #ifdef LOFS_DIAGNOSTIC
367 	printf("lofs_mmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
368 #endif
369 
370 	return VOP_MMAP(LOFSVP(ap->a_vp), ap->a_fflags, ap->a_cred, ap->a_p);
371 }
372 
373 lofs_fsync(ap)
374 	struct vop_fsync_args /* {
375 		struct vnode *a_vp;
376 		struct ucred *a_cred;
377 		int  a_waitfor;
378 		struct proc *a_p;
379 	} */ *ap;
380 {
381 
382 #ifdef LOFS_DIAGNOSTIC
383 	printf("lofs_fsync(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
384 #endif
385 
386 	return VOP_FSYNC(LOFSVP(ap->a_vp), ap->a_cred, ap->a_waitfor, ap->a_p);
387 }
388 
389 lofs_seek(ap)
390 	struct vop_seek_args /* {
391 		struct vnode *a_vp;
392 		off_t  a_oldoff;
393 		off_t  a_newoff;
394 		struct ucred *a_cred;
395 	} */ *ap;
396 {
397 
398 #ifdef LOFS_DIAGNOSTIC
399 	printf("lofs_seek(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
400 #endif
401 
402 	return VOP_SEEK(LOFSVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred);
403 }
404 
405 lofs_remove(ap)
406 	struct vop_remove_args /* {
407 		struct vnode *a_dvp;
408 		struct vnode *a_vp;
409 		struct componentname *a_cnp;
410 	} */ *ap;
411 {
412 	int error;
413 
414 #ifdef LOFS_DIAGNOSTIC
415 	printf("lofs_remove(ap->a_vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
416 #endif
417 
418 	PUSHREF(xdvp, ap->a_dvp);
419 	VREF(ap->a_dvp);
420 	PUSHREF(xvp, ap->a_vp);
421 	VREF(ap->a_vp);
422 
423 	error = VOP_REMOVE(ap->a_dvp, ap->a_vp, ap->a_cnp);
424 
425 	POP(xvp, ap->a_vp);
426 	vrele(ap->a_vp);
427 	POP(xdvp, ap->a_dvp);
428 	vrele(ap->a_dvp);
429 
430 	return (error);
431 }
432 
433 /*
434  * vp is this.
435  * ni_dvp is the locked parent of the target.
436  * ni_vp is NULL.
437  */
438 lofs_link(ap)
439 	struct vop_link_args /* {
440 		struct vnode *a_vp;
441 		struct vnode *a_tdvp;
442 		struct componentname *a_cnp;
443 	} */ *ap;
444 {
445 	int error;
446 
447 #ifdef LOFS_DIAGNOSTIC
448 	printf("lofs_link(ap->a_tdvp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
449 #endif
450 
451 	PUSHREF(xdvp, ap->a_vp);
452 	VREF(ap->a_vp);
453 
454 	error = VOP_LINK(ap->a_vp, LOFSVP(ap->a_tdvp), ap->a_cnp);
455 
456 	POP(xdvp, ap->a_vp);
457 	vrele(ap->a_vp);
458 
459 	return (error);
460 }
461 
462 lofs_rename(ap)
463 	struct vop_rename_args  /* {
464 		struct vnode *a_fdvp;
465 		struct vnode *a_fvp;
466 		struct componentname *a_fcnp;
467 		struct vnode *a_tdvp;
468 		struct vnode *a_tvp;
469 		struct componentname *a_tcnp;
470 	} */ *ap;
471 {
472 	struct vnode *fvp, *tvp;
473 	struct vnode *tdvp;
474 #ifdef notdef
475 	struct vnode *fsvp, *tsvp;
476 #endif
477 	int error;
478 
479 #ifdef LOFS_DIAGNOSTIC
480 	printf("lofs_rename(fdvp = %x->%x)\n", ap->a_fdvp, LOFSVP(ap->a_fdvp));
481 	/*printf("lofs_rename(tdvp = %x->%x)\n", tndp->ni_dvp, LOFSVP(tndp->ni_dvp));*/
482 #endif
483 
484 #ifdef LOFS_DIAGNOSTIC
485 	printf("lofs_rename - switch source dvp\n");
486 #endif
487 	/*
488 	 * Switch source directory to point to lofsed vnode
489 	 */
490 	PUSHREF(fdvp, ap->a_fdvp);
491 	VREF(ap->a_fdvp);
492 
493 #ifdef LOFS_DIAGNOSTIC
494 	printf("lofs_rename - switch source vp\n");
495 #endif
496 	/*
497 	 * And source object if it is lofsed...
498 	 */
499 	fvp = ap->a_fvp;
500 	if (fvp && fvp->v_op == lofs_vnodeop_p) {
501 		ap->a_fvp = LOFSVP(fvp);
502 		VREF(ap->a_fvp);
503 	} else {
504 		fvp = 0;
505 	}
506 
507 #ifdef notdef
508 #ifdef LOFS_DIAGNOSTIC
509 	printf("lofs_rename - switch source start vp\n");
510 #endif
511 	/*
512 	 * And source startdir object if it is lofsed...
513 	 */
514 	fsvp = fndp->ni_startdir;
515 	if (fsvp && fsvp->v_op == lofs_vnodeop_p) {
516 		fndp->ni_startdir = LOFSVP(fsvp);
517 		VREF(fndp->ni_startdir);
518 	} else {
519 		fsvp = 0;
520 	}
521 #endif
522 
523 #ifdef LOFS_DIAGNOSTIC
524 	printf("lofs_rename - switch target dvp\n");
525 #endif
526 	/*
527  	 * Switch target directory to point to lofsed vnode
528 	 */
529 	tdvp = ap->a_tdvp;
530 	if (tdvp && tdvp->v_op == lofs_vnodeop_p) {
531 		ap->a_tdvp = LOFSVP(tdvp);
532 		VREF(ap->a_tdvp);
533 	} else {
534 		tdvp = 0;
535 	}
536 
537 #ifdef LOFS_DIAGNOSTIC
538 	printf("lofs_rename - switch target vp\n");
539 #endif
540 	/*
541 	 * And target object if it is lofsed...
542 	 */
543 	tvp = ap->a_tvp;
544 	if (tvp && tvp->v_op == lofs_vnodeop_p) {
545 		ap->a_tvp = LOFSVP(tvp);
546 		VREF(ap->a_tvp);
547 	} else {
548 		tvp = 0;
549 	}
550 
551 #ifdef notdef
552 #ifdef LOFS_DIAGNOSTIC
553 	printf("lofs_rename - switch target start vp\n");
554 #endif
555 	/*
556 	 * And target startdir object if it is lofsed...
557 	 */
558 	tsvp = tndp->ni_startdir;
559 	if (tsvp && tsvp->v_op == lofs_vnodeop_p) {
560 		tndp->ni_startdir = LOFSVP(fsvp);
561 		VREF(tndp->ni_startdir);
562 	} else {
563 		tsvp = 0;
564 	}
565 #endif
566 
567 #ifdef LOFS_DIAGNOSTIC
568 	printf("lofs_rename - VOP_RENAME(%x, %x, %x, %x)\n",
569 		ap->a_fdvp, ap->a_fvp, ap->a_tdvp, ap->a_tvp);
570 	vprint("ap->a_fdvp", ap->a_fdvp);
571 	vprint("ap->a_fvp", ap->a_fvp);
572 	vprint("ap->a_tdvp", ap->a_tdvp);
573 	if (ap->a_tvp) vprint("ap->a_tvp", ap->a_tvp);
574 	DELAY(16000000);
575 #endif
576 
577 	error = VOP_RENAME(ap->a_fdvp, ap->a_fvp, ap->a_fcnp, ap->a_tdvp, ap->a_tvp, ap->a_tcnp);
578 
579 	/*
580 	 * Put everything back...
581 	 */
582 
583 #ifdef notdef
584 #ifdef LOFS_DIAGNOSTIC
585 	printf("lofs_rename - restore target startdir\n");
586 #endif
587 
588 	if (tsvp) {
589 		if (tndp->ni_startdir)
590 			vrele(tndp->ni_startdir);
591 		tndp->ni_startdir = tsvp;
592 	}
593 #endif
594 
595 #ifdef LOFS_DIAGNOSTIC
596 	printf("lofs_rename - restore target vp\n");
597 #endif
598 
599 	if (tvp) {
600 		ap->a_tvp = tvp;
601 		vrele(ap->a_tvp);
602 	}
603 
604 #ifdef LOFS_DIAGNOSTIC
605 	printf("lofs_rename - restore target dvp\n");
606 #endif
607 
608 	if (tdvp) {
609 		ap->a_tdvp = tdvp;
610 		vrele(ap->a_tdvp);
611 	}
612 
613 #ifdef notdef
614 #ifdef LOFS_DIAGNOSTIC
615 	printf("lofs_rename - restore source startdir\n");
616 #endif
617 
618 	if (fsvp) {
619 		if (fndp->ni_startdir)
620 			vrele(fndp->ni_startdir);
621 		fndp->ni_startdir = fsvp;
622 	}
623 #endif
624 
625 #ifdef LOFS_DIAGNOSTIC
626 	printf("lofs_rename - restore source vp\n");
627 #endif
628 
629 
630 	if (fvp) {
631 		ap->a_fvp = fvp;
632 		vrele(ap->a_fvp);
633 	}
634 
635 #ifdef LOFS_DIAGNOSTIC
636 	printf("lofs_rename - restore source dvp\n");
637 #endif
638 
639 	POP(fdvp, ap->a_fdvp);
640 	vrele(ap->a_fdvp);
641 
642 	return (error);
643 }
644 
645 /*
646  * ni_dvp is the locked (alias) parent.
647  * ni_vp is NULL.
648  */
649 lofs_mkdir(ap)
650 	struct vop_mkdir_args /* {
651 		struct vnode *a_dvp;
652 		struct vnode **a_vpp;
653 		struct componentname *a_cnp;
654 		struct vattr *a_vap;
655 	} */ *ap;
656 {
657 	int error;
658 	struct vnode *dvp = ap->a_dvp;
659 	struct vnode *xdvp;
660 	struct vnode *newvp;
661 
662 #ifdef LOFS_DIAGNOSTIC
663 	printf("lofs_mkdir(vp = %x->%x)\n", dvp, LOFSVP(dvp));
664 #endif
665 
666 	xdvp = dvp;
667 	dvp = LOFSVP(xdvp);
668 	VREF(dvp);
669 
670 	error = VOP_MKDIR(dvp, &newvp, ap->a_cnp, ap->a_vap);
671 
672 	if (error) {
673 		*ap->a_vpp = NULLVP;
674 		vrele(xdvp);
675 		return (error);
676 	}
677 
678 	/*
679 	 * Make a new lofs node
680 	 */
681 	/*VREF(dvp);*/
682 
683 	error = make_lofs(dvp->v_mount, &newvp);
684 
685 	*ap->a_vpp = newvp;
686 
687 	return (error);
688 }
689 
690 /*
691  * ni_dvp is the locked parent.
692  * ni_vp is the entry to be removed.
693  */
694 lofs_rmdir(ap)
695 	struct vop_rmdir_args /* {
696 		struct vnode *a_dvp;
697 		struct vnode *a_vp;
698 		struct componentname *a_cnp;
699 	} */ *ap;
700 {
701 	struct vnode *vp = ap->a_vp;
702 	struct vnode *dvp = ap->a_dvp;
703 	int error;
704 
705 #ifdef LOFS_DIAGNOSTIC
706 	printf("lofs_rmdir(dvp = %x->%x)\n", dvp, LOFSVP(dvp));
707 #endif
708 
709 	PUSHREF(xdvp, dvp);
710 	VREF(dvp);
711 	PUSHREF(xvp, vp);
712 	VREF(vp);
713 
714 	error = VOP_RMDIR(dvp, vp, ap->a_cnp);
715 
716 	POP(xvp, vp);
717 	vrele(vp);
718 	POP(xdvp, dvp);
719 	vrele(dvp);
720 
721 	return (error);
722 }
723 
724 /*
725  * ni_dvp is the locked parent.
726  * ni_vp is NULL.
727  */
728 lofs_symlink(ap)
729 	struct vop_symlink_args /* {
730 		struct vnode *a_dvp;
731 		struct vnode **a_vpp;
732 		struct componentname *a_cnp;
733 		struct vattr *a_vap;
734 		char *a_target;
735 	} */ *ap;
736 {
737 	int error;
738 
739 #ifdef LOFS_DIAGNOSTIC
740 	printf("VOP_SYMLINK(vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
741 #endif
742 
743 	PUSHREF(xdvp, ap->a_dvp);
744 	VREF(ap->a_dvp);
745 
746 	error = VOP_SYMLINK(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_target);
747 
748 	POP(xdvp, ap->a_dvp);
749 	vrele(ap->a_dvp);
750 
751 	return (error);
752 }
753 
754 lofs_readdir(ap)
755 	struct vop_readdir_args /* {
756 		struct vnode *a_vp;
757 		struct uio *a_uio;
758 		struct ucred *a_cred;
759 	} */ *ap;
760 {
761 
762 #ifdef LOFS_DIAGNOSTIC
763 	printf("lofs_readdir(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
764 #endif
765 
766 	return VOP_READDIR(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred);
767 }
768 
769 lofs_readlink(ap)
770 	struct vop_readlink_args /* {
771 		struct vnode *a_vp;
772 		struct uio *a_uio;
773 		struct ucred *a_cred;
774 	} */ *ap;
775 {
776 
777 #ifdef LOFS_DIAGNOSTIC
778 	printf("lofs_readlink(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
779 #endif
780 
781 	return VOP_READLINK(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred);
782 }
783 
784 /*
785  * Anyone's guess...
786  */
787 lofs_abortop(ap)
788 	struct vop_abortop_args /* {
789 		struct vnode *a_dvp;
790 		struct componentname *a_cnp;
791 	} */ *ap;
792 {
793 	int error;
794 
795 	PUSHREF(xdvp, ap->a_dvp);
796 
797 	error = VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
798 
799 	POP(xdvp, ap->a_dvp);
800 
801 	return (error);
802 }
803 
804 lofs_inactive(ap)
805 	struct vop_inactive_args /* {
806 		struct vnode *a_vp;
807 	} */ *ap;
808 {
809 	struct vnode *targetvp = LOFSVP(ap->a_vp);
810 
811 #ifdef LOFS_DIAGNOSTIC
812 	printf("lofs_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
813 #endif
814 
815 #ifdef DIAGNOSTIC
816 	{ extern int prtactive;
817 	if (prtactive && ap->a_vp->v_usecount != 0)
818 		vprint("lofs_inactive: pushing active", ap->a_vp);
819 	}
820 #endif
821 
822 	if (targetvp) {
823 		vrele(targetvp);
824 		LOFSP(ap->a_vp)->a_lofsvp = 0;
825 	}
826 }
827 
828 lofs_reclaim(ap)
829 	struct vop_reclaim_args /* {
830 		struct vnode *a_vp;
831 	} */ *ap;
832 {
833 	struct vnode *targetvp;
834 
835 #ifdef LOFS_DIAGNOSTIC
836 	printf("lofs_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
837 #endif
838 	remque(LOFSP(ap->a_vp));
839 	targetvp = LOFSVP(ap->a_vp);
840 	if (targetvp) {
841 		printf("lofs: delayed vrele of %x\n", targetvp);
842 		vrele(targetvp);	/* XXX should never happen */
843 	}
844 	FREE(ap->a_vp->v_data, M_TEMP);
845 	ap->a_vp->v_data = 0;
846 	return (0);
847 }
848 
849 lofs_lock(ap)
850 	struct vop_lock_args /* {
851 		struct vnode *a_vp;
852 	} */ *ap;
853 {
854 	int error;
855 	struct vnode *targetvp = LOFSVP(ap->a_vp);
856 
857 #ifdef LOFS_DIAGNOSTIC
858 	printf("lofs_lock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
859 	/*vprint("lofs_lock ap->a_vp", ap->a_vp);
860 	if (targetvp)
861 		vprint("lofs_lock ->ap->a_vp", targetvp);
862 	else
863 		printf("lofs_lock ->ap->a_vp = NIL\n");*/
864 #endif
865 
866 	if (targetvp) {
867 		error = VOP_LOCK(targetvp);
868 		if (error)
869 			return (error);
870 	}
871 
872 	return (0);
873 }
874 
875 lofs_unlock(ap)
876 	struct vop_unlock_args /* {
877 		struct vnode *a_vp;
878 	} */ *ap;
879 {
880 	struct vnode *targetvp = LOFSVP(ap->a_vp);
881 
882 #ifdef LOFS_DIAGNOSTIC
883 	printf("lofs_unlock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
884 #endif
885 
886 	if (targetvp)
887 		return (VOP_UNLOCK(targetvp));
888 	return (0);
889 }
890 
891 lofs_bmap(ap)
892 	struct vop_bmap_args /* {
893 		struct vnode *a_vp;
894 		daddr_t  a_bn;
895 		struct vnode **a_vpp;
896 		daddr_t *a_bnp;
897 	} */ *ap;
898 {
899 
900 #ifdef LOFS_DIAGNOSTIC
901 	printf("lofs_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
902 #endif
903 
904 	return VOP_BMAP(LOFSVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
905 }
906 
907 lofs_strategy(ap)
908 	struct vop_strategy_args /* {
909 		struct buf *a_bp;
910 	} */ *ap;
911 {
912 	int error;
913 
914 #ifdef LOFS_DIAGNOSTIC
915 	printf("lofs_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, LOFSVP(ap->a_bp->b_vp));
916 #endif
917 
918 	PUSHREF(vp, ap->a_bp->b_vp);
919 
920 	error = VOP_STRATEGY(ap->a_bp);
921 
922 	POP(vp, ap->a_bp->b_vp);
923 
924 	return (error);
925 }
926 
927 lofs_print(ap)
928 	struct vop_print_args /* {
929 		struct vnode *a_vp;
930 	} */ *ap;
931 {
932 
933 	struct vnode *targetvp = LOFSVP(ap->a_vp);
934 	printf("tag VT_LOFS ref ");
935 	if (targetvp)
936 		return (VOP_PRINT(targetvp));
937 	printf("NULLVP\n");
938 	return (0);
939 }
940 
941 lofs_islocked(ap)
942 	struct vop_islocked_args /* {
943 		struct vnode *a_vp;
944 	} */ *ap;
945 {
946 
947 	struct vnode *targetvp = LOFSVP(ap->a_vp);
948 	if (targetvp)
949 		return (VOP_ISLOCKED(targetvp));
950 	return (0);
951 }
952 
953 lofs_advlock(ap)
954 	struct vop_advlock_args /* {
955 		struct vnode *a_vp;
956 		caddr_t  a_id;
957 		int  a_op;
958 		struct flock *a_fl;
959 		int  a_flags;
960 	} */ *ap;
961 {
962 
963 	return VOP_ADVLOCK(LOFSVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
964 }
965 
966 /*
967  * LOFS directory offset lookup.
968  * Currently unsupported.
969  */
970 lofs_blkatoff(ap)
971 	struct vop_blkatoff_args /* {
972 		struct vnode *a_vp;
973 		off_t a_offset;
974 		char **a_res;
975 		struct buf **a_bpp;
976 	} */ *ap;
977 {
978 
979 	return (EOPNOTSUPP);
980 }
981 
982 /*
983  * LOFS flat namespace allocation.
984  * Currently unsupported.
985  */
986 lofs_valloc(ap)
987 	struct vop_valloc_args /* {
988 		struct vnode *a_pvp;
989 		int a_mode;
990 		struct ucred *a_cred;
991 		struct vnode **a_vpp;
992 	} */ *ap;
993 {
994 
995 	return (EOPNOTSUPP);
996 }
997 
998 /*
999  * LOFS flat namespace free.
1000  * Currently unsupported.
1001  */
1002 /*void*/
1003 lofs_vfree(ap)
1004 	struct vop_vfree_args /* {
1005 		struct vnode *a_pvp;
1006 		ino_t a_ino;
1007 		int a_mode;
1008 	} */ *ap;
1009 {
1010 
1011 	return (0);
1012 }
1013 
1014 /*
1015  * LOFS file truncation.
1016  */
1017 lofs_truncate(ap)
1018 	struct vop_truncate_args /* {
1019 		struct vnode *a_vp;
1020 		off_t a_length;
1021 		int a_flags;
1022 		struct ucred *a_cred;
1023 		struct proc *a_p;
1024 	} */ *ap;
1025 {
1026 
1027 	/* Use lofs_setattr */
1028 	printf("lofs_truncate: need to implement!!");
1029 	return (EOPNOTSUPP);
1030 }
1031 
1032 /*
1033  * LOFS update.
1034  */
1035 lofs_update(ap)
1036 	struct vop_update_args /* {
1037 		struct vnode *a_vp;
1038 		struct timeval *a_ta;
1039 		struct timeval *a_tm;
1040 		int a_waitfor;
1041 	} */ *ap;
1042 {
1043 
1044 	/* Use lofs_setattr */
1045 	printf("lofs_update: need to implement!!");
1046 	return (EOPNOTSUPP);
1047 }
1048 
1049 /*
1050  * LOFS bwrite
1051  */
1052 lofs_bwrite(ap)
1053 	struct vop_bwrite_args /* {
1054 		struct buf *a_bp;
1055 	} */ *ap;
1056 {
1057 
1058 	return (EOPNOTSUPP);
1059 }
1060 
1061 /*
1062  * Global vfs data structures for ufs
1063  */
1064 int (**lofs_vnodeop_p)();
1065 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
1066 	{ &vop_default_desc, vn_default_error },
1067 	{ &vop_lookup_desc, lofs_lookup },		/* lookup */
1068 	{ &vop_create_desc, lofs_create },		/* create */
1069 	{ &vop_mknod_desc, lofs_mknod },		/* mknod */
1070 	{ &vop_open_desc, lofs_open },		/* open */
1071 	{ &vop_close_desc, lofs_close },		/* close */
1072 	{ &vop_access_desc, lofs_access },		/* access */
1073 	{ &vop_getattr_desc, lofs_getattr },		/* getattr */
1074 	{ &vop_setattr_desc, lofs_setattr },		/* setattr */
1075 	{ &vop_read_desc, lofs_read },		/* read */
1076 	{ &vop_write_desc, lofs_write },		/* write */
1077 	{ &vop_ioctl_desc, lofs_ioctl },		/* ioctl */
1078 	{ &vop_select_desc, lofs_select },		/* select */
1079 	{ &vop_mmap_desc, lofs_mmap },		/* mmap */
1080 	{ &vop_fsync_desc, lofs_fsync },		/* fsync */
1081 	{ &vop_seek_desc, lofs_seek },		/* seek */
1082 	{ &vop_remove_desc, lofs_remove },		/* remove */
1083 	{ &vop_link_desc, lofs_link },		/* link */
1084 	{ &vop_rename_desc, lofs_rename },		/* rename */
1085 	{ &vop_mkdir_desc, lofs_mkdir },		/* mkdir */
1086 	{ &vop_rmdir_desc, lofs_rmdir },		/* rmdir */
1087 	{ &vop_symlink_desc, lofs_symlink },		/* symlink */
1088 	{ &vop_readdir_desc, lofs_readdir },		/* readdir */
1089 	{ &vop_readlink_desc, lofs_readlink },		/* readlink */
1090 	{ &vop_abortop_desc, lofs_abortop },		/* abortop */
1091 	{ &vop_inactive_desc, lofs_inactive },		/* inactive */
1092 	{ &vop_reclaim_desc, lofs_reclaim },		/* reclaim */
1093 	{ &vop_lock_desc, lofs_lock },		/* lock */
1094 	{ &vop_unlock_desc, lofs_unlock },		/* unlock */
1095 	{ &vop_bmap_desc, lofs_bmap },		/* bmap */
1096 	{ &vop_strategy_desc, lofs_strategy },		/* strategy */
1097 	{ &vop_print_desc, lofs_print },		/* print */
1098 	{ &vop_islocked_desc, lofs_islocked },		/* islocked */
1099 	{ &vop_advlock_desc, lofs_advlock },		/* advlock */
1100 	{ &vop_blkatoff_desc, lofs_blkatoff },		/* blkatoff */
1101 	{ &vop_valloc_desc, lofs_valloc },		/* valloc */
1102 	{ &vop_vfree_desc, lofs_vfree },		/* vfree */
1103 	{ &vop_truncate_desc, lofs_truncate },		/* truncate */
1104 	{ &vop_update_desc, lofs_update },		/* update */
1105 	{ &vop_bwrite_desc, lofs_bwrite },		/* bwrite */
1106 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
1107 };
1108 struct vnodeopv_desc lofs_vnodeop_opv_desc =
1109 	{ &lofs_vnodeop_p, lofs_vnodeop_entries };
1110