1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
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	8.1 (Berkeley) 06/10/93
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 	struct vnode *targetvp = LOFSVP(ap->a_vp);
382 
383 #ifdef LOFS_DIAGNOSTIC
384 	printf("lofs_fsync(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
385 #endif
386 
387 	if (targetvp)
388 		return VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, ap->a_p);
389 	return (0);
390 }
391 
392 lofs_seek(ap)
393 	struct vop_seek_args /* {
394 		struct vnode *a_vp;
395 		off_t  a_oldoff;
396 		off_t  a_newoff;
397 		struct ucred *a_cred;
398 	} */ *ap;
399 {
400 
401 #ifdef LOFS_DIAGNOSTIC
402 	printf("lofs_seek(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
403 #endif
404 
405 	return VOP_SEEK(LOFSVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred);
406 }
407 
408 lofs_remove(ap)
409 	struct vop_remove_args /* {
410 		struct vnode *a_dvp;
411 		struct vnode *a_vp;
412 		struct componentname *a_cnp;
413 	} */ *ap;
414 {
415 	int error;
416 
417 #ifdef LOFS_DIAGNOSTIC
418 	printf("lofs_remove(ap->a_vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
419 #endif
420 
421 	PUSHREF(xdvp, ap->a_dvp);
422 	VREF(ap->a_dvp);
423 	PUSHREF(xvp, ap->a_vp);
424 	VREF(ap->a_vp);
425 
426 	error = VOP_REMOVE(ap->a_dvp, ap->a_vp, ap->a_cnp);
427 
428 	POP(xvp, ap->a_vp);
429 	vrele(ap->a_vp);
430 	POP(xdvp, ap->a_dvp);
431 	vrele(ap->a_dvp);
432 
433 	return (error);
434 }
435 
436 /*
437  * vp is this.
438  * ni_dvp is the locked parent of the target.
439  * ni_vp is NULL.
440  */
441 lofs_link(ap)
442 	struct vop_link_args /* {
443 		struct vnode *a_vp;
444 		struct vnode *a_tdvp;
445 		struct componentname *a_cnp;
446 	} */ *ap;
447 {
448 	int error;
449 
450 #ifdef LOFS_DIAGNOSTIC
451 	printf("lofs_link(ap->a_tdvp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
452 #endif
453 
454 	PUSHREF(xdvp, ap->a_vp);
455 	VREF(ap->a_vp);
456 
457 	error = VOP_LINK(ap->a_vp, LOFSVP(ap->a_tdvp), ap->a_cnp);
458 
459 	POP(xdvp, ap->a_vp);
460 	vrele(ap->a_vp);
461 
462 	return (error);
463 }
464 
465 lofs_rename(ap)
466 	struct vop_rename_args  /* {
467 		struct vnode *a_fdvp;
468 		struct vnode *a_fvp;
469 		struct componentname *a_fcnp;
470 		struct vnode *a_tdvp;
471 		struct vnode *a_tvp;
472 		struct componentname *a_tcnp;
473 	} */ *ap;
474 {
475 	struct vnode *fvp, *tvp;
476 	struct vnode *tdvp;
477 #ifdef notdef
478 	struct vnode *fsvp, *tsvp;
479 #endif
480 	int error;
481 
482 #ifdef LOFS_DIAGNOSTIC
483 	printf("lofs_rename(fdvp = %x->%x)\n", ap->a_fdvp, LOFSVP(ap->a_fdvp));
484 	/*printf("lofs_rename(tdvp = %x->%x)\n", tndp->ni_dvp, LOFSVP(tndp->ni_dvp));*/
485 #endif
486 
487 #ifdef LOFS_DIAGNOSTIC
488 	printf("lofs_rename - switch source dvp\n");
489 #endif
490 	/*
491 	 * Switch source directory to point to lofsed vnode
492 	 */
493 	PUSHREF(fdvp, ap->a_fdvp);
494 	VREF(ap->a_fdvp);
495 
496 #ifdef LOFS_DIAGNOSTIC
497 	printf("lofs_rename - switch source vp\n");
498 #endif
499 	/*
500 	 * And source object if it is lofsed...
501 	 */
502 	fvp = ap->a_fvp;
503 	if (fvp && fvp->v_op == lofs_vnodeop_p) {
504 		ap->a_fvp = LOFSVP(fvp);
505 		VREF(ap->a_fvp);
506 	} else {
507 		fvp = 0;
508 	}
509 
510 #ifdef notdef
511 #ifdef LOFS_DIAGNOSTIC
512 	printf("lofs_rename - switch source start vp\n");
513 #endif
514 	/*
515 	 * And source startdir object if it is lofsed...
516 	 */
517 	fsvp = fndp->ni_startdir;
518 	if (fsvp && fsvp->v_op == lofs_vnodeop_p) {
519 		fndp->ni_startdir = LOFSVP(fsvp);
520 		VREF(fndp->ni_startdir);
521 	} else {
522 		fsvp = 0;
523 	}
524 #endif
525 
526 #ifdef LOFS_DIAGNOSTIC
527 	printf("lofs_rename - switch target dvp\n");
528 #endif
529 	/*
530  	 * Switch target directory to point to lofsed vnode
531 	 */
532 	tdvp = ap->a_tdvp;
533 	if (tdvp && tdvp->v_op == lofs_vnodeop_p) {
534 		ap->a_tdvp = LOFSVP(tdvp);
535 		VREF(ap->a_tdvp);
536 	} else {
537 		tdvp = 0;
538 	}
539 
540 #ifdef LOFS_DIAGNOSTIC
541 	printf("lofs_rename - switch target vp\n");
542 #endif
543 	/*
544 	 * And target object if it is lofsed...
545 	 */
546 	tvp = ap->a_tvp;
547 	if (tvp && tvp->v_op == lofs_vnodeop_p) {
548 		ap->a_tvp = LOFSVP(tvp);
549 		VREF(ap->a_tvp);
550 	} else {
551 		tvp = 0;
552 	}
553 
554 #ifdef notdef
555 #ifdef LOFS_DIAGNOSTIC
556 	printf("lofs_rename - switch target start vp\n");
557 #endif
558 	/*
559 	 * And target startdir object if it is lofsed...
560 	 */
561 	tsvp = tndp->ni_startdir;
562 	if (tsvp && tsvp->v_op == lofs_vnodeop_p) {
563 		tndp->ni_startdir = LOFSVP(fsvp);
564 		VREF(tndp->ni_startdir);
565 	} else {
566 		tsvp = 0;
567 	}
568 #endif
569 
570 #ifdef LOFS_DIAGNOSTIC
571 	printf("lofs_rename - VOP_RENAME(%x, %x, %x, %x)\n",
572 		ap->a_fdvp, ap->a_fvp, ap->a_tdvp, ap->a_tvp);
573 	vprint("ap->a_fdvp", ap->a_fdvp);
574 	vprint("ap->a_fvp", ap->a_fvp);
575 	vprint("ap->a_tdvp", ap->a_tdvp);
576 	if (ap->a_tvp) vprint("ap->a_tvp", ap->a_tvp);
577 	DELAY(16000000);
578 #endif
579 
580 	error = VOP_RENAME(ap->a_fdvp, ap->a_fvp, ap->a_fcnp, ap->a_tdvp, ap->a_tvp, ap->a_tcnp);
581 
582 	/*
583 	 * Put everything back...
584 	 */
585 
586 #ifdef notdef
587 #ifdef LOFS_DIAGNOSTIC
588 	printf("lofs_rename - restore target startdir\n");
589 #endif
590 
591 	if (tsvp) {
592 		if (tndp->ni_startdir)
593 			vrele(tndp->ni_startdir);
594 		tndp->ni_startdir = tsvp;
595 	}
596 #endif
597 
598 #ifdef LOFS_DIAGNOSTIC
599 	printf("lofs_rename - restore target vp\n");
600 #endif
601 
602 	if (tvp) {
603 		ap->a_tvp = tvp;
604 		vrele(ap->a_tvp);
605 	}
606 
607 #ifdef LOFS_DIAGNOSTIC
608 	printf("lofs_rename - restore target dvp\n");
609 #endif
610 
611 	if (tdvp) {
612 		ap->a_tdvp = tdvp;
613 		vrele(ap->a_tdvp);
614 	}
615 
616 #ifdef notdef
617 #ifdef LOFS_DIAGNOSTIC
618 	printf("lofs_rename - restore source startdir\n");
619 #endif
620 
621 	if (fsvp) {
622 		if (fndp->ni_startdir)
623 			vrele(fndp->ni_startdir);
624 		fndp->ni_startdir = fsvp;
625 	}
626 #endif
627 
628 #ifdef LOFS_DIAGNOSTIC
629 	printf("lofs_rename - restore source vp\n");
630 #endif
631 
632 
633 	if (fvp) {
634 		ap->a_fvp = fvp;
635 		vrele(ap->a_fvp);
636 	}
637 
638 #ifdef LOFS_DIAGNOSTIC
639 	printf("lofs_rename - restore source dvp\n");
640 #endif
641 
642 	POP(fdvp, ap->a_fdvp);
643 	vrele(ap->a_fdvp);
644 
645 	return (error);
646 }
647 
648 /*
649  * ni_dvp is the locked (alias) parent.
650  * ni_vp is NULL.
651  */
652 lofs_mkdir(ap)
653 	struct vop_mkdir_args /* {
654 		struct vnode *a_dvp;
655 		struct vnode **a_vpp;
656 		struct componentname *a_cnp;
657 		struct vattr *a_vap;
658 	} */ *ap;
659 {
660 	int error;
661 	struct vnode *dvp = ap->a_dvp;
662 	struct vnode *xdvp;
663 	struct vnode *newvp;
664 
665 #ifdef LOFS_DIAGNOSTIC
666 	printf("lofs_mkdir(vp = %x->%x)\n", dvp, LOFSVP(dvp));
667 #endif
668 
669 	xdvp = dvp;
670 	dvp = LOFSVP(xdvp);
671 	VREF(dvp);
672 
673 	error = VOP_MKDIR(dvp, &newvp, ap->a_cnp, ap->a_vap);
674 
675 	if (error) {
676 		*ap->a_vpp = NULLVP;
677 		vrele(xdvp);
678 		return (error);
679 	}
680 
681 	/*
682 	 * Make a new lofs node
683 	 */
684 	/*VREF(dvp);*/
685 
686 	error = make_lofs(dvp->v_mount, &newvp);
687 
688 	*ap->a_vpp = newvp;
689 
690 	return (error);
691 }
692 
693 /*
694  * ni_dvp is the locked parent.
695  * ni_vp is the entry to be removed.
696  */
697 lofs_rmdir(ap)
698 	struct vop_rmdir_args /* {
699 		struct vnode *a_dvp;
700 		struct vnode *a_vp;
701 		struct componentname *a_cnp;
702 	} */ *ap;
703 {
704 	struct vnode *vp = ap->a_vp;
705 	struct vnode *dvp = ap->a_dvp;
706 	int error;
707 
708 #ifdef LOFS_DIAGNOSTIC
709 	printf("lofs_rmdir(dvp = %x->%x)\n", dvp, LOFSVP(dvp));
710 #endif
711 
712 	PUSHREF(xdvp, dvp);
713 	VREF(dvp);
714 	PUSHREF(xvp, vp);
715 	VREF(vp);
716 
717 	error = VOP_RMDIR(dvp, vp, ap->a_cnp);
718 
719 	POP(xvp, vp);
720 	vrele(vp);
721 	POP(xdvp, dvp);
722 	vrele(dvp);
723 
724 	return (error);
725 }
726 
727 /*
728  * ni_dvp is the locked parent.
729  * ni_vp is NULL.
730  */
731 lofs_symlink(ap)
732 	struct vop_symlink_args /* {
733 		struct vnode *a_dvp;
734 		struct vnode **a_vpp;
735 		struct componentname *a_cnp;
736 		struct vattr *a_vap;
737 		char *a_target;
738 	} */ *ap;
739 {
740 	int error;
741 
742 #ifdef LOFS_DIAGNOSTIC
743 	printf("VOP_SYMLINK(vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
744 #endif
745 
746 	PUSHREF(xdvp, ap->a_dvp);
747 	VREF(ap->a_dvp);
748 
749 	error = VOP_SYMLINK(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_target);
750 
751 	POP(xdvp, ap->a_dvp);
752 	vrele(ap->a_dvp);
753 
754 	return (error);
755 }
756 
757 lofs_readdir(ap)
758 	struct vop_readdir_args /* {
759 		struct vnode *a_vp;
760 		struct uio *a_uio;
761 		struct ucred *a_cred;
762 	} */ *ap;
763 {
764 
765 #ifdef LOFS_DIAGNOSTIC
766 	printf("lofs_readdir(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
767 #endif
768 
769 	return VOP_READDIR(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred);
770 }
771 
772 lofs_readlink(ap)
773 	struct vop_readlink_args /* {
774 		struct vnode *a_vp;
775 		struct uio *a_uio;
776 		struct ucred *a_cred;
777 	} */ *ap;
778 {
779 
780 #ifdef LOFS_DIAGNOSTIC
781 	printf("lofs_readlink(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
782 #endif
783 
784 	return VOP_READLINK(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred);
785 }
786 
787 /*
788  * Anyone's guess...
789  */
790 lofs_abortop(ap)
791 	struct vop_abortop_args /* {
792 		struct vnode *a_dvp;
793 		struct componentname *a_cnp;
794 	} */ *ap;
795 {
796 	int error;
797 
798 	PUSHREF(xdvp, ap->a_dvp);
799 
800 	error = VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
801 
802 	POP(xdvp, ap->a_dvp);
803 
804 	return (error);
805 }
806 
807 lofs_inactive(ap)
808 	struct vop_inactive_args /* {
809 		struct vnode *a_vp;
810 	} */ *ap;
811 {
812 	struct vnode *targetvp = LOFSVP(ap->a_vp);
813 
814 #ifdef LOFS_DIAGNOSTIC
815 	printf("lofs_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
816 #endif
817 
818 #ifdef DIAGNOSTIC
819 	{ extern int prtactive;
820 	if (prtactive && ap->a_vp->v_usecount != 0)
821 		vprint("lofs_inactive: pushing active", ap->a_vp);
822 	}
823 #endif
824 
825 	if (targetvp) {
826 		vrele(targetvp);
827 		LOFSP(ap->a_vp)->a_lofsvp = 0;
828 	}
829 }
830 
831 lofs_reclaim(ap)
832 	struct vop_reclaim_args /* {
833 		struct vnode *a_vp;
834 	} */ *ap;
835 {
836 	struct vnode *targetvp;
837 
838 #ifdef LOFS_DIAGNOSTIC
839 	printf("lofs_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
840 #endif
841 	remque(LOFSP(ap->a_vp));
842 	targetvp = LOFSVP(ap->a_vp);
843 	if (targetvp) {
844 		printf("lofs: delayed vrele of %x\n", targetvp);
845 		vrele(targetvp);	/* XXX should never happen */
846 	}
847 	FREE(ap->a_vp->v_data, M_TEMP);
848 	ap->a_vp->v_data = 0;
849 	return (0);
850 }
851 
852 lofs_lock(ap)
853 	struct vop_lock_args /* {
854 		struct vnode *a_vp;
855 	} */ *ap;
856 {
857 	int error;
858 	register struct vnode *vp = ap->a_vp;
859 	struct vnode *targetvp;
860 
861 	while (vp->v_flag & VXLOCK) {
862 		vp->v_flag |= VXWANT;
863 		sleep((caddr_t)vp, PINOD);
864 	}
865 	if (vp->v_tag == VT_NON)
866 		return (ENOENT);
867 	targetvp = LOFSVP(ap->a_vp);
868 
869 #ifdef LOFS_DIAGNOSTIC
870 	printf("lofs_lock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
871 	/*vprint("lofs_lock ap->a_vp", ap->a_vp);
872 	if (targetvp)
873 		vprint("lofs_lock ->ap->a_vp", targetvp);
874 	else
875 		printf("lofs_lock ->ap->a_vp = NIL\n");*/
876 #endif
877 
878 	if (targetvp && (error = VOP_LOCK(targetvp)))
879 		return (error);
880 	return (0);
881 }
882 
883 lofs_unlock(ap)
884 	struct vop_unlock_args /* {
885 		struct vnode *a_vp;
886 	} */ *ap;
887 {
888 	struct vnode *targetvp = LOFSVP(ap->a_vp);
889 
890 #ifdef LOFS_DIAGNOSTIC
891 	printf("lofs_unlock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
892 #endif
893 
894 	if (targetvp)
895 		return (VOP_UNLOCK(targetvp));
896 	return (0);
897 }
898 
899 lofs_bmap(ap)
900 	struct vop_bmap_args /* {
901 		struct vnode *a_vp;
902 		daddr_t  a_bn;
903 		struct vnode **a_vpp;
904 		daddr_t *a_bnp;
905 		int *a_runp;
906 	} */ *ap;
907 {
908 
909 #ifdef LOFS_DIAGNOSTIC
910 	printf("lofs_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
911 #endif
912 
913 	return VOP_BMAP(LOFSVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
914 }
915 
916 lofs_strategy(ap)
917 	struct vop_strategy_args /* {
918 		struct buf *a_bp;
919 	} */ *ap;
920 {
921 	int error;
922 
923 #ifdef LOFS_DIAGNOSTIC
924 	printf("lofs_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, LOFSVP(ap->a_bp->b_vp));
925 #endif
926 
927 	PUSHREF(vp, ap->a_bp->b_vp);
928 
929 	error = VOP_STRATEGY(ap->a_bp);
930 
931 	POP(vp, ap->a_bp->b_vp);
932 
933 	return (error);
934 }
935 
936 lofs_print(ap)
937 	struct vop_print_args /* {
938 		struct vnode *a_vp;
939 	} */ *ap;
940 {
941 
942 	struct vnode *targetvp = LOFSVP(ap->a_vp);
943 	printf("tag VT_LOFS ref ");
944 	if (targetvp)
945 		return (VOP_PRINT(targetvp));
946 	printf("NULLVP\n");
947 	return (0);
948 }
949 
950 lofs_islocked(ap)
951 	struct vop_islocked_args /* {
952 		struct vnode *a_vp;
953 	} */ *ap;
954 {
955 
956 	struct vnode *targetvp = LOFSVP(ap->a_vp);
957 	if (targetvp)
958 		return (VOP_ISLOCKED(targetvp));
959 	return (0);
960 }
961 
962 lofs_advlock(ap)
963 	struct vop_advlock_args /* {
964 		struct vnode *a_vp;
965 		caddr_t  a_id;
966 		int  a_op;
967 		struct flock *a_fl;
968 		int  a_flags;
969 	} */ *ap;
970 {
971 
972 	return VOP_ADVLOCK(LOFSVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
973 }
974 
975 /*
976  * LOFS directory offset lookup.
977  * Currently unsupported.
978  */
979 lofs_blkatoff(ap)
980 	struct vop_blkatoff_args /* {
981 		struct vnode *a_vp;
982 		off_t a_offset;
983 		char **a_res;
984 		struct buf **a_bpp;
985 	} */ *ap;
986 {
987 
988 	return (EOPNOTSUPP);
989 }
990 
991 /*
992  * LOFS flat namespace allocation.
993  * Currently unsupported.
994  */
995 lofs_valloc(ap)
996 	struct vop_valloc_args /* {
997 		struct vnode *a_pvp;
998 		int a_mode;
999 		struct ucred *a_cred;
1000 		struct vnode **a_vpp;
1001 	} */ *ap;
1002 {
1003 
1004 	return (EOPNOTSUPP);
1005 }
1006 
1007 /*
1008  * LOFS flat namespace free.
1009  * Currently unsupported.
1010  */
1011 /*void*/
1012 lofs_vfree(ap)
1013 	struct vop_vfree_args /* {
1014 		struct vnode *a_pvp;
1015 		ino_t a_ino;
1016 		int a_mode;
1017 	} */ *ap;
1018 {
1019 
1020 	return (0);
1021 }
1022 
1023 /*
1024  * LOFS file truncation.
1025  */
1026 lofs_truncate(ap)
1027 	struct vop_truncate_args /* {
1028 		struct vnode *a_vp;
1029 		off_t a_length;
1030 		int a_flags;
1031 		struct ucred *a_cred;
1032 		struct proc *a_p;
1033 	} */ *ap;
1034 {
1035 
1036 	/* Use lofs_setattr */
1037 	printf("lofs_truncate: need to implement!!");
1038 	return (EOPNOTSUPP);
1039 }
1040 
1041 /*
1042  * LOFS update.
1043  */
1044 lofs_update(ap)
1045 	struct vop_update_args /* {
1046 		struct vnode *a_vp;
1047 		struct timeval *a_ta;
1048 		struct timeval *a_tm;
1049 		int a_waitfor;
1050 	} */ *ap;
1051 {
1052 
1053 	/* Use lofs_setattr */
1054 	printf("lofs_update: need to implement!!");
1055 	return (EOPNOTSUPP);
1056 }
1057 
1058 /*
1059  * LOFS bwrite
1060  */
1061 lofs_bwrite(ap)
1062 	struct vop_bwrite_args /* {
1063 		struct buf *a_bp;
1064 	} */ *ap;
1065 {
1066 
1067 	return (EOPNOTSUPP);
1068 }
1069 
1070 /*
1071  * Global vfs data structures for ufs
1072  */
1073 int (**lofs_vnodeop_p)();
1074 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
1075 	{ &vop_default_desc, vn_default_error },
1076 	{ &vop_lookup_desc, lofs_lookup },		/* lookup */
1077 	{ &vop_create_desc, lofs_create },		/* create */
1078 	{ &vop_mknod_desc, lofs_mknod },		/* mknod */
1079 	{ &vop_open_desc, lofs_open },		/* open */
1080 	{ &vop_close_desc, lofs_close },		/* close */
1081 	{ &vop_access_desc, lofs_access },		/* access */
1082 	{ &vop_getattr_desc, lofs_getattr },		/* getattr */
1083 	{ &vop_setattr_desc, lofs_setattr },		/* setattr */
1084 	{ &vop_read_desc, lofs_read },		/* read */
1085 	{ &vop_write_desc, lofs_write },		/* write */
1086 	{ &vop_ioctl_desc, lofs_ioctl },		/* ioctl */
1087 	{ &vop_select_desc, lofs_select },		/* select */
1088 	{ &vop_mmap_desc, lofs_mmap },		/* mmap */
1089 	{ &vop_fsync_desc, lofs_fsync },		/* fsync */
1090 	{ &vop_seek_desc, lofs_seek },		/* seek */
1091 	{ &vop_remove_desc, lofs_remove },		/* remove */
1092 	{ &vop_link_desc, lofs_link },		/* link */
1093 	{ &vop_rename_desc, lofs_rename },		/* rename */
1094 	{ &vop_mkdir_desc, lofs_mkdir },		/* mkdir */
1095 	{ &vop_rmdir_desc, lofs_rmdir },		/* rmdir */
1096 	{ &vop_symlink_desc, lofs_symlink },		/* symlink */
1097 	{ &vop_readdir_desc, lofs_readdir },		/* readdir */
1098 	{ &vop_readlink_desc, lofs_readlink },		/* readlink */
1099 	{ &vop_abortop_desc, lofs_abortop },		/* abortop */
1100 	{ &vop_inactive_desc, lofs_inactive },		/* inactive */
1101 	{ &vop_reclaim_desc, lofs_reclaim },		/* reclaim */
1102 	{ &vop_lock_desc, lofs_lock },		/* lock */
1103 	{ &vop_unlock_desc, lofs_unlock },		/* unlock */
1104 	{ &vop_bmap_desc, lofs_bmap },		/* bmap */
1105 	{ &vop_strategy_desc, lofs_strategy },		/* strategy */
1106 	{ &vop_print_desc, lofs_print },		/* print */
1107 	{ &vop_islocked_desc, lofs_islocked },		/* islocked */
1108 	{ &vop_advlock_desc, lofs_advlock },		/* advlock */
1109 	{ &vop_blkatoff_desc, lofs_blkatoff },		/* blkatoff */
1110 	{ &vop_valloc_desc, lofs_valloc },		/* valloc */
1111 	{ &vop_vfree_desc, lofs_vfree },		/* vfree */
1112 	{ &vop_truncate_desc, lofs_truncate },		/* truncate */
1113 	{ &vop_update_desc, lofs_update },		/* update */
1114 	{ &vop_bwrite_desc, lofs_bwrite },		/* bwrite */
1115 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
1116 };
1117 struct vnodeopv_desc lofs_vnodeop_opv_desc =
1118 	{ &lofs_vnodeop_p, lofs_vnodeop_entries };
1119