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.4 (Berkeley) 11/14/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 	register struct vnode *vp = ap->a_vp;
856 	struct vnode *targetvp;
857 
858 	while (vp->v_flag & VXLOCK) {
859 		vp->v_flag |= VXWANT;
860 		sleep((caddr_t)vp, PINOD);
861 	}
862 	if (vp->v_tag == VT_NON)
863 		return (ENOENT);
864 	targetvp = LOFSVP(ap->a_vp);
865 
866 #ifdef LOFS_DIAGNOSTIC
867 	printf("lofs_lock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
868 	/*vprint("lofs_lock ap->a_vp", ap->a_vp);
869 	if (targetvp)
870 		vprint("lofs_lock ->ap->a_vp", targetvp);
871 	else
872 		printf("lofs_lock ->ap->a_vp = NIL\n");*/
873 #endif
874 
875 	if (targetvp && (error = VOP_LOCK(targetvp)))
876 		return (error);
877 	return (0);
878 }
879 
880 lofs_unlock(ap)
881 	struct vop_unlock_args /* {
882 		struct vnode *a_vp;
883 	} */ *ap;
884 {
885 	struct vnode *targetvp = LOFSVP(ap->a_vp);
886 
887 #ifdef LOFS_DIAGNOSTIC
888 	printf("lofs_unlock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
889 #endif
890 
891 	if (targetvp)
892 		return (VOP_UNLOCK(targetvp));
893 	return (0);
894 }
895 
896 lofs_bmap(ap)
897 	struct vop_bmap_args /* {
898 		struct vnode *a_vp;
899 		daddr_t  a_bn;
900 		struct vnode **a_vpp;
901 		daddr_t *a_bnp;
902 		int *a_runp;
903 	} */ *ap;
904 {
905 
906 #ifdef LOFS_DIAGNOSTIC
907 	printf("lofs_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
908 #endif
909 
910 	return VOP_BMAP(LOFSVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
911 }
912 
913 lofs_strategy(ap)
914 	struct vop_strategy_args /* {
915 		struct buf *a_bp;
916 	} */ *ap;
917 {
918 	int error;
919 
920 #ifdef LOFS_DIAGNOSTIC
921 	printf("lofs_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, LOFSVP(ap->a_bp->b_vp));
922 #endif
923 
924 	PUSHREF(vp, ap->a_bp->b_vp);
925 
926 	error = VOP_STRATEGY(ap->a_bp);
927 
928 	POP(vp, ap->a_bp->b_vp);
929 
930 	return (error);
931 }
932 
933 lofs_print(ap)
934 	struct vop_print_args /* {
935 		struct vnode *a_vp;
936 	} */ *ap;
937 {
938 
939 	struct vnode *targetvp = LOFSVP(ap->a_vp);
940 	printf("tag VT_LOFS ref ");
941 	if (targetvp)
942 		return (VOP_PRINT(targetvp));
943 	printf("NULLVP\n");
944 	return (0);
945 }
946 
947 lofs_islocked(ap)
948 	struct vop_islocked_args /* {
949 		struct vnode *a_vp;
950 	} */ *ap;
951 {
952 
953 	struct vnode *targetvp = LOFSVP(ap->a_vp);
954 	if (targetvp)
955 		return (VOP_ISLOCKED(targetvp));
956 	return (0);
957 }
958 
959 lofs_advlock(ap)
960 	struct vop_advlock_args /* {
961 		struct vnode *a_vp;
962 		caddr_t  a_id;
963 		int  a_op;
964 		struct flock *a_fl;
965 		int  a_flags;
966 	} */ *ap;
967 {
968 
969 	return VOP_ADVLOCK(LOFSVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
970 }
971 
972 /*
973  * LOFS directory offset lookup.
974  * Currently unsupported.
975  */
976 lofs_blkatoff(ap)
977 	struct vop_blkatoff_args /* {
978 		struct vnode *a_vp;
979 		off_t a_offset;
980 		char **a_res;
981 		struct buf **a_bpp;
982 	} */ *ap;
983 {
984 
985 	return (EOPNOTSUPP);
986 }
987 
988 /*
989  * LOFS flat namespace allocation.
990  * Currently unsupported.
991  */
992 lofs_valloc(ap)
993 	struct vop_valloc_args /* {
994 		struct vnode *a_pvp;
995 		int a_mode;
996 		struct ucred *a_cred;
997 		struct vnode **a_vpp;
998 	} */ *ap;
999 {
1000 
1001 	return (EOPNOTSUPP);
1002 }
1003 
1004 /*
1005  * LOFS flat namespace free.
1006  * Currently unsupported.
1007  */
1008 /*void*/
1009 lofs_vfree(ap)
1010 	struct vop_vfree_args /* {
1011 		struct vnode *a_pvp;
1012 		ino_t a_ino;
1013 		int a_mode;
1014 	} */ *ap;
1015 {
1016 
1017 	return (0);
1018 }
1019 
1020 /*
1021  * LOFS file truncation.
1022  */
1023 lofs_truncate(ap)
1024 	struct vop_truncate_args /* {
1025 		struct vnode *a_vp;
1026 		off_t a_length;
1027 		int a_flags;
1028 		struct ucred *a_cred;
1029 		struct proc *a_p;
1030 	} */ *ap;
1031 {
1032 
1033 	/* Use lofs_setattr */
1034 	printf("lofs_truncate: need to implement!!");
1035 	return (EOPNOTSUPP);
1036 }
1037 
1038 /*
1039  * LOFS update.
1040  */
1041 lofs_update(ap)
1042 	struct vop_update_args /* {
1043 		struct vnode *a_vp;
1044 		struct timeval *a_ta;
1045 		struct timeval *a_tm;
1046 		int a_waitfor;
1047 	} */ *ap;
1048 {
1049 
1050 	/* Use lofs_setattr */
1051 	printf("lofs_update: need to implement!!");
1052 	return (EOPNOTSUPP);
1053 }
1054 
1055 /*
1056  * LOFS bwrite
1057  */
1058 lofs_bwrite(ap)
1059 	struct vop_bwrite_args /* {
1060 		struct buf *a_bp;
1061 	} */ *ap;
1062 {
1063 
1064 	return (EOPNOTSUPP);
1065 }
1066 
1067 /*
1068  * Global vfs data structures for ufs
1069  */
1070 int (**lofs_vnodeop_p)();
1071 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
1072 	{ &vop_default_desc, vn_default_error },
1073 	{ &vop_lookup_desc, lofs_lookup },		/* lookup */
1074 	{ &vop_create_desc, lofs_create },		/* create */
1075 	{ &vop_mknod_desc, lofs_mknod },		/* mknod */
1076 	{ &vop_open_desc, lofs_open },		/* open */
1077 	{ &vop_close_desc, lofs_close },		/* close */
1078 	{ &vop_access_desc, lofs_access },		/* access */
1079 	{ &vop_getattr_desc, lofs_getattr },		/* getattr */
1080 	{ &vop_setattr_desc, lofs_setattr },		/* setattr */
1081 	{ &vop_read_desc, lofs_read },		/* read */
1082 	{ &vop_write_desc, lofs_write },		/* write */
1083 	{ &vop_ioctl_desc, lofs_ioctl },		/* ioctl */
1084 	{ &vop_select_desc, lofs_select },		/* select */
1085 	{ &vop_mmap_desc, lofs_mmap },		/* mmap */
1086 	{ &vop_fsync_desc, lofs_fsync },		/* fsync */
1087 	{ &vop_seek_desc, lofs_seek },		/* seek */
1088 	{ &vop_remove_desc, lofs_remove },		/* remove */
1089 	{ &vop_link_desc, lofs_link },		/* link */
1090 	{ &vop_rename_desc, lofs_rename },		/* rename */
1091 	{ &vop_mkdir_desc, lofs_mkdir },		/* mkdir */
1092 	{ &vop_rmdir_desc, lofs_rmdir },		/* rmdir */
1093 	{ &vop_symlink_desc, lofs_symlink },		/* symlink */
1094 	{ &vop_readdir_desc, lofs_readdir },		/* readdir */
1095 	{ &vop_readlink_desc, lofs_readlink },		/* readlink */
1096 	{ &vop_abortop_desc, lofs_abortop },		/* abortop */
1097 	{ &vop_inactive_desc, lofs_inactive },		/* inactive */
1098 	{ &vop_reclaim_desc, lofs_reclaim },		/* reclaim */
1099 	{ &vop_lock_desc, lofs_lock },		/* lock */
1100 	{ &vop_unlock_desc, lofs_unlock },		/* unlock */
1101 	{ &vop_bmap_desc, lofs_bmap },		/* bmap */
1102 	{ &vop_strategy_desc, lofs_strategy },		/* strategy */
1103 	{ &vop_print_desc, lofs_print },		/* print */
1104 	{ &vop_islocked_desc, lofs_islocked },		/* islocked */
1105 	{ &vop_advlock_desc, lofs_advlock },		/* advlock */
1106 	{ &vop_blkatoff_desc, lofs_blkatoff },		/* blkatoff */
1107 	{ &vop_valloc_desc, lofs_valloc },		/* valloc */
1108 	{ &vop_vfree_desc, lofs_vfree },		/* vfree */
1109 	{ &vop_truncate_desc, lofs_truncate },		/* truncate */
1110 	{ &vop_update_desc, lofs_update },		/* update */
1111 	{ &vop_bwrite_desc, lofs_bwrite },		/* bwrite */
1112 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
1113 };
1114 struct vnodeopv_desc lofs_vnodeop_opv_desc =
1115 	{ &lofs_vnodeop_p, lofs_vnodeop_entries };
1116