xref: /csrg-svn/sys/miscfs/nullfs/null_vnops.c (revision 54754)
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) 6/18/92
12  *
13  * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
14  */
15 
16 /*
17  * Null layer 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) = NULLTOLOWERVP(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 null_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 NULLFS_DIAGNOSTIC
72 	printf("null_lookup(ap->a_dvp = %x->%x, \"%s\", op = %d)\n",
73 		dvp, NULLTOLOWERVP(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 null_lock].  all that
80 	 * must be done here is to keep track of reference counts.
81 	 */
82 	targetdvp = NULLTOLOWERVP(dvp);
83 	/*VREF(targetdvp);*/
84 #ifdef NULLFS_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 NULLFS_DIAGNOSTIC
97 		printf("null_lookup(%x->%x) = %d\n", dvp, NULLTOLOWERVP(dvp), error);
98 #endif
99 		return (error);
100 	}
101 #ifdef NULLFS_DIAGNOSTIC
102 	printf("null_lookup(%x->%x) = OK\n", dvp, NULLTOLOWERVP(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 NULLFS_DIAGNOSTIC
115 		printf("null_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_null_node(dvp->v_mount, ap->a_vpp));
122 	}
123 
124 #ifdef NULLFS_DIAGNOSTIC
125 	printf("null_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 null_mknod (ap)
137 	struct vop_mknod_args *ap;
138 {
139 	USES_VOP_MKNOD;
140 	int error;
141 
142 #ifdef NULLFS_DIAGNOSTIC
143 	printf("null_mknod(vp = %x->%x)\n", ap->a_dvp, NULLTOLOWERVP(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 null_create (ap)
163 	struct vop_create_args *ap;
164 {
165 	USES_VOP_CREATE;
166 	int error;
167 
168 #ifdef NULLFS_DIAGNOSTIC
169 	printf("null_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, NULLTOLOWERVP(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 NULLFS_DIAGNOSTIC
181 	printf("null_create(ap->a_dvp = %x->%x)\n", ap->a_dvp, NULLTOLOWERVP(ap->a_dvp));
182 #endif
183 
184 	return (error);
185 }
186 
187 null_open (ap)
188 	struct vop_open_args *ap;
189 {
190 	USES_VOP_OPEN;
191 #ifdef NULLFS_DIAGNOSTIC
192 	printf("null_open(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
193 #endif
194 
195 	return VOP_OPEN(NULLTOLOWERVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
196 }
197 
198 null_close (ap)
199 	struct vop_close_args *ap;
200 {
201 	USES_VOP_CLOSE;
202 #ifdef NULLFS_DIAGNOSTIC
203 	printf("null_close(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
204 #endif
205 
206 	return VOP_CLOSE(NULLTOLOWERVP(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p);
207 }
208 
209 null_access (ap)
210 	struct vop_access_args *ap;
211 {
212 	USES_VOP_ACCESS;
213 #ifdef NULLFS_DIAGNOSTIC
214 	printf("null_access(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
215 #endif
216 
217 	return VOP_ACCESS(NULLTOLOWERVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_p);
218 }
219 
220 null_getattr (ap)
221 	struct vop_getattr_args *ap;
222 {
223 	USES_VOP_GETATTR;
224 	int error;
225 
226 #ifdef NULLFS_DIAGNOSTIC
227 	printf("null_getattr(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
228 #endif
229 
230 	/*
231 	 * Get the stats from the underlying filesystem
232 	 */
233 	error = VOP_GETATTR(NULLTOLOWERVP(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 null_setattr (ap)
245 	struct vop_setattr_args *ap;
246 {
247 	USES_VOP_SETATTR;
248 #ifdef NULLFS_DIAGNOSTIC
249 	printf("null_setattr(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
250 #endif
251 
252 	return VOP_SETATTR(NULLTOLOWERVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_p);
253 }
254 
255 null_read (ap)
256 	struct vop_read_args *ap;
257 {
258 	USES_VOP_READ;
259 #ifdef NULLFS_DIAGNOSTIC
260 	printf("null_read(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
261 #endif
262 
263 	return VOP_READ(NULLTOLOWERVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
264 }
265 
266 null_write (ap)
267 	struct vop_write_args *ap;
268 {
269 	USES_VOP_WRITE;
270 #ifdef NULLFS_DIAGNOSTIC
271 	printf("null_write(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
272 #endif
273 
274 	return VOP_WRITE(NULLTOLOWERVP(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred);
275 }
276 
277 null_ioctl (ap)
278 	struct vop_ioctl_args *ap;
279 {
280 	USES_VOP_IOCTL;
281 #ifdef NULLFS_DIAGNOSTIC
282 	printf("null_ioctl(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
283 #endif
284 
285 	return VOP_IOCTL(NULLTOLOWERVP(ap->a_vp), ap->a_command, ap->a_data, ap->a_fflag, ap->a_cred, ap->a_p);
286 }
287 
288 null_select (ap)
289 	struct vop_select_args *ap;
290 {
291 	USES_VOP_SELECT;
292 #ifdef NULLFS_DIAGNOSTIC
293 	printf("null_select(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
294 #endif
295 
296 	return VOP_SELECT(NULLTOLOWERVP(ap->a_vp), ap->a_which, ap->a_fflags, ap->a_cred, ap->a_p);
297 }
298 
299 null_mmap (ap)
300 	struct vop_mmap_args *ap;
301 {
302 	USES_VOP_MMAP;
303 #ifdef NULLFS_DIAGNOSTIC
304 	printf("null_mmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
305 #endif
306 
307 	return VOP_MMAP(NULLTOLOWERVP(ap->a_vp), ap->a_fflags, ap->a_cred, ap->a_p);
308 }
309 
310 null_fsync (ap)
311 	struct vop_fsync_args *ap;
312 {
313 	USES_VOP_FSYNC;
314 #ifdef NULLFS_DIAGNOSTIC
315 	printf("null_fsync(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
316 #endif
317 
318 	return VOP_FSYNC(NULLTOLOWERVP(ap->a_vp), ap->a_fflags, ap->a_cred, ap->a_waitfor, ap->a_p);
319 }
320 
321 null_seek (ap)
322 	struct vop_seek_args *ap;
323 {
324 	USES_VOP_SEEK;
325 #ifdef NULLFS_DIAGNOSTIC
326 	printf("null_seek(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
327 #endif
328 
329 	return VOP_SEEK(NULLTOLOWERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred);
330 }
331 
332 null_remove (ap)
333 	struct vop_remove_args *ap;
334 {
335 	USES_VOP_REMOVE;
336 	int error;
337 
338 #ifdef NULLFS_DIAGNOSTIC
339 	printf("null_remove(ap->a_vp = %x->%x)\n", ap->a_dvp, NULLTOLOWERVP(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 null_link (ap)
363 	struct vop_link_args *ap;
364 {
365 	USES_VOP_LINK;
366 	int error;
367 
368 #ifdef NULLFS_DIAGNOSTIC
369 	printf("null_link(ap->a_tdvp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(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, NULLTOLOWERVP(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 null_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 NULLFS_DIAGNOSTIC
395 	printf("null_rename(fdvp = %x->%x)\n", ap->a_fdvp, NULLTOLOWERVP(ap->a_fdvp));
396 	/*printf("null_rename(tdvp = %x->%x)\n", tndp->ni_dvp, NULLTOLOWERVP(tndp->ni_dvp));*/
397 #endif
398 
399 #ifdef NULLFS_DIAGNOSTIC
400 	printf("null_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 NULLFS_DIAGNOSTIC
409 	printf("null_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 == null_vnodeop_p) {
416 		ap->a_fvp = NULLTOLOWERVP(fvp);
417 		VREF(ap->a_fvp);
418 	} else {
419 		fvp = 0;
420 	}
421 
422 #if 0
423 #ifdef NULLFS_DIAGNOSTIC
424 	printf("null_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 == null_vnodeop_p) {
431 		fndp->ni_startdir = NULLTOLOWERVP(fsvp);
432 		VREF(fndp->ni_startdir);
433 	} else {
434 		fsvp = 0;
435 	}
436 #endif
437 
438 #ifdef NULLFS_DIAGNOSTIC
439 	printf("null_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 == null_vnodeop_p) {
446 		ap->a_tdvp = NULLTOLOWERVP(tdvp);
447 		VREF(ap->a_tdvp);
448 	} else {
449 		tdvp = 0;
450 	}
451 
452 #ifdef NULLFS_DIAGNOSTIC
453 	printf("null_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 == null_vnodeop_p) {
460 		ap->a_tvp = NULLTOLOWERVP(tvp);
461 		VREF(ap->a_tvp);
462 	} else {
463 		tvp = 0;
464 	}
465 
466 #if 0
467 #ifdef NULLFS_DIAGNOSTIC
468 	printf("null_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 == null_vnodeop_p) {
475 		tndp->ni_startdir = NULLTOLOWERVP(fsvp);
476 		VREF(tndp->ni_startdir);
477 	} else {
478 		tsvp = 0;
479 	}
480 #endif
481 
482 #ifdef NULLFS_DIAGNOSTIC
483 	printf("null_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 NULLFS_DIAGNOSTIC
500 	printf("null_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 NULLFS_DIAGNOSTIC
511 	printf("null_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 NULLFS_DIAGNOSTIC
520 	printf("null_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 NULLFS_DIAGNOSTIC
530 	printf("null_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 NULLFS_DIAGNOSTIC
541 	printf("null_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 NULLFS_DIAGNOSTIC
551 	printf("null_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 null_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 NULLFS_DIAGNOSTIC
574 	printf("null_mkdir(vp = %x->%x)\n", dvp, NULLTOLOWERVP(dvp));
575 #endif
576 
577 	xdvp = dvp;
578 	dvp = NULLTOLOWERVP(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_null_node(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 null_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 NULLFS_DIAGNOSTIC
614 	printf("null_rmdir(dvp = %x->%x)\n", dvp, NULLTOLOWERVP(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 null_symlink (ap)
637 	struct vop_symlink_args *ap;
638 {
639 	USES_VOP_SYMLINK;
640 	int error;
641 
642 #ifdef NULLFS_DIAGNOSTIC
643 	printf("VOP_SYMLINK(vp = %x->%x)\n", ap->a_dvp, NULLTOLOWERVP(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 null_readdir (ap)
658 	struct vop_readdir_args *ap;
659 {
660 	USES_VOP_READDIR;
661 #ifdef NULLFS_DIAGNOSTIC
662 	printf("null_readdir(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
663 #endif
664 
665 	return VOP_READDIR(NULLTOLOWERVP(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflagp);
666 }
667 
668 null_readlink (ap)
669 	struct vop_readlink_args *ap;
670 {
671 	USES_VOP_READLINK;
672 #ifdef NULLFS_DIAGNOSTIC
673 	printf("null_readlink(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
674 #endif
675 
676 	return VOP_READLINK(NULLTOLOWERVP(ap->a_vp), ap->a_uio, ap->a_cred);
677 }
678 
679 /*
680  * Anyone's guess...
681  */
682 null_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 null_inactive (ap)
698 	struct vop_inactive_args *ap;
699 {
700 	USES_VOP_INACTIVE;
701 	struct vnode *targetvp = NULLTOLOWERVP(ap->a_vp);
702 #ifdef NULLFS_DIAGNOSTIC
703 	printf("null_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("null_inactive: pushing active", ap->a_vp);
710 	}
711 #endif
712 
713 	if (targetvp) {
714 		vrele(targetvp);
715 		VTONULLNODE(ap->a_vp)->null_lowervp = 0;
716 	}
717 }
718 
719 null_reclaim (ap)
720 	struct vop_reclaim_args *ap;
721 {
722 	USES_VOP_RECLAIM;
723 	struct vnode *targetvp;
724 #ifdef NULLFS_DIAGNOSTIC
725 	printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
726 #endif
727 	remque(VTONULLNODE(ap->a_vp));
728 	targetvp = NULLTOLOWERVP(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 null_lock (ap)
739 	struct vop_lock_args *ap;
740 {
741 	USES_VOP_LOCK;
742 	int error;
743 	struct vnode *targetvp = NULLTOLOWERVP(ap->a_vp);
744 
745 #ifdef NULLFS_DIAGNOSTIC
746 	printf("null_lock(ap->a_vp = %x->%x)\n", ap->a_vp, targetvp);
747 	/*vprint("null_lock ap->a_vp", ap->a_vp);
748 	if (targetvp)
749 		vprint("null_lock ->ap->a_vp", targetvp);
750 	else
751 		printf("null_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 null_unlock (ap)
764 	struct vop_unlock_args *ap;
765 {
766 	USES_VOP_UNLOCK;
767 	struct vnode *targetvp = NULLTOLOWERVP(ap->a_vp);
768 
769 #ifdef NULLFS_DIAGNOSTIC
770 	printf("null_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 null_bmap (ap)
779 	struct vop_bmap_args *ap;
780 {
781 	USES_VOP_BMAP;
782 #ifdef NULLFS_DIAGNOSTIC
783 	printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp));
784 #endif
785 
786 	return VOP_BMAP(NULLTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
787 }
788 
789 null_strategy (ap)
790 	struct vop_strategy_args *ap;
791 {
792 	USES_VOP_STRATEGY;
793 	int error;
794 
795 #ifdef NULLFS_DIAGNOSTIC
796 	printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLTOLOWERVP(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 null_print (ap)
809 	struct vop_print_args *ap;
810 {
811 	USES_VOP_PRINT;
812 	struct vnode *targetvp = NULLTOLOWERVP(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 null_islocked (ap)
821 	struct vop_islocked_args *ap;
822 {
823 	USES_VOP_ISLOCKED;
824 	struct vnode *targetvp = NULLTOLOWERVP(ap->a_vp);
825 	if (targetvp)
826 		return (VOP_ISLOCKED(targetvp));
827 	return (0);
828 }
829 
830 null_advlock (ap)
831 	struct vop_advlock_args *ap;
832 {
833 	USES_VOP_ADVLOCK;
834 	return VOP_ADVLOCK(NULLTOLOWERVP(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 null_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 null_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 null_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 null_vfree (ap)
876 	struct vop_vfree_args *ap;
877 {
878 
879 	return;
880 }
881 
882 /*
883  * LOFS file truncation.
884  */
885 null_truncate (ap)
886 	struct vop_truncate_args *ap;
887 {
888 
889 	/* Use null_setattr */
890 	printf("null_truncate: need to implement!!");
891 	return (EOPNOTSUPP);
892 }
893 
894 /*
895  * LOFS update.
896  */
897 null_update (ap)
898 	struct vop_update_args *ap;
899 {
900 
901 	/* Use null_setattr */
902 	printf("null_update: need to implement!!");
903 	return (EOPNOTSUPP);
904 }
905 
906 /*
907  * LOFS bwrite
908  */
909 null_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 (**null_vnodeop_p)();
919 struct vnodeopv_entry_desc lofs_vnodeop_entries[] = {
920 	{ &vop_default_desc, vn_default_error },
921 	{ &vop_lookup_desc, null_lookup },		/* lookup */
922 	{ &vop_create_desc, null_create },		/* create */
923 	{ &vop_mknod_desc, null_mknod },		/* mknod */
924 	{ &vop_open_desc, null_open },		/* open */
925 	{ &vop_close_desc, null_close },		/* close */
926 	{ &vop_access_desc, null_access },		/* access */
927 	{ &vop_getattr_desc, null_getattr },		/* getattr */
928 	{ &vop_setattr_desc, null_setattr },		/* setattr */
929 	{ &vop_read_desc, null_read },		/* read */
930 	{ &vop_write_desc, null_write },		/* write */
931 	{ &vop_ioctl_desc, null_ioctl },		/* ioctl */
932 	{ &vop_select_desc, null_select },		/* select */
933 	{ &vop_mmap_desc, null_mmap },		/* mmap */
934 	{ &vop_fsync_desc, null_fsync },		/* fsync */
935 	{ &vop_seek_desc, null_seek },		/* seek */
936 	{ &vop_remove_desc, null_remove },		/* remove */
937 	{ &vop_link_desc, null_link },		/* link */
938 	{ &vop_rename_desc, null_rename },		/* rename */
939 	{ &vop_mkdir_desc, null_mkdir },		/* mkdir */
940 	{ &vop_rmdir_desc, null_rmdir },		/* rmdir */
941 	{ &vop_symlink_desc, null_symlink },		/* symlink */
942 	{ &vop_readdir_desc, null_readdir },		/* readdir */
943 	{ &vop_readlink_desc, null_readlink },		/* readlink */
944 	{ &vop_abortop_desc, null_abortop },		/* abortop */
945 	{ &vop_inactive_desc, null_inactive },		/* inactive */
946 	{ &vop_reclaim_desc, null_reclaim },		/* reclaim */
947 	{ &vop_lock_desc, null_lock },		/* lock */
948 	{ &vop_unlock_desc, null_unlock },		/* unlock */
949 	{ &vop_bmap_desc, null_bmap },		/* bmap */
950 	{ &vop_strategy_desc, null_strategy },		/* strategy */
951 	{ &vop_print_desc, null_print },		/* print */
952 	{ &vop_islocked_desc, null_islocked },		/* islocked */
953 	{ &vop_advlock_desc, null_advlock },		/* advlock */
954 	{ &vop_blkatoff_desc, null_blkatoff },		/* blkatoff */
955 	{ &vop_vget_desc, null_vget },		/* vget */
956 	{ &vop_valloc_desc, null_valloc },		/* valloc */
957 	{ &vop_vfree_desc, null_vfree },		/* vfree */
958 	{ &vop_truncate_desc, null_truncate },		/* truncate */
959 	{ &vop_update_desc, null_update },		/* update */
960 	{ &vop_bwrite_desc, null_bwrite },		/* bwrite */
961 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
962 };
963 struct vnodeopv_desc lofs_vnodeop_opv_desc =
964 	{ &null_vnodeop_p, lofs_vnodeop_entries };
965