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