xref: /freebsd/sys/fs/unionfs/union_vnops.c (revision 952d112864d8008aa87278a30a539d888a8493cd)
1 /*
2  * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
3  * Copyright (c) 1992, 1993, 1994, 1995
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)union_vnops.c	8.32 (Berkeley) 6/23/95
38  * $Id: union_vnops.c,v 1.19 1997/02/22 09:40:42 peter Exp $
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/fcntl.h>
45 #include <sys/time.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <sys/kernel.h>
49 #include <sys/vnode.h>
50 #include <sys/mount.h>
51 #include <sys/namei.h>
52 #include <sys/malloc.h>
53 #include <sys/buf.h>
54 #include <sys/queue.h>
55 #include <sys/lock.h>
56 #include <miscfs/union/union.h>
57 
58 #define FIXUP(un, p) { \
59 	if (((un)->un_flags & UN_ULOCK) == 0) { \
60 		union_fixup(un, p); \
61 	} \
62 }
63 
64 extern int	union_abortop __P((struct vop_abortop_args *ap));
65 extern int	union_access __P((struct vop_access_args *ap));
66 extern int	union_advlock __P((struct vop_advlock_args *ap));
67 extern int	union_bmap __P((struct vop_bmap_args *ap));
68 extern int	union_close __P((struct vop_close_args *ap));
69 extern int	union_create __P((struct vop_create_args *ap));
70 static void	union_fixup __P((struct union_node *un, struct proc *p));
71 extern int	union_fsync __P((struct vop_fsync_args *ap));
72 extern int	union_getattr __P((struct vop_getattr_args *ap));
73 extern int	union_inactive __P((struct vop_inactive_args *ap));
74 extern int	union_ioctl __P((struct vop_ioctl_args *ap));
75 extern int	union_islocked __P((struct vop_islocked_args *ap));
76 extern int	union_lease __P((struct vop_lease_args *ap));
77 extern int	union_link __P((struct vop_link_args *ap));
78 extern int	union_lock __P((struct vop_lock_args *ap));
79 extern int	union_lookup __P((struct vop_lookup_args *ap));
80 static int	union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp,
81 				   struct vnode **vpp,
82 				   struct componentname *cnp));
83 extern int	union_mkdir __P((struct vop_mkdir_args *ap));
84 extern int	union_mknod __P((struct vop_mknod_args *ap));
85 extern int	union_mmap __P((struct vop_mmap_args *ap));
86 extern int	union_open __P((struct vop_open_args *ap));
87 extern int	union_pathconf __P((struct vop_pathconf_args *ap));
88 extern int	union_print __P((struct vop_print_args *ap));
89 extern int	union_read __P((struct vop_read_args *ap));
90 extern int	union_readdir __P((struct vop_readdir_args *ap));
91 extern int	union_readlink __P((struct vop_readlink_args *ap));
92 extern int	union_reclaim __P((struct vop_reclaim_args *ap));
93 extern int	union_remove __P((struct vop_remove_args *ap));
94 extern int	union_rename __P((struct vop_rename_args *ap));
95 extern int	union_revoke __P((struct vop_revoke_args *ap));
96 extern int	union_rmdir __P((struct vop_rmdir_args *ap));
97 extern int	union_seek __P((struct vop_seek_args *ap));
98 extern int	union_select __P((struct vop_select_args *ap));
99 extern int	union_setattr __P((struct vop_setattr_args *ap));
100 extern int	union_strategy __P((struct vop_strategy_args *ap));
101 extern int	union_symlink __P((struct vop_symlink_args *ap));
102 extern int	union_unlock __P((struct vop_unlock_args *ap));
103 extern int	union_whiteout __P((struct vop_whiteout_args *ap));
104 extern int	union_write __P((struct vop_read_args *ap));
105 
106 static void
107 union_fixup(un, p)
108 	struct union_node *un;
109 	struct proc *p;
110 {
111 
112 	vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
113 	un->un_flags |= UN_ULOCK;
114 }
115 
116 static int
117 union_lookup1(udvp, dvpp, vpp, cnp)
118 	struct vnode *udvp;
119 	struct vnode **dvpp;
120 	struct vnode **vpp;
121 	struct componentname *cnp;
122 {
123 	int error;
124 	struct proc *p = cnp->cn_proc;
125 	struct vnode *tdvp;
126 	struct vnode *dvp;
127 	struct mount *mp;
128 
129 	dvp = *dvpp;
130 
131 	/*
132 	 * If stepping up the directory tree, check for going
133 	 * back across the mount point, in which case do what
134 	 * lookup would do by stepping back down the mount
135 	 * hierarchy.
136 	 */
137 	if (cnp->cn_flags & ISDOTDOT) {
138 		while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
139 			/*
140 			 * Don't do the NOCROSSMOUNT check
141 			 * at this level.  By definition,
142 			 * union fs deals with namespaces, not
143 			 * filesystems.
144 			 */
145 			tdvp = dvp;
146 			*dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
147 			vput(tdvp);
148 			VREF(dvp);
149 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
150 		}
151 	}
152 
153         error = VOP_LOOKUP(dvp, &tdvp, cnp);
154 	if (error)
155 		return (error);
156 
157 	/*
158 	 * The parent directory will have been unlocked, unless lookup
159 	 * found the last component.  In which case, re-lock the node
160 	 * here to allow it to be unlocked again (phew) in union_lookup.
161 	 */
162 	if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
163 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
164 
165 	dvp = tdvp;
166 
167 	/*
168 	 * Lastly check if the current node is a mount point in
169 	 * which case walk up the mount hierarchy making sure not to
170 	 * bump into the root of the mount tree (ie. dvp != udvp).
171 	 */
172 	while (dvp != udvp && (dvp->v_type == VDIR) &&
173 	       (mp = dvp->v_mountedhere)) {
174 
175 		if (vfs_busy(mp, 0, 0, p))
176 			continue;
177 
178 		error = VFS_ROOT(mp, &tdvp);
179 		vfs_unbusy(mp, p);
180 		if (error) {
181 			vput(dvp);
182 			return (error);
183 		}
184 
185 		vput(dvp);
186 		dvp = tdvp;
187 	}
188 
189 	*vpp = dvp;
190 	return (0);
191 }
192 
193 int
194 union_lookup(ap)
195 	struct vop_lookup_args /* {
196 		struct vnodeop_desc *a_desc;
197 		struct vnode *a_dvp;
198 		struct vnode **a_vpp;
199 		struct componentname *a_cnp;
200 	} */ *ap;
201 {
202 	int error;
203 	int uerror, lerror;
204 	struct vnode *uppervp, *lowervp;
205 	struct vnode *upperdvp, *lowerdvp;
206 	struct vnode *dvp = ap->a_dvp;
207 	struct union_node *dun = VTOUNION(dvp);
208 	struct componentname *cnp = ap->a_cnp;
209 	struct proc *p = cnp->cn_proc;
210 	int lockparent = cnp->cn_flags & LOCKPARENT;
211 	struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
212 	struct ucred *saved_cred;
213 	int iswhiteout;
214 	struct vattr va;
215 
216 #ifdef notyet
217 	if (cnp->cn_namelen == 3 &&
218 			cnp->cn_nameptr[2] == '.' &&
219 			cnp->cn_nameptr[1] == '.' &&
220 			cnp->cn_nameptr[0] == '.') {
221 		dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
222 		if (dvp == NULLVP)
223 			return (ENOENT);
224 		VREF(dvp);
225 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
226 		if (!lockparent || !(cnp->cn_flags & ISLASTCN))
227 			VOP_UNLOCK(ap->a_dvp, 0, p);
228 		return (0);
229 	}
230 #endif
231 
232 	cnp->cn_flags |= LOCKPARENT;
233 
234 	upperdvp = dun->un_uppervp;
235 	lowerdvp = dun->un_lowervp;
236 	uppervp = NULLVP;
237 	lowervp = NULLVP;
238 	iswhiteout = 0;
239 
240 	/*
241 	 * do the lookup in the upper level.
242 	 * if that level comsumes additional pathnames,
243 	 * then assume that something special is going
244 	 * on and just return that vnode.
245 	 */
246 	if (upperdvp != NULLVP) {
247 		FIXUP(dun, p);
248 		uerror = union_lookup1(um->um_uppervp, &upperdvp,
249 					&uppervp, cnp);
250 		/*if (uppervp == upperdvp)
251 			dun->un_flags |= UN_KLOCK;*/
252 
253 		if (cnp->cn_consume != 0) {
254 			*ap->a_vpp = uppervp;
255 			if (!lockparent)
256 				cnp->cn_flags &= ~LOCKPARENT;
257 			return (uerror);
258 		}
259 		if (uerror == ENOENT || uerror == EJUSTRETURN) {
260 			if (cnp->cn_flags & ISWHITEOUT) {
261 				iswhiteout = 1;
262 			} else if (lowerdvp != NULLVP) {
263 				lerror = VOP_GETATTR(upperdvp, &va,
264 					cnp->cn_cred, cnp->cn_proc);
265 				if (lerror == 0 && (va.va_flags & OPAQUE))
266 					iswhiteout = 1;
267 			}
268 		}
269 	} else {
270 		uerror = ENOENT;
271 	}
272 
273 	/*
274 	 * in a similar way to the upper layer, do the lookup
275 	 * in the lower layer.   this time, if there is some
276 	 * component magic going on, then vput whatever we got
277 	 * back from the upper layer and return the lower vnode
278 	 * instead.
279 	 */
280 	if (lowerdvp != NULLVP && !iswhiteout) {
281 		int nameiop;
282 
283 		vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p);
284 
285 		/*
286 		 * Only do a LOOKUP on the bottom node, since
287 		 * we won't be making changes to it anyway.
288 		 */
289 		nameiop = cnp->cn_nameiop;
290 		cnp->cn_nameiop = LOOKUP;
291 		if (um->um_op == UNMNT_BELOW) {
292 			saved_cred = cnp->cn_cred;
293 			cnp->cn_cred = um->um_cred;
294 		}
295 		lerror = union_lookup1(um->um_lowervp, &lowerdvp,
296 				&lowervp, cnp);
297 		if (um->um_op == UNMNT_BELOW)
298 			cnp->cn_cred = saved_cred;
299 		cnp->cn_nameiop = nameiop;
300 
301 		if (lowervp != lowerdvp)
302 			VOP_UNLOCK(lowerdvp, 0, p);
303 
304 		if (cnp->cn_consume != 0) {
305 			if (uppervp != NULLVP) {
306 				if (uppervp == upperdvp)
307 					vrele(uppervp);
308 				else
309 					vput(uppervp);
310 				uppervp = NULLVP;
311 			}
312 			*ap->a_vpp = lowervp;
313 			if (!lockparent)
314 				cnp->cn_flags &= ~LOCKPARENT;
315 			return (lerror);
316 		}
317 	} else {
318 		lerror = ENOENT;
319 		if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
320 			lowervp = LOWERVP(dun->un_pvp);
321 			if (lowervp != NULLVP) {
322 				VREF(lowervp);
323 				vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p);
324 				lerror = 0;
325 			}
326 		}
327 	}
328 
329 	if (!lockparent)
330 		cnp->cn_flags &= ~LOCKPARENT;
331 
332 	/*
333 	 * at this point, we have uerror and lerror indicating
334 	 * possible errors with the lookups in the upper and lower
335 	 * layers.  additionally, uppervp and lowervp are (locked)
336 	 * references to existing vnodes in the upper and lower layers.
337 	 *
338 	 * there are now three cases to consider.
339 	 * 1. if both layers returned an error, then return whatever
340 	 *    error the upper layer generated.
341 	 *
342 	 * 2. if the top layer failed and the bottom layer succeeded
343 	 *    then two subcases occur.
344 	 *    a.  the bottom vnode is not a directory, in which
345 	 *	  case just return a new union vnode referencing
346 	 *	  an empty top layer and the existing bottom layer.
347 	 *    b.  the bottom vnode is a directory, in which case
348 	 *	  create a new directory in the top-level and
349 	 *	  continue as in case 3.
350 	 *
351 	 * 3. if the top layer succeeded then return a new union
352 	 *    vnode referencing whatever the new top layer and
353 	 *    whatever the bottom layer returned.
354 	 */
355 
356 	*ap->a_vpp = NULLVP;
357 
358 	/* case 1. */
359 	if ((uerror != 0) && (lerror != 0)) {
360 		return (uerror);
361 	}
362 
363 	/* case 2. */
364 	if (uerror != 0 /* && (lerror == 0) */ ) {
365 		if (lowervp->v_type == VDIR) { /* case 2b. */
366 			dun->un_flags &= ~UN_ULOCK;
367 			VOP_UNLOCK(upperdvp, 0, p);
368 			uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
369 			vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p);
370 			dun->un_flags |= UN_ULOCK;
371 
372 			if (uerror) {
373 				if (lowervp != NULLVP) {
374 					vput(lowervp);
375 					lowervp = NULLVP;
376 				}
377 				return (uerror);
378 			}
379 		}
380 	}
381 
382 	if (lowervp != NULLVP)
383 		VOP_UNLOCK(lowervp, 0, p);
384 
385 	error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
386 			      uppervp, lowervp, 1);
387 
388 	if (error) {
389 		if (uppervp != NULLVP)
390 			vput(uppervp);
391 		if (lowervp != NULLVP)
392 			vrele(lowervp);
393 	} else {
394 		if (*ap->a_vpp != dvp)
395 			if (!lockparent || !(cnp->cn_flags & ISLASTCN))
396 				VOP_UNLOCK(dvp, 0, p);
397 	}
398 
399 	return (error);
400 }
401 
402 int
403 union_create(ap)
404 	struct vop_create_args /* {
405 		struct vnode *a_dvp;
406 		struct vnode **a_vpp;
407 		struct componentname *a_cnp;
408 		struct vattr *a_vap;
409 	} */ *ap;
410 {
411 	struct union_node *un = VTOUNION(ap->a_dvp);
412 	struct vnode *dvp = un->un_uppervp;
413 	struct componentname *cnp = ap->a_cnp;
414 	struct proc *p = cnp->cn_proc;
415 
416 	if (dvp != NULLVP) {
417 		int error;
418 		struct vnode *vp;
419 		struct mount *mp;
420 
421 		FIXUP(un, p);
422 
423 		VREF(dvp);
424 		un->un_flags |= UN_KLOCK;
425 		mp = ap->a_dvp->v_mount;
426 		vput(ap->a_dvp);
427 		error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
428 		if (error)
429 			return (error);
430 
431 		error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
432 				NULLVP, 1);
433 		if (error)
434 			vput(vp);
435 		return (error);
436 	}
437 
438 	vput(ap->a_dvp);
439 	return (EROFS);
440 }
441 
442 int
443 union_whiteout(ap)
444 	struct vop_whiteout_args /* {
445 		struct vnode *a_dvp;
446 		struct componentname *a_cnp;
447 		int a_flags;
448 	} */ *ap;
449 {
450 	struct union_node *un = VTOUNION(ap->a_dvp);
451 	struct componentname *cnp = ap->a_cnp;
452 	struct proc *p = cnp->cn_proc;
453 
454 	if (un->un_uppervp == NULLVP)
455 		return (EOPNOTSUPP);
456 
457 	FIXUP(un, p);
458 	return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags));
459 }
460 
461 int
462 union_mknod(ap)
463 	struct vop_mknod_args /* {
464 		struct vnode *a_dvp;
465 		struct vnode **a_vpp;
466 		struct componentname *a_cnp;
467 		struct vattr *a_vap;
468 	} */ *ap;
469 {
470 	struct union_node *un = VTOUNION(ap->a_dvp);
471 	struct vnode *dvp = un->un_uppervp;
472 	struct componentname *cnp = ap->a_cnp;
473 	struct proc *p = cnp->cn_proc;
474 
475 	if (dvp != NULLVP) {
476 		int error;
477 		struct vnode *vp;
478 		struct mount *mp;
479 
480 		FIXUP(un, p);
481 
482 		VREF(dvp);
483 		un->un_flags |= UN_KLOCK;
484 		mp = ap->a_dvp->v_mount;
485 		vput(ap->a_dvp);
486 		error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap);
487 		if (error)
488 			return (error);
489 
490 		if (vp != NULLVP) {
491 			error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
492 					cnp, vp, NULLVP, 1);
493 			if (error)
494 				vput(vp);
495 		}
496 		return (error);
497 	}
498 
499 	vput(ap->a_dvp);
500 	return (EROFS);
501 }
502 
503 int
504 union_open(ap)
505 	struct vop_open_args /* {
506 		struct vnodeop_desc *a_desc;
507 		struct vnode *a_vp;
508 		int a_mode;
509 		struct ucred *a_cred;
510 		struct proc *a_p;
511 	} */ *ap;
512 {
513 	struct union_node *un = VTOUNION(ap->a_vp);
514 	struct vnode *tvp;
515 	int mode = ap->a_mode;
516 	struct ucred *cred = ap->a_cred;
517 	struct proc *p = ap->a_p;
518 	int error;
519 
520 	/*
521 	 * If there is an existing upper vp then simply open that.
522 	 */
523 	tvp = un->un_uppervp;
524 	if (tvp == NULLVP) {
525 		/*
526 		 * If the lower vnode is being opened for writing, then
527 		 * copy the file contents to the upper vnode and open that,
528 		 * otherwise can simply open the lower vnode.
529 		 */
530 		tvp = un->un_lowervp;
531 		if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
532 			error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
533 			if (error == 0)
534 				error = VOP_OPEN(un->un_uppervp, mode, cred, p);
535 			return (error);
536 		}
537 
538 		/*
539 		 * Just open the lower vnode
540 		 */
541 		un->un_openl++;
542 		vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
543 		error = VOP_OPEN(tvp, mode, cred, p);
544 		VOP_UNLOCK(tvp, 0, p);
545 
546 		return (error);
547 	}
548 
549 	FIXUP(un, p);
550 
551 	error = VOP_OPEN(tvp, mode, cred, p);
552 
553 	return (error);
554 }
555 
556 int
557 union_close(ap)
558 	struct vop_close_args /* {
559 		struct vnode *a_vp;
560 		int  a_fflag;
561 		struct ucred *a_cred;
562 		struct proc *a_p;
563 	} */ *ap;
564 {
565 	struct union_node *un = VTOUNION(ap->a_vp);
566 	struct vnode *vp;
567 
568 	if ((vp = un->un_uppervp) == NULLVP) {
569 #ifdef UNION_DIAGNOSTIC
570 		if (un->un_openl <= 0)
571 			panic("union: un_openl cnt");
572 #endif
573 		--un->un_openl;
574 		vp = un->un_lowervp;
575 	}
576 
577 	ap->a_vp = vp;
578 	return (VCALL(vp, VOFFSET(vop_close), ap));
579 }
580 
581 /*
582  * Check access permission on the union vnode.
583  * The access check being enforced is to check
584  * against both the underlying vnode, and any
585  * copied vnode.  This ensures that no additional
586  * file permissions are given away simply because
587  * the user caused an implicit file copy.
588  */
589 int
590 union_access(ap)
591 	struct vop_access_args /* {
592 		struct vnodeop_desc *a_desc;
593 		struct vnode *a_vp;
594 		int a_mode;
595 		struct ucred *a_cred;
596 		struct proc *a_p;
597 	} */ *ap;
598 {
599 	struct union_node *un = VTOUNION(ap->a_vp);
600 	struct proc *p = ap->a_p;
601 	int error = EACCES;
602 	struct vnode *vp;
603 
604 	if ((vp = un->un_uppervp) != NULLVP) {
605 		FIXUP(un, p);
606 		ap->a_vp = vp;
607 		return (VCALL(vp, VOFFSET(vop_access), ap));
608 	}
609 
610 	if ((vp = un->un_lowervp) != NULLVP) {
611 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
612 		ap->a_vp = vp;
613 		error = VCALL(vp, VOFFSET(vop_access), ap);
614 		if (error == 0) {
615 			struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
616 
617 			if (um->um_op == UNMNT_BELOW) {
618 				ap->a_cred = um->um_cred;
619 				error = VCALL(vp, VOFFSET(vop_access), ap);
620 			}
621 		}
622 		VOP_UNLOCK(vp, 0, p);
623 		if (error)
624 			return (error);
625 	}
626 
627 	return (error);
628 }
629 
630 /*
631  * We handle getattr only to change the fsid and
632  * track object sizes
633  */
634 int
635 union_getattr(ap)
636 	struct vop_getattr_args /* {
637 		struct vnode *a_vp;
638 		struct vattr *a_vap;
639 		struct ucred *a_cred;
640 		struct proc *a_p;
641 	} */ *ap;
642 {
643 	int error;
644 	struct union_node *un = VTOUNION(ap->a_vp);
645 	struct vnode *vp = un->un_uppervp;
646 	struct proc *p = ap->a_p;
647 	struct vattr *vap;
648 	struct vattr va;
649 
650 
651 	/*
652 	 * Some programs walk the filesystem hierarchy by counting
653 	 * links to directories to avoid stat'ing all the time.
654 	 * This means the link count on directories needs to be "correct".
655 	 * The only way to do that is to call getattr on both layers
656 	 * and fix up the link count.  The link count will not necessarily
657 	 * be accurate but will be large enough to defeat the tree walkers.
658 	 */
659 
660 	vap = ap->a_vap;
661 
662 	vp = un->un_uppervp;
663 	if (vp != NULLVP) {
664 		/*
665 		 * It's not clear whether VOP_GETATTR is to be
666 		 * called with the vnode locked or not.  stat() calls
667 		 * it with (vp) locked, and fstat calls it with
668 		 * (vp) unlocked.
669 		 * In the mean time, compensate here by checking
670 		 * the union_node's lock flag.
671 		 */
672 		if (un->un_flags & UN_LOCKED)
673 			FIXUP(un, p);
674 
675 		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
676 		if (error)
677 			return (error);
678 		union_newsize(ap->a_vp, vap->va_size, VNOVAL);
679 	}
680 
681 	if (vp == NULLVP) {
682 		vp = un->un_lowervp;
683 	} else if (vp->v_type == VDIR) {
684 		vp = un->un_lowervp;
685 		vap = &va;
686 	} else {
687 		vp = NULLVP;
688 	}
689 
690 	if (vp != NULLVP) {
691 		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
692 		if (error)
693 			return (error);
694 		union_newsize(ap->a_vp, VNOVAL, vap->va_size);
695 	}
696 
697 	if ((vap != ap->a_vap) && (vap->va_type == VDIR))
698 		ap->a_vap->va_nlink += vap->va_nlink;
699 
700 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
701 	return (0);
702 }
703 
704 int
705 union_setattr(ap)
706 	struct vop_setattr_args /* {
707 		struct vnode *a_vp;
708 		struct vattr *a_vap;
709 		struct ucred *a_cred;
710 		struct proc *a_p;
711 	} */ *ap;
712 {
713 	struct union_node *un = VTOUNION(ap->a_vp);
714 	struct proc *p = ap->a_p;
715 	int error;
716 
717 	/*
718 	 * Handle case of truncating lower object to zero size,
719 	 * by creating a zero length upper object.  This is to
720 	 * handle the case of open with O_TRUNC and O_CREAT.
721 	 */
722 	if ((un->un_uppervp == NULLVP) &&
723 	    /* assert(un->un_lowervp != NULLVP) */
724 	    (un->un_lowervp->v_type == VREG)) {
725 		error = union_copyup(un, (ap->a_vap->va_size != 0),
726 						ap->a_cred, ap->a_p);
727 		if (error)
728 			return (error);
729 	}
730 
731 	/*
732 	 * Try to set attributes in upper layer,
733 	 * otherwise return read-only filesystem error.
734 	 */
735 	if (un->un_uppervp != NULLVP) {
736 		FIXUP(un, p);
737 		error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
738 					ap->a_cred, ap->a_p);
739 		if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
740 			union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
741 	} else {
742 		error = EROFS;
743 	}
744 
745 	return (error);
746 }
747 
748 int
749 union_read(ap)
750 	struct vop_read_args /* {
751 		struct vnode *a_vp;
752 		struct uio *a_uio;
753 		int  a_ioflag;
754 		struct ucred *a_cred;
755 	} */ *ap;
756 {
757 	int error;
758 	struct proc *p = ap->a_uio->uio_procp;
759 	struct vnode *vp = OTHERVP(ap->a_vp);
760 	int dolock = (vp == LOWERVP(ap->a_vp));
761 
762 	if (dolock)
763 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
764 	else
765 		FIXUP(VTOUNION(ap->a_vp), p);
766 	error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
767 	if (dolock)
768 		VOP_UNLOCK(vp, 0, p);
769 
770 	/*
771 	 * XXX
772 	 * perhaps the size of the underlying object has changed under
773 	 * our feet.  take advantage of the offset information present
774 	 * in the uio structure.
775 	 */
776 	if (error == 0) {
777 		struct union_node *un = VTOUNION(ap->a_vp);
778 		off_t cur = ap->a_uio->uio_offset;
779 
780 		if (vp == un->un_uppervp) {
781 			if (cur > un->un_uppersz)
782 				union_newsize(ap->a_vp, cur, VNOVAL);
783 		} else {
784 			if (cur > un->un_lowersz)
785 				union_newsize(ap->a_vp, VNOVAL, cur);
786 		}
787 	}
788 
789 	return (error);
790 }
791 
792 int
793 union_write(ap)
794 	struct vop_read_args /* {
795 		struct vnode *a_vp;
796 		struct uio *a_uio;
797 		int  a_ioflag;
798 		struct ucred *a_cred;
799 	} */ *ap;
800 {
801 	int error;
802 	struct vnode *vp;
803 	struct union_node *un = VTOUNION(ap->a_vp);
804 	struct proc *p = ap->a_uio->uio_procp;
805 
806 	vp = UPPERVP(ap->a_vp);
807 	if (vp == NULLVP)
808 		panic("union: missing upper layer in write");
809 
810 	FIXUP(un, p);
811 	error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
812 
813 	/*
814 	 * the size of the underlying object may be changed by the
815 	 * write.
816 	 */
817 	if (error == 0) {
818 		off_t cur = ap->a_uio->uio_offset;
819 
820 		if (cur > un->un_uppersz)
821 			union_newsize(ap->a_vp, cur, VNOVAL);
822 	}
823 
824 	return (error);
825 }
826 
827 int
828 union_lease(ap)
829 	struct vop_lease_args /* {
830 		struct vnode *a_vp;
831 		struct proc *a_p;
832 		struct ucred *a_cred;
833 		int a_flag;
834 	} */ *ap;
835 {
836 	register struct vnode *ovp = OTHERVP(ap->a_vp);
837 
838 	ap->a_vp = ovp;
839 	return (VCALL(ovp, VOFFSET(vop_lease), ap));
840 }
841 
842 int
843 union_ioctl(ap)
844 	struct vop_ioctl_args /* {
845 		struct vnode *a_vp;
846 		int  a_command;
847 		caddr_t  a_data;
848 		int  a_fflag;
849 		struct ucred *a_cred;
850 		struct proc *a_p;
851 	} */ *ap;
852 {
853 	register struct vnode *ovp = OTHERVP(ap->a_vp);
854 
855 	ap->a_vp = ovp;
856 	return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
857 }
858 
859 int
860 union_select(ap)
861 	struct vop_select_args /* {
862 		struct vnode *a_vp;
863 		int  a_which;
864 		int  a_fflags;
865 		struct ucred *a_cred;
866 		struct proc *a_p;
867 	} */ *ap;
868 {
869 	register struct vnode *ovp = OTHERVP(ap->a_vp);
870 
871 	ap->a_vp = ovp;
872 	return (VCALL(ovp, VOFFSET(vop_select), ap));
873 }
874 
875 int
876 union_revoke(ap)
877 	struct vop_revoke_args /* {
878 		struct vnode *a_vp;
879 		int a_flags;
880 		struct proc *a_p;
881 	} */ *ap;
882 {
883 	struct vnode *vp = ap->a_vp;
884 
885 	if (UPPERVP(vp))
886 		VOP_REVOKE(UPPERVP(vp), ap->a_flags);
887 	if (LOWERVP(vp))
888 		VOP_REVOKE(LOWERVP(vp), ap->a_flags);
889 	vgone(vp);
890 	return (0);
891 }
892 
893 int
894 union_mmap(ap)
895 	struct vop_mmap_args /* {
896 		struct vnode *a_vp;
897 		int  a_fflags;
898 		struct ucred *a_cred;
899 		struct proc *a_p;
900 	} */ *ap;
901 {
902 	register struct vnode *ovp = OTHERVP(ap->a_vp);
903 
904 	ap->a_vp = ovp;
905 	return (VCALL(ovp, VOFFSET(vop_mmap), ap));
906 }
907 
908 int
909 union_fsync(ap)
910 	struct vop_fsync_args /* {
911 		struct vnode *a_vp;
912 		struct ucred *a_cred;
913 		int  a_waitfor;
914 		struct proc *a_p;
915 	} */ *ap;
916 {
917 	int error = 0;
918 	struct proc *p = ap->a_p;
919 	struct vnode *targetvp = OTHERVP(ap->a_vp);
920 
921 	if (targetvp != NULLVP) {
922 		int dolock = (targetvp == LOWERVP(ap->a_vp));
923 
924 		if (dolock)
925 			vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
926 		else
927 			FIXUP(VTOUNION(ap->a_vp), p);
928 		error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p);
929 		if (dolock)
930 			VOP_UNLOCK(targetvp, 0, p);
931 	}
932 
933 	return (error);
934 }
935 
936 int
937 union_seek(ap)
938 	struct vop_seek_args /* {
939 		struct vnode *a_vp;
940 		off_t  a_oldoff;
941 		off_t  a_newoff;
942 		struct ucred *a_cred;
943 	} */ *ap;
944 {
945 	register struct vnode *ovp = OTHERVP(ap->a_vp);
946 
947 	ap->a_vp = ovp;
948 	return (VCALL(ovp, VOFFSET(vop_seek), ap));
949 }
950 
951 int
952 union_remove(ap)
953 	struct vop_remove_args /* {
954 		struct vnode *a_dvp;
955 		struct vnode *a_vp;
956 		struct componentname *a_cnp;
957 	} */ *ap;
958 {
959 	int error;
960 	struct union_node *dun = VTOUNION(ap->a_dvp);
961 	struct union_node *un = VTOUNION(ap->a_vp);
962 	struct componentname *cnp = ap->a_cnp;
963 	struct proc *p = cnp->cn_proc;
964 
965 	if (dun->un_uppervp == NULLVP)
966 		panic("union remove: null upper vnode");
967 
968 	if (un->un_uppervp != NULLVP) {
969 		struct vnode *dvp = dun->un_uppervp;
970 		struct vnode *vp = un->un_uppervp;
971 
972 		FIXUP(dun, p);
973 		VREF(dvp);
974 		dun->un_flags |= UN_KLOCK;
975 		vput(ap->a_dvp);
976 		FIXUP(un, p);
977 		VREF(vp);
978 		un->un_flags |= UN_KLOCK;
979 		vput(ap->a_vp);
980 
981 		if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
982 			cnp->cn_flags |= DOWHITEOUT;
983 		error = VOP_REMOVE(dvp, vp, cnp);
984 		if (!error)
985 			union_removed_upper(un);
986 	} else {
987 		FIXUP(dun, p);
988 		error = union_mkwhiteout(
989 			MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
990 			dun->un_uppervp, ap->a_cnp, un->un_path);
991 		vput(ap->a_dvp);
992 		vput(ap->a_vp);
993 	}
994 
995 	return (error);
996 }
997 
998 int
999 union_link(ap)
1000 	struct vop_link_args /* {
1001 		struct vnode *a_tdvp;
1002 		struct vnode *a_vp;
1003 		struct componentname *a_cnp;
1004 	} */ *ap;
1005 {
1006 	int error = 0;
1007 	struct componentname *cnp = ap->a_cnp;
1008 	struct proc *p = cnp->cn_proc;
1009 	struct union_node *un;
1010 	struct vnode *vp;
1011 	struct vnode *tdvp;
1012 
1013 	un = VTOUNION(ap->a_tdvp);
1014 
1015 	if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
1016 		vp = ap->a_vp;
1017 	} else {
1018 		struct union_node *tun = VTOUNION(ap->a_vp);
1019 		if (tun->un_uppervp == NULLVP) {
1020 			vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
1021 			if (un->un_uppervp == tun->un_dirvp) {
1022 				un->un_flags &= ~UN_ULOCK;
1023 				VOP_UNLOCK(un->un_uppervp, 0, p);
1024 			}
1025 			error = union_copyup(tun, 1, cnp->cn_cred, p);
1026 			if (un->un_uppervp == tun->un_dirvp) {
1027 				vn_lock(un->un_uppervp,
1028 						LK_EXCLUSIVE | LK_RETRY, p);
1029 				un->un_flags |= UN_ULOCK;
1030 			}
1031 			VOP_UNLOCK(ap->a_vp, 0, p);
1032 		}
1033 		vp = tun->un_uppervp;
1034 	}
1035 
1036 	tdvp = un->un_uppervp;
1037 	if (tdvp == NULLVP)
1038 		error = EROFS;
1039 
1040 	if (error) {
1041 		vput(ap->a_tdvp);
1042 		return (error);
1043 	}
1044 
1045 	FIXUP(un, p);
1046 	VREF(tdvp);
1047 	un->un_flags |= UN_KLOCK;
1048 	vput(ap->a_tdvp);
1049 
1050 	return (VOP_LINK(vp, tdvp, cnp));
1051 }
1052 
1053 int
1054 union_rename(ap)
1055 	struct vop_rename_args  /* {
1056 		struct vnode *a_fdvp;
1057 		struct vnode *a_fvp;
1058 		struct componentname *a_fcnp;
1059 		struct vnode *a_tdvp;
1060 		struct vnode *a_tvp;
1061 		struct componentname *a_tcnp;
1062 	} */ *ap;
1063 {
1064 	int error;
1065 
1066 	struct vnode *fdvp = ap->a_fdvp;
1067 	struct vnode *fvp = ap->a_fvp;
1068 	struct vnode *tdvp = ap->a_tdvp;
1069 	struct vnode *tvp = ap->a_tvp;
1070 
1071 	if (fdvp->v_op == union_vnodeop_p) {	/* always true */
1072 		struct union_node *un = VTOUNION(fdvp);
1073 		if (un->un_uppervp == NULLVP) {
1074 			/*
1075 			 * this should never happen in normal
1076 			 * operation but might if there was
1077 			 * a problem creating the top-level shadow
1078 			 * directory.
1079 			 */
1080 			error = EXDEV;
1081 			goto bad;
1082 		}
1083 
1084 		fdvp = un->un_uppervp;
1085 		VREF(fdvp);
1086 		vrele(ap->a_fdvp);
1087 	}
1088 
1089 	if (fvp->v_op == union_vnodeop_p) {	/* always true */
1090 		struct union_node *un = VTOUNION(fvp);
1091 		if (un->un_uppervp == NULLVP) {
1092 			/* XXX: should do a copyup */
1093 			error = EXDEV;
1094 			goto bad;
1095 		}
1096 
1097 		if (un->un_lowervp != NULLVP)
1098 			ap->a_fcnp->cn_flags |= DOWHITEOUT;
1099 
1100 		fvp = un->un_uppervp;
1101 		VREF(fvp);
1102 		vrele(ap->a_fvp);
1103 	}
1104 
1105 	if (tdvp->v_op == union_vnodeop_p) {
1106 		struct union_node *un = VTOUNION(tdvp);
1107 		if (un->un_uppervp == NULLVP) {
1108 			/*
1109 			 * this should never happen in normal
1110 			 * operation but might if there was
1111 			 * a problem creating the top-level shadow
1112 			 * directory.
1113 			 */
1114 			error = EXDEV;
1115 			goto bad;
1116 		}
1117 
1118 		tdvp = un->un_uppervp;
1119 		VREF(tdvp);
1120 		un->un_flags |= UN_KLOCK;
1121 		vput(ap->a_tdvp);
1122 	}
1123 
1124 	if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
1125 		struct union_node *un = VTOUNION(tvp);
1126 
1127 		tvp = un->un_uppervp;
1128 		if (tvp != NULLVP) {
1129 			VREF(tvp);
1130 			un->un_flags |= UN_KLOCK;
1131 		}
1132 		vput(ap->a_tvp);
1133 	}
1134 
1135 	return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
1136 
1137 bad:
1138 	vrele(fdvp);
1139 	vrele(fvp);
1140 	vput(tdvp);
1141 	if (tvp != NULLVP)
1142 		vput(tvp);
1143 
1144 	return (error);
1145 }
1146 
1147 int
1148 union_mkdir(ap)
1149 	struct vop_mkdir_args /* {
1150 		struct vnode *a_dvp;
1151 		struct vnode **a_vpp;
1152 		struct componentname *a_cnp;
1153 		struct vattr *a_vap;
1154 	} */ *ap;
1155 {
1156 	struct union_node *un = VTOUNION(ap->a_dvp);
1157 	struct vnode *dvp = un->un_uppervp;
1158 	struct componentname *cnp = ap->a_cnp;
1159 	struct proc *p = cnp->cn_proc;
1160 
1161 	if (dvp != NULLVP) {
1162 		int error;
1163 		struct vnode *vp;
1164 
1165 		FIXUP(un, p);
1166 		VREF(dvp);
1167 		un->un_flags |= UN_KLOCK;
1168 		VOP_UNLOCK(ap->a_dvp, 0, p);
1169 		error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap);
1170 		if (error) {
1171 			vrele(ap->a_dvp);
1172 			return (error);
1173 		}
1174 
1175 		error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
1176 				NULLVP, cnp, vp, NULLVP, 1);
1177 		vrele(ap->a_dvp);
1178 		if (error)
1179 			vput(vp);
1180 		return (error);
1181 	}
1182 
1183 	vput(ap->a_dvp);
1184 	return (EROFS);
1185 }
1186 
1187 int
1188 union_rmdir(ap)
1189 	struct vop_rmdir_args /* {
1190 		struct vnode *a_dvp;
1191 		struct vnode *a_vp;
1192 		struct componentname *a_cnp;
1193 	} */ *ap;
1194 {
1195 	int error;
1196 	struct union_node *dun = VTOUNION(ap->a_dvp);
1197 	struct union_node *un = VTOUNION(ap->a_vp);
1198 	struct componentname *cnp = ap->a_cnp;
1199 	struct proc *p = cnp->cn_proc;
1200 
1201 	if (dun->un_uppervp == NULLVP)
1202 		panic("union rmdir: null upper vnode");
1203 
1204 	if (un->un_uppervp != NULLVP) {
1205 		struct vnode *dvp = dun->un_uppervp;
1206 		struct vnode *vp = un->un_uppervp;
1207 
1208 		FIXUP(dun, p);
1209 		VREF(dvp);
1210 		dun->un_flags |= UN_KLOCK;
1211 		vput(ap->a_dvp);
1212 		FIXUP(un, p);
1213 		VREF(vp);
1214 		un->un_flags |= UN_KLOCK;
1215 		vput(ap->a_vp);
1216 
1217 		if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
1218 			cnp->cn_flags |= DOWHITEOUT;
1219 		error = VOP_RMDIR(dvp, vp, ap->a_cnp);
1220 		if (!error)
1221 			union_removed_upper(un);
1222 	} else {
1223 		FIXUP(dun, p);
1224 		error = union_mkwhiteout(
1225 			MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
1226 			dun->un_uppervp, ap->a_cnp, un->un_path);
1227 		vput(ap->a_dvp);
1228 		vput(ap->a_vp);
1229 	}
1230 
1231 	return (error);
1232 }
1233 
1234 int
1235 union_symlink(ap)
1236 	struct vop_symlink_args /* {
1237 		struct vnode *a_dvp;
1238 		struct vnode **a_vpp;
1239 		struct componentname *a_cnp;
1240 		struct vattr *a_vap;
1241 		char *a_target;
1242 	} */ *ap;
1243 {
1244 	struct union_node *un = VTOUNION(ap->a_dvp);
1245 	struct vnode *dvp = un->un_uppervp;
1246 	struct componentname *cnp = ap->a_cnp;
1247 	struct proc *p = cnp->cn_proc;
1248 
1249 	if (dvp != NULLVP) {
1250 		int error;
1251 		struct vnode *vp;
1252 
1253 		FIXUP(un, p);
1254 		VREF(dvp);
1255 		un->un_flags |= UN_KLOCK;
1256 		vput(ap->a_dvp);
1257 		error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target);
1258 		*ap->a_vpp = NULLVP;
1259 		return (error);
1260 	}
1261 
1262 	vput(ap->a_dvp);
1263 	return (EROFS);
1264 }
1265 
1266 /*
1267  * union_readdir works in concert with getdirentries and
1268  * readdir(3) to provide a list of entries in the unioned
1269  * directories.  getdirentries is responsible for walking
1270  * down the union stack.  readdir(3) is responsible for
1271  * eliminating duplicate names from the returned data stream.
1272  */
1273 int
1274 union_readdir(ap)
1275 	struct vop_readdir_args /* {
1276 		struct vnode *a_vp;
1277 		struct uio *a_uio;
1278 		struct ucred *a_cred;
1279 		int *a_eofflag;
1280 		u_long *a_cookies;
1281 		int a_ncookies;
1282 	} */ *ap;
1283 {
1284 	struct union_node *un = VTOUNION(ap->a_vp);
1285 	struct vnode *uvp = un->un_uppervp;
1286 	struct proc *p = ap->a_uio->uio_procp;
1287 
1288 	if (uvp == NULLVP)
1289 		return (0);
1290 
1291 	FIXUP(un, p);
1292 	ap->a_vp = uvp;
1293 	return (VCALL(uvp, VOFFSET(vop_readdir), ap));
1294 }
1295 
1296 int
1297 union_readlink(ap)
1298 	struct vop_readlink_args /* {
1299 		struct vnode *a_vp;
1300 		struct uio *a_uio;
1301 		struct ucred *a_cred;
1302 	} */ *ap;
1303 {
1304 	int error;
1305 	struct uio *uio = ap->a_uio;
1306 	struct proc *p = uio->uio_procp;
1307 	struct vnode *vp = OTHERVP(ap->a_vp);
1308 	int dolock = (vp == LOWERVP(ap->a_vp));
1309 
1310 	if (dolock)
1311 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1312 	else
1313 		FIXUP(VTOUNION(ap->a_vp), p);
1314 	ap->a_vp = vp;
1315 	error = VCALL(vp, VOFFSET(vop_readlink), ap);
1316 	if (dolock)
1317 		VOP_UNLOCK(vp, 0, p);
1318 
1319 	return (error);
1320 }
1321 
1322 int
1323 union_abortop(ap)
1324 	struct vop_abortop_args /* {
1325 		struct vnode *a_dvp;
1326 		struct componentname *a_cnp;
1327 	} */ *ap;
1328 {
1329 	int error;
1330 	struct componentname *cnp = ap->a_cnp;
1331 	struct proc *p = cnp->cn_proc;
1332 	struct vnode *vp = OTHERVP(ap->a_dvp);
1333 	struct union_node *un = VTOUNION(ap->a_dvp);
1334 	int islocked = un->un_flags & UN_LOCKED;
1335 	int dolock = (vp == LOWERVP(ap->a_dvp));
1336 
1337 	if (islocked) {
1338 		if (dolock)
1339 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1340 		else
1341 			FIXUP(VTOUNION(ap->a_dvp), p);
1342 	}
1343 	ap->a_dvp = vp;
1344 	error = VCALL(vp, VOFFSET(vop_abortop), ap);
1345 	if (islocked && dolock)
1346 		VOP_UNLOCK(vp, 0, p);
1347 
1348 	return (error);
1349 }
1350 
1351 int
1352 union_inactive(ap)
1353 	struct vop_inactive_args /* {
1354 		struct vnode *a_vp;
1355 		struct proc *a_p;
1356 	} */ *ap;
1357 {
1358 	struct vnode *vp = ap->a_vp;
1359 	struct proc *p = ap->a_p;
1360 	struct union_node *un = VTOUNION(vp);
1361 	struct vnode **vpp;
1362 
1363 	/*
1364 	 * Do nothing (and _don't_ bypass).
1365 	 * Wait to vrele lowervp until reclaim,
1366 	 * so that until then our union_node is in the
1367 	 * cache and reusable.
1368 	 *
1369 	 * NEEDSWORK: Someday, consider inactive'ing
1370 	 * the lowervp and then trying to reactivate it
1371 	 * with capabilities (v_id)
1372 	 * like they do in the name lookup cache code.
1373 	 * That's too much work for now.
1374 	 */
1375 
1376 	if (un->un_dircache != 0) {
1377 		for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
1378 			vrele(*vpp);
1379 		free(un->un_dircache, M_TEMP);
1380 		un->un_dircache = 0;
1381 	}
1382 
1383 	VOP_UNLOCK(vp, 0, p);
1384 
1385 	if ((un->un_flags & UN_CACHED) == 0)
1386 		vgone(vp);
1387 
1388 	return (0);
1389 }
1390 
1391 int
1392 union_reclaim(ap)
1393 	struct vop_reclaim_args /* {
1394 		struct vnode *a_vp;
1395 	} */ *ap;
1396 {
1397 
1398 	union_freevp(ap->a_vp);
1399 
1400 	return (0);
1401 }
1402 
1403 int
1404 union_lock(ap)
1405 	struct vop_lock_args *ap;
1406 {
1407 	struct vnode *vp = ap->a_vp;
1408 	struct proc *p = ap->a_p;
1409 	int flags = ap->a_flags;
1410 	struct union_node *un;
1411 	int error;
1412 
1413 	vop_nolock(ap);
1414 	/*
1415 	 * Need to do real lockmgr-style locking here.
1416 	 * in the mean time, draining won't work quite right,
1417 	 * which could lead to a few race conditions.
1418 	 * the following test was here, but is not quite right, we
1419 	 * still need to take the lock:
1420 	if ((flags & LK_TYPE_MASK) == LK_DRAIN)
1421 		return (0);
1422 	 */
1423 	flags &= ~LK_INTERLOCK;
1424 
1425 start:
1426 	un = VTOUNION(vp);
1427 
1428 	if (un->un_uppervp != NULLVP) {
1429 		if (((un->un_flags & UN_ULOCK) == 0) &&
1430 		    (vp->v_usecount != 0)) {
1431 			error = vn_lock(un->un_uppervp, flags, p);
1432 			if (error)
1433 				return (error);
1434 			un->un_flags |= UN_ULOCK;
1435 		}
1436 #ifdef DIAGNOSTIC
1437 		if (un->un_flags & UN_KLOCK) {
1438 			vprint("union: dangling klock", vp);
1439 			panic("union: dangling upper lock (%lx)", vp);
1440 		}
1441 #endif
1442 	}
1443 
1444 	if (un->un_flags & UN_LOCKED) {
1445 #ifdef DIAGNOSTIC
1446 		if (curproc && un->un_pid == curproc->p_pid &&
1447 			    un->un_pid > -1 && curproc->p_pid > -1)
1448 			panic("union: locking against myself");
1449 #endif
1450 		un->un_flags |= UN_WANT;
1451 		tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0);
1452 		goto start;
1453 	}
1454 
1455 #ifdef DIAGNOSTIC
1456 	if (curproc)
1457 		un->un_pid = curproc->p_pid;
1458 	else
1459 		un->un_pid = -1;
1460 #endif
1461 
1462 	un->un_flags |= UN_LOCKED;
1463 	return (0);
1464 }
1465 
1466 /*
1467  * When operations want to vput() a union node yet retain a lock on
1468  * the upper vnode (say, to do some further operations like link(),
1469  * mkdir(), ...), they set UN_KLOCK on the union node, then call
1470  * vput() which calls VOP_UNLOCK() and comes here.  union_unlock()
1471  * unlocks the union node (leaving the upper vnode alone), clears the
1472  * KLOCK flag, and then returns to vput().  The caller then does whatever
1473  * is left to do with the upper vnode, and ensures that it gets unlocked.
1474  *
1475  * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
1476  */
1477 int
1478 union_unlock(ap)
1479 	struct vop_unlock_args /* {
1480 		struct vnode *a_vp;
1481 		int a_flags;
1482 		struct proc *a_p;
1483 	} */ *ap;
1484 {
1485 	struct union_node *un = VTOUNION(ap->a_vp);
1486 	struct proc *p = ap->a_p;
1487 
1488 #ifdef DIAGNOSTIC
1489 	if ((un->un_flags & UN_LOCKED) == 0)
1490 		panic("union: unlock unlocked node");
1491 	if (curproc && un->un_pid != curproc->p_pid &&
1492 			curproc->p_pid > -1 && un->un_pid > -1)
1493 		panic("union: unlocking other process's union node");
1494 #endif
1495 
1496 	un->un_flags &= ~UN_LOCKED;
1497 
1498 	if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
1499 		VOP_UNLOCK(un->un_uppervp, 0, p);
1500 
1501 	un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
1502 
1503 	if (un->un_flags & UN_WANT) {
1504 		un->un_flags &= ~UN_WANT;
1505 		wakeup((caddr_t) &un->un_flags);
1506 	}
1507 
1508 #ifdef DIAGNOSTIC
1509 	un->un_pid = 0;
1510 #endif
1511 	vop_nounlock(ap);
1512 
1513 	return (0);
1514 }
1515 
1516 int
1517 union_bmap(ap)
1518 	struct vop_bmap_args /* {
1519 		struct vnode *a_vp;
1520 		daddr_t  a_bn;
1521 		struct vnode **a_vpp;
1522 		daddr_t *a_bnp;
1523 		int *a_runp;
1524 		int *a_runb;
1525 	} */ *ap;
1526 {
1527 	int error;
1528 	struct proc *p = curproc;		/* XXX */
1529 	struct vnode *vp = OTHERVP(ap->a_vp);
1530 	int dolock = (vp == LOWERVP(ap->a_vp));
1531 
1532 	if (dolock)
1533 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1534 	else
1535 		FIXUP(VTOUNION(ap->a_vp), p);
1536 	ap->a_vp = vp;
1537 	error = VCALL(vp, VOFFSET(vop_bmap), ap);
1538 	if (dolock)
1539 		VOP_UNLOCK(vp, 0, p);
1540 
1541 	return (error);
1542 }
1543 
1544 int
1545 union_print(ap)
1546 	struct vop_print_args /* {
1547 		struct vnode *a_vp;
1548 	} */ *ap;
1549 {
1550 	struct vnode *vp = ap->a_vp;
1551 
1552 	printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n",
1553 			vp, UPPERVP(vp), LOWERVP(vp));
1554 	if (UPPERVP(vp) != NULLVP)
1555 		vprint("union: upper", UPPERVP(vp));
1556 	if (LOWERVP(vp) != NULLVP)
1557 		vprint("union: lower", LOWERVP(vp));
1558 
1559 	return (0);
1560 }
1561 
1562 int
1563 union_islocked(ap)
1564 	struct vop_islocked_args /* {
1565 		struct vnode *a_vp;
1566 	} */ *ap;
1567 {
1568 
1569 	return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
1570 }
1571 
1572 int
1573 union_pathconf(ap)
1574 	struct vop_pathconf_args /* {
1575 		struct vnode *a_vp;
1576 		int a_name;
1577 		int *a_retval;
1578 	} */ *ap;
1579 {
1580 	int error;
1581 	struct proc *p = curproc;		/* XXX */
1582 	struct vnode *vp = OTHERVP(ap->a_vp);
1583 	int dolock = (vp == LOWERVP(ap->a_vp));
1584 
1585 	if (dolock)
1586 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1587 	else
1588 		FIXUP(VTOUNION(ap->a_vp), p);
1589 	ap->a_vp = vp;
1590 	error = VCALL(vp, VOFFSET(vop_pathconf), ap);
1591 	if (dolock)
1592 		VOP_UNLOCK(vp, 0, p);
1593 
1594 	return (error);
1595 }
1596 
1597 int
1598 union_advlock(ap)
1599 	struct vop_advlock_args /* {
1600 		struct vnode *a_vp;
1601 		caddr_t  a_id;
1602 		int  a_op;
1603 		struct flock *a_fl;
1604 		int  a_flags;
1605 	} */ *ap;
1606 {
1607 	register struct vnode *ovp = OTHERVP(ap->a_vp);
1608 
1609 	ap->a_vp = ovp;
1610 	return (VCALL(ovp, VOFFSET(vop_advlock), ap));
1611 }
1612 
1613 
1614 /*
1615  * XXX - vop_strategy must be hand coded because it has no
1616  * vnode in its arguments.
1617  * This goes away with a merged VM/buffer cache.
1618  */
1619 int
1620 union_strategy(ap)
1621 	struct vop_strategy_args /* {
1622 		struct buf *a_bp;
1623 	} */ *ap;
1624 {
1625 	struct buf *bp = ap->a_bp;
1626 	int error;
1627 	struct vnode *savedvp;
1628 
1629 	savedvp = bp->b_vp;
1630 	bp->b_vp = OTHERVP(bp->b_vp);
1631 
1632 #ifdef DIAGNOSTIC
1633 	if (bp->b_vp == NULLVP)
1634 		panic("union_strategy: nil vp");
1635 	if (((bp->b_flags & B_READ) == 0) &&
1636 	    (bp->b_vp == LOWERVP(savedvp)))
1637 		panic("union_strategy: writing to lowervp");
1638 #endif
1639 
1640 	error = VOP_STRATEGY(bp);
1641 	bp->b_vp = savedvp;
1642 
1643 	return (error);
1644 }
1645 
1646 /*
1647  * Global vfs data structures
1648  */
1649 vop_t **union_vnodeop_p;
1650 struct vnodeopv_entry_desc union_vnodeop_entries[] = {
1651 	{ &vop_default_desc, (vop_t *)vn_default_error },
1652 	{ &vop_lookup_desc, (vop_t *)union_lookup },		/* lookup */
1653 	{ &vop_create_desc, (vop_t *)union_create },		/* create */
1654 	{ &vop_whiteout_desc, (vop_t *)union_whiteout },	/* whiteout */
1655 	{ &vop_mknod_desc, (vop_t *)union_mknod },		/* mknod */
1656 	{ &vop_open_desc, (vop_t *)union_open },		/* open */
1657 	{ &vop_close_desc, (vop_t *)union_close },		/* close */
1658 	{ &vop_access_desc, (vop_t *)union_access },		/* access */
1659 	{ &vop_getattr_desc, (vop_t *)union_getattr },		/* getattr */
1660 	{ &vop_setattr_desc, (vop_t *)union_setattr },		/* setattr */
1661 	{ &vop_read_desc, (vop_t *)union_read },		/* read */
1662 	{ &vop_write_desc, (vop_t *)union_write },		/* write */
1663 	{ &vop_lease_desc, (vop_t *)union_lease },		/* lease */
1664 	{ &vop_ioctl_desc, (vop_t *)union_ioctl },		/* ioctl */
1665 	{ &vop_select_desc, (vop_t *)union_select },		/* select */
1666 	{ &vop_revoke_desc, (vop_t *)union_revoke },		/* revoke */
1667 	{ &vop_mmap_desc, (vop_t *)union_mmap },		/* mmap */
1668 	{ &vop_fsync_desc, (vop_t *)union_fsync },		/* fsync */
1669 	{ &vop_seek_desc, (vop_t *)union_seek },		/* seek */
1670 	{ &vop_remove_desc, (vop_t *)union_remove },		/* remove */
1671 	{ &vop_link_desc, (vop_t *)union_link },		/* link */
1672 	{ &vop_rename_desc, (vop_t *)union_rename },		/* rename */
1673 	{ &vop_mkdir_desc, (vop_t *)union_mkdir },		/* mkdir */
1674 	{ &vop_rmdir_desc, (vop_t *)union_rmdir },		/* rmdir */
1675 	{ &vop_symlink_desc, (vop_t *)union_symlink },		/* symlink */
1676 	{ &vop_readdir_desc, (vop_t *)union_readdir },		/* readdir */
1677 	{ &vop_readlink_desc, (vop_t *)union_readlink },	/* readlink */
1678 	{ &vop_abortop_desc, (vop_t *)union_abortop },		/* abortop */
1679 	{ &vop_inactive_desc, (vop_t *)union_inactive },	/* inactive */
1680 	{ &vop_reclaim_desc, (vop_t *)union_reclaim },		/* reclaim */
1681 	{ &vop_lock_desc, (vop_t *)union_lock },		/* lock */
1682 	{ &vop_unlock_desc, (vop_t *)union_unlock },		/* unlock */
1683 	{ &vop_bmap_desc, (vop_t *)union_bmap },		/* bmap */
1684 	{ &vop_strategy_desc, (vop_t *)union_strategy },	/* strategy */
1685 	{ &vop_print_desc, (vop_t *)union_print },		/* print */
1686 	{ &vop_islocked_desc, (vop_t *)union_islocked },	/* islocked */
1687 	{ &vop_pathconf_desc, (vop_t *)union_pathconf },	/* pathconf */
1688 	{ &vop_advlock_desc, (vop_t *)union_advlock },		/* advlock */
1689 #ifdef notdef
1690 	{ &vop_blkatoff_desc, (vop_t *)union_blkatoff },	/* blkatoff */
1691 	{ &vop_valloc_desc, (vop_t *)union_valloc },		/* valloc */
1692 	{ &vop_vfree_desc, (vop_t *)union_vfree },		/* vfree */
1693 	{ &vop_truncate_desc, (vop_t *)union_truncate },	/* truncate */
1694 	{ &vop_update_desc, (vop_t *)union_update },		/* update */
1695 	{ &vop_bwrite_desc, (vop_t *)union_bwrite },		/* bwrite */
1696 #endif
1697 	{ NULL, NULL }
1698 };
1699 struct vnodeopv_desc union_vnodeop_opv_desc =
1700 	{ &union_vnodeop_p, union_vnodeop_entries };
1701 
1702 VNODEOP_SET(union_vnodeop_opv_desc);
1703