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, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
6 * Copyright (c) 2006, 2012 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$
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/kdb.h>
53#include <sys/fcntl.h>
54#include <sys/stat.h>
55#include <sys/dirent.h>
56#include <sys/proc.h>
57#include <sys/bio.h>
58#include <sys/buf.h>
59
60#include <fs/unionfs/union.h>
61
62#include <vm/vm.h>
63#include <vm/vm_extern.h>
64#include <vm/vm_object.h>
65#include <vm/vnode_pager.h>
66
67#if 0
68#define UNIONFS_INTERNAL_DEBUG(msg, args...)    printf(msg, ## args)
69#define UNIONFS_IDBG_RENAME
70#else
71#define UNIONFS_INTERNAL_DEBUG(msg, args...)
72#endif
73
74#define KASSERT_UNIONFS_VNODE(vp) \
75	KASSERT(((vp)->v_op == &unionfs_vnodeops), \
76	    ("unionfs: it is not unionfs-vnode"))
77
78static int
79unionfs_lookup(struct vop_cachedlookup_args *ap)
80{
81	int		iswhiteout;
82	int		lockflag;
83	int		error , uerror, lerror;
84	u_long		nameiop;
85	u_long		cnflags, cnflagsbk;
86	struct unionfs_node *dunp;
87	struct vnode   *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
88	struct vattr	va;
89	struct componentname *cnp;
90	struct thread  *td;
91
92	iswhiteout = 0;
93	lockflag = 0;
94	error = uerror = lerror = ENOENT;
95	cnp = ap->a_cnp;
96	nameiop = cnp->cn_nameiop;
97	cnflags = cnp->cn_flags;
98	dvp = ap->a_dvp;
99	dunp = VTOUNIONFS(dvp);
100	udvp = dunp->un_uppervp;
101	ldvp = dunp->un_lowervp;
102	vp = uvp = lvp = NULLVP;
103	td = curthread;
104	*(ap->a_vpp) = NULLVP;
105
106	UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr);
107
108	if (dvp->v_type != VDIR)
109		return (ENOTDIR);
110
111	/*
112	 * If read-only and op is not LOOKUP, will return EROFS.
113	 */
114	if ((cnflags & ISLASTCN) &&
115	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
116	    LOOKUP != nameiop)
117		return (EROFS);
118
119	/*
120	 * lookup dotdot
121	 */
122	if (cnflags & ISDOTDOT) {
123		if (LOOKUP != nameiop && udvp == NULLVP)
124			return (EROFS);
125
126		if (udvp != NULLVP) {
127			dtmpvp = udvp;
128			if (ldvp != NULLVP)
129				VOP_UNLOCK(ldvp, LK_RELEASE);
130		}
131		else
132			dtmpvp = ldvp;
133
134		error = VOP_LOOKUP(dtmpvp, &vp, cnp);
135
136		if (dtmpvp == udvp && ldvp != NULLVP) {
137			VOP_UNLOCK(udvp, LK_RELEASE);
138			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
139		}
140
141		if (error == 0) {
142			/*
143			 * Exchange lock and reference from vp to
144			 * dunp->un_dvp. vp is upper/lower vnode, but it
145			 * will need to return the unionfs vnode.
146			 */
147			if (nameiop == DELETE  || nameiop == RENAME ||
148			    (cnp->cn_lkflags & LK_TYPE_MASK))
149				VOP_UNLOCK(vp, LK_RELEASE);
150			vrele(vp);
151
152			VOP_UNLOCK(dvp, LK_RELEASE);
153			*(ap->a_vpp) = dunp->un_dvp;
154			vref(dunp->un_dvp);
155
156			if (nameiop == DELETE || nameiop == RENAME)
157				vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
158			else if (cnp->cn_lkflags & LK_TYPE_MASK)
159				vn_lock(dunp->un_dvp, cnp->cn_lkflags |
160				    LK_RETRY);
161
162			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
163		} else if (error == ENOENT && (cnflags & MAKEENTRY) &&
164		    nameiop != CREATE)
165			cache_enter(dvp, NULLVP, cnp);
166
167		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
168
169		return (error);
170	}
171
172	/*
173	 * lookup upper layer
174	 */
175	if (udvp != NULLVP) {
176		uerror = VOP_LOOKUP(udvp, &uvp, cnp);
177
178		if (uerror == 0) {
179			if (udvp == uvp) {	/* is dot */
180				vrele(uvp);
181				*(ap->a_vpp) = dvp;
182				vref(dvp);
183
184				UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror);
185
186				return (uerror);
187			}
188			if (nameiop == DELETE || nameiop == RENAME ||
189			    (cnp->cn_lkflags & LK_TYPE_MASK))
190				VOP_UNLOCK(uvp, LK_RELEASE);
191		}
192
193		/* check whiteout */
194		if (uerror == ENOENT || uerror == EJUSTRETURN)
195			if (cnp->cn_flags & ISWHITEOUT)
196				iswhiteout = 1;	/* don't lookup lower */
197		if (iswhiteout == 0 && ldvp != NULLVP)
198			if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) &&
199			    (va.va_flags & OPAQUE))
200				iswhiteout = 1;	/* don't lookup lower */
201#if 0
202		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr);
203#endif
204	}
205
206	/*
207	 * lookup lower layer
208	 */
209	if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
210		/* always op is LOOKUP */
211		cnp->cn_nameiop = LOOKUP;
212		cnflagsbk = cnp->cn_flags;
213		cnp->cn_flags = cnflags;
214
215		lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
216
217		cnp->cn_nameiop = nameiop;
218		if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
219			cnp->cn_flags = cnflagsbk;
220
221		if (lerror == 0) {
222			if (ldvp == lvp) {	/* is dot */
223				if (uvp != NULLVP)
224					vrele(uvp);	/* no need? */
225				vrele(lvp);
226				*(ap->a_vpp) = dvp;
227				vref(dvp);
228
229				UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror);
230
231				return (lerror);
232			}
233			if (cnp->cn_lkflags & LK_TYPE_MASK)
234				VOP_UNLOCK(lvp, LK_RELEASE);
235		}
236	}
237
238	/*
239	 * check lookup result
240	 */
241	if (uvp == NULLVP && lvp == NULLVP) {
242		UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n",
243		    (udvp != NULLVP ? uerror : lerror));
244		return (udvp != NULLVP ? uerror : lerror);
245	}
246
247	/*
248	 * check vnode type
249	 */
250	if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
251		vrele(lvp);
252		lvp = NULLVP;
253	}
254
255	/*
256	 * check shadow dir
257	 */
258	if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
259	    lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
260	    !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
261	    (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
262		/* get unionfs vnode in order to create a new shadow dir. */
263		error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
264		    cnp, td);
265		if (error != 0)
266			goto unionfs_lookup_out;
267
268		if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
269			VOP_UNLOCK(vp, LK_RELEASE);
270		if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
271			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
272			lockflag = 1;
273		}
274		error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
275		    udvp, VTOUNIONFS(vp), cnp, td);
276		if (lockflag != 0)
277			VOP_UNLOCK(vp, LK_RELEASE);
278		if (error != 0) {
279			UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
280			if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
281				vput(vp);
282			else
283				vrele(vp);
284			goto unionfs_lookup_out;
285		}
286		if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
287			vn_lock(vp, LK_SHARED | LK_RETRY);
288	}
289	/*
290	 * get unionfs vnode.
291	 */
292	else {
293		if (uvp != NULLVP)
294			error = uerror;
295		else
296			error = lerror;
297		if (error != 0)
298			goto unionfs_lookup_out;
299		/*
300		 * get socket vnode.
301		 */
302		if (uvp != NULLVP && uvp->v_type == VSOCK) {
303			vp = uvp;
304			vref(vp);
305			if (cnp->cn_lkflags & LK_TYPE_MASK)
306				vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
307		}
308		else if (lvp != NULLVP && lvp->v_type == VSOCK) {
309			vp = lvp;
310			vref(vp);
311			if (cnp->cn_lkflags & LK_TYPE_MASK)
312				vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
313		}
314		/*
315		 * get unionfs vnode.
316		 */
317		else
318			error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
319			    dvp, &vp, cnp, td);
320		if (error != 0) {
321			UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode.");
322			goto unionfs_lookup_out;
323		}
324		if ((nameiop == DELETE || nameiop == RENAME) &&
325		    (cnp->cn_lkflags & LK_TYPE_MASK) == 0)
326			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
327	}
328
329	*(ap->a_vpp) = vp;
330
331	if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK)
332		cache_enter(dvp, vp, cnp);
333
334unionfs_lookup_out:
335	if (uvp != NULLVP)
336		vrele(uvp);
337	if (lvp != NULLVP)
338		vrele(lvp);
339
340	if (error == ENOENT && (cnflags & MAKEENTRY) && nameiop != CREATE)
341		cache_enter(dvp, NULLVP, cnp);
342
343	UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
344
345	return (error);
346}
347
348static int
349unionfs_create(struct vop_create_args *ap)
350{
351	struct unionfs_node *dunp;
352	struct componentname *cnp;
353	struct vnode   *udvp;
354	struct vnode   *vp;
355	int		error;
356
357	UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
358
359	KASSERT_UNIONFS_VNODE(ap->a_dvp);
360
361	dunp = VTOUNIONFS(ap->a_dvp);
362	cnp = ap->a_cnp;
363	udvp = dunp->un_uppervp;
364	error = EROFS;
365
366	if (udvp != NULLVP) {
367		error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
368		if (error != 0)
369			goto unionfs_create_abort;
370
371		if (vp->v_type == VSOCK)
372			*(ap->a_vpp) = vp;
373		else {
374			VOP_UNLOCK(vp, LK_RELEASE);
375			error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
376			    ap->a_dvp, ap->a_vpp, cnp, curthread);
377			vrele(vp);
378		}
379	}
380
381unionfs_create_abort:
382	UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
383
384	return (error);
385}
386
387static int
388unionfs_whiteout(struct vop_whiteout_args *ap)
389{
390	struct unionfs_node *dunp;
391	struct componentname *cnp;
392	struct vnode   *udvp;
393	int		error;
394
395	UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
396
397	KASSERT_UNIONFS_VNODE(ap->a_dvp);
398
399	dunp = VTOUNIONFS(ap->a_dvp);
400	cnp = ap->a_cnp;
401	udvp = dunp->un_uppervp;
402	error = EOPNOTSUPP;
403
404	if (udvp != NULLVP) {
405		switch (ap->a_flags) {
406		case CREATE:
407		case DELETE:
408		case LOOKUP:
409			error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
410			break;
411		default:
412			error = EINVAL;
413			break;
414		}
415	}
416
417	UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
418
419	return (error);
420}
421
422static int
423unionfs_mknod(struct vop_mknod_args *ap)
424{
425	struct unionfs_node *dunp;
426	struct componentname *cnp;
427	struct vnode   *udvp;
428	struct vnode   *vp;
429	int		error;
430
431	UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
432
433	KASSERT_UNIONFS_VNODE(ap->a_dvp);
434
435	dunp = VTOUNIONFS(ap->a_dvp);
436	cnp = ap->a_cnp;
437	udvp = dunp->un_uppervp;
438	error = EROFS;
439
440	if (udvp != NULLVP) {
441		error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
442		if (error != 0)
443			goto unionfs_mknod_abort;
444
445		if (vp->v_type == VSOCK)
446			*(ap->a_vpp) = vp;
447		else {
448			VOP_UNLOCK(vp, LK_RELEASE);
449			error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
450			    ap->a_dvp, ap->a_vpp, cnp, curthread);
451			vrele(vp);
452		}
453	}
454
455unionfs_mknod_abort:
456	UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
457
458	return (error);
459}
460
461static int
462unionfs_open(struct vop_open_args *ap)
463{
464	int		error;
465	struct unionfs_node *unp;
466	struct unionfs_node_status *unsp;
467	struct vnode   *uvp;
468	struct vnode   *lvp;
469	struct vnode   *targetvp;
470	struct ucred   *cred;
471	struct thread  *td;
472
473	UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
474
475	KASSERT_UNIONFS_VNODE(ap->a_vp);
476
477	error = 0;
478	unp = VTOUNIONFS(ap->a_vp);
479	uvp = unp->un_uppervp;
480	lvp = unp->un_lowervp;
481	targetvp = NULLVP;
482	cred = ap->a_cred;
483	td = ap->a_td;
484
485	unionfs_get_node_status(unp, td, &unsp);
486
487	if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
488		/* vnode is already opend. */
489		if (unsp->uns_upper_opencnt > 0)
490			targetvp = uvp;
491		else
492			targetvp = lvp;
493
494		if (targetvp == lvp &&
495		    (ap->a_mode & FWRITE) && lvp->v_type == VREG)
496			targetvp = NULLVP;
497	}
498	if (targetvp == NULLVP) {
499		if (uvp == NULLVP) {
500			if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
501				error = unionfs_copyfile(unp,
502				    !(ap->a_mode & O_TRUNC), cred, td);
503				if (error != 0)
504					goto unionfs_open_abort;
505				targetvp = uvp = unp->un_uppervp;
506			} else
507				targetvp = lvp;
508		} else
509			targetvp = uvp;
510	}
511
512	error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
513	if (error == 0) {
514		if (targetvp == uvp) {
515			if (uvp->v_type == VDIR && lvp != NULLVP &&
516			    unsp->uns_lower_opencnt <= 0) {
517				/* open lower for readdir */
518				error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
519				if (error != 0) {
520					VOP_CLOSE(uvp, ap->a_mode, cred, td);
521					goto unionfs_open_abort;
522				}
523				unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
524				unsp->uns_lower_opencnt++;
525			}
526			unsp->uns_upper_opencnt++;
527		} else {
528			unsp->uns_lower_opencnt++;
529			unsp->uns_lower_openmode = ap->a_mode;
530		}
531		ap->a_vp->v_object = targetvp->v_object;
532	}
533
534unionfs_open_abort:
535	if (error != 0)
536		unionfs_tryrem_node_status(unp, unsp);
537
538	UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
539
540	return (error);
541}
542
543static int
544unionfs_close(struct vop_close_args *ap)
545{
546	int		error;
547	int		locked;
548	struct unionfs_node *unp;
549	struct unionfs_node_status *unsp;
550	struct ucred   *cred;
551	struct thread  *td;
552	struct vnode   *vp;
553	struct vnode   *ovp;
554
555	UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
556
557	KASSERT_UNIONFS_VNODE(ap->a_vp);
558
559	locked = 0;
560	vp = ap->a_vp;
561	unp = VTOUNIONFS(vp);
562	cred = ap->a_cred;
563	td = ap->a_td;
564
565	if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
566		if (vn_lock(vp, LK_UPGRADE) != 0)
567			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
568		locked = 1;
569	}
570	unionfs_get_node_status(unp, td, &unsp);
571
572	if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
573#ifdef DIAGNOSTIC
574		printf("unionfs_close: warning: open count is 0\n");
575#endif
576		if (unp->un_uppervp != NULLVP)
577			ovp = unp->un_uppervp;
578		else
579			ovp = unp->un_lowervp;
580	} else if (unsp->uns_upper_opencnt > 0)
581		ovp = unp->un_uppervp;
582	else
583		ovp = unp->un_lowervp;
584
585	error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
586
587	if (error != 0)
588		goto unionfs_close_abort;
589
590	vp->v_object = ovp->v_object;
591
592	if (ovp == unp->un_uppervp) {
593		unsp->uns_upper_opencnt--;
594		if (unsp->uns_upper_opencnt == 0) {
595			if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
596				VOP_CLOSE(unp->un_lowervp, FREAD, cred, td);
597				unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
598				unsp->uns_lower_opencnt--;
599			}
600			if (unsp->uns_lower_opencnt > 0)
601				vp->v_object = unp->un_lowervp->v_object;
602		}
603	} else
604		unsp->uns_lower_opencnt--;
605
606unionfs_close_abort:
607	unionfs_tryrem_node_status(unp, unsp);
608
609	if (locked != 0)
610		vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
611
612	UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
613
614	return (error);
615}
616
617/*
618 * Check the access mode toward shadow file/dir.
619 */
620static int
621unionfs_check_corrected_access(accmode_t accmode,
622			     struct vattr *va,
623			     struct ucred *cred)
624{
625	int		count;
626	uid_t		uid;	/* upper side vnode's uid */
627	gid_t		gid;	/* upper side vnode's gid */
628	u_short		vmode;	/* upper side vnode's mode */
629	u_short		mask;
630
631	mask = 0;
632	uid = va->va_uid;
633	gid = va->va_gid;
634	vmode = va->va_mode;
635
636	/* check owner */
637	if (cred->cr_uid == uid) {
638		if (accmode & VEXEC)
639			mask |= S_IXUSR;
640		if (accmode & VREAD)
641			mask |= S_IRUSR;
642		if (accmode & VWRITE)
643			mask |= S_IWUSR;
644		return ((vmode & mask) == mask ? 0 : EACCES);
645	}
646
647	/* check group */
648	count = 0;
649	if (groupmember(gid, cred)) {
650		if (accmode & VEXEC)
651			mask |= S_IXGRP;
652		if (accmode & VREAD)
653			mask |= S_IRGRP;
654		if (accmode & VWRITE)
655			mask |= S_IWGRP;
656		return ((vmode & mask) == mask ? 0 : EACCES);
657	}
658
659	/* check other */
660	if (accmode & VEXEC)
661		mask |= S_IXOTH;
662	if (accmode & VREAD)
663		mask |= S_IROTH;
664	if (accmode & VWRITE)
665		mask |= S_IWOTH;
666
667	return ((vmode & mask) == mask ? 0 : EACCES);
668}
669
670static int
671unionfs_access(struct vop_access_args *ap)
672{
673	struct unionfs_mount *ump;
674	struct unionfs_node *unp;
675	struct vnode   *uvp;
676	struct vnode   *lvp;
677	struct thread  *td;
678	struct vattr	va;
679	accmode_t	accmode;
680	int		error;
681
682	UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
683
684	KASSERT_UNIONFS_VNODE(ap->a_vp);
685
686	ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
687	unp = VTOUNIONFS(ap->a_vp);
688	uvp = unp->un_uppervp;
689	lvp = unp->un_lowervp;
690	td = ap->a_td;
691	accmode = ap->a_accmode;
692	error = EACCES;
693
694	if ((accmode & VWRITE) &&
695	    (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
696		switch (ap->a_vp->v_type) {
697		case VREG:
698		case VDIR:
699		case VLNK:
700			return (EROFS);
701		default:
702			break;
703		}
704	}
705
706	if (uvp != NULLVP) {
707		error = VOP_ACCESS(uvp, accmode, ap->a_cred, td);
708
709		UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
710
711		return (error);
712	}
713
714	if (lvp != NULLVP) {
715		if (accmode & VWRITE) {
716			if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
717				switch (ap->a_vp->v_type) {
718				case VREG:
719				case VDIR:
720				case VLNK:
721					return (EROFS);
722				default:
723					break;
724				}
725			} else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
726				/* check shadow file/dir */
727				if (ump->um_copymode != UNIONFS_TRANSPARENT) {
728					error = unionfs_create_uppervattr(ump,
729					    lvp, &va, ap->a_cred, td);
730					if (error != 0)
731						return (error);
732
733					error = unionfs_check_corrected_access(
734					    accmode, &va, ap->a_cred);
735					if (error != 0)
736						return (error);
737				}
738			}
739			accmode &= ~(VWRITE | VAPPEND);
740			accmode |= VREAD; /* will copy to upper */
741		}
742		error = VOP_ACCESS(lvp, accmode, ap->a_cred, td);
743	}
744
745	UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
746
747	return (error);
748}
749
750static int
751unionfs_getattr(struct vop_getattr_args *ap)
752{
753	int		error;
754	struct unionfs_node *unp;
755	struct unionfs_mount *ump;
756	struct vnode   *uvp;
757	struct vnode   *lvp;
758	struct thread  *td;
759	struct vattr	va;
760
761	UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
762
763	KASSERT_UNIONFS_VNODE(ap->a_vp);
764
765	unp = VTOUNIONFS(ap->a_vp);
766	ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
767	uvp = unp->un_uppervp;
768	lvp = unp->un_lowervp;
769	td = curthread;
770
771	if (uvp != NULLVP) {
772		if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
773			ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
774
775		UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
776		    ap->a_vap->va_mode, ap->a_vap->va_uid,
777		    ap->a_vap->va_gid, error);
778
779		return (error);
780	}
781
782	error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
783
784	if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
785		/* correct the attr toward shadow file/dir. */
786		if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
787			unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
788			ap->a_vap->va_mode = va.va_mode;
789			ap->a_vap->va_uid = va.va_uid;
790			ap->a_vap->va_gid = va.va_gid;
791		}
792	}
793
794	if (error == 0)
795		ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
796
797	UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
798	    ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
799
800	return (error);
801}
802
803static int
804unionfs_setattr(struct vop_setattr_args *ap)
805{
806	int		error;
807	struct unionfs_node *unp;
808	struct vnode   *uvp;
809	struct vnode   *lvp;
810	struct thread  *td;
811	struct vattr   *vap;
812
813	UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
814
815	KASSERT_UNIONFS_VNODE(ap->a_vp);
816
817	error = EROFS;
818	unp = VTOUNIONFS(ap->a_vp);
819	uvp = unp->un_uppervp;
820	lvp = unp->un_lowervp;
821	td = curthread;
822	vap = ap->a_vap;
823
824	if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
825	    (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
826	     vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
827	     vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
828		return (EROFS);
829
830	if (uvp == NULLVP && lvp->v_type == VREG) {
831		error = unionfs_copyfile(unp, (vap->va_size != 0),
832		    ap->a_cred, td);
833		if (error != 0)
834			return (error);
835		uvp = unp->un_uppervp;
836	}
837
838	if (uvp != NULLVP)
839		error = VOP_SETATTR(uvp, vap, ap->a_cred);
840
841	UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
842
843	return (error);
844}
845
846static int
847unionfs_read(struct vop_read_args *ap)
848{
849	int		error;
850	struct unionfs_node *unp;
851	struct vnode   *tvp;
852
853	/* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
854
855	KASSERT_UNIONFS_VNODE(ap->a_vp);
856
857	unp = VTOUNIONFS(ap->a_vp);
858	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
859
860	error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
861
862	/* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
863
864	return (error);
865}
866
867static int
868unionfs_write(struct vop_write_args *ap)
869{
870	int		error;
871	struct unionfs_node *unp;
872	struct vnode   *tvp;
873
874	/* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
875
876	KASSERT_UNIONFS_VNODE(ap->a_vp);
877
878	unp = VTOUNIONFS(ap->a_vp);
879	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
880
881	error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
882
883	/* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
884
885	return (error);
886}
887
888static int
889unionfs_ioctl(struct vop_ioctl_args *ap)
890{
891	int error;
892	struct unionfs_node *unp;
893	struct unionfs_node_status *unsp;
894	struct vnode   *ovp;
895
896	UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
897
898	KASSERT_UNIONFS_VNODE(ap->a_vp);
899
900 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
901	unp = VTOUNIONFS(ap->a_vp);
902	unionfs_get_node_status(unp, ap->a_td, &unsp);
903	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
904	unionfs_tryrem_node_status(unp, unsp);
905	VOP_UNLOCK(ap->a_vp, LK_RELEASE);
906
907	if (ovp == NULLVP)
908		return (EBADF);
909
910	error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
911	    ap->a_cred, ap->a_td);
912
913	UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error);
914
915	return (error);
916}
917
918static int
919unionfs_poll(struct vop_poll_args *ap)
920{
921	struct unionfs_node *unp;
922	struct unionfs_node_status *unsp;
923	struct vnode   *ovp;
924
925	KASSERT_UNIONFS_VNODE(ap->a_vp);
926
927 	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
928	unp = VTOUNIONFS(ap->a_vp);
929	unionfs_get_node_status(unp, ap->a_td, &unsp);
930	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
931	unionfs_tryrem_node_status(unp, unsp);
932	VOP_UNLOCK(ap->a_vp, LK_RELEASE);
933
934	if (ovp == NULLVP)
935		return (EBADF);
936
937	return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
938}
939
940static int
941unionfs_fsync(struct vop_fsync_args *ap)
942{
943	struct unionfs_node *unp;
944	struct unionfs_node_status *unsp;
945	struct vnode   *ovp;
946
947	KASSERT_UNIONFS_VNODE(ap->a_vp);
948
949	unp = VTOUNIONFS(ap->a_vp);
950	unionfs_get_node_status(unp, ap->a_td, &unsp);
951	ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
952	unionfs_tryrem_node_status(unp, unsp);
953
954	if (ovp == NULLVP)
955		return (EBADF);
956
957	return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td));
958}
959
960static int
961unionfs_remove(struct vop_remove_args *ap)
962{
963	int		error;
964	char	       *path;
965	struct unionfs_node *dunp;
966	struct unionfs_node *unp;
967	struct unionfs_mount *ump;
968	struct vnode   *udvp;
969	struct vnode   *uvp;
970	struct vnode   *lvp;
971	struct vnode   *vp;
972	struct componentname *cnp;
973	struct componentname cn;
974	struct thread  *td;
975
976	UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
977
978	KASSERT_UNIONFS_VNODE(ap->a_dvp);
979
980	error = 0;
981	dunp = VTOUNIONFS(ap->a_dvp);
982	udvp = dunp->un_uppervp;
983	cnp = ap->a_cnp;
984	td = curthread;
985
986	if (ap->a_vp->v_op != &unionfs_vnodeops) {
987		if (ap->a_vp->v_type != VSOCK)
988			return (EINVAL);
989		ump = NULL;
990		vp = uvp = lvp = NULLVP;
991		/* search vnode */
992		VOP_UNLOCK(ap->a_vp, LK_RELEASE);
993		error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
994		    cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE);
995		if (error != 0 && error != ENOENT) {
996			vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
997			return (error);
998		}
999
1000		if (error == 0 && vp == ap->a_vp) {
1001			/* target vnode in upper */
1002			uvp = vp;
1003			vrele(vp);
1004			path = NULL;
1005		} else {
1006			/* target vnode in lower */
1007			if (vp != NULLVP) {
1008				if (udvp == vp)
1009					vrele(vp);
1010				else
1011					vput(vp);
1012			}
1013			vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1014			lvp = ap->a_vp;
1015			path = ap->a_cnp->cn_nameptr;
1016		}
1017	} else {
1018		ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1019		unp = VTOUNIONFS(ap->a_vp);
1020		uvp = unp->un_uppervp;
1021		lvp = unp->un_lowervp;
1022		path = unp->un_path;
1023	}
1024
1025	if (udvp == NULLVP)
1026		return (EROFS);
1027
1028	if (uvp != NULLVP) {
1029		/*
1030		 * XXX: if the vnode type is VSOCK, it will create whiteout
1031		 *      after remove.
1032		 */
1033		if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
1034		    lvp != NULLVP)
1035			cnp->cn_flags |= DOWHITEOUT;
1036		error = VOP_REMOVE(udvp, uvp, cnp);
1037	} else if (lvp != NULLVP)
1038		error = unionfs_mkwhiteout(udvp, cnp, td, path);
1039
1040	UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
1041
1042	return (error);
1043}
1044
1045static int
1046unionfs_link(struct vop_link_args *ap)
1047{
1048	int		error;
1049	int		needrelookup;
1050	struct unionfs_node *dunp;
1051	struct unionfs_node *unp;
1052	struct vnode   *udvp;
1053	struct vnode   *uvp;
1054	struct componentname *cnp;
1055	struct thread  *td;
1056
1057	UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
1058
1059	KASSERT_UNIONFS_VNODE(ap->a_tdvp);
1060	KASSERT_UNIONFS_VNODE(ap->a_vp);
1061
1062	error = 0;
1063	needrelookup = 0;
1064	dunp = VTOUNIONFS(ap->a_tdvp);
1065	unp = NULL;
1066	udvp = dunp->un_uppervp;
1067	uvp = NULLVP;
1068	cnp = ap->a_cnp;
1069	td = curthread;
1070
1071	if (udvp == NULLVP)
1072		return (EROFS);
1073
1074	if (ap->a_vp->v_op != &unionfs_vnodeops)
1075		uvp = ap->a_vp;
1076	else {
1077		unp = VTOUNIONFS(ap->a_vp);
1078
1079		if (unp->un_uppervp == NULLVP) {
1080			if (ap->a_vp->v_type != VREG)
1081				return (EOPNOTSUPP);
1082
1083			error = unionfs_copyfile(unp, 1, cnp->cn_cred, td);
1084			if (error != 0)
1085				return (error);
1086			needrelookup = 1;
1087		}
1088		uvp = unp->un_uppervp;
1089	}
1090
1091	if (needrelookup != 0)
1092		error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td);
1093
1094	if (error == 0)
1095		error = VOP_LINK(udvp, uvp, cnp);
1096
1097	UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1098
1099	return (error);
1100}
1101
1102static int
1103unionfs_rename(struct vop_rename_args *ap)
1104{
1105	int		error;
1106	struct vnode   *fdvp;
1107	struct vnode   *fvp;
1108	struct componentname *fcnp;
1109	struct vnode   *tdvp;
1110	struct vnode   *tvp;
1111	struct componentname *tcnp;
1112	struct vnode   *ltdvp;
1113	struct vnode   *ltvp;
1114	struct thread  *td;
1115
1116	/* rename target vnodes */
1117	struct vnode   *rfdvp;
1118	struct vnode   *rfvp;
1119	struct vnode   *rtdvp;
1120	struct vnode   *rtvp;
1121
1122	int		needrelookup;
1123	struct unionfs_mount *ump;
1124	struct unionfs_node *unp;
1125
1126	UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1127
1128	error = 0;
1129	fdvp = ap->a_fdvp;
1130	fvp = ap->a_fvp;
1131	fcnp = ap->a_fcnp;
1132	tdvp = ap->a_tdvp;
1133	tvp = ap->a_tvp;
1134	tcnp = ap->a_tcnp;
1135	ltdvp = NULLVP;
1136	ltvp = NULLVP;
1137	td = curthread;
1138	rfdvp = fdvp;
1139	rfvp = fvp;
1140	rtdvp = tdvp;
1141	rtvp = tvp;
1142	needrelookup = 0;
1143
1144#ifdef DIAGNOSTIC
1145	if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF))
1146		panic("unionfs_rename: no name");
1147#endif
1148
1149	/* check for cross device rename */
1150	if (fvp->v_mount != tdvp->v_mount ||
1151	    (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
1152		if (fvp->v_op != &unionfs_vnodeops)
1153			error = ENODEV;
1154		else
1155			error = EXDEV;
1156		goto unionfs_rename_abort;
1157	}
1158
1159	/* Renaming a file to itself has no effect. */
1160	if (fvp == tvp)
1161		goto unionfs_rename_abort;
1162
1163	/*
1164	 * from/to vnode is unionfs node.
1165	 */
1166
1167	KASSERT_UNIONFS_VNODE(fdvp);
1168	KASSERT_UNIONFS_VNODE(fvp);
1169	KASSERT_UNIONFS_VNODE(tdvp);
1170	if (tvp != NULLVP)
1171		KASSERT_UNIONFS_VNODE(tvp);
1172
1173	unp = VTOUNIONFS(fdvp);
1174#ifdef UNIONFS_IDBG_RENAME
1175	UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp);
1176#endif
1177	if (unp->un_uppervp == NULLVP) {
1178		error = ENODEV;
1179		goto unionfs_rename_abort;
1180	}
1181	rfdvp = unp->un_uppervp;
1182	vref(rfdvp);
1183
1184	unp = VTOUNIONFS(fvp);
1185#ifdef UNIONFS_IDBG_RENAME
1186	UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp);
1187#endif
1188	ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
1189	if (unp->un_uppervp == NULLVP) {
1190		switch (fvp->v_type) {
1191		case VREG:
1192			if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1193				goto unionfs_rename_abort;
1194			error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
1195			VOP_UNLOCK(fvp, LK_RELEASE);
1196			if (error != 0)
1197				goto unionfs_rename_abort;
1198			break;
1199		case VDIR:
1200			if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1201				goto unionfs_rename_abort;
1202			error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
1203			VOP_UNLOCK(fvp, LK_RELEASE);
1204			if (error != 0)
1205				goto unionfs_rename_abort;
1206			break;
1207		default:
1208			error = ENODEV;
1209			goto unionfs_rename_abort;
1210		}
1211
1212		needrelookup = 1;
1213	}
1214
1215	if (unp->un_lowervp != NULLVP)
1216		fcnp->cn_flags |= DOWHITEOUT;
1217	rfvp = unp->un_uppervp;
1218	vref(rfvp);
1219
1220	unp = VTOUNIONFS(tdvp);
1221#ifdef UNIONFS_IDBG_RENAME
1222	UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp);
1223#endif
1224	if (unp->un_uppervp == NULLVP) {
1225		error = ENODEV;
1226		goto unionfs_rename_abort;
1227	}
1228	rtdvp = unp->un_uppervp;
1229	ltdvp = unp->un_lowervp;
1230	vref(rtdvp);
1231
1232	if (tdvp == tvp) {
1233		rtvp = rtdvp;
1234		vref(rtvp);
1235	} else if (tvp != NULLVP) {
1236		unp = VTOUNIONFS(tvp);
1237#ifdef UNIONFS_IDBG_RENAME
1238		UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp);
1239#endif
1240		if (unp->un_uppervp == NULLVP)
1241			rtvp = NULLVP;
1242		else {
1243			if (tvp->v_type == VDIR) {
1244				error = EINVAL;
1245				goto unionfs_rename_abort;
1246			}
1247			rtvp = unp->un_uppervp;
1248			ltvp = unp->un_lowervp;
1249			vref(rtvp);
1250		}
1251	}
1252
1253	if (rfvp == rtvp)
1254		goto unionfs_rename_abort;
1255
1256	if (needrelookup != 0) {
1257		if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
1258			goto unionfs_rename_abort;
1259		error = unionfs_relookup_for_delete(fdvp, fcnp, td);
1260		VOP_UNLOCK(fdvp, LK_RELEASE);
1261		if (error != 0)
1262			goto unionfs_rename_abort;
1263
1264		/* Locke of tvp is canceled in order to avoid recursive lock. */
1265		if (tvp != NULLVP && tvp != tdvp)
1266			VOP_UNLOCK(tvp, LK_RELEASE);
1267		error = unionfs_relookup_for_rename(tdvp, tcnp, td);
1268		if (tvp != NULLVP && tvp != tdvp)
1269			vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1270		if (error != 0)
1271			goto unionfs_rename_abort;
1272	}
1273
1274	error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1275
1276	if (error == 0) {
1277		if (rtvp != NULLVP && rtvp->v_type == VDIR)
1278			cache_purge(tdvp);
1279		if (fvp->v_type == VDIR && fdvp != tdvp)
1280			cache_purge(fdvp);
1281	}
1282
1283	if (ltdvp != NULLVP)
1284		VOP_UNLOCK(ltdvp, LK_RELEASE);
1285	if (tdvp != rtdvp)
1286		vrele(tdvp);
1287	if (ltvp != NULLVP)
1288		VOP_UNLOCK(ltvp, LK_RELEASE);
1289	if (tvp != rtvp && tvp != NULLVP) {
1290		if (rtvp == NULLVP)
1291			vput(tvp);
1292		else
1293			vrele(tvp);
1294	}
1295	if (fdvp != rfdvp)
1296		vrele(fdvp);
1297	if (fvp != rfvp)
1298		vrele(fvp);
1299
1300	UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1301
1302	return (error);
1303
1304unionfs_rename_abort:
1305	vput(tdvp);
1306	if (tdvp != rtdvp)
1307		vrele(rtdvp);
1308	if (tvp != NULLVP) {
1309		if (tdvp != tvp)
1310			vput(tvp);
1311		else
1312			vrele(tvp);
1313	}
1314	if (tvp != rtvp && rtvp != NULLVP)
1315		vrele(rtvp);
1316	if (fdvp != rfdvp)
1317		vrele(rfdvp);
1318	if (fvp != rfvp)
1319		vrele(rfvp);
1320	vrele(fdvp);
1321	vrele(fvp);
1322
1323	UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1324
1325	return (error);
1326}
1327
1328static int
1329unionfs_mkdir(struct vop_mkdir_args *ap)
1330{
1331	int		error;
1332	int		lkflags;
1333	struct unionfs_node *dunp;
1334	struct componentname *cnp;
1335	struct thread  *td;
1336	struct vnode   *udvp;
1337	struct vnode   *uvp;
1338	struct vattr	va;
1339
1340	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1341
1342	KASSERT_UNIONFS_VNODE(ap->a_dvp);
1343
1344	error = EROFS;
1345	dunp = VTOUNIONFS(ap->a_dvp);
1346	cnp = ap->a_cnp;
1347	lkflags = cnp->cn_lkflags;
1348	td = curthread;
1349	udvp = dunp->un_uppervp;
1350
1351	if (udvp != NULLVP) {
1352		/* check opaque */
1353		if (!(cnp->cn_flags & ISWHITEOUT)) {
1354			error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1355			if (error != 0)
1356				return (error);
1357			if (va.va_flags & OPAQUE)
1358				cnp->cn_flags |= ISWHITEOUT;
1359		}
1360
1361		if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
1362			VOP_UNLOCK(uvp, LK_RELEASE);
1363			cnp->cn_lkflags = LK_EXCLUSIVE;
1364			error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1365			    ap->a_dvp, ap->a_vpp, cnp, td);
1366			cnp->cn_lkflags = lkflags;
1367			vrele(uvp);
1368		}
1369	}
1370
1371	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1372
1373	return (error);
1374}
1375
1376static int
1377unionfs_rmdir(struct vop_rmdir_args *ap)
1378{
1379	int		error;
1380	struct unionfs_node *dunp;
1381	struct unionfs_node *unp;
1382	struct unionfs_mount *ump;
1383	struct componentname *cnp;
1384	struct thread  *td;
1385	struct vnode   *udvp;
1386	struct vnode   *uvp;
1387	struct vnode   *lvp;
1388
1389	UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1390
1391	KASSERT_UNIONFS_VNODE(ap->a_dvp);
1392	KASSERT_UNIONFS_VNODE(ap->a_vp);
1393
1394	error = 0;
1395	dunp = VTOUNIONFS(ap->a_dvp);
1396	unp = VTOUNIONFS(ap->a_vp);
1397	cnp = ap->a_cnp;
1398	td = curthread;
1399	udvp = dunp->un_uppervp;
1400	uvp = unp->un_uppervp;
1401	lvp = unp->un_lowervp;
1402
1403	if (udvp == NULLVP)
1404		return (EROFS);
1405
1406	if (udvp == uvp)
1407		return (EOPNOTSUPP);
1408
1409	if (uvp != NULLVP) {
1410		if (lvp != NULLVP) {
1411			error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1412			if (error != 0)
1413				return (error);
1414		}
1415		ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1416		if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1417			cnp->cn_flags |= DOWHITEOUT;
1418		error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td);
1419		if (!error)
1420			error = VOP_RMDIR(udvp, uvp, cnp);
1421	}
1422	else if (lvp != NULLVP)
1423		error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path);
1424
1425	if (error == 0) {
1426		cache_purge(ap->a_dvp);
1427		cache_purge(ap->a_vp);
1428	}
1429
1430	UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1431
1432	return (error);
1433}
1434
1435static int
1436unionfs_symlink(struct vop_symlink_args *ap)
1437{
1438	int		error;
1439	int		lkflags;
1440	struct unionfs_node *dunp;
1441	struct componentname *cnp;
1442	struct thread  *td;
1443	struct vnode   *udvp;
1444	struct vnode   *uvp;
1445
1446	UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1447
1448	KASSERT_UNIONFS_VNODE(ap->a_dvp);
1449
1450	error = EROFS;
1451	dunp = VTOUNIONFS(ap->a_dvp);
1452	cnp = ap->a_cnp;
1453	lkflags = cnp->cn_lkflags;
1454	td = curthread;
1455	udvp = dunp->un_uppervp;
1456
1457	if (udvp != NULLVP) {
1458		error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1459		if (error == 0) {
1460			VOP_UNLOCK(uvp, LK_RELEASE);
1461			cnp->cn_lkflags = LK_EXCLUSIVE;
1462			error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1463			    ap->a_dvp, ap->a_vpp, cnp, td);
1464			cnp->cn_lkflags = lkflags;
1465			vrele(uvp);
1466		}
1467	}
1468
1469	UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1470
1471	return (error);
1472}
1473
1474static int
1475unionfs_readdir(struct vop_readdir_args *ap)
1476{
1477	int		error;
1478	int		eofflag;
1479	int		locked;
1480	int		uio_offset_bk;
1481	struct unionfs_node *unp;
1482	struct unionfs_node_status *unsp;
1483	struct uio     *uio;
1484	struct vnode   *vp;
1485	struct vnode   *uvp;
1486	struct vnode   *lvp;
1487	struct thread  *td;
1488	struct vattr    va;
1489
1490	int		ncookies_bk;
1491	u_long         *cookies_bk;
1492
1493	UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1494
1495	KASSERT_UNIONFS_VNODE(ap->a_vp);
1496
1497	error = 0;
1498	eofflag = 0;
1499	locked = 0;
1500	uio_offset_bk = 0;
1501	uio = ap->a_uio;
1502	uvp = NULLVP;
1503	lvp = NULLVP;
1504	td = uio->uio_td;
1505	ncookies_bk = 0;
1506	cookies_bk = NULL;
1507
1508	vp = ap->a_vp;
1509	if (vp->v_type != VDIR)
1510		return (ENOTDIR);
1511
1512	/* check the open count. unionfs needs to open before readdir. */
1513	if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
1514		if (vn_lock(vp, LK_UPGRADE) != 0)
1515			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1516		locked = 1;
1517	}
1518	unp = VTOUNIONFS(vp);
1519	if (unp == NULL)
1520		error = EBADF;
1521	else {
1522		uvp = unp->un_uppervp;
1523		lvp = unp->un_lowervp;
1524		unionfs_get_node_status(unp, td, &unsp);
1525		if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1526			(lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1527			unionfs_tryrem_node_status(unp, unsp);
1528			error = EBADF;
1529		}
1530	}
1531	if (locked)
1532		vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
1533	if (error != 0)
1534		goto unionfs_readdir_exit;
1535
1536	/* check opaque */
1537	if (uvp != NULLVP && lvp != NULLVP) {
1538		if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1539			goto unionfs_readdir_exit;
1540		if (va.va_flags & OPAQUE)
1541			lvp = NULLVP;
1542	}
1543
1544	/* upper only */
1545	if (uvp != NULLVP && lvp == NULLVP) {
1546		error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1547		    ap->a_ncookies, ap->a_cookies);
1548		unsp->uns_readdir_status = 0;
1549
1550		goto unionfs_readdir_exit;
1551	}
1552
1553	/* lower only */
1554	if (uvp == NULLVP && lvp != NULLVP) {
1555		error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1556		    ap->a_ncookies, ap->a_cookies);
1557		unsp->uns_readdir_status = 2;
1558
1559		goto unionfs_readdir_exit;
1560	}
1561
1562	/*
1563	 * readdir upper and lower
1564	 */
1565	KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
1566	KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
1567	if (uio->uio_offset == 0)
1568		unsp->uns_readdir_status = 0;
1569
1570	if (unsp->uns_readdir_status == 0) {
1571		/* read upper */
1572		error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1573				    ap->a_ncookies, ap->a_cookies);
1574
1575		if (error != 0 || eofflag == 0)
1576			goto unionfs_readdir_exit;
1577		unsp->uns_readdir_status = 1;
1578
1579		/*
1580		 * UFS(and other FS) needs size of uio_resid larger than
1581		 * DIRBLKSIZ.
1582		 * size of DIRBLKSIZ equals DEV_BSIZE.
1583		 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1584		 */
1585		if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1586			goto unionfs_readdir_exit;
1587
1588		/*
1589		 * Backup cookies.
1590		 * It prepares to readdir in lower.
1591		 */
1592		if (ap->a_ncookies != NULL) {
1593			ncookies_bk = *(ap->a_ncookies);
1594			*(ap->a_ncookies) = 0;
1595		}
1596		if (ap->a_cookies != NULL) {
1597			cookies_bk = *(ap->a_cookies);
1598			*(ap->a_cookies) = NULL;
1599		}
1600	}
1601
1602	/* initialize for readdir in lower */
1603	if (unsp->uns_readdir_status == 1) {
1604		unsp->uns_readdir_status = 2;
1605		/*
1606		 * Backup uio_offset. See the comment after the
1607		 * VOP_READDIR call on the lower layer.
1608		 */
1609		uio_offset_bk = uio->uio_offset;
1610		uio->uio_offset = 0;
1611	}
1612
1613	if (lvp == NULLVP) {
1614		error = EBADF;
1615		goto unionfs_readdir_exit;
1616	}
1617	/* read lower */
1618	error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1619			    ap->a_ncookies, ap->a_cookies);
1620
1621	/*
1622	 * We can't return an uio_offset of 0: this would trigger an
1623	 * infinite loop, because the next call to unionfs_readdir would
1624	 * always restart with the upper layer (uio_offset == 0) and
1625	 * always return some data.
1626	 *
1627	 * This happens when the lower layer root directory is removed.
1628	 * (A root directory deleting of unionfs should not be permitted.
1629	 *  But current VFS can not do it.)
1630	 */
1631	if (uio->uio_offset == 0)
1632		uio->uio_offset = uio_offset_bk;
1633
1634	if (cookies_bk != NULL) {
1635		/* merge cookies */
1636		int		size;
1637		u_long         *newcookies, *pos;
1638
1639		size = *(ap->a_ncookies) + ncookies_bk;
1640		newcookies = (u_long *) malloc(size * sizeof(u_long),
1641		    M_TEMP, M_WAITOK);
1642		pos = newcookies;
1643
1644		memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long));
1645		pos += ncookies_bk;
1646		memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long));
1647		free(cookies_bk, M_TEMP);
1648		free(*(ap->a_cookies), M_TEMP);
1649		*(ap->a_ncookies) = size;
1650		*(ap->a_cookies) = newcookies;
1651	}
1652
1653unionfs_readdir_exit:
1654	if (error != 0 && ap->a_eofflag != NULL)
1655		*(ap->a_eofflag) = 1;
1656
1657	UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1658
1659	return (error);
1660}
1661
1662static int
1663unionfs_readlink(struct vop_readlink_args *ap)
1664{
1665	int error;
1666	struct unionfs_node *unp;
1667	struct vnode   *vp;
1668
1669	UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1670
1671	KASSERT_UNIONFS_VNODE(ap->a_vp);
1672
1673	unp = VTOUNIONFS(ap->a_vp);
1674	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1675
1676	error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1677
1678	UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1679
1680	return (error);
1681}
1682
1683static int
1684unionfs_getwritemount(struct vop_getwritemount_args *ap)
1685{
1686	int		error;
1687	struct vnode   *uvp;
1688	struct vnode   *vp;
1689
1690	UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
1691
1692	error = 0;
1693	vp = ap->a_vp;
1694
1695	if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY))
1696		return (EACCES);
1697
1698	KASSERT_UNIONFS_VNODE(vp);
1699
1700	uvp = UNIONFSVPTOUPPERVP(vp);
1701	if (uvp == NULLVP && VREG == vp->v_type)
1702		uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp);
1703
1704	if (uvp != NULLVP)
1705		error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
1706	else {
1707		VI_LOCK(vp);
1708		if (vp->v_iflag & VI_FREE)
1709			error = EOPNOTSUPP;
1710		else
1711			error = EACCES;
1712		VI_UNLOCK(vp);
1713	}
1714
1715	UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
1716
1717	return (error);
1718}
1719
1720static int
1721unionfs_inactive(struct vop_inactive_args *ap)
1722{
1723	ap->a_vp->v_object = NULL;
1724	vrecycle(ap->a_vp);
1725	return (0);
1726}
1727
1728static int
1729unionfs_reclaim(struct vop_reclaim_args *ap)
1730{
1731	/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1732
1733	unionfs_noderem(ap->a_vp, ap->a_td);
1734
1735	/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1736
1737	return (0);
1738}
1739
1740static int
1741unionfs_print(struct vop_print_args *ap)
1742{
1743	struct unionfs_node *unp;
1744	/* struct unionfs_node_status *unsp; */
1745
1746	unp = VTOUNIONFS(ap->a_vp);
1747	/* unionfs_get_node_status(unp, curthread, &unsp); */
1748
1749	printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1750	    ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1751	/*
1752	printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1753	    unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1754	*/
1755
1756	if (unp->un_uppervp != NULLVP)
1757		vprint("unionfs: upper", unp->un_uppervp);
1758	if (unp->un_lowervp != NULLVP)
1759		vprint("unionfs: lower", unp->un_lowervp);
1760
1761	return (0);
1762}
1763
1764static int
1765unionfs_islocked(struct vop_islocked_args *ap)
1766{
1767	struct unionfs_node *unp;
1768
1769	KASSERT_UNIONFS_VNODE(ap->a_vp);
1770
1771	unp = VTOUNIONFS(ap->a_vp);
1772	if (unp == NULL)
1773		return (vop_stdislocked(ap));
1774
1775	if (unp->un_uppervp != NULLVP)
1776		return (VOP_ISLOCKED(unp->un_uppervp));
1777	if (unp->un_lowervp != NULLVP)
1778		return (VOP_ISLOCKED(unp->un_lowervp));
1779	return (vop_stdislocked(ap));
1780}
1781
1782static int
1783unionfs_get_llt_revlock(struct vnode *vp, int flags)
1784{
1785	int revlock;
1786
1787	revlock = 0;
1788
1789	switch (flags & LK_TYPE_MASK) {
1790	case LK_SHARED:
1791		if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1792			revlock = LK_UPGRADE;
1793		else
1794			revlock = LK_RELEASE;
1795		break;
1796	case LK_EXCLUSIVE:
1797	case LK_UPGRADE:
1798		revlock = LK_RELEASE;
1799		break;
1800	case LK_DOWNGRADE:
1801		revlock = LK_UPGRADE;
1802		break;
1803	default:
1804		break;
1805	}
1806
1807	return (revlock);
1808}
1809
1810/*
1811 * The state of an acquired lock is adjusted similarly to
1812 * the time of error generating.
1813 * flags: LK_RELEASE or LK_UPGRADE
1814 */
1815static void
1816unionfs_revlock(struct vnode *vp, int flags)
1817{
1818	if (flags & LK_RELEASE)
1819		VOP_UNLOCK(vp, flags);
1820	else {
1821		/* UPGRADE */
1822		if (vn_lock(vp, flags) != 0)
1823			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1824	}
1825}
1826
1827static int
1828unionfs_lock(struct vop_lock1_args *ap)
1829{
1830	int		error;
1831	int		flags;
1832	int		revlock;
1833	int		interlock;
1834	int		uhold;
1835	struct mount   *mp;
1836	struct unionfs_mount *ump;
1837	struct unionfs_node *unp;
1838	struct vnode   *vp;
1839	struct vnode   *uvp;
1840	struct vnode   *lvp;
1841
1842	KASSERT_UNIONFS_VNODE(ap->a_vp);
1843
1844	error = 0;
1845	interlock = 1;
1846	uhold = 0;
1847	flags = ap->a_flags;
1848	vp = ap->a_vp;
1849
1850	if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
1851		return (VOP_UNLOCK(vp, flags | LK_RELEASE));
1852
1853	if ((flags & LK_INTERLOCK) == 0)
1854		VI_LOCK(vp);
1855
1856	mp = vp->v_mount;
1857	if (mp == NULL)
1858		goto unionfs_lock_null_vnode;
1859
1860	ump = MOUNTTOUNIONFSMOUNT(mp);
1861	unp = VTOUNIONFS(vp);
1862	if (ump == NULL || unp == NULL)
1863		goto unionfs_lock_null_vnode;
1864	lvp = unp->un_lowervp;
1865	uvp = unp->un_uppervp;
1866
1867	if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0)
1868		panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
1869
1870	if ((vp->v_iflag & VI_OWEINACT) != 0)
1871		flags |= LK_NOWAIT;
1872
1873	/*
1874	 * Sometimes, lower or upper is already exclusive locked.
1875	 * (ex. vfs_domount: mounted vnode is already locked.)
1876	 */
1877	if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
1878	    vp == ump->um_rootvp)
1879		flags |= LK_CANRECURSE;
1880
1881	if (lvp != NULLVP) {
1882		if (uvp != NULLVP && flags & LK_UPGRADE) {
1883			/* Share Lock is once released and a deadlock is avoided.  */
1884			VI_LOCK_FLAGS(uvp, MTX_DUPOK);
1885			vholdl(uvp);
1886			uhold = 1;
1887			VI_UNLOCK(vp);
1888			VOP_UNLOCK(uvp, LK_RELEASE | LK_INTERLOCK);
1889			VI_LOCK(vp);
1890			unp = VTOUNIONFS(vp);
1891			if (unp == NULL) {
1892				/* vnode is released. */
1893				VI_UNLOCK(vp);
1894				VOP_UNLOCK(lvp, LK_RELEASE);
1895				vdrop(uvp);
1896				return (EBUSY);
1897			}
1898		}
1899		VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1900		flags |= LK_INTERLOCK;
1901		vholdl(lvp);
1902
1903		VI_UNLOCK(vp);
1904		ap->a_flags &= ~LK_INTERLOCK;
1905
1906		error = VOP_LOCK(lvp, flags);
1907
1908		VI_LOCK(vp);
1909		unp = VTOUNIONFS(vp);
1910		if (unp == NULL) {
1911			/* vnode is released. */
1912			VI_UNLOCK(vp);
1913			if (error == 0)
1914				VOP_UNLOCK(lvp, LK_RELEASE);
1915			vdrop(lvp);
1916			if (uhold != 0)
1917				vdrop(uvp);
1918			return (vop_stdlock(ap));
1919		}
1920	}
1921
1922	if (error == 0 && uvp != NULLVP) {
1923		if (uhold && flags & LK_UPGRADE) {
1924			flags &= ~LK_TYPE_MASK;
1925			flags |= LK_EXCLUSIVE;
1926		}
1927		VI_LOCK_FLAGS(uvp, MTX_DUPOK);
1928		flags |= LK_INTERLOCK;
1929		if (uhold == 0) {
1930			vholdl(uvp);
1931			uhold = 1;
1932		}
1933
1934		VI_UNLOCK(vp);
1935		ap->a_flags &= ~LK_INTERLOCK;
1936
1937		error = VOP_LOCK(uvp, flags);
1938
1939		VI_LOCK(vp);
1940		unp = VTOUNIONFS(vp);
1941		if (unp == NULL) {
1942			/* vnode is released. */
1943			VI_UNLOCK(vp);
1944			if (error == 0)
1945				VOP_UNLOCK(uvp, LK_RELEASE);
1946			vdrop(uvp);
1947			if (lvp != NULLVP) {
1948				VOP_UNLOCK(lvp, LK_RELEASE);
1949				vdrop(lvp);
1950			}
1951			return (vop_stdlock(ap));
1952		}
1953		if (error != 0 && lvp != NULLVP) {
1954			/* rollback */
1955			VI_UNLOCK(vp);
1956			unionfs_revlock(lvp, revlock);
1957			interlock = 0;
1958		}
1959	}
1960
1961	if (interlock)
1962		VI_UNLOCK(vp);
1963	if (lvp != NULLVP)
1964		vdrop(lvp);
1965	if (uhold != 0)
1966		vdrop(uvp);
1967
1968	return (error);
1969
1970unionfs_lock_null_vnode:
1971	ap->a_flags |= LK_INTERLOCK;
1972	return (vop_stdlock(ap));
1973}
1974
1975static int
1976unionfs_unlock(struct vop_unlock_args *ap)
1977{
1978	int		error;
1979	int		flags;
1980	int		mtxlkflag;
1981	int		uhold;
1982	struct vnode   *vp;
1983	struct vnode   *lvp;
1984	struct vnode   *uvp;
1985	struct unionfs_node *unp;
1986
1987	KASSERT_UNIONFS_VNODE(ap->a_vp);
1988
1989	error = 0;
1990	mtxlkflag = 0;
1991	uhold = 0;
1992	flags = ap->a_flags | LK_RELEASE;
1993	vp = ap->a_vp;
1994
1995	if ((flags & LK_INTERLOCK) != 0)
1996		mtxlkflag = 1;
1997	else if (mtx_owned(VI_MTX(vp)) == 0) {
1998		VI_LOCK(vp);
1999		mtxlkflag = 2;
2000	}
2001
2002	unp = VTOUNIONFS(vp);
2003	if (unp == NULL)
2004		goto unionfs_unlock_null_vnode;
2005	lvp = unp->un_lowervp;
2006	uvp = unp->un_uppervp;
2007
2008	if (lvp != NULLVP) {
2009		VI_LOCK_FLAGS(lvp, MTX_DUPOK);
2010		flags |= LK_INTERLOCK;
2011		vholdl(lvp);
2012
2013		VI_UNLOCK(vp);
2014		ap->a_flags &= ~LK_INTERLOCK;
2015
2016		error = VOP_UNLOCK(lvp, flags);
2017
2018		VI_LOCK(vp);
2019	}
2020
2021	if (error == 0 && uvp != NULLVP) {
2022		VI_LOCK_FLAGS(uvp, MTX_DUPOK);
2023		flags |= LK_INTERLOCK;
2024		vholdl(uvp);
2025		uhold = 1;
2026
2027		VI_UNLOCK(vp);
2028		ap->a_flags &= ~LK_INTERLOCK;
2029
2030		error = VOP_UNLOCK(uvp, flags);
2031
2032		VI_LOCK(vp);
2033	}
2034
2035	VI_UNLOCK(vp);
2036	if (lvp != NULLVP)
2037		vdrop(lvp);
2038	if (uhold != 0)
2039		vdrop(uvp);
2040	if (mtxlkflag == 0)
2041		VI_LOCK(vp);
2042
2043	return error;
2044
2045unionfs_unlock_null_vnode:
2046	if (mtxlkflag == 2)
2047		VI_UNLOCK(vp);
2048	return (vop_stdunlock(ap));
2049}
2050
2051static int
2052unionfs_pathconf(struct vop_pathconf_args *ap)
2053{
2054	struct unionfs_node *unp;
2055	struct vnode   *vp;
2056
2057	KASSERT_UNIONFS_VNODE(ap->a_vp);
2058
2059	unp = VTOUNIONFS(ap->a_vp);
2060	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2061
2062	return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2063}
2064
2065static int
2066unionfs_advlock(struct vop_advlock_args *ap)
2067{
2068	int error;
2069	struct unionfs_node *unp;
2070	struct unionfs_node_status *unsp;
2071	struct vnode   *vp;
2072	struct vnode   *uvp;
2073	struct thread  *td;
2074
2075	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2076
2077	KASSERT_UNIONFS_VNODE(ap->a_vp);
2078
2079	vp = ap->a_vp;
2080	td = curthread;
2081
2082	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2083
2084	unp = VTOUNIONFS(ap->a_vp);
2085	uvp = unp->un_uppervp;
2086
2087	if (uvp == NULLVP) {
2088		error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2089		if (error != 0)
2090			goto unionfs_advlock_abort;
2091		uvp = unp->un_uppervp;
2092
2093		unionfs_get_node_status(unp, td, &unsp);
2094		if (unsp->uns_lower_opencnt > 0) {
2095			/* try reopen the vnode */
2096			error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2097				td->td_ucred, td, NULL);
2098			if (error)
2099				goto unionfs_advlock_abort;
2100			unsp->uns_upper_opencnt++;
2101			VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td);
2102			unsp->uns_lower_opencnt--;
2103		} else
2104			unionfs_tryrem_node_status(unp, unsp);
2105	}
2106
2107	VOP_UNLOCK(vp, LK_RELEASE);
2108
2109	error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2110
2111	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2112
2113	return error;
2114
2115unionfs_advlock_abort:
2116	VOP_UNLOCK(vp, LK_RELEASE);
2117
2118	UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2119
2120	return error;
2121}
2122
2123static int
2124unionfs_strategy(struct vop_strategy_args *ap)
2125{
2126	struct unionfs_node *unp;
2127	struct vnode   *vp;
2128
2129	KASSERT_UNIONFS_VNODE(ap->a_vp);
2130
2131	unp = VTOUNIONFS(ap->a_vp);
2132	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2133
2134#ifdef DIAGNOSTIC
2135	if (vp == NULLVP)
2136		panic("unionfs_strategy: nullvp");
2137
2138	if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2139		panic("unionfs_strategy: writing to lowervp");
2140#endif
2141
2142	return (VOP_STRATEGY(vp, ap->a_bp));
2143}
2144
2145static int
2146unionfs_getacl(struct vop_getacl_args *ap)
2147{
2148	int		error;
2149	struct unionfs_node *unp;
2150	struct vnode   *vp;
2151
2152	KASSERT_UNIONFS_VNODE(ap->a_vp);
2153
2154	unp = VTOUNIONFS(ap->a_vp);
2155	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2156
2157	UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2158
2159	error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2160
2161	UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2162
2163	return (error);
2164}
2165
2166static int
2167unionfs_setacl(struct vop_setacl_args *ap)
2168{
2169	int		error;
2170	struct unionfs_node *unp;
2171	struct vnode   *uvp;
2172	struct vnode   *lvp;
2173	struct thread  *td;
2174
2175	UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2176
2177	KASSERT_UNIONFS_VNODE(ap->a_vp);
2178
2179	error = EROFS;
2180	unp = VTOUNIONFS(ap->a_vp);
2181	uvp = unp->un_uppervp;
2182	lvp = unp->un_lowervp;
2183	td = ap->a_td;
2184
2185	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2186		return (EROFS);
2187
2188	if (uvp == NULLVP && lvp->v_type == VREG) {
2189		if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2190			return (error);
2191		uvp = unp->un_uppervp;
2192	}
2193
2194	if (uvp != NULLVP)
2195		error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2196
2197	UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2198
2199	return (error);
2200}
2201
2202static int
2203unionfs_aclcheck(struct vop_aclcheck_args *ap)
2204{
2205	int		error;
2206	struct unionfs_node *unp;
2207	struct vnode   *vp;
2208
2209	UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2210
2211	KASSERT_UNIONFS_VNODE(ap->a_vp);
2212
2213	unp = VTOUNIONFS(ap->a_vp);
2214	vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2215
2216	error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2217
2218	UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2219
2220	return (error);
2221}
2222
2223static int
2224unionfs_openextattr(struct vop_openextattr_args *ap)
2225{
2226	int		error;
2227	struct unionfs_node *unp;
2228	struct vnode   *vp;
2229	struct vnode   *tvp;
2230
2231	KASSERT_UNIONFS_VNODE(ap->a_vp);
2232
2233	vp = ap->a_vp;
2234	unp = VTOUNIONFS(vp);
2235	tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2236
2237	if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2238	    (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2239		return (EBUSY);
2240
2241	error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2242
2243	if (error == 0) {
2244		if (vn_lock(vp, LK_UPGRADE) != 0)
2245			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2246		if (tvp == unp->un_uppervp)
2247			unp->un_flag |= UNIONFS_OPENEXTU;
2248		else
2249			unp->un_flag |= UNIONFS_OPENEXTL;
2250		vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2251	}
2252
2253	return (error);
2254}
2255
2256static int
2257unionfs_closeextattr(struct vop_closeextattr_args *ap)
2258{
2259	int		error;
2260	struct unionfs_node *unp;
2261	struct vnode   *vp;
2262	struct vnode   *tvp;
2263
2264	KASSERT_UNIONFS_VNODE(ap->a_vp);
2265
2266	vp = ap->a_vp;
2267	unp = VTOUNIONFS(vp);
2268	tvp = NULLVP;
2269
2270	if (unp->un_flag & UNIONFS_OPENEXTU)
2271		tvp = unp->un_uppervp;
2272	else if (unp->un_flag & UNIONFS_OPENEXTL)
2273		tvp = unp->un_lowervp;
2274
2275	if (tvp == NULLVP)
2276		return (EOPNOTSUPP);
2277
2278	error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2279
2280	if (error == 0) {
2281		if (vn_lock(vp, LK_UPGRADE) != 0)
2282			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2283		if (tvp == unp->un_uppervp)
2284			unp->un_flag &= ~UNIONFS_OPENEXTU;
2285		else
2286			unp->un_flag &= ~UNIONFS_OPENEXTL;
2287		vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2288	}
2289
2290	return (error);
2291}
2292
2293static int
2294unionfs_getextattr(struct vop_getextattr_args *ap)
2295{
2296	struct unionfs_node *unp;
2297	struct vnode   *vp;
2298
2299	KASSERT_UNIONFS_VNODE(ap->a_vp);
2300
2301	unp = VTOUNIONFS(ap->a_vp);
2302	vp = NULLVP;
2303
2304	if (unp->un_flag & UNIONFS_OPENEXTU)
2305		vp = unp->un_uppervp;
2306	else if (unp->un_flag & UNIONFS_OPENEXTL)
2307		vp = unp->un_lowervp;
2308
2309	if (vp == NULLVP)
2310		return (EOPNOTSUPP);
2311
2312	return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2313	    ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2314}
2315
2316static int
2317unionfs_setextattr(struct vop_setextattr_args *ap)
2318{
2319	int		error;
2320	struct unionfs_node *unp;
2321	struct vnode   *uvp;
2322	struct vnode   *lvp;
2323	struct vnode   *ovp;
2324	struct ucred   *cred;
2325	struct thread  *td;
2326
2327	KASSERT_UNIONFS_VNODE(ap->a_vp);
2328
2329	error = EROFS;
2330	unp = VTOUNIONFS(ap->a_vp);
2331	uvp = unp->un_uppervp;
2332	lvp = unp->un_lowervp;
2333	ovp = NULLVP;
2334	cred = ap->a_cred;
2335	td = ap->a_td;
2336
2337	UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag);
2338
2339	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2340		return (EROFS);
2341
2342	if (unp->un_flag & UNIONFS_OPENEXTU)
2343		ovp = unp->un_uppervp;
2344	else if (unp->un_flag & UNIONFS_OPENEXTL)
2345		ovp = unp->un_lowervp;
2346
2347	if (ovp == NULLVP)
2348		return (EOPNOTSUPP);
2349
2350	if (ovp == lvp && lvp->v_type == VREG) {
2351		VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2352		if (uvp == NULLVP &&
2353		    (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2354unionfs_setextattr_reopen:
2355			if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2356			    VOP_OPENEXTATTR(lvp, cred, td)) {
2357#ifdef DIAGNOSTIC
2358				panic("unionfs: VOP_OPENEXTATTR failed");
2359#endif
2360				unp->un_flag &= ~UNIONFS_OPENEXTL;
2361			}
2362			goto unionfs_setextattr_abort;
2363		}
2364		uvp = unp->un_uppervp;
2365		if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2366			goto unionfs_setextattr_reopen;
2367		unp->un_flag &= ~UNIONFS_OPENEXTL;
2368		unp->un_flag |= UNIONFS_OPENEXTU;
2369		ovp = uvp;
2370	}
2371
2372	if (ovp == uvp)
2373		error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2374		    ap->a_uio, cred, td);
2375
2376unionfs_setextattr_abort:
2377	UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2378
2379	return (error);
2380}
2381
2382static int
2383unionfs_listextattr(struct vop_listextattr_args *ap)
2384{
2385	struct unionfs_node *unp;
2386	struct vnode   *vp;
2387
2388	KASSERT_UNIONFS_VNODE(ap->a_vp);
2389
2390	unp = VTOUNIONFS(ap->a_vp);
2391	vp = NULLVP;
2392
2393	if (unp->un_flag & UNIONFS_OPENEXTU)
2394		vp = unp->un_uppervp;
2395	else if (unp->un_flag & UNIONFS_OPENEXTL)
2396		vp = unp->un_lowervp;
2397
2398	if (vp == NULLVP)
2399		return (EOPNOTSUPP);
2400
2401	return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2402	    ap->a_size, ap->a_cred, ap->a_td));
2403}
2404
2405static int
2406unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2407{
2408	int		error;
2409	struct unionfs_node *unp;
2410	struct vnode   *uvp;
2411	struct vnode   *lvp;
2412	struct vnode   *ovp;
2413	struct ucred   *cred;
2414	struct thread  *td;
2415
2416	KASSERT_UNIONFS_VNODE(ap->a_vp);
2417
2418	error = EROFS;
2419	unp = VTOUNIONFS(ap->a_vp);
2420	uvp = unp->un_uppervp;
2421	lvp = unp->un_lowervp;
2422	ovp = NULLVP;
2423	cred = ap->a_cred;
2424	td = ap->a_td;
2425
2426	UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag);
2427
2428	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2429		return (EROFS);
2430
2431	if (unp->un_flag & UNIONFS_OPENEXTU)
2432		ovp = unp->un_uppervp;
2433	else if (unp->un_flag & UNIONFS_OPENEXTL)
2434		ovp = unp->un_lowervp;
2435
2436	if (ovp == NULLVP)
2437		return (EOPNOTSUPP);
2438
2439	if (ovp == lvp && lvp->v_type == VREG) {
2440		VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2441		if (uvp == NULLVP &&
2442		    (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2443unionfs_deleteextattr_reopen:
2444			if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2445			    VOP_OPENEXTATTR(lvp, cred, td)) {
2446#ifdef DIAGNOSTIC
2447				panic("unionfs: VOP_OPENEXTATTR failed");
2448#endif
2449				unp->un_flag &= ~UNIONFS_OPENEXTL;
2450			}
2451			goto unionfs_deleteextattr_abort;
2452		}
2453		uvp = unp->un_uppervp;
2454		if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2455			goto unionfs_deleteextattr_reopen;
2456		unp->un_flag &= ~UNIONFS_OPENEXTL;
2457		unp->un_flag |= UNIONFS_OPENEXTU;
2458		ovp = uvp;
2459	}
2460
2461	if (ovp == uvp)
2462		error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2463		    ap->a_cred, ap->a_td);
2464
2465unionfs_deleteextattr_abort:
2466	UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2467
2468	return (error);
2469}
2470
2471static int
2472unionfs_setlabel(struct vop_setlabel_args *ap)
2473{
2474	int		error;
2475	struct unionfs_node *unp;
2476	struct vnode   *uvp;
2477	struct vnode   *lvp;
2478	struct thread  *td;
2479
2480	UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2481
2482	KASSERT_UNIONFS_VNODE(ap->a_vp);
2483
2484	error = EROFS;
2485	unp = VTOUNIONFS(ap->a_vp);
2486	uvp = unp->un_uppervp;
2487	lvp = unp->un_lowervp;
2488	td = ap->a_td;
2489
2490	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2491		return (EROFS);
2492
2493	if (uvp == NULLVP && lvp->v_type == VREG) {
2494		if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2495			return (error);
2496		uvp = unp->un_uppervp;
2497	}
2498
2499	if (uvp != NULLVP)
2500		error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2501
2502	UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2503
2504	return (error);
2505}
2506
2507static int
2508unionfs_vptofh(struct vop_vptofh_args *ap)
2509{
2510	return (EOPNOTSUPP);
2511}
2512
2513struct vop_vector unionfs_vnodeops = {
2514	.vop_default =		&default_vnodeops,
2515
2516	.vop_access =		unionfs_access,
2517	.vop_aclcheck =		unionfs_aclcheck,
2518	.vop_advlock =		unionfs_advlock,
2519	.vop_bmap =		VOP_EOPNOTSUPP,
2520	.vop_cachedlookup =	unionfs_lookup,
2521	.vop_close =		unionfs_close,
2522	.vop_closeextattr =	unionfs_closeextattr,
2523	.vop_create =		unionfs_create,
2524	.vop_deleteextattr =	unionfs_deleteextattr,
2525	.vop_fsync =		unionfs_fsync,
2526	.vop_getacl =		unionfs_getacl,
2527	.vop_getattr =		unionfs_getattr,
2528	.vop_getextattr =	unionfs_getextattr,
2529	.vop_getwritemount =	unionfs_getwritemount,
2530	.vop_inactive =		unionfs_inactive,
2531	.vop_islocked =		unionfs_islocked,
2532	.vop_ioctl =		unionfs_ioctl,
2533	.vop_link =		unionfs_link,
2534	.vop_listextattr =	unionfs_listextattr,
2535	.vop_lock1 =		unionfs_lock,
2536	.vop_lookup =		vfs_cache_lookup,
2537	.vop_mkdir =		unionfs_mkdir,
2538	.vop_mknod =		unionfs_mknod,
2539	.vop_open =		unionfs_open,
2540	.vop_openextattr =	unionfs_openextattr,
2541	.vop_pathconf =		unionfs_pathconf,
2542	.vop_poll =		unionfs_poll,
2543	.vop_print =		unionfs_print,
2544	.vop_read =		unionfs_read,
2545	.vop_readdir =		unionfs_readdir,
2546	.vop_readlink =		unionfs_readlink,
2547	.vop_reclaim =		unionfs_reclaim,
2548	.vop_remove =		unionfs_remove,
2549	.vop_rename =		unionfs_rename,
2550	.vop_rmdir =		unionfs_rmdir,
2551	.vop_setacl =		unionfs_setacl,
2552	.vop_setattr =		unionfs_setattr,
2553	.vop_setextattr =	unionfs_setextattr,
2554	.vop_setlabel =		unionfs_setlabel,
2555	.vop_strategy =		unionfs_strategy,
2556	.vop_symlink =		unionfs_symlink,
2557	.vop_unlock =		unionfs_unlock,
2558	.vop_whiteout =		unionfs_whiteout,
2559	.vop_write =		unionfs_write,
2560	.vop_vptofh =		unionfs_vptofh,
2561};
2562