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