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.
5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
6 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Jan-Simon Pendry.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)union_vnops.c	8.32 (Berkeley) 6/23/95
37 * $FreeBSD: src/sys/fs/unionfs/union_vnops.c,v 1.152 2008/01/13 14:44:06 attilio Exp $
38 *
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/conf.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mount.h>
48#include <sys/mutex.h>
49#include <sys/namei.h>
50#include <sys/sysctl.h>
51#include <sys/vnode.h>
52#include <sys/buf.h>
53#include <sys/fcntl.h>
54#include <sys/stat.h>
55#include <sys/dirent.h>
56#include <sys/proc.h>
57
58#include <fs/unionfs/unionfs.h>
59#include <miscfs/genfs/genfs.h>
60#include <miscfs/specfs/specdev.h>
61
62#if 0
63#define UNIONFS_INTERNAL_DEBUG(msg, args...)    printf(msg, ## args)
64#define UNIONFS_IDBG_RENAME
65#else
66#define UNIONFS_INTERNAL_DEBUG(msg, args...)
67#endif
68
69static int
70unionfs_parsepath(void *v)
71{
72	struct vop_parsepath_args /* {
73		struct vnode *a_dvp;
74		const char *a_name;
75		size_t *a_retval;
76	} */ *ap = v;
77	struct unionfs_node *dunp;
78	struct vnode *upperdvp, *lowerdvp;
79	size_t upper, lower;
80	int error;
81
82	dunp = VTOUNIONFS(ap->a_dvp);
83	upperdvp = dunp->un_uppervp;
84	lowerdvp = dunp->un_lowervp;
85
86	error = VOP_PARSEPATH(upperdvp, ap->a_name, &upper);
87	if (error) {
88		return error;
89	}
90
91	error = VOP_PARSEPATH(lowerdvp, ap->a_name, &lower);
92	if (error) {
93		return error;
94	}
95
96	/*
97	 * If they're different, use the larger one. This is not a
98	 * comprehensive solution, but it's sufficient for the
99	 * non-default cases of parsepath that currently exist.
100	 */
101	*ap->a_retval = MAX(upper, lower);
102	return 0;
103}
104
105static int
106unionfs_lookup(void *v)
107{
108	struct vop_lookup_v2_args /* {
109		struct vnodeop_desc *a_desc;
110		struct vnode *a_dvp;
111		struct vnode **a_vpp;
112		struct componentname *a_cnp;
113	} */ *ap = v;
114	int		iswhiteout;
115	int		error , uerror, lerror;
116	u_long		nameiop;
117	u_long		cnflags, cnflagsbk;
118	struct unionfs_node *dunp;
119	struct vnode   *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
120	struct vattr	va;
121	struct componentname *cnp;
122
123	iswhiteout = 0;
124	error = uerror = lerror = ENOENT;
125	cnp = ap->a_cnp;
126	nameiop = cnp->cn_nameiop;
127	cnflags = cnp->cn_flags;
128	dvp = ap->a_dvp;
129	dunp = VTOUNIONFS(dvp);
130	udvp = dunp->un_uppervp;
131	ldvp = dunp->un_lowervp;
132	vp = uvp = lvp = NULLVP;
133	*(ap->a_vpp) = NULLVP;
134
135	UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr);
136
137	if (dvp->v_type != VDIR)
138		return (ENOTDIR);
139
140	/*
141	 * If read-only and op is not LOOKUP, will return EROFS.
142	 */
143	if ((cnflags & ISLASTCN) &&
144	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
145	    LOOKUP != nameiop)
146		return (EROFS);
147
148	/*
149	 * lookup dotdot
150	 */
151	if (cnflags & ISDOTDOT) {
152		if (LOOKUP != nameiop && udvp == NULLVP)
153			return (EROFS);
154
155		if (udvp != NULLVP) {
156			dtmpvp = udvp;
157			if (ldvp != NULLVP)
158				VOP_UNLOCK(ldvp);
159		}
160		else
161			dtmpvp = ldvp;
162
163		error = VOP_LOOKUP(dtmpvp, &vp, cnp);
164
165		if (dtmpvp == udvp && ldvp != NULLVP) {
166			VOP_UNLOCK(udvp);
167			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
168		}
169
170		if (error == 0) {
171			/*
172			 * Exchange lock and reference from vp to
173			 * dunp->un_dvp. vp is upper/lower vnode, but it
174			 * will need to return the unionfs vnode.
175			 */
176			if (nameiop == DELETE  || nameiop == RENAME)
177				VOP_UNLOCK(vp);
178			vrele(vp);
179
180			VOP_UNLOCK(dvp);
181			*(ap->a_vpp) = dunp->un_dvp;
182			vref(dunp->un_dvp);
183
184			vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
185			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
186		} else if (error == ENOENT && nameiop != CREATE)
187			cache_enter(dvp, NULLVP, cnp->cn_nameptr,
188				    cnp->cn_namelen, cnp->cn_flags);
189
190		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
191
192		return (error);
193	}
194
195	/*
196	 * lookup upper layer
197	 */
198	if (udvp != NULLVP) {
199		uerror = VOP_LOOKUP(udvp, &uvp, cnp);
200
201		if (uerror == 0) {
202			if (udvp == uvp) {	/* is dot */
203				vrele(uvp);
204				*(ap->a_vpp) = dvp;
205				vref(dvp);
206
207				UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror);
208
209				return (uerror);
210			}
211		}
212
213		/* check whiteout */
214		if (uerror == ENOENT || uerror == EJUSTRETURN)
215			if (cnp->cn_flags & ISWHITEOUT)
216				iswhiteout = 1;	/* don't lookup lower */
217		if (iswhiteout == 0 && ldvp != NULLVP)
218			if (VOP_GETATTR(udvp, &va, cnp->cn_cred) == 0 &&
219			    (va.va_flags & OPAQUE))
220				iswhiteout = 1;	/* don't lookup lower */
221#if 0
222		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr);
223#endif
224	}
225
226	/*
227	 * lookup lower layer
228	 */
229	if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
230		/* always op is LOOKUP */
231		cnp->cn_nameiop = LOOKUP;
232		cnflagsbk = cnp->cn_flags;
233		cnp->cn_flags = cnflags;
234
235		lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
236
237		cnp->cn_nameiop = nameiop;
238		if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
239			cnp->cn_flags = cnflagsbk;
240
241		if (lerror == 0) {
242			if (ldvp == lvp) {	/* is dot */
243				if (uvp != NULLVP)
244					vrele(uvp);	/* no need? */
245				vrele(lvp);
246				*(ap->a_vpp) = dvp;
247				vref(dvp);
248
249				UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror);
250				if (uvp != NULL)
251					VOP_UNLOCK(uvp);
252				return (lerror);
253			}
254		}
255	}
256
257	/*
258	 * check lookup result
259	 */
260	if (uvp == NULLVP && lvp == NULLVP) {
261		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n",
262		    (udvp != NULLVP ? uerror : lerror));
263		return (udvp != NULLVP ? uerror : lerror);
264	}
265
266	/*
267	 * check vnode type
268	 */
269	if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
270		vput(lvp);
271		lvp = NULLVP;
272	}
273
274	/*
275	 * check shadow dir
276	 */
277	if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
278	    lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
279	    !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
280	    (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
281		/* get unionfs vnode in order to create a new shadow dir. */
282		error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
283		    cnp);
284		if (error != 0)
285			goto unionfs_lookup_out;
286		error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
287		    udvp, VTOUNIONFS(vp), cnp);
288		if (error != 0) {
289			UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
290			vput(vp);
291			goto unionfs_lookup_out;
292		}
293	}
294	/*
295	 * get unionfs vnode.
296	 */
297	else {
298		if (uvp != NULLVP)
299			error = uerror;
300		else
301			error = lerror;
302		if (error != 0)
303			goto unionfs_lookup_out;
304		error = unionfs_nodeget(dvp->v_mount, uvp, lvp, dvp, &vp, cnp);
305		if (error != 0) {
306			UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode.");
307			goto unionfs_lookup_out;
308		}
309	}
310
311	*(ap->a_vpp) = vp;
312
313	cache_enter(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen,
314		    cnp->cn_flags);
315
316	/* XXXAD lock status on error */
317unionfs_lookup_out:
318	if (uvp != NULLVP)
319		vrele(uvp);
320	if (lvp != NULLVP)
321		vrele(lvp);
322
323	if (error == ENOENT && nameiop != CREATE)
324		cache_enter(dvp, NULLVP, cnp->cn_nameptr, cnp->cn_namelen,
325			    cnp->cn_flags);
326
327	UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
328
329	return (error);
330}
331
332static int
333unionfs_create(void *v)
334{
335	struct vop_create_v3_args /* {
336		struct vnode *a_dvp;
337		struct vnode **a_vpp;
338		struct componentname *a_cnp;
339		struct vattr *a_vap;
340	} */ *ap = v;
341	struct unionfs_node *dunp;
342	struct componentname *cnp;
343	struct vnode   *udvp;
344	struct vnode   *vp;
345	int		error;
346
347	UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
348
349	dunp = VTOUNIONFS(ap->a_dvp);
350	cnp = ap->a_cnp;
351	udvp = dunp->un_uppervp;
352	error = EROFS;
353
354	if (udvp != NULLVP) {
355		if ((error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap)) == 0) {
356			error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
357			    ap->a_dvp, ap->a_vpp, cnp);
358			if (error) {
359				vput(vp);
360			} else {
361				vrele(vp);
362			}
363		}
364	}
365
366	UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
367
368	return (error);
369}
370
371static int
372unionfs_whiteout(void *v)
373{
374	struct vop_whiteout_args *ap = v;
375	struct unionfs_node *dunp;
376	struct componentname *cnp;
377	struct vnode   *udvp;
378	int		error;
379
380	UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
381
382	dunp = VTOUNIONFS(ap->a_dvp);
383	cnp = ap->a_cnp;
384	udvp = dunp->un_uppervp;
385	error = EOPNOTSUPP;
386
387	if (udvp != NULLVP) {
388		switch (ap->a_flags) {
389		case CREATE:
390		case DELETE:
391		case LOOKUP:
392			error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
393			break;
394		default:
395			error = EINVAL;
396			break;
397		}
398	}
399
400	UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
401
402	return (error);
403}
404
405static int
406unionfs_mknod(void *v)
407{
408	struct vop_mknod_v3_args /* {
409		struct vnode *a_dvp;
410		struct vnode **a_vpp;
411		struct componentname *a_cnp;
412		struct vattr *a_vap;
413	} */ *ap = v;
414	struct unionfs_node *dunp;
415	struct componentname *cnp;
416	struct vnode   *udvp;
417	struct vnode   *vp;
418	int		error;
419
420	UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
421
422	dunp = VTOUNIONFS(ap->a_dvp);
423	cnp = ap->a_cnp;
424	udvp = dunp->un_uppervp;
425	error = EROFS;
426
427	if (udvp != NULLVP) {
428		if ((error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap)) == 0) {
429			error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
430			    ap->a_dvp, ap->a_vpp, cnp);
431			if (error) {
432				vput(vp);
433			} else {
434				vrele(vp);
435			}
436		}
437	}
438
439	UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
440
441	return (error);
442}
443
444static int
445unionfs_open(void *v)
446{
447	struct vop_open_args *ap = v;
448	int		error;
449	struct unionfs_node *unp;
450	struct unionfs_node_status *unsp;
451	struct vnode   *uvp;
452	struct vnode   *lvp;
453	struct vnode   *targetvp;
454	kauth_cred_t   cred;
455
456	UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
457
458	error = 0;
459	unp = VTOUNIONFS(ap->a_vp);
460	uvp = unp->un_uppervp;
461	lvp = unp->un_lowervp;
462	targetvp = NULLVP;
463	cred = ap->a_cred;
464
465	unionfs_get_node_status(unp, &unsp);
466
467	if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
468		/* vnode is already opend. */
469		if (unsp->uns_upper_opencnt > 0)
470			targetvp = uvp;
471		else
472			targetvp = lvp;
473
474		if (targetvp == lvp &&
475		    (ap->a_mode & FWRITE) && lvp->v_type == VREG)
476			targetvp = NULLVP;
477	}
478	if (targetvp == NULLVP) {
479		if (uvp == NULLVP) {
480			if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
481				error = unionfs_copyfile(unp,
482				    !(ap->a_mode & O_TRUNC), cred);
483				if (error != 0)
484					goto unionfs_open_abort;
485				targetvp = uvp = unp->un_uppervp;
486			} else
487				targetvp = lvp;
488		} else
489			targetvp = uvp;
490	}
491
492	error = VOP_OPEN(targetvp, ap->a_mode, cred);
493	if (error == 0) {
494		if (targetvp == uvp) {
495			if (uvp->v_type == VDIR && lvp != NULLVP &&
496			    unsp->uns_lower_opencnt <= 0) {
497				/* open lower for readdir */
498				error = VOP_OPEN(lvp, FREAD, cred);
499				if (error != 0) {
500					VOP_CLOSE(uvp, ap->a_mode, cred);
501					goto unionfs_open_abort;
502				}
503				unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
504				unsp->uns_lower_opencnt++;
505			}
506			unsp->uns_upper_opencnt++;
507		} else {
508			unsp->uns_lower_opencnt++;
509			unsp->uns_lower_openmode = ap->a_mode;
510		}
511	}
512
513unionfs_open_abort:
514	if (error != 0)
515		unionfs_tryrem_node_status(unp, unsp);
516
517	UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
518
519	return (error);
520}
521
522static int
523unionfs_close(void *v)
524{
525	struct vop_close_args *ap = v;
526	int		error;
527	struct unionfs_node *unp;
528	struct unionfs_node_status *unsp;
529	kauth_cred_t   cred;
530	struct vnode   *ovp;
531
532	UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
533
534	KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
535	unp = VTOUNIONFS(ap->a_vp);
536	cred = ap->a_cred;
537
538	unionfs_get_node_status(unp, &unsp);
539
540	if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
541#ifdef DIAGNOSTIC
542		printf("unionfs_close: warning: open count is 0\n");
543#endif
544		if (unp->un_uppervp != NULLVP)
545			ovp = unp->un_uppervp;
546		else
547			ovp = unp->un_lowervp;
548	} else if (unsp->uns_upper_opencnt > 0)
549		ovp = unp->un_uppervp;
550	else
551		ovp = unp->un_lowervp;
552
553	error = VOP_CLOSE(ovp, ap->a_fflag, cred);
554
555	if (error != 0)
556		goto unionfs_close_abort;
557
558	if (ovp == unp->un_uppervp) {
559		unsp->uns_upper_opencnt--;
560		if (unsp->uns_upper_opencnt == 0) {
561			if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
562				VOP_CLOSE(unp->un_lowervp, FREAD, cred);
563				unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
564				unsp->uns_lower_opencnt--;
565			}
566		}
567	} else
568		unsp->uns_lower_opencnt--;
569
570unionfs_close_abort:
571	unionfs_tryrem_node_status(unp, unsp);
572
573	UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
574
575	return (error);
576}
577
578/*
579 * Check the access mode toward shadow file/dir.
580 */
581static int
582unionfs_check_corrected_access(u_short mode, struct vattr *va, kauth_cred_t cred)
583{
584	uid_t		uid;	/* upper side vnode's uid */
585	gid_t		gid;	/* upper side vnode's gid */
586	u_short		vmode;	/* upper side vnode's mode */
587	u_short		mask;
588
589	mask = 0;
590	uid = va->va_uid;
591	gid = va->va_gid;
592	vmode = va->va_mode;
593
594	/* check owner */
595	if (kauth_cred_getuid(cred) == uid) {
596		if (mode & VEXEC)
597			mask |= S_IXUSR;
598		if (mode & VREAD)
599			mask |= S_IRUSR;
600		if (mode & VWRITE)
601			mask |= S_IWUSR;
602		return ((vmode & mask) == mask ? 0 : EACCES);
603	}
604
605	/* check group */
606	if (kauth_cred_groupmember(cred, gid) == 0) {
607		if (mode & VEXEC)
608			mask |= S_IXGRP;
609		if (mode & VREAD)
610			mask |= S_IRGRP;
611		if (mode & VWRITE)
612			mask |= S_IWGRP;
613		return ((vmode & mask) == mask ? 0 : EACCES);
614	}
615
616	/* check other */
617	if (mode & VEXEC)
618		mask |= S_IXOTH;
619	if (mode & VREAD)
620		mask |= S_IROTH;
621	if (mode & VWRITE)
622		mask |= S_IWOTH;
623
624	return ((vmode & mask) == mask ? 0 : EACCES);
625}
626
627static int
628unionfs_access(void *v)
629{
630	struct vop_access_args /* {
631		struct vnodeop_desc *a_desc;
632		struct vnode *a_vp;
633		accmode_t a_accmode;
634		kauth_cred_t a_cred;
635	} */ *ap = v;
636	struct unionfs_mount *ump;
637	struct unionfs_node *unp;
638	struct vnode   *uvp;
639	struct vnode   *lvp;
640	struct vattr	va;
641	int		accmode;
642	int		error;
643
644	UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
645
646	ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
647	unp = VTOUNIONFS(ap->a_vp);
648	uvp = unp->un_uppervp;
649	lvp = unp->un_lowervp;
650	accmode = ap->a_accmode;
651	error = EACCES;
652
653	if ((accmode & VWRITE) &&
654	    (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
655		switch (ap->a_vp->v_type) {
656		case VREG:
657		case VDIR:
658		case VLNK:
659			return (EROFS);
660		default:
661			break;
662		}
663	}
664
665	if (uvp != NULLVP) {
666		error = VOP_ACCESS(uvp, accmode, ap->a_cred);
667
668		UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
669
670		return (error);
671	}
672
673	if (lvp != NULLVP) {
674		if (accmode & VWRITE) {
675			if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
676				switch (ap->a_vp->v_type) {
677				case VREG:
678				case VDIR:
679				case VLNK:
680					return (EROFS);
681				default:
682					break;
683				}
684			} else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
685				/* check shadow file/dir */
686				if (ump->um_copymode != UNIONFS_TRANSPARENT) {
687					error = unionfs_create_uppervattr(ump,
688					    lvp, &va, ap->a_cred);
689					if (error != 0)
690						return (error);
691
692					error = unionfs_check_corrected_access(
693					    accmode, &va, ap->a_cred);
694					if (error != 0)
695						return (error);
696				}
697			}
698			accmode &= ~VWRITE;
699			accmode |= VREAD; /* will copy to upper */
700		}
701		error = VOP_ACCESS(lvp, accmode, ap->a_cred);
702	}
703
704	UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
705
706	return (error);
707}
708
709static int
710unionfs_getattr(void *v)
711{
712	struct vop_getattr_args *ap = v;
713	int		error;
714	struct unionfs_node *unp;
715	struct unionfs_mount *ump;
716	struct vnode   *uvp;
717	struct vnode   *lvp;
718	struct vattr	va;
719
720	UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
721
722	unp = VTOUNIONFS(ap->a_vp);
723	ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
724	uvp = unp->un_uppervp;
725	lvp = unp->un_lowervp;
726
727	if (uvp != NULLVP) {
728		if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
729			ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid;
730
731		UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
732		    ap->a_vap->va_mode, ap->a_vap->va_uid,
733		    ap->a_vap->va_gid, error);
734
735		return (error);
736	}
737
738	error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
739
740	if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
741		/* correct the attr toward shadow file/dir. */
742		if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
743			unionfs_create_uppervattr_core(ump, ap->a_vap, &va);
744			ap->a_vap->va_mode = va.va_mode;
745			ap->a_vap->va_uid = va.va_uid;
746			ap->a_vap->va_gid = va.va_gid;
747		}
748	}
749
750	if (error == 0)
751		ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid;
752
753	UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
754	    ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
755
756	return (error);
757}
758
759static int
760unionfs_setattr(void *v)
761{
762	struct vop_setattr_args /* {
763		struct vnode *a_vp;
764		struct vattr *a_vap;
765		kauth_cred_t a_cred;
766	} */ *ap = v;
767	int		error;
768	struct unionfs_node *unp;
769	struct vnode   *uvp;
770	struct vnode   *lvp;
771	struct vattr   *vap;
772
773	UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
774
775	error = EROFS;
776	unp = VTOUNIONFS(ap->a_vp);
777	uvp = unp->un_uppervp;
778	lvp = unp->un_lowervp;
779	vap = ap->a_vap;
780
781	if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
782	    (vap->va_flags != (unsigned long )VNOVAL ||
783	     vap->va_uid != (uid_t)VNOVAL ||
784	     vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
785	     vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
786		return (EROFS);
787
788	if (uvp == NULLVP && lvp->v_type == VREG) {
789		error = unionfs_copyfile(unp, (vap->va_size != 0),
790		    ap->a_cred);
791		if (error != 0)
792			return (error);
793		uvp = unp->un_uppervp;
794	}
795
796	if (uvp != NULLVP)
797		error = VOP_SETATTR(uvp, vap, ap->a_cred);
798
799	UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
800
801	return (error);
802}
803
804static int
805unionfs_read(void *v)
806{
807	struct vop_read_args *ap = v;
808	int		error;
809	struct unionfs_node *unp;
810	struct vnode   *tvp;
811
812	/* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
813
814	unp = VTOUNIONFS(ap->a_vp);
815	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
816
817	error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
818
819	/* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
820
821	return (error);
822}
823
824static int
825unionfs_write(void *v)
826{
827	struct vop_write_args *ap = v;
828	int		error;
829	struct unionfs_node *unp;
830	struct vnode   *tvp;
831
832	/* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
833
834	unp = VTOUNIONFS(ap->a_vp);
835	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
836
837	error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
838
839	/* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
840
841	return (error);
842}
843
844static int
845unionfs_ioctl(void *v)
846{
847	struct vop_ioctl_args *ap = v;
848	int error;
849	struct unionfs_node *unp;
850	struct unionfs_node_status *unsp;
851	struct vnode   *ovp;
852
853	UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
854
855 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
856	unp = VTOUNIONFS(ap->a_vp);
857	unionfs_get_node_status(unp, &unsp);
858	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
859	unionfs_tryrem_node_status(unp, unsp);
860	VOP_UNLOCK(ap->a_vp);
861
862	if (ovp == NULLVP)
863		return (EBADF);
864
865	error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
866	    ap->a_cred);
867
868	UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error);
869
870	return (error);
871}
872
873static int
874unionfs_poll(void *v)
875{
876	struct vop_poll_args *ap = v;
877	struct unionfs_node *unp;
878	struct unionfs_node_status *unsp;
879	struct vnode   *ovp;
880
881 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
882	unp = VTOUNIONFS(ap->a_vp);
883	unionfs_get_node_status(unp, &unsp);
884	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
885	unionfs_tryrem_node_status(unp, unsp);
886	VOP_UNLOCK(ap->a_vp);
887
888	if (ovp == NULLVP)
889		return (EBADF);
890
891	return (VOP_POLL(ovp, ap->a_events));
892}
893
894static int
895unionfs_fsync(void *v)
896{
897	struct vop_fsync_args *ap = v;
898	struct unionfs_node *unp;
899	struct unionfs_node_status *unsp;
900	struct vnode   *ovp;
901
902	unp = VTOUNIONFS(ap->a_vp);
903	unionfs_get_node_status(unp, &unsp);
904	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
905	unionfs_tryrem_node_status(unp, unsp);
906
907	if (ovp == NULLVP)
908		return (EBADF);
909
910	return (VOP_FSYNC(ovp, ap->a_cred, ap->a_flags, ap->a_offlo, ap->a_offhi));
911}
912
913static int
914unionfs_remove(void *v)
915{
916	struct vop_remove_v3_args *ap = v;
917	int		error;
918	struct unionfs_node *dunp;
919	struct unionfs_node *unp;
920	struct unionfs_mount *ump;
921	struct vnode   *udvp;
922	struct vnode   *uvp;
923	struct vnode   *lvp;
924	struct componentname *cnp;
925
926	UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
927
928	error = 0;
929	dunp = VTOUNIONFS(ap->a_dvp);
930	unp = VTOUNIONFS(ap->a_vp);
931	udvp = dunp->un_uppervp;
932	uvp = unp->un_uppervp;
933	lvp = unp->un_lowervp;
934	cnp = ap->a_cnp;
935
936	if (udvp == NULLVP) {
937		vput(ap->a_vp);
938		return (EROFS);
939	}
940
941	if (uvp != NULLVP) {
942		ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
943		if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
944			cnp->cn_flags |= DOWHITEOUT;
945		error = VOP_REMOVE(udvp, uvp, cnp);
946	} else if (lvp != NULLVP)
947		error = unionfs_mkwhiteout(udvp, cnp, unp->un_path);
948
949	UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
950
951	return (error);
952}
953
954static int
955unionfs_link(void *v)
956{
957#if 0
958	struct vop_link_v2_args *ap = v;
959	int		error;
960	int		needrelookup;
961	struct unionfs_node *dunp;
962	struct unionfs_node *unp;
963	struct vnode   *udvp;
964	struct vnode   *uvp;
965	struct componentname *cnp;
966
967	UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
968
969	error = 0;
970	needrelookup = 0;
971	dunp = VTOUNIONFS(ap->a_tdvp);
972	unp = NULL;
973	udvp = dunp->un_uppervp;
974	uvp = NULLVP;
975	cnp = ap->a_cnp;
976
977	if (udvp == NULLVP)
978		return (EROFS);
979
980	if (ap->a_vp->v_op != unionfs_vnodeop_p)
981		uvp = ap->a_vp;
982	else {
983		unp = VTOUNIONFS(ap->a_vp);
984
985		if (unp->un_uppervp == NULLVP) {
986			if (ap->a_vp->v_type != VREG)
987				return (EOPNOTSUPP);
988
989			error = unionfs_copyfile(unp, 1, cnp->cn_cred);
990			if (error != 0)
991				return (error);
992			needrelookup = 1;
993		}
994		uvp = unp->un_uppervp;
995	}
996
997	if (needrelookup != 0)
998		error = unionfs_relookup_for_create(ap->a_tdvp, cnp);
999
1000	if (error == 0)
1001		error = VOP_LINK(udvp, uvp, cnp);
1002
1003	UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1004
1005	return (error);
1006#else
1007	panic("XXXAD");
1008	return 0;
1009#endif
1010}
1011
1012static int
1013unionfs_rename(void *v)
1014{
1015	struct vop_rename_args *ap = v;
1016	int		error;
1017	struct vnode   *fdvp;
1018	struct vnode   *fvp;
1019	struct componentname *fcnp;
1020	struct vnode   *tdvp;
1021	struct vnode   *tvp;
1022	struct componentname *tcnp;
1023	struct vnode   *ltdvp;
1024	struct vnode   *ltvp;
1025
1026	/* rename target vnodes */
1027	struct vnode   *rfdvp;
1028	struct vnode   *rfvp;
1029	struct vnode   *rtdvp;
1030	struct vnode   *rtvp;
1031
1032	int		needrelookup;
1033	struct unionfs_mount *ump;
1034	struct unionfs_node *unp;
1035
1036	UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1037
1038	error = 0;
1039	fdvp = ap->a_fdvp;
1040	fvp = ap->a_fvp;
1041	fcnp = ap->a_fcnp;
1042	tdvp = ap->a_tdvp;
1043	tvp = ap->a_tvp;
1044	tcnp = ap->a_tcnp;
1045	ltdvp = NULLVP;
1046	ltvp = NULLVP;
1047	rfdvp = fdvp;
1048	rfvp = fvp;
1049	rtdvp = tdvp;
1050	rtvp = tvp;
1051	needrelookup = 0;
1052
1053	/* check for cross device rename */
1054	if (fvp->v_mount != tdvp->v_mount ||
1055	    (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
1056		error = EXDEV;
1057		goto unionfs_rename_abort;
1058	}
1059
1060	/* Renaming a file to itself has no effect. */
1061	if (fvp == tvp)
1062		goto unionfs_rename_abort;
1063
1064	/*
1065	 * from/to vnode is unionfs node.
1066	 */
1067
1068	unp = VTOUNIONFS(fdvp);
1069#ifdef UNIONFS_IDBG_RENAME
1070	UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp);
1071#endif
1072	if (unp->un_uppervp == NULLVP) {
1073		error = ENODEV;
1074		goto unionfs_rename_abort;
1075	}
1076	rfdvp = unp->un_uppervp;
1077	vref(rfdvp);
1078
1079	unp = VTOUNIONFS(fvp);
1080#ifdef UNIONFS_IDBG_RENAME
1081	UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp);
1082#endif
1083	ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
1084	if (unp->un_uppervp == NULLVP) {
1085		switch (fvp->v_type) {
1086		case VREG:
1087			if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1088				goto unionfs_rename_abort;
1089			error = unionfs_copyfile(unp, 1, fcnp->cn_cred);
1090			VOP_UNLOCK(fvp);
1091			if (error != 0)
1092				goto unionfs_rename_abort;
1093			break;
1094		case VDIR:
1095			if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1096				goto unionfs_rename_abort;
1097			error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp);
1098			VOP_UNLOCK(fvp);
1099			if (error != 0)
1100				goto unionfs_rename_abort;
1101			break;
1102		default:
1103			error = ENODEV;
1104			goto unionfs_rename_abort;
1105		}
1106
1107		needrelookup = 1;
1108	}
1109
1110	if (unp->un_lowervp != NULLVP)
1111		fcnp->cn_flags |= DOWHITEOUT;
1112	rfvp = unp->un_uppervp;
1113	vref(rfvp);
1114
1115	unp = VTOUNIONFS(tdvp);
1116#ifdef UNIONFS_IDBG_RENAME
1117	UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp);
1118#endif
1119	if (unp->un_uppervp == NULLVP) {
1120		error = ENODEV;
1121		goto unionfs_rename_abort;
1122	}
1123	rtdvp = unp->un_uppervp;
1124	ltdvp = unp->un_lowervp;
1125	vref(rtdvp);
1126
1127	if (tdvp == tvp) {
1128		rtvp = rtdvp;
1129		vref(rtvp);
1130	} else if (tvp != NULLVP) {
1131		unp = VTOUNIONFS(tvp);
1132#ifdef UNIONFS_IDBG_RENAME
1133		UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp);
1134#endif
1135		if (unp->un_uppervp == NULLVP)
1136			rtvp = NULLVP;
1137		else {
1138			if (tvp->v_type == VDIR) {
1139				error = EINVAL;
1140				goto unionfs_rename_abort;
1141			}
1142			rtvp = unp->un_uppervp;
1143			ltvp = unp->un_lowervp;
1144			vref(rtvp);
1145		}
1146	}
1147
1148	if (needrelookup != 0) {
1149		if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
1150			goto unionfs_rename_abort;
1151		error = unionfs_relookup_for_delete(fdvp, fcnp);
1152		VOP_UNLOCK(fdvp);
1153		if (error != 0)
1154			goto unionfs_rename_abort;
1155
1156		/* Locke of tvp is canceled in order to avoid recursive lock. */
1157		if (tvp != NULLVP && tvp != tdvp)
1158			VOP_UNLOCK(tvp);
1159		error = unionfs_relookup_for_rename(tdvp, tcnp);
1160		if (tvp != NULLVP && tvp != tdvp)
1161			vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1162		if (error != 0)
1163			goto unionfs_rename_abort;
1164	}
1165
1166	error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1167
1168	if (error == 0) {
1169		if (rtvp != NULLVP && rtvp->v_type == VDIR)
1170			cache_purge(tdvp);
1171		if (fvp->v_type == VDIR && fdvp != tdvp)
1172			cache_purge(fdvp);
1173	}
1174
1175	if (fdvp != rfdvp)
1176		vrele(fdvp);
1177	if (fvp != rfvp)
1178		vrele(fvp);
1179	if (ltdvp != NULLVP)
1180		VOP_UNLOCK(ltdvp);
1181	if (tdvp != rtdvp)
1182		vrele(tdvp);
1183	if (ltvp != NULLVP)
1184		VOP_UNLOCK(ltvp);
1185	if (tvp != rtvp && tvp != NULLVP) {
1186		if (rtvp == NULLVP)
1187			vput(tvp);
1188		else
1189			vrele(tvp);
1190	}
1191
1192	UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1193
1194	return (error);
1195
1196unionfs_rename_abort:
1197	if (fdvp != rfdvp)
1198		vrele(rfdvp);
1199	if (fvp != rfvp)
1200		vrele(rfvp);
1201	if (tdvp != rtdvp)
1202		vrele(rtdvp);
1203	vput(tdvp);
1204	if (tvp != rtvp && rtvp != NULLVP)
1205		vrele(rtvp);
1206	if (tvp != NULLVP) {
1207		if (tdvp != tvp)
1208			vput(tvp);
1209		else
1210			vrele(tvp);
1211	}
1212	vrele(fdvp);
1213	vrele(fvp);
1214
1215	UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1216
1217	return (error);
1218}
1219
1220static int
1221unionfs_mkdir(void *v)
1222{
1223	struct vop_mkdir_v3_args /* {
1224		struct vnode *a_dvp;
1225		struct vnode **a_vpp;
1226		struct componentname *a_cnp;
1227		struct vattr *a_vap;
1228	} */ *ap = v;
1229	int		error;
1230	struct unionfs_node *dunp;
1231	struct componentname *cnp;
1232	struct vnode   *udvp;
1233	struct vnode   *uvp;
1234	struct vattr	va;
1235
1236	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1237
1238	error = EROFS;
1239	dunp = VTOUNIONFS(ap->a_dvp);
1240	cnp = ap->a_cnp;
1241	udvp = dunp->un_uppervp;
1242
1243	if (udvp != NULLVP) {
1244		/* check opaque */
1245		if (!(cnp->cn_flags & ISWHITEOUT)) {
1246			error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1247			if (error != 0)
1248				return (error);
1249			if (va.va_flags & OPAQUE)
1250				cnp->cn_flags |= ISWHITEOUT;
1251		}
1252
1253		if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
1254			error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1255			    ap->a_dvp, ap->a_vpp, cnp);
1256			if (error) {
1257				vput(uvp);
1258			} else {
1259				vrele(uvp);
1260			}
1261		}
1262	}
1263
1264	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1265
1266	return (error);
1267}
1268
1269static int
1270unionfs_rmdir(void *v)
1271{
1272	struct vop_rmdir_v2_args *ap = v;
1273	int		error;
1274	struct unionfs_node *dunp;
1275	struct unionfs_node *unp;
1276	struct unionfs_mount *ump;
1277	struct componentname *cnp;
1278	struct vnode   *udvp;
1279	struct vnode   *uvp;
1280	struct vnode   *lvp;
1281
1282	UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1283
1284	error = 0;
1285	dunp = VTOUNIONFS(ap->a_dvp);
1286	unp = VTOUNIONFS(ap->a_vp);
1287	cnp = ap->a_cnp;
1288	udvp = dunp->un_uppervp;
1289	uvp = unp->un_uppervp;
1290	lvp = unp->un_lowervp;
1291
1292	if (udvp == NULLVP) {
1293		vput(ap->a_vp);
1294		return (EROFS);
1295	}
1296
1297	if (udvp == uvp)
1298		return (EOPNOTSUPP);
1299
1300	if (uvp != NULLVP) {
1301		if (lvp != NULLVP) {
1302			error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred);
1303			if (error != 0)
1304				return (error);
1305		}
1306		ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1307		if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1308			cnp->cn_flags |= DOWHITEOUT;
1309		error = VOP_RMDIR(udvp, uvp, cnp);
1310	}
1311	else if (lvp != NULLVP)
1312		error = unionfs_mkwhiteout(udvp, cnp, unp->un_path);
1313
1314	if (error == 0) {
1315		cache_purge(ap->a_dvp);
1316		cache_purge(ap->a_vp);
1317	}
1318
1319	UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1320
1321	return (error);
1322}
1323
1324static int
1325unionfs_symlink(void *v)
1326{
1327	struct vop_symlink_v3_args /* {
1328		struct vnode *a_dvp;
1329		struct vnode **a_vpp;
1330		struct componentname *a_cnp;
1331		struct vattr *a_vap;
1332		char *a_target;
1333	} */ *ap = v;
1334	int		error;
1335	struct unionfs_node *dunp;
1336	struct componentname *cnp;
1337	struct vnode   *udvp;
1338	struct vnode   *uvp;
1339
1340	UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1341
1342	error = EROFS;
1343	dunp = VTOUNIONFS(ap->a_dvp);
1344	cnp = ap->a_cnp;
1345	udvp = dunp->un_uppervp;
1346
1347	if (udvp != NULLVP) {
1348		error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1349		if (error == 0) {
1350			error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1351			    ap->a_dvp, ap->a_vpp, cnp);
1352			if (error) {
1353				vput(uvp);
1354			} else {
1355				vrele(uvp);
1356			}
1357		}
1358	}
1359
1360	UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1361
1362	return (error);
1363}
1364
1365static int
1366unionfs_readdir(void *v)
1367{
1368	struct vop_readdir_args *ap = v;
1369	int		error;
1370	int		eofflag;
1371	struct unionfs_node *unp;
1372	struct unionfs_node_status *unsp;
1373	struct uio     *uio;
1374	struct vnode   *uvp;
1375	struct vnode   *lvp;
1376	struct vattr    va;
1377
1378	int		ncookies_bk;
1379	off_t          *cookies_bk;
1380
1381	UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1382
1383	error = 0;
1384	eofflag = 0;
1385	unp = VTOUNIONFS(ap->a_vp);
1386	uio = ap->a_uio;
1387	uvp = unp->un_uppervp;
1388	lvp = unp->un_lowervp;
1389	ncookies_bk = 0;
1390	cookies_bk = NULL;
1391
1392	if (ap->a_vp->v_type != VDIR)
1393		return (ENOTDIR);
1394
1395	/* check opaque */
1396	if (uvp != NULLVP && lvp != NULLVP) {
1397		if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1398			goto unionfs_readdir_exit;
1399		if (va.va_flags & OPAQUE)
1400			lvp = NULLVP;
1401	}
1402
1403	/* check the open count. unionfs needs to open before readdir. */
1404	VOP_UNLOCK(ap->a_vp);
1405	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1406	unionfs_get_node_status(unp, &unsp);
1407	if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1408	    (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1409		unionfs_tryrem_node_status(unp, unsp);
1410		error = EBADF;
1411	}
1412	if (error != 0)
1413		goto unionfs_readdir_exit;
1414
1415	/* upper only */
1416	if (uvp != NULLVP && lvp == NULLVP) {
1417		error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1418		    ap->a_cookies, ap->a_ncookies);
1419		unsp->uns_readdir_status = 0;
1420
1421		goto unionfs_readdir_exit;
1422	}
1423
1424	/* lower only */
1425	if (uvp == NULLVP && lvp != NULLVP) {
1426		error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1427		    ap->a_cookies, ap->a_ncookies);
1428		unsp->uns_readdir_status = 2;
1429
1430		goto unionfs_readdir_exit;
1431	}
1432
1433	/*
1434	 * readdir upper and lower
1435	 */
1436	KASSERT(uvp != NULLVP);
1437	KASSERT(lvp != NULLVP);
1438	if (uio->uio_offset == 0)
1439		unsp->uns_readdir_status = 0;
1440
1441	if (unsp->uns_readdir_status == 0) {
1442		/* read upper */
1443		error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1444				    ap->a_cookies, ap->a_ncookies);
1445
1446		if (error != 0 || eofflag == 0)
1447			goto unionfs_readdir_exit;
1448		unsp->uns_readdir_status = 1;
1449
1450		/*
1451		 * ufs(and other fs) needs size of uio_resid larger than
1452		 * DIRBLKSIZ.
1453		 * size of DIRBLKSIZ equals DEV_BSIZE.
1454		 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1455		 */
1456		if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1457			goto unionfs_readdir_exit;
1458
1459		/*
1460		 * backup cookies
1461		 * It prepares to readdir in lower.
1462		 */
1463		if (ap->a_ncookies != NULL) {
1464			ncookies_bk = *(ap->a_ncookies);
1465			*(ap->a_ncookies) = 0;
1466		}
1467		if (ap->a_cookies != NULL) {
1468			cookies_bk = *(ap->a_cookies);
1469			*(ap->a_cookies) = NULL;
1470		}
1471	}
1472
1473	/* initialize for readdir in lower */
1474	if (unsp->uns_readdir_status == 1) {
1475		unsp->uns_readdir_status = 2;
1476		uio->uio_offset = 0;
1477	}
1478
1479	if (lvp == NULLVP) {
1480		error = EBADF;
1481		goto unionfs_readdir_exit;
1482	}
1483	/* read lower */
1484	error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1485			    ap->a_cookies, ap->a_ncookies);
1486
1487	if (cookies_bk != NULL) {
1488		/* merge cookies */
1489		int		size;
1490		off_t         *newcookies, *pos;
1491
1492		size = *(ap->a_ncookies) + ncookies_bk;
1493		newcookies = (off_t *) malloc(size * sizeof(off_t),
1494		    M_TEMP, M_WAITOK);
1495		pos = newcookies;
1496
1497		memcpy(pos, cookies_bk, ncookies_bk * sizeof(off_t));
1498		pos += ncookies_bk * sizeof(off_t);
1499		memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(off_t));
1500		free(cookies_bk, M_TEMP);
1501		free(*(ap->a_cookies), M_TEMP);
1502		*(ap->a_ncookies) = size;
1503		*(ap->a_cookies) = newcookies;
1504	}
1505
1506unionfs_readdir_exit:
1507	if (error != 0 && ap->a_eofflag != NULL)
1508		*(ap->a_eofflag) = 1;
1509
1510	UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1511
1512	return (error);
1513}
1514
1515static int
1516unionfs_readlink(void *v)
1517{
1518	struct vop_readlink_args *ap = v;
1519	int error;
1520	struct unionfs_node *unp;
1521	struct vnode   *vp;
1522
1523	UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1524
1525	unp = VTOUNIONFS(ap->a_vp);
1526	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1527
1528	error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1529
1530	UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1531
1532	return (error);
1533}
1534
1535static int
1536unionfs_inactive(void *v)
1537{
1538	struct vop_inactive_v2_args *ap = v;
1539	*ap->a_recycle = true;
1540	return (0);
1541}
1542
1543static int
1544unionfs_reclaim(void *v)
1545{
1546	struct vop_reclaim_v2_args *ap = v;
1547
1548	/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1549
1550	VOP_UNLOCK(ap->a_vp);
1551
1552	unionfs_noderem(ap->a_vp);
1553
1554	/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1555
1556	return (0);
1557}
1558
1559static int
1560unionfs_print(void *v)
1561{
1562	struct vop_print_args *ap = v;
1563	struct unionfs_node *unp;
1564	/* struct unionfs_node_status *unsp; */
1565
1566	unp = VTOUNIONFS(ap->a_vp);
1567	/* unionfs_get_node_status(unp, &unsp); */
1568
1569	printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1570	    ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1571	/*
1572	printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1573	    unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1574	*/
1575
1576	if (unp->un_uppervp != NULLVP)
1577		vprint("unionfs: upper", unp->un_uppervp);
1578	if (unp->un_lowervp != NULLVP)
1579		vprint("unionfs: lower", unp->un_lowervp);
1580
1581	return (0);
1582}
1583
1584static int
1585unionfs_lock(void *v)
1586{
1587	struct vop_lock_args *ap = v;
1588	int		error;
1589	int		flags;
1590	struct vnode   *lvp;
1591	struct vnode   *uvp;
1592	struct unionfs_node *unp;
1593
1594	unp = VTOUNIONFS(ap->a_vp);
1595	lvp = unp->un_lowervp;
1596	uvp = unp->un_uppervp;
1597	flags = ap->a_flags;
1598	error = 0;
1599
1600	if (lvp != NULLVP) {
1601		error = VOP_LOCK(lvp, flags);
1602	}
1603	if (error == 0 && uvp != NULLVP) {
1604		error = VOP_LOCK(uvp, flags);
1605		if (error != 0) {
1606			VOP_UNLOCK(lvp);
1607		}
1608	}
1609
1610	return error;
1611}
1612
1613static int
1614unionfs_unlock(void *v)
1615{
1616	struct vop_unlock_args *ap = v;
1617	int		error;
1618	struct vnode   *lvp;
1619	struct vnode   *uvp;
1620	struct unionfs_node *unp;
1621
1622	unp = VTOUNIONFS(ap->a_vp);
1623	lvp = unp->un_lowervp;
1624	uvp = unp->un_uppervp;
1625	error = 0;
1626
1627	if (lvp != NULLVP) {
1628		error = VOP_UNLOCK(lvp);
1629	}
1630	if (error == 0 && uvp != NULLVP) {
1631		error = VOP_UNLOCK(uvp);
1632	}
1633
1634	return error;
1635}
1636
1637static int
1638unionfs_pathconf(void *v)
1639{
1640	struct vop_pathconf_args *ap = v;
1641	struct unionfs_node *unp;
1642	struct vnode   *vp;
1643
1644	unp = VTOUNIONFS(ap->a_vp);
1645	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1646
1647	return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
1648}
1649
1650static int
1651unionfs_advlock(void *v)
1652{
1653	struct vop_advlock_args *ap = v;
1654	int error;
1655	struct unionfs_node *unp;
1656	struct unionfs_node_status *unsp;
1657	struct vnode   *vp;
1658	struct vnode   *uvp;
1659	kauth_cred_t	cred;
1660
1661	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
1662
1663	vp = ap->a_vp;
1664	cred = kauth_cred_get();
1665
1666	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1667
1668	unp = VTOUNIONFS(ap->a_vp);
1669	uvp = unp->un_uppervp;
1670
1671	if (uvp == NULLVP) {
1672		error = unionfs_copyfile(unp, 1, cred);
1673		if (error != 0)
1674			goto unionfs_advlock_abort;
1675		uvp = unp->un_uppervp;
1676
1677		unionfs_get_node_status(unp, &unsp);
1678		if (unsp->uns_lower_opencnt > 0) {
1679			/* try reopen the vnode */
1680			error = VOP_OPEN(uvp, unsp->uns_lower_openmode, cred);
1681			if (error)
1682				goto unionfs_advlock_abort;
1683			unsp->uns_upper_opencnt++;
1684			VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, cred);
1685			unsp->uns_lower_opencnt--;
1686		} else
1687			unionfs_tryrem_node_status(unp, unsp);
1688	}
1689
1690	VOP_UNLOCK(vp);
1691
1692	error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
1693
1694	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
1695
1696	return error;
1697
1698unionfs_advlock_abort:
1699	VOP_UNLOCK(vp);
1700
1701	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
1702
1703	return error;
1704}
1705
1706static int
1707unionfs_strategy(void *v)
1708{
1709	struct vop_strategy_args *ap = v;
1710	struct unionfs_node *unp;
1711	struct vnode   *vp;
1712
1713	unp = VTOUNIONFS(ap->a_vp);
1714	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1715
1716#ifdef DIAGNOSTIC
1717	if (vp == NULLVP)
1718		panic("unionfs_strategy: nullvp");
1719	if ((ap->a_bp->b_flags & B_READ) == 0 && vp == unp->un_lowervp)
1720		panic("unionfs_strategy: writing to lowervp");
1721#endif
1722
1723	return (VOP_STRATEGY(vp, ap->a_bp));
1724}
1725
1726static int
1727unionfs_kqfilter(void *v)
1728{
1729	struct vop_kqfilter_args *ap = v;
1730	struct unionfs_node *unp;
1731	struct vnode   *tvp;
1732
1733	unp = VTOUNIONFS(ap->a_vp);
1734	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1735
1736	return VOP_KQFILTER(tvp, ap->a_kn);
1737}
1738
1739static int
1740unionfs_bmap(void *v)
1741{
1742	struct vop_bmap_args *ap = v;
1743	struct unionfs_node *unp;
1744	struct vnode   *tvp;
1745
1746	unp = VTOUNIONFS(ap->a_vp);
1747	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1748
1749	return VOP_BMAP(tvp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
1750}
1751
1752static int
1753unionfs_mmap(void *v)
1754{
1755	struct vop_mmap_args *ap = v;
1756	struct unionfs_node *unp;
1757	struct vnode   *tvp;
1758
1759	unp = VTOUNIONFS(ap->a_vp);
1760	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1761
1762	return VOP_MMAP(tvp, ap->a_prot, ap->a_cred);
1763}
1764
1765static int
1766unionfs_abortop(void *v)
1767{
1768	struct vop_abortop_args *ap = v;
1769	struct unionfs_node *unp;
1770	struct vnode   *tvp;
1771
1772	unp = VTOUNIONFS(ap->a_dvp);
1773	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1774
1775	return VOP_ABORTOP(tvp, ap->a_cnp);
1776}
1777
1778static int
1779unionfs_islocked(void *v)
1780{
1781	struct vop_islocked_args *ap = v;
1782	struct unionfs_node *unp;
1783	struct vnode   *tvp;
1784
1785	unp = VTOUNIONFS(ap->a_vp);
1786	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1787
1788	return VOP_ISLOCKED(tvp);
1789}
1790
1791static int
1792unionfs_seek(void *v)
1793{
1794	struct vop_seek_args *ap = v;
1795	struct unionfs_node *unp;
1796	struct vnode   *tvp;
1797
1798	unp = VTOUNIONFS(ap->a_vp);
1799	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1800
1801	return VOP_SEEK(tvp, ap->a_oldoff, ap->a_newoff, ap->a_cred);
1802}
1803
1804static int
1805unionfs_putpages(void *v)
1806{
1807	struct vop_putpages_args /* {
1808		struct vnode *a_vp;
1809		voff_t a_offlo;
1810		voff_t a_offhi;
1811		int a_flags;
1812	} */ *ap = v;
1813	struct vnode *vp = ap->a_vp, *tvp;
1814	struct unionfs_node *unp;
1815
1816	KASSERT(rw_lock_held(vp->v_uobj.vmobjlock));
1817
1818	unp = VTOUNIONFS(vp);
1819	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1820	KASSERT(tvp->v_uobj.vmobjlock == vp->v_uobj.vmobjlock);
1821
1822	if (ap->a_flags & PGO_RECLAIM) {
1823		rw_exit(vp->v_uobj.vmobjlock);
1824		return 0;
1825	}
1826	return VOP_PUTPAGES(tvp, ap->a_offlo, ap->a_offhi, ap->a_flags);
1827}
1828
1829static int
1830unionfs_getpages(void *v)
1831{
1832	struct vop_getpages_args /* {
1833		struct vnode *a_vp;
1834		voff_t a_offset;
1835		struct vm_page **a_m;
1836		int *a_count;
1837		int a_centeridx;
1838		vm_prot_t a_access_type;
1839		int a_advice;
1840		int a_flags;
1841	} */ *ap = v;
1842	struct vnode *vp = ap->a_vp, *tvp;
1843	struct unionfs_node *unp;
1844
1845	KASSERT(rw_lock_held(vp->v_uobj.vmobjlock));
1846
1847	unp = VTOUNIONFS(vp);
1848	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1849	KASSERT(tvp->v_uobj.vmobjlock == vp->v_uobj.vmobjlock);
1850
1851	if (ap->a_flags & PGO_LOCKED) {
1852		return EBUSY;
1853	}
1854	return VOP_GETPAGES(tvp, ap->a_offset, ap->a_m, ap->a_count,
1855	    ap->a_centeridx, ap->a_access_type, ap->a_advice, ap->a_flags);
1856}
1857
1858static int
1859unionfs_revoke(void *v)
1860{
1861	struct vop_revoke_args *ap = v;
1862	struct unionfs_node *unp;
1863	struct vnode   *tvp;
1864	int error;
1865
1866	unp = VTOUNIONFS(ap->a_vp);
1867	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1868
1869	error = VOP_REVOKE(tvp, ap->a_flags);
1870	if (error == 0) {
1871		vgone(ap->a_vp);	/* ??? */
1872	}
1873	return error;
1874}
1875
1876/*
1877 * Global vfs data structures
1878 */
1879int (**unionfs_vnodeop_p)(void *);
1880const struct vnodeopv_entry_desc unionfs_vnodeop_entries[] = {
1881	{ &vop_default_desc, vn_default_error },
1882	{ &vop_parsepath_desc, unionfs_parsepath },	/* parsepath */
1883	{ &vop_lookup_desc, unionfs_lookup },		/* lookup */
1884	{ &vop_create_desc, unionfs_create },		/* create */
1885	{ &vop_whiteout_desc, unionfs_whiteout },	/* whiteout */
1886	{ &vop_mknod_desc, unionfs_mknod },		/* mknod */
1887	{ &vop_open_desc, unionfs_open },		/* open */
1888	{ &vop_close_desc, unionfs_close },		/* close */
1889	{ &vop_access_desc, unionfs_access },		/* access */
1890	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
1891	{ &vop_getattr_desc, unionfs_getattr },		/* getattr */
1892	{ &vop_setattr_desc, unionfs_setattr },		/* setattr */
1893	{ &vop_read_desc, unionfs_read },		/* read */
1894	{ &vop_write_desc, unionfs_write },		/* write */
1895	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
1896	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
1897	{ &vop_ioctl_desc, unionfs_ioctl },		/* ioctl */
1898	{ &vop_poll_desc, unionfs_poll },		/* select */
1899	{ &vop_revoke_desc, unionfs_revoke },		/* revoke */
1900	{ &vop_mmap_desc, unionfs_mmap },		/* mmap */
1901	{ &vop_fsync_desc, unionfs_fsync },		/* fsync */
1902	{ &vop_seek_desc, unionfs_seek },		/* seek */
1903	{ &vop_remove_desc, unionfs_remove },		/* remove */
1904	{ &vop_link_desc, unionfs_link },		/* link */
1905	{ &vop_rename_desc, unionfs_rename },		/* rename */
1906	{ &vop_mkdir_desc, unionfs_mkdir },		/* mkdir */
1907	{ &vop_rmdir_desc, unionfs_rmdir },		/* rmdir */
1908	{ &vop_symlink_desc, unionfs_symlink },		/* symlink */
1909	{ &vop_readdir_desc, unionfs_readdir },		/* readdir */
1910	{ &vop_readlink_desc, unionfs_readlink },	/* readlink */
1911	{ &vop_abortop_desc, unionfs_abortop },		/* abortop */
1912	{ &vop_inactive_desc, unionfs_inactive },	/* inactive */
1913	{ &vop_reclaim_desc, unionfs_reclaim },		/* reclaim */
1914	{ &vop_lock_desc, unionfs_lock },		/* lock */
1915	{ &vop_unlock_desc, unionfs_unlock },		/* unlock */
1916	{ &vop_bmap_desc, unionfs_bmap },		/* bmap */
1917	{ &vop_strategy_desc, unionfs_strategy },	/* strategy */
1918	{ &vop_print_desc, unionfs_print },		/* print */
1919	{ &vop_islocked_desc, unionfs_islocked },	/* islocked */
1920	{ &vop_pathconf_desc, unionfs_pathconf },	/* pathconf */
1921	{ &vop_advlock_desc, unionfs_advlock },		/* advlock */
1922	{ &vop_getpages_desc, unionfs_getpages },	/* getpages */
1923	{ &vop_putpages_desc, unionfs_putpages },	/* putpages */
1924	{ &vop_kqfilter_desc, unionfs_kqfilter },	/* kqfilter */
1925#ifdef notdef
1926	{ &vop_bwrite_desc, unionfs_bwrite },		/* bwrite */
1927#endif
1928	{ NULL, NULL }
1929};
1930const struct vnodeopv_desc unionfs_vnodeop_opv_desc =
1931	{ &unionfs_vnodeop_p, unionfs_vnodeop_entries };
1932