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