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	1.2 (Berkeley) 06/18/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 <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 *ap;
63 {
64 	USES_VOP_LOOKUP;
65 	struct vnode *dvp = ap->a_dvp;
66 	struct vnode *newvp;
67 	struct vnode *targetdvp;
68 	int error;
69 	int flag = ap->a_cnp->cn_nameiop /*& OPMASK*/;
70 
71 #ifdef LOFS_DIAGNOSTIC
72 	printf("lofs_lookup(ap->a_dvp = %x->%x, \"%s\", op = %d)\n",
73 		dvp, LOFSVP(dvp), ap->a_cnp->cn_nameptr, flag);
74 #endif
75 
76 	/*
77 	 * (ap->a_dvp) was locked when passed in, and it will be replaced
78 	 * with the target vnode, BUT that will already have been
79 	 * locked when (ap->a_dvp) was locked [see lofs_lock].  all that
80 	 * must be done here is to keep track of reference counts.
81 	 */
82 	targetdvp = LOFSVP(dvp);
83 	/*VREF(targetdvp);*/
84 #ifdef LOFS_DIAGNOSTIC
85 	vprint("lofs VOP_LOOKUP", targetdvp);
86 #endif
87 
88 	/*
89 	 * Call lookup on the looped vnode
90 	 */
91 	error = VOP_LOOKUP(targetdvp, &newvp, ap->a_cnp);
92 	/*vrele(targetdvp);*/
93 
94 	if (error) {
95 		*ap->a_vpp = NULLVP;
96 #ifdef LOFS_DIAGNOSTIC
97 		printf("lofs_lookup(%x->%x) = %d\n", dvp, LOFSVP(dvp), error);
98 #endif
99 		return (error);
100 	}
101 #ifdef LOFS_DIAGNOSTIC
102 	printf("lofs_lookup(%x->%x) = OK\n", dvp, LOFSVP(dvp));
103 #endif
104 
105 	*ap->a_vpp = newvp;
106 
107 	/*
108 	 * If we just found a directory then make
109 	 * a loopback node for it and return the loopback
110 	 * instead of the real vnode.  Otherwise simply
111 	 * return the aliased directory and vnode.
112 	 */
113 	if (newvp && newvp->v_type == VDIR && flag == LOOKUP) {
114 #ifdef LOFS_DIAGNOSTIC
115 		printf("lofs_lookup: found VDIR\n");
116 #endif
117 		/*
118 		 * At this point, newvp is the vnode to be looped.
119 		 * Activate a loopback and return the looped vnode.
120 		 */
121 		return (make_lofs(dvp->v_mount, ap->a_vpp));
122 	}
123 
124 #ifdef LOFS_DIAGNOSTIC
125 	printf("lofs_lookup: not VDIR\n");
126 #endif
127 
128 	return (0);
129 }
130 
131 /*
132  * this = ni_dvp
133  * ni_dvp references the locked directory.
134  * ni_vp is NULL.
135  */
136 lofs_mknod (ap)
137 	struct vop_mknod_args *ap;
138 {
139 	USES_VOP_MKNOD;
140 	int error;
141 
142 #ifdef LOFS_DIAGNOSTIC
143 	printf("lofs_mknod(vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
144 #endif
145 
146 	PUSHREF(xdvp, ap->a_dvp);
147 	VREF(ap->a_dvp);
148 
149 	error = VOP_MKNOD(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
150 
151 	POP(xdvp, ap->a_dvp);
152 	vrele(ap->a_dvp);
153 
154 	return (error);
155 }
156 
157 /*
158  * this = ni_dvp;
159  * ni_dvp references the locked directory
160  * ni_vp is NULL.
161  */
162 lofs_create (ap)
163 	struct vop_create_args *ap;
164 {
165 	USES_VOP_CREATE;
166 	int error;
167 
168 #ifdef LOFS_DIAGNOSTIC
169 	printf("lofs_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
170 #endif
171 
172 	PUSHREF(xdvp, ap->a_dvp);
173 	VREF(ap->a_dvp);
174 
175 	error = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
176 
177 	POP(xdvp, ap->a_dvp);
178 	vrele(ap->a_dvp);
179 
180 #ifdef LOFS_DIAGNOSTIC
181 	printf("lofs_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
182 #endif
183 
184 	return (error);
185 }
186 
187 lofs_open (ap)
188 	struct vop_open_args *ap;
189 {
190 	USES_VOP_OPEN;
191 #ifdef LOFS_DIAGNOSTIC
192 	printf("lofs_open(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
193 #endif
194 
195 	return VOP_OPEN(LOFSVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
196 }
197 
198 lofs_close (ap)
199 	struct vop_close_args *ap;
200 {
201 	USES_VOP_CLOSE;
202 #ifdef LOFS_DIAGNOSTIC
203 	printf("lofs_close(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
204 #endif
205 
206 	return VOP_CLOSE(LOFSVP(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p);
207 }
208 
209 lofs_access (ap)
210 	struct vop_access_args *ap;
211 {
212 	USES_VOP_ACCESS;
213 #ifdef LOFS_DIAGNOSTIC
214 	printf("lofs_access(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
215 #endif
216 
217 	return VOP_ACCESS(LOFSVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
218 }
219 
220 lofs_getattr (ap)
221 	struct vop_getattr_args *ap;
222 {
223 	USES_VOP_GETATTR;
224 	int error;
225 
226 #ifdef LOFS_DIAGNOSTIC
227 	printf("lofs_getattr(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
228 #endif
229 
230 	/*
231 	 * Get the stats from the underlying filesystem
232 	 */
233 	error = VOP_GETATTR(LOFSVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_p);
234 	if (error)
235 		return (error);
236 	/*
237 	 * and replace the fsid field with the loopback number
238 	 * to preserve the namespace.
239 	 */
240 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
241 	return (0);
242 }
243 
244 lofs_setattr (ap)
245 	struct vop_setattr_args *ap;
246 {
247 	USES_VOP_SETATTR;
248 #ifdef LOFS_DIAGNOSTIC
249 	printf("lofs_setattr(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
250 #endif
251 
252 	return VOP_SETATTR(LOFSVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_p);
253 }
254 
255 lofs_read (ap)
256 	struct vop_read_args *ap;
257 {
258 	USES_VOP_READ;
259 #ifdef LOFS_DIAGNOSTIC
260 	printf("lofs_read(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
261 #endif
262 
263 	return VOP_READ(LOFSVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
264 }
265 
266 lofs_write (ap)
267 	struct vop_write_args *ap;
268 {
269 	USES_VOP_WRITE;
270 #ifdef LOFS_DIAGNOSTIC
271 	printf("lofs_write(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
272 #endif
273 
274 	return VOP_WRITE(LOFSVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
275 }
276 
277 lofs_ioctl (ap)
278 	struct vop_ioctl_args *ap;
279 {
280 	USES_VOP_IOCTL;
281 #ifdef LOFS_DIAGNOSTIC
282 	printf("lofs_ioctl(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
283 #endif
284 
285 	return VOP_IOCTL(LOFSVP(ap->a_vp), ap->a_command, ap->a_data, ap->a_fflag, ap->a_cred, ap->a_p);
286 }
287 
288 lofs_select (ap)
289 	struct vop_select_args *ap;
290 {
291 	USES_VOP_SELECT;
292 #ifdef LOFS_DIAGNOSTIC
293 	printf("lofs_select(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
294 #endif
295 
296 	return VOP_SELECT(LOFSVP(ap->a_vp), ap->a_which, ap->a_fflags, ap->a_cred, ap->a_p);
297 }
298 
299 lofs_mmap (ap)
300 	struct vop_mmap_args *ap;
301 {
302 	USES_VOP_MMAP;
303 #ifdef LOFS_DIAGNOSTIC
304 	printf("lofs_mmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
305 #endif
306 
307 	return VOP_MMAP(LOFSVP(ap->a_vp), ap->a_fflags, ap->a_cred, ap->a_p);
308 }
309 
310 lofs_fsync (ap)
311 	struct vop_fsync_args *ap;
312 {
313 	USES_VOP_FSYNC;
314 #ifdef LOFS_DIAGNOSTIC
315 	printf("lofs_fsync(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
316 #endif
317 
318 	return VOP_FSYNC(LOFSVP(ap->a_vp), ap->a_fflags, ap->a_cred, ap->a_waitfor, ap->a_p);
319 }
320 
321 lofs_seek (ap)
322 	struct vop_seek_args *ap;
323 {
324 	USES_VOP_SEEK;
325 #ifdef LOFS_DIAGNOSTIC
326 	printf("lofs_seek(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
327 #endif
328 
329 	return VOP_SEEK(LOFSVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred);
330 }
331 
332 lofs_remove (ap)
333 	struct vop_remove_args *ap;
334 {
335 	USES_VOP_REMOVE;
336 	int error;
337 
338 #ifdef LOFS_DIAGNOSTIC
339 	printf("lofs_remove(ap->a_vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
340 #endif
341 
342 	PUSHREF(xdvp, ap->a_dvp);
343 	VREF(ap->a_dvp);
344 	PUSHREF(xvp, ap->a_vp);
345 	VREF(ap->a_vp);
346 
347 	error = VOP_REMOVE(ap->a_dvp, ap->a_vp, ap->a_cnp);
348 
349 	POP(xvp, ap->a_vp);
350 	vrele(ap->a_vp);
351 	POP(xdvp, ap->a_dvp);
352 	vrele(ap->a_dvp);
353 
354 	return (error);
355 }
356 
357 /*
358  * vp is this.
359  * ni_dvp is the locked parent of the target.
360  * ni_vp is NULL.
361  */
362 lofs_link (ap)
363 	struct vop_link_args *ap;
364 {
365 	USES_VOP_LINK;
366 	int error;
367 
368 #ifdef LOFS_DIAGNOSTIC
369 	printf("lofs_link(ap->a_tdvp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
370 #endif
371 
372 	PUSHREF(xdvp, ap->a_vp);
373 	VREF(ap->a_vp);
374 
375 	error = VOP_LINK(ap->a_vp, LOFSVP(ap->a_tdvp), ap->a_cnp);
376 
377 	POP(xdvp, ap->a_vp);
378 	vrele(ap->a_vp);
379 
380 	return (error);
381 }
382 
383 lofs_rename (ap)
384 	struct vop_rename_args *ap;
385 {
386 	USES_VOP_RENAME;
387 	struct vnode *fvp, *tvp;
388 	struct vnode *tdvp;
389 #if 0
390 	struct vnode *fsvp, *tsvp;
391 #endif
392 	int error;
393 
394 #ifdef LOFS_DIAGNOSTIC
395 	printf("lofs_rename(fdvp = %x->%x)\n", ap->a_fdvp, LOFSVP(ap->a_fdvp));
396 	/*printf("lofs_rename(tdvp = %x->%x)\n", tndp->ni_dvp, LOFSVP(tndp->ni_dvp));*/
397 #endif
398 
399 #ifdef LOFS_DIAGNOSTIC
400 	printf("lofs_rename - switch source dvp\n");
401 #endif
402 	/*
403 	 * Switch source directory to point to lofsed vnode
404 	 */
405 	PUSHREF(fdvp, ap->a_fdvp);
406 	VREF(ap->a_fdvp);
407 
408 #ifdef LOFS_DIAGNOSTIC
409 	printf("lofs_rename - switch source vp\n");
410 #endif
411 	/*
412 	 * And source object if it is lofsed...
413 	 */
414 	fvp = ap->a_fvp;
415 	if (fvp && fvp->v_op == lofs_vnodeop_p) {
416 		ap->a_fvp = LOFSVP(fvp);
417 		VREF(ap->a_fvp);
418 	} else {
419 		fvp = 0;
420 	}
421 
422 #if 0
423 #ifdef LOFS_DIAGNOSTIC
424 	printf("lofs_rename - switch source start vp\n");
425 #endif
426 	/*
427 	 * And source startdir object if it is lofsed...
428 	 */
429 	fsvp = fndp->ni_startdir;
430 	if (fsvp && fsvp->v_op == lofs_vnodeop_p) {
431 		fndp->ni_startdir = LOFSVP(fsvp);
432 		VREF(fndp->ni_startdir);
433 	} else {
434 		fsvp = 0;
435 	}
436 #endif
437 
438 #ifdef LOFS_DIAGNOSTIC
439 	printf("lofs_rename - switch target dvp\n");
440 #endif
441 	/*
442  	 * Switch target directory to point to lofsed vnode
443 	 */
444 	tdvp = ap->a_tdvp;
445 	if (tdvp && tdvp->v_op == lofs_vnodeop_p) {
446 		ap->a_tdvp = LOFSVP(tdvp);
447 		VREF(ap->a_tdvp);
448 	} else {
449 		tdvp = 0;
450 	}
451 
452 #ifdef LOFS_DIAGNOSTIC
453 	printf("lofs_rename - switch target vp\n");
454 #endif
455 	/*
456 	 * And target object if it is lofsed...
457 	 */
458 	tvp = ap->a_tvp;
459 	if (tvp && tvp->v_op == lofs_vnodeop_p) {
460 		ap->a_tvp = LOFSVP(tvp);
461 		VREF(ap->a_tvp);
462 	} else {
463 		tvp = 0;
464 	}
465 
466 #if 0
467 #ifdef LOFS_DIAGNOSTIC
468 	printf("lofs_rename - switch target start vp\n");
469 #endif
470 	/*
471 	 * And target startdir object if it is lofsed...
472 	 */
473 	tsvp = tndp->ni_startdir;
474 	if (tsvp && tsvp->v_op == lofs_vnodeop_p) {
475 		tndp->ni_startdir = LOFSVP(fsvp);
476 		VREF(tndp->ni_startdir);
477 	} else {
478 		tsvp = 0;
479 	}
480 #endif
481 
482 #ifdef LOFS_DIAGNOSTIC
483 	printf("lofs_rename - VOP_RENAME(%x, %x, %x, %x)\n",
484 		ap->a_fdvp, ap->a_fvp, ap->a_tdvp, ap->a_tvp);
485 	vprint("ap->a_fdvp", ap->a_fdvp);
486 	vprint("ap->a_fvp", ap->a_fvp);
487 	vprint("ap->a_tdvp", ap->a_tdvp);
488 	if (ap->a_tvp) vprint("ap->a_tvp", ap->a_tvp);
489 	DELAY(16000000);
490 #endif
491 
492 	error = VOP_RENAME(ap->a_fdvp, ap->a_fvp, ap->a_fcnp, ap->a_tdvp, ap->a_tvp, ap->a_tcnp);
493 
494 	/*
495 	 * Put everything back...
496 	 */
497 
498 #if 0
499 #ifdef LOFS_DIAGNOSTIC
500 	printf("lofs_rename - restore target startdir\n");
501 #endif
502 
503 	if (tsvp) {
504 		if (tndp->ni_startdir)
505 			vrele(tndp->ni_startdir);
506 		tndp->ni_startdir = tsvp;
507 	}
508 #endif
509 
510 #ifdef LOFS_DIAGNOSTIC
511 	printf("lofs_rename - restore target vp\n");
512 #endif
513 
514 	if (tvp) {
515 		ap->a_tvp = tvp;
516 		vrele(ap->a_tvp);
517 	}
518 
519 #ifdef LOFS_DIAGNOSTIC
520 	printf("lofs_rename - restore target dvp\n");
521 #endif
522 
523 	if (tdvp) {
524 		ap->a_tdvp = tdvp;
525 		vrele(ap->a_tdvp);
526 	}
527 
528 #if 0
529 #ifdef LOFS_DIAGNOSTIC
530 	printf("lofs_rename - restore source startdir\n");
531 #endif
532 
533 	if (fsvp) {
534 		if (fndp->ni_startdir)
535 			vrele(fndp->ni_startdir);
536 		fndp->ni_startdir = fsvp;
537 	}
538 #endif
539 
540 #ifdef LOFS_DIAGNOSTIC
541 	printf("lofs_rename - restore source vp\n");
542 #endif
543 
544 
545 	if (fvp) {
546 		ap->a_fvp = fvp;
547 		vrele(ap->a_fvp);
548 	}
549 
550 #ifdef LOFS_DIAGNOSTIC
551 	printf("lofs_rename - restore source dvp\n");
552 #endif
553 
554 	POP(fdvp, ap->a_fdvp);
555 	vrele(ap->a_fdvp);
556 
557 	return (error);
558 }
559 
560 /*
561  * ni_dvp is the locked (alias) parent.
562  * ni_vp is NULL.
563  */
564 lofs_mkdir (ap)
565 	struct vop_mkdir_args *ap;
566 {
567 	USES_VOP_MKDIR;
568 	int error;
569 	struct vnode *dvp = ap->a_dvp;
570 	struct vnode *xdvp;
571 	struct vnode *newvp;
572 
573 #ifdef LOFS_DIAGNOSTIC
574 	printf("lofs_mkdir(vp = %x->%x)\n", dvp, LOFSVP(dvp));
575 #endif
576 
577 	xdvp = dvp;
578 	dvp = LOFSVP(xdvp);
579 	/*VREF(dvp);*/
580 
581 	error = VOP_MKDIR(dvp, &newvp, ap->a_cnp, ap->a_vap);
582 
583 	if (error) {
584 		*ap->a_vpp = NULLVP;
585 		/*vrele(xdvp);*/
586 		return (error);
587 	}
588 
589 	/*
590 	 * Make a new lofs node
591 	 */
592 	/*VREF(dvp);*/
593 
594 	error = make_lofs(dvp->v_mount, &newvp);
595 
596 	*ap->a_vpp = newvp;
597 
598 	return (error);
599 }
600 
601 /*
602  * ni_dvp is the locked parent.
603  * ni_vp is the entry to be removed.
604  */
605 lofs_rmdir (ap)
606 	struct vop_rmdir_args *ap;
607 {
608 	USES_VOP_RMDIR;
609 	struct vnode *vp = ap->a_vp;
610 	struct vnode *dvp = ap->a_dvp;
611 	int error;
612 
613 #ifdef LOFS_DIAGNOSTIC
614 	printf("lofs_rmdir(dvp = %x->%x)\n", dvp, LOFSVP(dvp));
615 #endif
616 
617 	PUSHREF(xdvp, dvp);
618 	VREF(dvp);
619 	PUSHREF(xvp, vp);
620 	VREF(vp);
621 
622 	error = VOP_RMDIR(dvp, vp, ap->a_cnp);
623 
624 	POP(xvp, vp);
625 	vrele(vp);
626 	POP(xdvp, dvp);
627 	vrele(dvp);
628 
629 	return (error);
630 }
631 
632 /*
633  * ni_dvp is the locked parent.
634  * ni_vp is NULL.
635  */
636 lofs_symlink (ap)
637 	struct vop_symlink_args *ap;
638 {
639 	USES_VOP_SYMLINK;
640 	int error;
641 
642 #ifdef LOFS_DIAGNOSTIC
643 	printf("VOP_SYMLINK(vp = %x->%x)\n", ap->a_dvp, LOFSVP(ap->a_dvp));
644 #endif
645 
646 	PUSHREF(xdvp, ap->a_dvp);
647 	VREF(ap->a_dvp);
648 
649 	error = VOP_SYMLINK(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_target);
650 
651 	POP(xdvp, ap->a_dvp);
652 	vrele(ap->a_dvp);
653 
654 	return (error);
655 }
656 
657 lofs_readdir (ap)
658 	struct vop_readdir_args *ap;
659 {
660 	USES_VOP_READDIR;
661 #ifdef LOFS_DIAGNOSTIC
662 	printf("lofs_readdir(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
663 #endif
664 
665 	return VOP_READDIR(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflagp);
666 }
667 
668 lofs_readlink (ap)
669 	struct vop_readlink_args *ap;
670 {
671 	USES_VOP_READLINK;
672 #ifdef LOFS_DIAGNOSTIC
673 	printf("lofs_readlink(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
674 #endif
675 
676 	return VOP_READLINK(LOFSVP(ap->a_vp), ap->a_uio, ap->a_cred);
677 }
678 
679 /*
680  * Anyone's guess...
681  */
682 lofs_abortop (ap)
683 	struct vop_abortop_args *ap;
684 {
685 	USES_VOP_ABORTOP;
686 	int error;
687 
688 	PUSHREF(xdvp, ap->a_dvp);
689 
690 	error = VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
691 
692 	POP(xdvp, ap->a_dvp);
693 
694 	return (error);
695 }
696 
697 lofs_inactive (ap)
698 	struct vop_inactive_args *ap;
699 {
700 	USES_VOP_INACTIVE;
701 	struct vnode *targetvp = LOFSVP(ap->a_vp);
702 #ifdef LOFS_DIAGNOSTIC
703 	printf("lofs_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
704 #endif
705 
706 #ifdef DIAGNOSTIC
707 	{ extern int prtactive;
708 	if (prtactive && ap->a_vp->v_usecount != 0)
709 		vprint("lofs_inactive: pushing active", ap->a_vp);
710 	}
711 #endif
712 
713 	if (targetvp) {
714 		vrele(targetvp);
715 		LOFSP(ap->a_vp)->a_lofsvp = 0;
716 	}
717 }
718 
719 lofs_reclaim (ap)
720 	struct vop_reclaim_args *ap;
721 {
722 	USES_VOP_RECLAIM;
723 	struct vnode *targetvp;
724 #ifdef LOFS_DIAGNOSTIC
725 	printf("lofs_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
726 #endif
727 	remque(LOFSP(ap->a_vp));
728 	targetvp = LOFSVP(ap->a_vp);
729 	if (targetvp) {
730 		printf("lofs: delayed vrele of %x\n", targetvp);
731 		vrele(targetvp);	/* XXX should never happen */
732 	}
733 	FREE(ap->a_vp->v_data, M_TEMP);
734 	ap->a_vp->v_data = 0;
735 	return (0);
736 }
737 
738 lofs_lock (ap)
739 	struct vop_lock_args *ap;
740 {
741 	USES_VOP_LOCK;
742 	int error;
743 	struct vnode *targetvp = LOFSVP(ap->a_vp);
744 
745 #ifdef LOFS_DIAGNOSTIC
746 	printf("lofs_lock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
747 	/*vprint("lofs_lock ap->a_vp", ap->a_vp);
748 	if (targetvp)
749 		vprint("lofs_lock ->ap->a_vp", targetvp);
750 	else
751 		printf("lofs_lock ->ap->a_vp = NIL\n");*/
752 #endif
753 
754 	if (targetvp) {
755 		error = VOP_LOCK(targetvp);
756 		if (error)
757 			return (error);
758 	}
759 
760 	return (0);
761 }
762 
763 lofs_unlock (ap)
764 	struct vop_unlock_args *ap;
765 {
766 	USES_VOP_UNLOCK;
767 	struct vnode *targetvp = LOFSVP(ap->a_vp);
768 
769 #ifdef LOFS_DIAGNOSTIC
770 	printf("lofs_unlock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
771 #endif
772 
773 	if (targetvp)
774 		return (VOP_UNLOCK(targetvp));
775 	return (0);
776 }
777 
778 lofs_bmap (ap)
779 	struct vop_bmap_args *ap;
780 {
781 	USES_VOP_BMAP;
782 #ifdef LOFS_DIAGNOSTIC
783 	printf("lofs_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, LOFSVP(ap->a_vp));
784 #endif
785 
786 	return VOP_BMAP(LOFSVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
787 }
788 
789 lofs_strategy (ap)
790 	struct vop_strategy_args *ap;
791 {
792 	USES_VOP_STRATEGY;
793 	int error;
794 
795 #ifdef LOFS_DIAGNOSTIC
796 	printf("lofs_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, LOFSVP(ap->a_bp->b_vp));
797 #endif
798 
799 	PUSHREF(vp, ap->a_bp->b_vp);
800 
801 	error = VOP_STRATEGY(ap->a_bp);
802 
803 	POP(vp, ap->a_bp->b_vp);
804 
805 	return (error);
806 }
807 
808 lofs_print (ap)
809 	struct vop_print_args *ap;
810 {
811 	USES_VOP_PRINT;
812 	struct vnode *targetvp = LOFSVP(ap->a_vp);
813 	printf("tag VT_LOFS ref ");
814 	if (targetvp)
815 		return (VOP_PRINT(targetvp));
816 	printf("NULLVP\n");
817 	return (0);
818 }
819 
820 lofs_islocked (ap)
821 	struct vop_islocked_args *ap;
822 {
823 	USES_VOP_ISLOCKED;
824 	struct vnode *targetvp = LOFSVP(ap->a_vp);
825 	if (targetvp)
826 		return (VOP_ISLOCKED(targetvp));
827 	return (0);
828 }
829 
830 lofs_advlock (ap)
831 	struct vop_advlock_args *ap;
832 {
833 	USES_VOP_ADVLOCK;
834 	return VOP_ADVLOCK(LOFSVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
835 }
836 
837 /*
838  * LOFS directory offset lookup.
839  * Currently unsupported.
840  */
841 lofs_blkatoff (ap)
842 	struct vop_blkatoff_args *ap;
843 {
844 
845 	return (EOPNOTSUPP);
846 }
847 
848 /*
849  * LOFS flat namespace lookup.
850  * Currently unsupported.
851  */
852 lofs_vget (ap)
853 	struct vop_vget_args *ap;
854 {
855 
856 	return (EOPNOTSUPP);
857 }
858 
859 /*
860  * LOFS flat namespace allocation.
861  * Currently unsupported.
862  */
863 lofs_valloc (ap)
864 	struct vop_valloc_args *ap;
865 {
866 
867 	return (EOPNOTSUPP);
868 }
869 
870 /*
871  * LOFS flat namespace free.
872  * Currently unsupported.
873  */
874 /*void*/
875 lofs_vfree (ap)
876 	struct vop_vfree_args *ap;
877 {
878 
879 	return;
880 }
881 
882 /*
883  * LOFS file truncation.
884  */
885 lofs_truncate (ap)
886 	struct vop_truncate_args *ap;
887 {
888 
889 	/* Use lofs_setattr */
890 	printf("lofs_truncate: need to implement!!");
891 	return (EOPNOTSUPP);
892 }
893 
894 /*
895  * LOFS update.
896  */
897 lofs_update (ap)
898 	struct vop_update_args *ap;
899 {
900 
901 	/* Use lofs_setattr */
902 	printf("lofs_update: need to implement!!");
903 	return (EOPNOTSUPP);
904 }
905 
906 /*
907  * LOFS bwrite
908  */
909 lofs_bwrite (ap)
910 	struct vop_bwrite_args *ap;
911 {
912 	return (EOPNOTSUPP);
913 }
914 
915 /*
916  * Global vfs data structures for ufs
917  */
918 int (**lofs_vnodeop_p)();
919 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
920 	{ &vop_default_desc, vn_default_error },
921 	{ &vop_lookup_desc, lofs_lookup },		/* lookup */
922 	{ &vop_create_desc, lofs_create },		/* create */
923 	{ &vop_mknod_desc, lofs_mknod },		/* mknod */
924 	{ &vop_open_desc, lofs_open },		/* open */
925 	{ &vop_close_desc, lofs_close },		/* close */
926 	{ &vop_access_desc, lofs_access },		/* access */
927 	{ &vop_getattr_desc, lofs_getattr },		/* getattr */
928 	{ &vop_setattr_desc, lofs_setattr },		/* setattr */
929 	{ &vop_read_desc, lofs_read },		/* read */
930 	{ &vop_write_desc, lofs_write },		/* write */
931 	{ &vop_ioctl_desc, lofs_ioctl },		/* ioctl */
932 	{ &vop_select_desc, lofs_select },		/* select */
933 	{ &vop_mmap_desc, lofs_mmap },		/* mmap */
934 	{ &vop_fsync_desc, lofs_fsync },		/* fsync */
935 	{ &vop_seek_desc, lofs_seek },		/* seek */
936 	{ &vop_remove_desc, lofs_remove },		/* remove */
937 	{ &vop_link_desc, lofs_link },		/* link */
938 	{ &vop_rename_desc, lofs_rename },		/* rename */
939 	{ &vop_mkdir_desc, lofs_mkdir },		/* mkdir */
940 	{ &vop_rmdir_desc, lofs_rmdir },		/* rmdir */
941 	{ &vop_symlink_desc, lofs_symlink },		/* symlink */
942 	{ &vop_readdir_desc, lofs_readdir },		/* readdir */
943 	{ &vop_readlink_desc, lofs_readlink },		/* readlink */
944 	{ &vop_abortop_desc, lofs_abortop },		/* abortop */
945 	{ &vop_inactive_desc, lofs_inactive },		/* inactive */
946 	{ &vop_reclaim_desc, lofs_reclaim },		/* reclaim */
947 	{ &vop_lock_desc, lofs_lock },		/* lock */
948 	{ &vop_unlock_desc, lofs_unlock },		/* unlock */
949 	{ &vop_bmap_desc, lofs_bmap },		/* bmap */
950 	{ &vop_strategy_desc, lofs_strategy },		/* strategy */
951 	{ &vop_print_desc, lofs_print },		/* print */
952 	{ &vop_islocked_desc, lofs_islocked },		/* islocked */
953 	{ &vop_advlock_desc, lofs_advlock },		/* advlock */
954 	{ &vop_blkatoff_desc, lofs_blkatoff },		/* blkatoff */
955 	{ &vop_vget_desc, lofs_vget },		/* vget */
956 	{ &vop_valloc_desc, lofs_valloc },		/* valloc */
957 	{ &vop_vfree_desc, lofs_vfree },		/* vfree */
958 	{ &vop_truncate_desc, lofs_truncate },		/* truncate */
959 	{ &vop_update_desc, lofs_update },		/* update */
960 	{ &vop_bwrite_desc, lofs_bwrite },		/* bwrite */
961 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
962 };
963 struct vnodeopv_desc lofs_vnodeop_opv_desc =
964 	{ &lofs_vnodeop_p, lofs_vnodeop_entries };
965