1d167cf6fSWarner Losh /*- 2996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. 3996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 4d00947d8SCraig Rodrigues * The Regents of the University of California. 5d00947d8SCraig Rodrigues * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 6d00947d8SCraig Rodrigues * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 7d00947d8SCraig Rodrigues * All rights reserved. 8df8bae1dSRodney W. Grimes * 9df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 10df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 20df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36996c772fSJohn Dyson * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 37c3aac50fSPeter Wemm * $FreeBSD$ 38d00947d8SCraig Rodrigues * 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes #include <sys/param.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 43d00947d8SCraig Rodrigues #include <sys/conf.h> 44d00947d8SCraig Rodrigues #include <sys/kernel.h> 45d00947d8SCraig Rodrigues #include <sys/lock.h> 46d00947d8SCraig Rodrigues #include <sys/malloc.h> 47d00947d8SCraig Rodrigues #include <sys/mount.h> 48d00947d8SCraig Rodrigues #include <sys/mutex.h> 49d00947d8SCraig Rodrigues #include <sys/namei.h> 50d00947d8SCraig Rodrigues #include <sys/sysctl.h> 51d00947d8SCraig Rodrigues #include <sys/vnode.h> 52d00947d8SCraig Rodrigues #include <sys/kdb.h> 533ac4d1efSBruce Evans #include <sys/fcntl.h> 54996c772fSJohn Dyson #include <sys/stat.h> 55d00947d8SCraig Rodrigues #include <sys/dirent.h> 56d00947d8SCraig Rodrigues #include <sys/proc.h> 573d253c11SCraig Rodrigues #include <sys/bio.h> 583d253c11SCraig Rodrigues #include <sys/buf.h> 59d00947d8SCraig Rodrigues 6099d300a1SRuslan Ermilov #include <fs/unionfs/union.h> 61df8bae1dSRodney W. Grimes 622a31267eSMatthew Dillon #include <vm/vm.h> 63d00947d8SCraig Rodrigues #include <vm/vm_extern.h> 64d00947d8SCraig Rodrigues #include <vm/vm_object.h> 652a31267eSMatthew Dillon #include <vm/vnode_pager.h> 662a31267eSMatthew Dillon 67d00947d8SCraig Rodrigues #if 0 68d00947d8SCraig Rodrigues #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) 69d00947d8SCraig Rodrigues #define UNIONFS_IDBG_RENAME 702a31267eSMatthew Dillon #else 71d00947d8SCraig Rodrigues #define UNIONFS_INTERNAL_DEBUG(msg, args...) 722a31267eSMatthew Dillon #endif 73df8bae1dSRodney W. Grimes 741e5da15aSDaichi GOTO #define KASSERT_UNIONFS_VNODE(vp) \ 751e5da15aSDaichi GOTO KASSERT(((vp)->v_op == &unionfs_vnodeops), \ 761e5da15aSDaichi GOTO ("unionfs: it is not unionfs-vnode")) 771e5da15aSDaichi GOTO 78d00947d8SCraig Rodrigues /* lockmgr lock <-> reverse table */ 79d00947d8SCraig Rodrigues struct lk_lr_table { 80d00947d8SCraig Rodrigues int lock; 81d00947d8SCraig Rodrigues int revlock; 82d00947d8SCraig Rodrigues }; 839b5e8b3aSBruce Evans 84d00947d8SCraig Rodrigues static struct lk_lr_table un_llt[] = { 85d00947d8SCraig Rodrigues {LK_SHARED, LK_RELEASE}, 86d00947d8SCraig Rodrigues {LK_EXCLUSIVE, LK_RELEASE}, 87d00947d8SCraig Rodrigues {LK_UPGRADE, LK_DOWNGRADE}, 88d00947d8SCraig Rodrigues {LK_DOWNGRADE, LK_UPGRADE}, 89d00947d8SCraig Rodrigues {0, 0} 90d00947d8SCraig Rodrigues }; 91df8bae1dSRodney W. Grimes 922a31267eSMatthew Dillon 93df8bae1dSRodney W. Grimes static int 94dc2dd185SDaichi GOTO unionfs_lookup(struct vop_cachedlookup_args *ap) 95df8bae1dSRodney W. Grimes { 96d00947d8SCraig Rodrigues int iswhiteout; 97d00947d8SCraig Rodrigues int lockflag; 98d00947d8SCraig Rodrigues int error , uerror, lerror; 99d00947d8SCraig Rodrigues u_long nameiop; 100d00947d8SCraig Rodrigues u_long cnflags, cnflagsbk; 101d00947d8SCraig Rodrigues struct unionfs_node *dunp; 102d00947d8SCraig Rodrigues struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp; 103d00947d8SCraig Rodrigues struct vattr va; 104d00947d8SCraig Rodrigues struct componentname *cnp; 105d00947d8SCraig Rodrigues struct thread *td; 106d00947d8SCraig Rodrigues 107d00947d8SCraig Rodrigues iswhiteout = 0; 108d00947d8SCraig Rodrigues lockflag = 0; 109d00947d8SCraig Rodrigues error = uerror = lerror = ENOENT; 110d00947d8SCraig Rodrigues cnp = ap->a_cnp; 111d00947d8SCraig Rodrigues nameiop = cnp->cn_nameiop; 112d00947d8SCraig Rodrigues cnflags = cnp->cn_flags; 113d00947d8SCraig Rodrigues dvp = ap->a_dvp; 114d00947d8SCraig Rodrigues dunp = VTOUNIONFS(dvp); 115d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 116d00947d8SCraig Rodrigues ldvp = dunp->un_lowervp; 117d00947d8SCraig Rodrigues vp = uvp = lvp = NULLVP; 118d00947d8SCraig Rodrigues td = curthread; 119d00947d8SCraig Rodrigues *(ap->a_vpp) = NULLVP; 120d00947d8SCraig Rodrigues 121d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr); 122d00947d8SCraig Rodrigues 123d00947d8SCraig Rodrigues if (dvp->v_type != VDIR) 124d00947d8SCraig Rodrigues return (ENOTDIR); 125df8bae1dSRodney W. Grimes 126df8bae1dSRodney W. Grimes /* 127d00947d8SCraig Rodrigues * If read-only and op is not LOOKUP, will return EROFS. 128df8bae1dSRodney W. Grimes */ 129d00947d8SCraig Rodrigues if ((cnflags & ISLASTCN) && 130d00947d8SCraig Rodrigues (dvp->v_mount->mnt_flag & MNT_RDONLY) && 131d00947d8SCraig Rodrigues LOOKUP != nameiop) 132d00947d8SCraig Rodrigues return (EROFS); 133d00947d8SCraig Rodrigues 134df8bae1dSRodney W. Grimes /* 135d00947d8SCraig Rodrigues * lookup dotdot 136df8bae1dSRodney W. Grimes */ 137d00947d8SCraig Rodrigues if (cnflags & ISDOTDOT) { 138d00947d8SCraig Rodrigues if (LOOKUP != nameiop && udvp == NULLVP) 139d00947d8SCraig Rodrigues return (EROFS); 140d00947d8SCraig Rodrigues 141d00947d8SCraig Rodrigues if (udvp != NULLVP) { 142d00947d8SCraig Rodrigues dtmpvp = udvp; 143d00947d8SCraig Rodrigues if (ldvp != NULLVP) 14422db15c0SAttilio Rao VOP_UNLOCK(ldvp, 0); 145d00947d8SCraig Rodrigues } 146d00947d8SCraig Rodrigues else 147d00947d8SCraig Rodrigues dtmpvp = ldvp; 148d00947d8SCraig Rodrigues 149d00947d8SCraig Rodrigues error = VOP_LOOKUP(dtmpvp, &vp, cnp); 150d00947d8SCraig Rodrigues 151d00947d8SCraig Rodrigues if (dtmpvp == udvp && ldvp != NULLVP) { 15222db15c0SAttilio Rao VOP_UNLOCK(udvp, 0); 153cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 154df8bae1dSRodney W. Grimes } 155df8bae1dSRodney W. Grimes 1562a31267eSMatthew Dillon if (error == 0) { 157d00947d8SCraig Rodrigues /* 158d00947d8SCraig Rodrigues * Exchange lock and reference from vp to 159d00947d8SCraig Rodrigues * dunp->un_dvp. vp is upper/lower vnode, but it 160d00947d8SCraig Rodrigues * will need to return the unionfs vnode. 161d00947d8SCraig Rodrigues */ 162d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 163d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 16422db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 165d00947d8SCraig Rodrigues vrele(vp); 166d00947d8SCraig Rodrigues 16722db15c0SAttilio Rao VOP_UNLOCK(dvp, 0); 168d00947d8SCraig Rodrigues *(ap->a_vpp) = dunp->un_dvp; 169d00947d8SCraig Rodrigues vref(dunp->un_dvp); 170d00947d8SCraig Rodrigues 171d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME) 172cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY); 173d00947d8SCraig Rodrigues else if (cnp->cn_lkflags & LK_TYPE_MASK) 174cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, cnp->cn_lkflags | 175cb05b60aSAttilio Rao LK_RETRY); 176d00947d8SCraig Rodrigues 177cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 178dc2dd185SDaichi GOTO } else if (error == ENOENT && (cnflags & MAKEENTRY) && 179dc2dd185SDaichi GOTO nameiop != CREATE) 180dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 181d00947d8SCraig Rodrigues 182d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 183d00947d8SCraig Rodrigues 184d00947d8SCraig Rodrigues return (error); 1852a31267eSMatthew Dillon } 186d00947d8SCraig Rodrigues 187d00947d8SCraig Rodrigues /* 188d00947d8SCraig Rodrigues * lookup upper layer 189d00947d8SCraig Rodrigues */ 190d00947d8SCraig Rodrigues if (udvp != NULLVP) { 191d00947d8SCraig Rodrigues uerror = VOP_LOOKUP(udvp, &uvp, cnp); 192d00947d8SCraig Rodrigues 193d00947d8SCraig Rodrigues if (uerror == 0) { 194d00947d8SCraig Rodrigues if (udvp == uvp) { /* is dot */ 195d00947d8SCraig Rodrigues vrele(uvp); 196d00947d8SCraig Rodrigues *(ap->a_vpp) = dvp; 197d00947d8SCraig Rodrigues vref(dvp); 198d00947d8SCraig Rodrigues 199d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror); 200d00947d8SCraig Rodrigues 201d00947d8SCraig Rodrigues return (uerror); 202d00947d8SCraig Rodrigues } 203d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 204d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 20522db15c0SAttilio Rao VOP_UNLOCK(uvp, 0); 206d00947d8SCraig Rodrigues } 207d00947d8SCraig Rodrigues 208d00947d8SCraig Rodrigues /* check whiteout */ 209d00947d8SCraig Rodrigues if (uerror == ENOENT || uerror == EJUSTRETURN) 210d00947d8SCraig Rodrigues if (cnp->cn_flags & ISWHITEOUT) 211d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 212d00947d8SCraig Rodrigues if (iswhiteout == 0 && ldvp != NULLVP) 2130359a12eSAttilio Rao if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) && 214d00947d8SCraig Rodrigues (va.va_flags & OPAQUE)) 215d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 216d00947d8SCraig Rodrigues #if 0 217d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr); 218d00947d8SCraig Rodrigues #endif 219d00947d8SCraig Rodrigues } 220d00947d8SCraig Rodrigues 221d00947d8SCraig Rodrigues /* 222d00947d8SCraig Rodrigues * lookup lower layer 223d00947d8SCraig Rodrigues */ 224d00947d8SCraig Rodrigues if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) { 225d00947d8SCraig Rodrigues /* always op is LOOKUP */ 226d00947d8SCraig Rodrigues cnp->cn_nameiop = LOOKUP; 227d00947d8SCraig Rodrigues cnflagsbk = cnp->cn_flags; 228d00947d8SCraig Rodrigues cnp->cn_flags = cnflags; 229d00947d8SCraig Rodrigues 230d00947d8SCraig Rodrigues lerror = VOP_LOOKUP(ldvp, &lvp, cnp); 231d00947d8SCraig Rodrigues 232d00947d8SCraig Rodrigues cnp->cn_nameiop = nameiop; 233d00947d8SCraig Rodrigues if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) 234d00947d8SCraig Rodrigues cnp->cn_flags = cnflagsbk; 235d00947d8SCraig Rodrigues 236d00947d8SCraig Rodrigues if (lerror == 0) { 237d00947d8SCraig Rodrigues if (ldvp == lvp) { /* is dot */ 238d00947d8SCraig Rodrigues if (uvp != NULLVP) 239d00947d8SCraig Rodrigues vrele(uvp); /* no need? */ 240d00947d8SCraig Rodrigues vrele(lvp); 241d00947d8SCraig Rodrigues *(ap->a_vpp) = dvp; 242d00947d8SCraig Rodrigues vref(dvp); 243d00947d8SCraig Rodrigues 244d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror); 245d00947d8SCraig Rodrigues 246d00947d8SCraig Rodrigues return (lerror); 247d00947d8SCraig Rodrigues } 248d00947d8SCraig Rodrigues if (cnp->cn_lkflags & LK_TYPE_MASK) 24922db15c0SAttilio Rao VOP_UNLOCK(lvp, 0); 250d00947d8SCraig Rodrigues } 251d00947d8SCraig Rodrigues } 252d00947d8SCraig Rodrigues 253d00947d8SCraig Rodrigues /* 254d00947d8SCraig Rodrigues * check lookup result 255d00947d8SCraig Rodrigues */ 256d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp == NULLVP) { 257d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", 258d00947d8SCraig Rodrigues (udvp != NULLVP ? uerror : lerror)); 259d00947d8SCraig Rodrigues return (udvp != NULLVP ? uerror : lerror); 260d00947d8SCraig Rodrigues } 261d00947d8SCraig Rodrigues 262d00947d8SCraig Rodrigues /* 263d00947d8SCraig Rodrigues * check vnode type 264d00947d8SCraig Rodrigues */ 265d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) { 266d00947d8SCraig Rodrigues vrele(lvp); 267d00947d8SCraig Rodrigues lvp = NULLVP; 268d00947d8SCraig Rodrigues } 269d00947d8SCraig Rodrigues 270d00947d8SCraig Rodrigues /* 271d00947d8SCraig Rodrigues * check shadow dir 272d00947d8SCraig Rodrigues */ 273d00947d8SCraig Rodrigues if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP && 274d00947d8SCraig Rodrigues lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR && 275d00947d8SCraig Rodrigues !(dvp->v_mount->mnt_flag & MNT_RDONLY) && 276d00947d8SCraig Rodrigues (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) { 277d00947d8SCraig Rodrigues /* get unionfs vnode in order to create a new shadow dir. */ 278d00947d8SCraig Rodrigues error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp, 279d00947d8SCraig Rodrigues cnp, td); 280d00947d8SCraig Rodrigues if (error != 0) 281d00947d8SCraig Rodrigues goto unionfs_lookup_out; 282d00947d8SCraig Rodrigues 283d00947d8SCraig Rodrigues if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK)) 28422db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 28581c794f9SAttilio Rao if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) { 286cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 287d00947d8SCraig Rodrigues lockflag = 1; 288d00947d8SCraig Rodrigues } 289d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), 290d00947d8SCraig Rodrigues udvp, VTOUNIONFS(vp), cnp, td); 291d00947d8SCraig Rodrigues if (lockflag != 0) 29222db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 293d00947d8SCraig Rodrigues if (error != 0) { 294d00947d8SCraig Rodrigues UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir."); 295d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) 296d00947d8SCraig Rodrigues vput(vp); 297d00947d8SCraig Rodrigues else 298d00947d8SCraig Rodrigues vrele(vp); 299d00947d8SCraig Rodrigues goto unionfs_lookup_out; 300d00947d8SCraig Rodrigues } 301d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED) 302cb05b60aSAttilio Rao vn_lock(vp, LK_SHARED | LK_RETRY); 303d00947d8SCraig Rodrigues } 304d00947d8SCraig Rodrigues /* 305d00947d8SCraig Rodrigues * get unionfs vnode. 306d00947d8SCraig Rodrigues */ 307d00947d8SCraig Rodrigues else { 308d00947d8SCraig Rodrigues if (uvp != NULLVP) 309d00947d8SCraig Rodrigues error = uerror; 310d00947d8SCraig Rodrigues else 311d00947d8SCraig Rodrigues error = lerror; 312d00947d8SCraig Rodrigues if (error != 0) 313d00947d8SCraig Rodrigues goto unionfs_lookup_out; 3141e5da15aSDaichi GOTO /* 3151e5da15aSDaichi GOTO * get socket vnode. 3161e5da15aSDaichi GOTO */ 3171e5da15aSDaichi GOTO if (uvp != NULLVP && uvp->v_type == VSOCK) { 3181e5da15aSDaichi GOTO vp = uvp; 3191e5da15aSDaichi GOTO vref(vp); 3201e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3211e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3221e5da15aSDaichi GOTO } 3231e5da15aSDaichi GOTO else if (lvp != NULLVP && lvp->v_type == VSOCK) { 3241e5da15aSDaichi GOTO vp = lvp; 3251e5da15aSDaichi GOTO vref(vp); 3261e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3271e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3281e5da15aSDaichi GOTO } 3291e5da15aSDaichi GOTO /* 3301e5da15aSDaichi GOTO * get unionfs vnode. 3311e5da15aSDaichi GOTO */ 3321e5da15aSDaichi GOTO else 3331e5da15aSDaichi GOTO error = unionfs_nodeget(dvp->v_mount, uvp, lvp, 3341e5da15aSDaichi GOTO dvp, &vp, cnp, td); 335d00947d8SCraig Rodrigues if (error != 0) { 336d00947d8SCraig Rodrigues UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode."); 337d00947d8SCraig Rodrigues goto unionfs_lookup_out; 338d00947d8SCraig Rodrigues } 339d00947d8SCraig Rodrigues if ((nameiop == DELETE || nameiop == RENAME) && 340d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK) == 0) 341cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 342d00947d8SCraig Rodrigues } 343d00947d8SCraig Rodrigues 344d00947d8SCraig Rodrigues *(ap->a_vpp) = vp; 345d00947d8SCraig Rodrigues 3461e5da15aSDaichi GOTO if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK) 347dc2dd185SDaichi GOTO cache_enter(dvp, vp, cnp); 348dc2dd185SDaichi GOTO 349d00947d8SCraig Rodrigues unionfs_lookup_out: 350d00947d8SCraig Rodrigues if (uvp != NULLVP) 351d00947d8SCraig Rodrigues vrele(uvp); 352d00947d8SCraig Rodrigues if (lvp != NULLVP) 353d00947d8SCraig Rodrigues vrele(lvp); 354d00947d8SCraig Rodrigues 355dc2dd185SDaichi GOTO if (error == ENOENT && (cnflags & MAKEENTRY) && nameiop != CREATE) 356dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 357dc2dd185SDaichi GOTO 358d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 359d00947d8SCraig Rodrigues 3602a31267eSMatthew Dillon return (error); 361df8bae1dSRodney W. Grimes } 362df8bae1dSRodney W. Grimes 363c9bf0111SKATO Takenori static int 364d00947d8SCraig Rodrigues unionfs_create(struct vop_create_args *ap) 365996c772fSJohn Dyson { 366d00947d8SCraig Rodrigues struct unionfs_node *dunp; 367d00947d8SCraig Rodrigues struct componentname *cnp; 368d00947d8SCraig Rodrigues struct vnode *udvp; 369d00947d8SCraig Rodrigues struct vnode *vp; 3703bb3827fSDavid Schultz int error; 371996c772fSJohn Dyson 372d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n"); 373d00947d8SCraig Rodrigues 3741e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 3751e5da15aSDaichi GOTO 376d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 377d00947d8SCraig Rodrigues cnp = ap->a_cnp; 378d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 379d00947d8SCraig Rodrigues error = EROFS; 380d00947d8SCraig Rodrigues 381d00947d8SCraig Rodrigues if (udvp != NULLVP) { 3821e5da15aSDaichi GOTO error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap); 3831e5da15aSDaichi GOTO if (error != 0) 3841e5da15aSDaichi GOTO goto unionfs_create_abort; 3851e5da15aSDaichi GOTO 3861e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 3871e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 3881e5da15aSDaichi GOTO else { 38922db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 390d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 39122db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 392d00947d8SCraig Rodrigues vrele(vp); 393d00947d8SCraig Rodrigues } 394d00947d8SCraig Rodrigues } 395d00947d8SCraig Rodrigues 3961e5da15aSDaichi GOTO unionfs_create_abort: 397d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error); 398d00947d8SCraig Rodrigues 399d00947d8SCraig Rodrigues return (error); 400d00947d8SCraig Rodrigues } 401d00947d8SCraig Rodrigues 402d00947d8SCraig Rodrigues static int 403d00947d8SCraig Rodrigues unionfs_whiteout(struct vop_whiteout_args *ap) 404d00947d8SCraig Rodrigues { 405d00947d8SCraig Rodrigues struct unionfs_node *dunp; 406d00947d8SCraig Rodrigues struct componentname *cnp; 407d00947d8SCraig Rodrigues struct vnode *udvp; 408d00947d8SCraig Rodrigues int error; 409d00947d8SCraig Rodrigues 410d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n"); 411d00947d8SCraig Rodrigues 4121e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 4131e5da15aSDaichi GOTO 414d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 415d00947d8SCraig Rodrigues cnp = ap->a_cnp; 416d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 417d00947d8SCraig Rodrigues error = EOPNOTSUPP; 418d00947d8SCraig Rodrigues 419d00947d8SCraig Rodrigues if (udvp != NULLVP) { 420ac092fb3SDavid Schultz switch (ap->a_flags) { 421ac092fb3SDavid Schultz case CREATE: 422ac092fb3SDavid Schultz case DELETE: 4233bb3827fSDavid Schultz case LOOKUP: 424d00947d8SCraig Rodrigues error = VOP_WHITEOUT(udvp, cnp, ap->a_flags); 425ac092fb3SDavid Schultz break; 426ac092fb3SDavid Schultz default: 427d00947d8SCraig Rodrigues error = EINVAL; 428d00947d8SCraig Rodrigues break; 429ac092fb3SDavid Schultz } 430d00947d8SCraig Rodrigues } 431d00947d8SCraig Rodrigues 432d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error); 433d00947d8SCraig Rodrigues 4342a31267eSMatthew Dillon return (error); 4352a31267eSMatthew Dillon } 4362a31267eSMatthew Dillon 437c9bf0111SKATO Takenori static int 438d00947d8SCraig Rodrigues unionfs_mknod(struct vop_mknod_args *ap) 439df8bae1dSRodney W. Grimes { 440d00947d8SCraig Rodrigues struct unionfs_node *dunp; 441d00947d8SCraig Rodrigues struct componentname *cnp; 442d00947d8SCraig Rodrigues struct vnode *udvp; 443df8bae1dSRodney W. Grimes struct vnode *vp; 444d00947d8SCraig Rodrigues int error; 445df8bae1dSRodney W. Grimes 446d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n"); 447d00947d8SCraig Rodrigues 4481e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 4491e5da15aSDaichi GOTO 450d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 451d00947d8SCraig Rodrigues cnp = ap->a_cnp; 452d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 453d00947d8SCraig Rodrigues error = EROFS; 454d00947d8SCraig Rodrigues 455d00947d8SCraig Rodrigues if (udvp != NULLVP) { 4561e5da15aSDaichi GOTO error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap); 4571e5da15aSDaichi GOTO if (error != 0) 4581e5da15aSDaichi GOTO goto unionfs_mknod_abort; 4591e5da15aSDaichi GOTO 4601e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 4611e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 4621e5da15aSDaichi GOTO else { 46322db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 464d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 46522db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 466d00947d8SCraig Rodrigues vrele(vp); 467d00947d8SCraig Rodrigues } 468d00947d8SCraig Rodrigues } 469d00947d8SCraig Rodrigues 4701e5da15aSDaichi GOTO unionfs_mknod_abort: 471d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error); 472d00947d8SCraig Rodrigues 473d00947d8SCraig Rodrigues return (error); 474d00947d8SCraig Rodrigues } 475d00947d8SCraig Rodrigues 476d00947d8SCraig Rodrigues static int 477d00947d8SCraig Rodrigues unionfs_open(struct vop_open_args *ap) 478d00947d8SCraig Rodrigues { 479d00947d8SCraig Rodrigues int error; 480d00947d8SCraig Rodrigues struct unionfs_node *unp; 481d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 482d00947d8SCraig Rodrigues struct vnode *uvp; 483d00947d8SCraig Rodrigues struct vnode *lvp; 484d00947d8SCraig Rodrigues struct vnode *targetvp; 485d00947d8SCraig Rodrigues struct ucred *cred; 486d00947d8SCraig Rodrigues struct thread *td; 487d00947d8SCraig Rodrigues 488d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n"); 489d00947d8SCraig Rodrigues 4901e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 4911e5da15aSDaichi GOTO 492d00947d8SCraig Rodrigues error = 0; 493d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 494d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 495d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 496d00947d8SCraig Rodrigues targetvp = NULLVP; 497d00947d8SCraig Rodrigues cred = ap->a_cred; 498d00947d8SCraig Rodrigues td = ap->a_td; 499d00947d8SCraig Rodrigues 500d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 501d00947d8SCraig Rodrigues 502d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) { 503d00947d8SCraig Rodrigues /* vnode is already opend. */ 504d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt > 0) 505d00947d8SCraig Rodrigues targetvp = uvp; 506d00947d8SCraig Rodrigues else 507d00947d8SCraig Rodrigues targetvp = lvp; 508d00947d8SCraig Rodrigues 509d00947d8SCraig Rodrigues if (targetvp == lvp && 510d00947d8SCraig Rodrigues (ap->a_mode & FWRITE) && lvp->v_type == VREG) 511d00947d8SCraig Rodrigues targetvp = NULLVP; 512d00947d8SCraig Rodrigues } 513d00947d8SCraig Rodrigues if (targetvp == NULLVP) { 514d00947d8SCraig Rodrigues if (uvp == NULLVP) { 515d00947d8SCraig Rodrigues if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) { 516d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 517d00947d8SCraig Rodrigues !(ap->a_mode & O_TRUNC), cred, td); 518d00947d8SCraig Rodrigues if (error != 0) 519d00947d8SCraig Rodrigues goto unionfs_open_abort; 520d00947d8SCraig Rodrigues targetvp = uvp = unp->un_uppervp; 521d00947d8SCraig Rodrigues } else 522d00947d8SCraig Rodrigues targetvp = lvp; 523d00947d8SCraig Rodrigues } else 524d00947d8SCraig Rodrigues targetvp = uvp; 525d00947d8SCraig Rodrigues } 526d00947d8SCraig Rodrigues 5279e223287SKonstantin Belousov error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp); 528d00947d8SCraig Rodrigues if (error == 0) { 529d00947d8SCraig Rodrigues if (targetvp == uvp) { 530d00947d8SCraig Rodrigues if (uvp->v_type == VDIR && lvp != NULLVP && 531d00947d8SCraig Rodrigues unsp->uns_lower_opencnt <= 0) { 532d00947d8SCraig Rodrigues /* open lower for readdir */ 5339e223287SKonstantin Belousov error = VOP_OPEN(lvp, FREAD, cred, td, NULL); 534d00947d8SCraig Rodrigues if (error != 0) { 535d00947d8SCraig Rodrigues VOP_CLOSE(uvp, ap->a_mode, cred, td); 536d00947d8SCraig Rodrigues goto unionfs_open_abort; 537d00947d8SCraig Rodrigues } 538d00947d8SCraig Rodrigues unsp->uns_node_flag |= UNS_OPENL_4_READDIR; 539d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 540d00947d8SCraig Rodrigues } 541d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 542d00947d8SCraig Rodrigues } else { 543d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 544d00947d8SCraig Rodrigues unsp->uns_lower_openmode = ap->a_mode; 545d00947d8SCraig Rodrigues } 546d00947d8SCraig Rodrigues ap->a_vp->v_object = targetvp->v_object; 547d00947d8SCraig Rodrigues } 548d00947d8SCraig Rodrigues 549d00947d8SCraig Rodrigues unionfs_open_abort: 550d00947d8SCraig Rodrigues if (error != 0) 551fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 552d00947d8SCraig Rodrigues 553d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error); 554d00947d8SCraig Rodrigues 555d00947d8SCraig Rodrigues return (error); 556d00947d8SCraig Rodrigues } 557d00947d8SCraig Rodrigues 558d00947d8SCraig Rodrigues static int 559d00947d8SCraig Rodrigues unionfs_close(struct vop_close_args *ap) 560d00947d8SCraig Rodrigues { 561d00947d8SCraig Rodrigues int error; 562d00947d8SCraig Rodrigues int locked; 563d00947d8SCraig Rodrigues struct unionfs_node *unp; 564d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 565d00947d8SCraig Rodrigues struct ucred *cred; 566d00947d8SCraig Rodrigues struct thread *td; 567d00947d8SCraig Rodrigues struct vnode *ovp; 568d00947d8SCraig Rodrigues 569d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 570d00947d8SCraig Rodrigues 5711e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 5721e5da15aSDaichi GOTO 573d00947d8SCraig Rodrigues locked = 0; 57498155f1fSCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 575d00947d8SCraig Rodrigues cred = ap->a_cred; 576d00947d8SCraig Rodrigues td = ap->a_td; 577d00947d8SCraig Rodrigues 57881c794f9SAttilio Rao if (VOP_ISLOCKED(ap->a_vp) != LK_EXCLUSIVE) { 579cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 580d00947d8SCraig Rodrigues locked = 1; 581d00947d8SCraig Rodrigues } 582d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 583d00947d8SCraig Rodrigues 584d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 585d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 586d00947d8SCraig Rodrigues printf("unionfs_close: warning: open count is 0\n"); 587df8bae1dSRodney W. Grimes #endif 588d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 589d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 590d00947d8SCraig Rodrigues else 591d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 592d00947d8SCraig Rodrigues } else if (unsp->uns_upper_opencnt > 0) 593d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 594d00947d8SCraig Rodrigues else 595d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 596d00947d8SCraig Rodrigues 597d00947d8SCraig Rodrigues error = VOP_CLOSE(ovp, ap->a_fflag, cred, td); 598d00947d8SCraig Rodrigues 599d00947d8SCraig Rodrigues if (error != 0) 600d00947d8SCraig Rodrigues goto unionfs_close_abort; 601d00947d8SCraig Rodrigues 602d00947d8SCraig Rodrigues ap->a_vp->v_object = ovp->v_object; 603d00947d8SCraig Rodrigues 604d00947d8SCraig Rodrigues if (ovp == unp->un_uppervp) { 605d00947d8SCraig Rodrigues unsp->uns_upper_opencnt--; 606d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt == 0) { 607d00947d8SCraig Rodrigues if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 608d00947d8SCraig Rodrigues VOP_CLOSE(unp->un_lowervp, FREAD, cred, td); 609d00947d8SCraig Rodrigues unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 610d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 611df8bae1dSRodney W. Grimes } 612d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) 613d00947d8SCraig Rodrigues ap->a_vp->v_object = unp->un_lowervp->v_object; 614d00947d8SCraig Rodrigues } 615d00947d8SCraig Rodrigues } else 616d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 617d00947d8SCraig Rodrigues 618d00947d8SCraig Rodrigues unionfs_close_abort: 619fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 620d00947d8SCraig Rodrigues 621d00947d8SCraig Rodrigues if (locked != 0) 62222db15c0SAttilio Rao VOP_UNLOCK(ap->a_vp, 0); 623d00947d8SCraig Rodrigues 624d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 625d00947d8SCraig Rodrigues 626d00947d8SCraig Rodrigues return (error); 627df8bae1dSRodney W. Grimes } 628df8bae1dSRodney W. Grimes 629df8bae1dSRodney W. Grimes /* 630d00947d8SCraig Rodrigues * Check the access mode toward shadow file/dir. 631df8bae1dSRodney W. Grimes */ 632c9bf0111SKATO Takenori static int 63315bc6b2bSEdward Tomasz Napierala unionfs_check_corrected_access(accmode_t accmode, 634d00947d8SCraig Rodrigues struct vattr *va, 635d00947d8SCraig Rodrigues struct ucred *cred) 636df8bae1dSRodney W. Grimes { 637d00947d8SCraig Rodrigues int count; 638d00947d8SCraig Rodrigues uid_t uid; /* upper side vnode's uid */ 639d00947d8SCraig Rodrigues gid_t gid; /* upper side vnode's gid */ 640d00947d8SCraig Rodrigues u_short vmode; /* upper side vnode's mode */ 641d00947d8SCraig Rodrigues u_short mask; 642df8bae1dSRodney W. Grimes 643d00947d8SCraig Rodrigues mask = 0; 644d00947d8SCraig Rodrigues uid = va->va_uid; 645d00947d8SCraig Rodrigues gid = va->va_gid; 646d00947d8SCraig Rodrigues vmode = va->va_mode; 647d00947d8SCraig Rodrigues 648d00947d8SCraig Rodrigues /* check owner */ 649d00947d8SCraig Rodrigues if (cred->cr_uid == uid) { 65015bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 651d00947d8SCraig Rodrigues mask |= S_IXUSR; 65215bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 653d00947d8SCraig Rodrigues mask |= S_IRUSR; 65415bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 655d00947d8SCraig Rodrigues mask |= S_IWUSR; 656d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 657d00947d8SCraig Rodrigues } 658d00947d8SCraig Rodrigues 659d00947d8SCraig Rodrigues /* check group */ 660d00947d8SCraig Rodrigues count = 0; 661838d9858SBrooks Davis if (groupmember(gid, cred)) { 66215bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 663d00947d8SCraig Rodrigues mask |= S_IXGRP; 66415bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 665d00947d8SCraig Rodrigues mask |= S_IRGRP; 66615bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 667d00947d8SCraig Rodrigues mask |= S_IWGRP; 668d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 669d00947d8SCraig Rodrigues } 670d00947d8SCraig Rodrigues 671d00947d8SCraig Rodrigues /* check other */ 67215bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 673d00947d8SCraig Rodrigues mask |= S_IXOTH; 67415bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 675d00947d8SCraig Rodrigues mask |= S_IROTH; 67615bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 677d00947d8SCraig Rodrigues mask |= S_IWOTH; 678d00947d8SCraig Rodrigues 679d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 680d00947d8SCraig Rodrigues } 681d00947d8SCraig Rodrigues 682d00947d8SCraig Rodrigues static int 683d00947d8SCraig Rodrigues unionfs_access(struct vop_access_args *ap) 684d00947d8SCraig Rodrigues { 685d00947d8SCraig Rodrigues struct unionfs_mount *ump; 686d00947d8SCraig Rodrigues struct unionfs_node *unp; 687d00947d8SCraig Rodrigues struct vnode *uvp; 688d00947d8SCraig Rodrigues struct vnode *lvp; 689d00947d8SCraig Rodrigues struct thread *td; 690d00947d8SCraig Rodrigues struct vattr va; 69115bc6b2bSEdward Tomasz Napierala accmode_t accmode; 692d00947d8SCraig Rodrigues int error; 693d00947d8SCraig Rodrigues 694d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 695d00947d8SCraig Rodrigues 6961e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 6971e5da15aSDaichi GOTO 698d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 699d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 700d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 701d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 702d00947d8SCraig Rodrigues td = ap->a_td; 70315bc6b2bSEdward Tomasz Napierala accmode = ap->a_accmode; 704d00947d8SCraig Rodrigues error = EACCES; 705d00947d8SCraig Rodrigues 70615bc6b2bSEdward Tomasz Napierala if ((accmode & VWRITE) && 7072a31267eSMatthew Dillon (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 7086ca02614SKATO Takenori switch (ap->a_vp->v_type) { 709831a80b0SMatthew Dillon case VREG: 710831a80b0SMatthew Dillon case VDIR: 711831a80b0SMatthew Dillon case VLNK: 7126ca02614SKATO Takenori return (EROFS); 713831a80b0SMatthew Dillon default: 714831a80b0SMatthew Dillon break; 7156ca02614SKATO Takenori } 7166ca02614SKATO Takenori } 7172a31267eSMatthew Dillon 718d00947d8SCraig Rodrigues if (uvp != NULLVP) { 71915bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(uvp, accmode, ap->a_cred, td); 720d00947d8SCraig Rodrigues 721d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 722d00947d8SCraig Rodrigues 7232a31267eSMatthew Dillon return (error); 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes 726d00947d8SCraig Rodrigues if (lvp != NULLVP) { 72715bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) { 728d00947d8SCraig Rodrigues if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 729d00947d8SCraig Rodrigues switch (ap->a_vp->v_type) { 730d00947d8SCraig Rodrigues case VREG: 731d00947d8SCraig Rodrigues case VDIR: 732d00947d8SCraig Rodrigues case VLNK: 733d00947d8SCraig Rodrigues return (EROFS); 734d00947d8SCraig Rodrigues default: 735d00947d8SCraig Rodrigues break; 736df8bae1dSRodney W. Grimes } 737d00947d8SCraig Rodrigues } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 738d00947d8SCraig Rodrigues /* check shadow file/dir */ 739d00947d8SCraig Rodrigues if (ump->um_copymode != UNIONFS_TRANSPARENT) { 740d00947d8SCraig Rodrigues error = unionfs_create_uppervattr(ump, 741d00947d8SCraig Rodrigues lvp, &va, ap->a_cred, td); 742d00947d8SCraig Rodrigues if (error != 0) 743d00947d8SCraig Rodrigues return (error); 744d00947d8SCraig Rodrigues 745d00947d8SCraig Rodrigues error = unionfs_check_corrected_access( 74615bc6b2bSEdward Tomasz Napierala accmode, &va, ap->a_cred); 747d00947d8SCraig Rodrigues if (error != 0) 748df8bae1dSRodney W. Grimes return (error); 749df8bae1dSRodney W. Grimes } 750d00947d8SCraig Rodrigues } 75115bc6b2bSEdward Tomasz Napierala accmode &= ~VWRITE; 75215bc6b2bSEdward Tomasz Napierala accmode |= VREAD; /* will copy to upper */ 753d00947d8SCraig Rodrigues } 75415bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(lvp, accmode, ap->a_cred, td); 755d00947d8SCraig Rodrigues } 756df8bae1dSRodney W. Grimes 757d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 758d00947d8SCraig Rodrigues 759d00947d8SCraig Rodrigues return (error); 760d00947d8SCraig Rodrigues } 7612a31267eSMatthew Dillon 762c9bf0111SKATO Takenori static int 763d00947d8SCraig Rodrigues unionfs_getattr(struct vop_getattr_args *ap) 764df8bae1dSRodney W. Grimes { 765df8bae1dSRodney W. Grimes int error; 766d00947d8SCraig Rodrigues struct unionfs_node *unp; 767d00947d8SCraig Rodrigues struct unionfs_mount *ump; 768d00947d8SCraig Rodrigues struct vnode *uvp; 769d00947d8SCraig Rodrigues struct vnode *lvp; 770d00947d8SCraig Rodrigues struct thread *td; 771df8bae1dSRodney W. Grimes struct vattr va; 772df8bae1dSRodney W. Grimes 773d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 774df8bae1dSRodney W. Grimes 7751e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 7761e5da15aSDaichi GOTO 777d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 778d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 779d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 780d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 7810359a12eSAttilio Rao td = curthread; 782df8bae1dSRodney W. Grimes 783d00947d8SCraig Rodrigues if (uvp != NULLVP) { 7840359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 7856e4c3467STakanori Watanabe ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 786d354520eSTakanori Watanabe 787d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 788d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, 789d00947d8SCraig Rodrigues ap->a_vap->va_gid, error); 790d00947d8SCraig Rodrigues 791d00947d8SCraig Rodrigues return (error); 792d00947d8SCraig Rodrigues } 793d00947d8SCraig Rodrigues 7940359a12eSAttilio Rao error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 795d00947d8SCraig Rodrigues 796d00947d8SCraig Rodrigues if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 797d00947d8SCraig Rodrigues /* correct the attr toward shadow file/dir. */ 798d00947d8SCraig Rodrigues if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 799d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); 800d00947d8SCraig Rodrigues ap->a_vap->va_mode = va.va_mode; 801d00947d8SCraig Rodrigues ap->a_vap->va_uid = va.va_uid; 802d00947d8SCraig Rodrigues ap->a_vap->va_gid = va.va_gid; 803d00947d8SCraig Rodrigues } 804d00947d8SCraig Rodrigues } 805d00947d8SCraig Rodrigues 806d00947d8SCraig Rodrigues if (error == 0) 807d00947d8SCraig Rodrigues ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 808d00947d8SCraig Rodrigues 809d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 810d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 811d00947d8SCraig Rodrigues 812d00947d8SCraig Rodrigues return (error); 813df8bae1dSRodney W. Grimes } 814df8bae1dSRodney W. Grimes 815c9bf0111SKATO Takenori static int 816d00947d8SCraig Rodrigues unionfs_setattr(struct vop_setattr_args *ap) 817df8bae1dSRodney W. Grimes { 818df8bae1dSRodney W. Grimes int error; 819d00947d8SCraig Rodrigues struct unionfs_node *unp; 820d00947d8SCraig Rodrigues struct vnode *uvp; 821d00947d8SCraig Rodrigues struct vnode *lvp; 822d00947d8SCraig Rodrigues struct thread *td; 823d00947d8SCraig Rodrigues struct vattr *vap; 824df8bae1dSRodney W. Grimes 825d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 826d00947d8SCraig Rodrigues 8271e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8281e5da15aSDaichi GOTO 829d00947d8SCraig Rodrigues error = EROFS; 830d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 831d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 832d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 8330359a12eSAttilio Rao td = curthread; 834d00947d8SCraig Rodrigues vap = ap->a_vap; 835d00947d8SCraig Rodrigues 8366ca02614SKATO Takenori if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 8376ca02614SKATO Takenori (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 8386ca02614SKATO Takenori vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 839d00947d8SCraig Rodrigues vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 8406ca02614SKATO Takenori return (EROFS); 8416ca02614SKATO Takenori 842d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 843d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, (vap->va_size != 0), 844d00947d8SCraig Rodrigues ap->a_cred, td); 845d00947d8SCraig Rodrigues if (error != 0) 846df8bae1dSRodney W. Grimes return (error); 847d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 848df8bae1dSRodney W. Grimes } 849df8bae1dSRodney W. Grimes 850d00947d8SCraig Rodrigues if (uvp != NULLVP) 8510359a12eSAttilio Rao error = VOP_SETATTR(uvp, vap, ap->a_cred); 852d00947d8SCraig Rodrigues 853d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 854d00947d8SCraig Rodrigues 8552a31267eSMatthew Dillon return (error); 856df8bae1dSRodney W. Grimes } 857df8bae1dSRodney W. Grimes 858c9bf0111SKATO Takenori static int 859d00947d8SCraig Rodrigues unionfs_read(struct vop_read_args *ap) 860df8bae1dSRodney W. Grimes { 8612a31267eSMatthew Dillon int error; 862d00947d8SCraig Rodrigues struct unionfs_node *unp; 863d00947d8SCraig Rodrigues struct vnode *tvp; 864df8bae1dSRodney W. Grimes 865d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 8662a31267eSMatthew Dillon 8671e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8681e5da15aSDaichi GOTO 869d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 870d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 871996c772fSJohn Dyson 872d00947d8SCraig Rodrigues error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 873996c772fSJohn Dyson 874d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 875d00947d8SCraig Rodrigues 876df8bae1dSRodney W. Grimes return (error); 877df8bae1dSRodney W. Grimes } 878df8bae1dSRodney W. Grimes 879c9bf0111SKATO Takenori static int 880d00947d8SCraig Rodrigues unionfs_write(struct vop_write_args *ap) 881df8bae1dSRodney W. Grimes { 8822a31267eSMatthew Dillon int error; 883d00947d8SCraig Rodrigues struct unionfs_node *unp; 884d00947d8SCraig Rodrigues struct vnode *tvp; 885df8bae1dSRodney W. Grimes 886d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 887996c772fSJohn Dyson 8881e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8891e5da15aSDaichi GOTO 890d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 891d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 892996c772fSJohn Dyson 893d00947d8SCraig Rodrigues error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 894996c772fSJohn Dyson 895d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 896df8bae1dSRodney W. Grimes 897df8bae1dSRodney W. Grimes return (error); 898df8bae1dSRodney W. Grimes } 899df8bae1dSRodney W. Grimes 900c9bf0111SKATO Takenori static int 901d00947d8SCraig Rodrigues unionfs_ioctl(struct vop_ioctl_args *ap) 902df8bae1dSRodney W. Grimes { 903df8bae1dSRodney W. Grimes int error; 904d00947d8SCraig Rodrigues struct unionfs_node *unp; 905d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 906d00947d8SCraig Rodrigues struct vnode *ovp; 907df8bae1dSRodney W. Grimes 908d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 9092a31267eSMatthew Dillon 9101e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9111e5da15aSDaichi GOTO 912cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 913d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 914d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 915d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 916fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 91722db15c0SAttilio Rao VOP_UNLOCK(ap->a_vp, 0); 918d00947d8SCraig Rodrigues 919d00947d8SCraig Rodrigues if (ovp == NULLVP) 920d00947d8SCraig Rodrigues return (EBADF); 921d00947d8SCraig Rodrigues 922d00947d8SCraig Rodrigues error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 923d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 924d00947d8SCraig Rodrigues 925885868cdSRobert Watson UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error); 926d00947d8SCraig Rodrigues 927d00947d8SCraig Rodrigues return (error); 928df8bae1dSRodney W. Grimes } 929df8bae1dSRodney W. Grimes 930d00947d8SCraig Rodrigues static int 931d00947d8SCraig Rodrigues unionfs_poll(struct vop_poll_args *ap) 932d00947d8SCraig Rodrigues { 933d00947d8SCraig Rodrigues struct unionfs_node *unp; 934d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 935d00947d8SCraig Rodrigues struct vnode *ovp; 9362a31267eSMatthew Dillon 9371e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9381e5da15aSDaichi GOTO 939cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 940d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 941d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 942d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 943fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 94422db15c0SAttilio Rao VOP_UNLOCK(ap->a_vp, 0); 945d00947d8SCraig Rodrigues 946d00947d8SCraig Rodrigues if (ovp == NULLVP) 947d00947d8SCraig Rodrigues return (EBADF); 948d00947d8SCraig Rodrigues 949d00947d8SCraig Rodrigues return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td)); 950d00947d8SCraig Rodrigues } 951d00947d8SCraig Rodrigues 952d00947d8SCraig Rodrigues static int 953d00947d8SCraig Rodrigues unionfs_fsync(struct vop_fsync_args *ap) 954d00947d8SCraig Rodrigues { 955d00947d8SCraig Rodrigues struct unionfs_node *unp; 956d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 957d00947d8SCraig Rodrigues struct vnode *ovp; 958d00947d8SCraig Rodrigues 9591e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9601e5da15aSDaichi GOTO 961d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 962d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 963d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 964fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 965d00947d8SCraig Rodrigues 966d00947d8SCraig Rodrigues if (ovp == NULLVP) 967d00947d8SCraig Rodrigues return (EBADF); 968d00947d8SCraig Rodrigues 969d00947d8SCraig Rodrigues return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td)); 970d00947d8SCraig Rodrigues } 971d00947d8SCraig Rodrigues 972d00947d8SCraig Rodrigues static int 973d00947d8SCraig Rodrigues unionfs_remove(struct vop_remove_args *ap) 974d00947d8SCraig Rodrigues { 975d00947d8SCraig Rodrigues int error; 9761e5da15aSDaichi GOTO char *path; 977d00947d8SCraig Rodrigues struct unionfs_node *dunp; 978d00947d8SCraig Rodrigues struct unionfs_node *unp; 97920885defSDaichi GOTO struct unionfs_mount *ump; 980d00947d8SCraig Rodrigues struct vnode *udvp; 981d00947d8SCraig Rodrigues struct vnode *uvp; 982d00947d8SCraig Rodrigues struct vnode *lvp; 9831e5da15aSDaichi GOTO struct vnode *vp; 984d00947d8SCraig Rodrigues struct componentname *cnp; 9851e5da15aSDaichi GOTO struct componentname cn; 986d00947d8SCraig Rodrigues struct thread *td; 987d00947d8SCraig Rodrigues 988d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 989d00947d8SCraig Rodrigues 9901e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 9911e5da15aSDaichi GOTO 992d00947d8SCraig Rodrigues error = 0; 993d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 994d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 995d00947d8SCraig Rodrigues cnp = ap->a_cnp; 996d00947d8SCraig Rodrigues td = curthread; 997d00947d8SCraig Rodrigues 9981e5da15aSDaichi GOTO if (ap->a_vp->v_op != &unionfs_vnodeops) { 9991e5da15aSDaichi GOTO if (ap->a_vp->v_type != VSOCK) 10001e5da15aSDaichi GOTO return (EINVAL); 10011e5da15aSDaichi GOTO ump = NULL; 10021e5da15aSDaichi GOTO vp = uvp = lvp = NULLVP; 10031e5da15aSDaichi GOTO /* search vnode */ 10041e5da15aSDaichi GOTO VOP_UNLOCK(ap->a_vp, 0); 10051e5da15aSDaichi GOTO error = unionfs_relookup(udvp, &vp, cnp, &cn, td, 10061e5da15aSDaichi GOTO cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE); 10071e5da15aSDaichi GOTO if (error != 0 && error != ENOENT) { 10081e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 10091e5da15aSDaichi GOTO return (error); 10101e5da15aSDaichi GOTO } 10111e5da15aSDaichi GOTO 10121e5da15aSDaichi GOTO if (error == 0 && vp == ap->a_vp) { 10131e5da15aSDaichi GOTO /* target vnode in upper */ 10141e5da15aSDaichi GOTO uvp = vp; 10151e5da15aSDaichi GOTO vrele(vp); 10161e5da15aSDaichi GOTO path = NULL; 10171e5da15aSDaichi GOTO } else { 10181e5da15aSDaichi GOTO /* target vnode in lower */ 10191e5da15aSDaichi GOTO if (vp != NULLVP) { 10201e5da15aSDaichi GOTO if (udvp == vp) 10211e5da15aSDaichi GOTO vrele(vp); 10221e5da15aSDaichi GOTO else 10231e5da15aSDaichi GOTO vput(vp); 10241e5da15aSDaichi GOTO } 10251e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 10261e5da15aSDaichi GOTO lvp = ap->a_vp; 10271e5da15aSDaichi GOTO path = ap->a_cnp->cn_nameptr; 10281e5da15aSDaichi GOTO } 10291e5da15aSDaichi GOTO } else { 10301e5da15aSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 10311e5da15aSDaichi GOTO unp = VTOUNIONFS(ap->a_vp); 10321e5da15aSDaichi GOTO uvp = unp->un_uppervp; 10331e5da15aSDaichi GOTO lvp = unp->un_lowervp; 10341e5da15aSDaichi GOTO path = unp->un_path; 10351e5da15aSDaichi GOTO } 10361e5da15aSDaichi GOTO 1037d00947d8SCraig Rodrigues if (udvp == NULLVP) 1038d00947d8SCraig Rodrigues return (EROFS); 1039d00947d8SCraig Rodrigues 1040d00947d8SCraig Rodrigues if (uvp != NULLVP) { 10411e5da15aSDaichi GOTO /* 10421e5da15aSDaichi GOTO * XXX: if the vnode type is VSOCK, it will create whiteout 10431e5da15aSDaichi GOTO * after remove. 10441e5da15aSDaichi GOTO */ 10451e5da15aSDaichi GOTO if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS || 10461e5da15aSDaichi GOTO lvp != NULLVP) 1047d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1048d00947d8SCraig Rodrigues error = VOP_REMOVE(udvp, uvp, cnp); 1049d00947d8SCraig Rodrigues } else if (lvp != NULLVP) 10501e5da15aSDaichi GOTO error = unionfs_mkwhiteout(udvp, cnp, td, path); 1051d00947d8SCraig Rodrigues 1052d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 1053d00947d8SCraig Rodrigues 1054d00947d8SCraig Rodrigues return (error); 1055d00947d8SCraig Rodrigues } 1056d00947d8SCraig Rodrigues 1057d00947d8SCraig Rodrigues static int 1058d00947d8SCraig Rodrigues unionfs_link(struct vop_link_args *ap) 1059d00947d8SCraig Rodrigues { 1060d00947d8SCraig Rodrigues int error; 1061d00947d8SCraig Rodrigues int needrelookup; 1062d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1063d00947d8SCraig Rodrigues struct unionfs_node *unp; 1064d00947d8SCraig Rodrigues struct vnode *udvp; 1065d00947d8SCraig Rodrigues struct vnode *uvp; 1066d00947d8SCraig Rodrigues struct componentname *cnp; 1067d00947d8SCraig Rodrigues struct thread *td; 1068d00947d8SCraig Rodrigues 1069d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 1070d00947d8SCraig Rodrigues 10711e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_tdvp); 10721e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 10731e5da15aSDaichi GOTO 1074d00947d8SCraig Rodrigues error = 0; 1075d00947d8SCraig Rodrigues needrelookup = 0; 1076d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_tdvp); 1077d00947d8SCraig Rodrigues unp = NULL; 1078d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1079d00947d8SCraig Rodrigues uvp = NULLVP; 1080d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1081d00947d8SCraig Rodrigues td = curthread; 1082d00947d8SCraig Rodrigues 1083d00947d8SCraig Rodrigues if (udvp == NULLVP) 1084d00947d8SCraig Rodrigues return (EROFS); 1085d00947d8SCraig Rodrigues 1086d00947d8SCraig Rodrigues if (ap->a_vp->v_op != &unionfs_vnodeops) 1087d00947d8SCraig Rodrigues uvp = ap->a_vp; 1088d00947d8SCraig Rodrigues else { 1089d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1090d00947d8SCraig Rodrigues 1091d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1092d00947d8SCraig Rodrigues if (ap->a_vp->v_type != VREG) 1093d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1094d00947d8SCraig Rodrigues 1095d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, cnp->cn_cred, td); 1096d00947d8SCraig Rodrigues if (error != 0) 1097d00947d8SCraig Rodrigues return (error); 1098d00947d8SCraig Rodrigues needrelookup = 1; 1099d00947d8SCraig Rodrigues } 1100d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1101d00947d8SCraig Rodrigues } 1102d00947d8SCraig Rodrigues 1103d00947d8SCraig Rodrigues if (needrelookup != 0) 1104d00947d8SCraig Rodrigues error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td); 1105d00947d8SCraig Rodrigues 1106d00947d8SCraig Rodrigues if (error == 0) 1107d00947d8SCraig Rodrigues error = VOP_LINK(udvp, uvp, cnp); 1108d00947d8SCraig Rodrigues 1109d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 1110d00947d8SCraig Rodrigues 1111d00947d8SCraig Rodrigues return (error); 1112d00947d8SCraig Rodrigues } 1113d00947d8SCraig Rodrigues 1114d00947d8SCraig Rodrigues static int 1115d00947d8SCraig Rodrigues unionfs_rename(struct vop_rename_args *ap) 1116d00947d8SCraig Rodrigues { 1117d00947d8SCraig Rodrigues int error; 1118d00947d8SCraig Rodrigues struct vnode *fdvp; 1119d00947d8SCraig Rodrigues struct vnode *fvp; 1120d00947d8SCraig Rodrigues struct componentname *fcnp; 1121d00947d8SCraig Rodrigues struct vnode *tdvp; 1122d00947d8SCraig Rodrigues struct vnode *tvp; 1123d00947d8SCraig Rodrigues struct componentname *tcnp; 1124d00947d8SCraig Rodrigues struct vnode *ltdvp; 1125d00947d8SCraig Rodrigues struct vnode *ltvp; 1126d00947d8SCraig Rodrigues struct thread *td; 1127d00947d8SCraig Rodrigues 1128d00947d8SCraig Rodrigues /* rename target vnodes */ 1129d00947d8SCraig Rodrigues struct vnode *rfdvp; 1130d00947d8SCraig Rodrigues struct vnode *rfvp; 1131d00947d8SCraig Rodrigues struct vnode *rtdvp; 1132d00947d8SCraig Rodrigues struct vnode *rtvp; 1133d00947d8SCraig Rodrigues 1134d00947d8SCraig Rodrigues int needrelookup; 1135d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1136d00947d8SCraig Rodrigues struct unionfs_node *unp; 1137d00947d8SCraig Rodrigues 1138d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 1139d00947d8SCraig Rodrigues 1140d00947d8SCraig Rodrigues error = 0; 1141d00947d8SCraig Rodrigues fdvp = ap->a_fdvp; 1142d00947d8SCraig Rodrigues fvp = ap->a_fvp; 1143d00947d8SCraig Rodrigues fcnp = ap->a_fcnp; 1144d00947d8SCraig Rodrigues tdvp = ap->a_tdvp; 1145d00947d8SCraig Rodrigues tvp = ap->a_tvp; 1146d00947d8SCraig Rodrigues tcnp = ap->a_tcnp; 1147d00947d8SCraig Rodrigues ltdvp = NULLVP; 1148d00947d8SCraig Rodrigues ltvp = NULLVP; 1149d00947d8SCraig Rodrigues td = curthread; 1150d00947d8SCraig Rodrigues rfdvp = fdvp; 1151d00947d8SCraig Rodrigues rfvp = fvp; 1152d00947d8SCraig Rodrigues rtdvp = tdvp; 1153d00947d8SCraig Rodrigues rtvp = tvp; 1154d00947d8SCraig Rodrigues needrelookup = 0; 1155d00947d8SCraig Rodrigues 1156d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 1157d00947d8SCraig Rodrigues if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1158d00947d8SCraig Rodrigues panic("unionfs_rename: no name"); 11592a31267eSMatthew Dillon #endif 11602a31267eSMatthew Dillon 1161d00947d8SCraig Rodrigues /* check for cross device rename */ 1162d00947d8SCraig Rodrigues if (fvp->v_mount != tdvp->v_mount || 1163d00947d8SCraig Rodrigues (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 11641e5da15aSDaichi GOTO if (fvp->v_op != &unionfs_vnodeops) 11651e5da15aSDaichi GOTO error = ENODEV; 11661e5da15aSDaichi GOTO else 1167d00947d8SCraig Rodrigues error = EXDEV; 1168d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1169d00947d8SCraig Rodrigues } 1170d00947d8SCraig Rodrigues 1171d00947d8SCraig Rodrigues /* Renaming a file to itself has no effect. */ 1172d00947d8SCraig Rodrigues if (fvp == tvp) 1173d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1174d00947d8SCraig Rodrigues 1175d00947d8SCraig Rodrigues /* 1176d00947d8SCraig Rodrigues * from/to vnode is unionfs node. 1177d00947d8SCraig Rodrigues */ 1178d00947d8SCraig Rodrigues 11791e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fdvp); 11801e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fvp); 11811e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tdvp); 11821e5da15aSDaichi GOTO if (tvp != NULLVP) 11831e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tvp); 11841e5da15aSDaichi GOTO 1185d00947d8SCraig Rodrigues unp = VTOUNIONFS(fdvp); 1186d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1187d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp); 1188d00947d8SCraig Rodrigues #endif 1189d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1190d00947d8SCraig Rodrigues error = ENODEV; 1191d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1192d00947d8SCraig Rodrigues } 1193d00947d8SCraig Rodrigues rfdvp = unp->un_uppervp; 1194d00947d8SCraig Rodrigues vref(rfdvp); 1195d00947d8SCraig Rodrigues 1196d00947d8SCraig Rodrigues unp = VTOUNIONFS(fvp); 1197d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1198d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp); 1199d00947d8SCraig Rodrigues #endif 1200d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1201d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 12022a31267eSMatthew Dillon switch (fvp->v_type) { 12032a31267eSMatthew Dillon case VREG: 1204cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1205d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1206d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td); 120722db15c0SAttilio Rao VOP_UNLOCK(fvp, 0); 1208d00947d8SCraig Rodrigues if (error != 0) 1209d00947d8SCraig Rodrigues goto unionfs_rename_abort; 12102a31267eSMatthew Dillon break; 12112a31267eSMatthew Dillon case VDIR: 1212cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1213d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1214d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td); 121522db15c0SAttilio Rao VOP_UNLOCK(fvp, 0); 1216d00947d8SCraig Rodrigues if (error != 0) 1217d00947d8SCraig Rodrigues goto unionfs_rename_abort; 12182a31267eSMatthew Dillon break; 12192a31267eSMatthew Dillon default: 1220d00947d8SCraig Rodrigues error = ENODEV; 1221d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1222d00947d8SCraig Rodrigues } 1223d00947d8SCraig Rodrigues 1224d00947d8SCraig Rodrigues needrelookup = 1; 1225d00947d8SCraig Rodrigues } 1226d00947d8SCraig Rodrigues 1227d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1228d00947d8SCraig Rodrigues fcnp->cn_flags |= DOWHITEOUT; 1229d00947d8SCraig Rodrigues rfvp = unp->un_uppervp; 1230d00947d8SCraig Rodrigues vref(rfvp); 1231d00947d8SCraig Rodrigues 1232d00947d8SCraig Rodrigues unp = VTOUNIONFS(tdvp); 1233d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1234d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp); 1235d00947d8SCraig Rodrigues #endif 1236d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1237d00947d8SCraig Rodrigues error = ENODEV; 1238d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1239d00947d8SCraig Rodrigues } 1240d00947d8SCraig Rodrigues rtdvp = unp->un_uppervp; 1241d00947d8SCraig Rodrigues ltdvp = unp->un_lowervp; 1242d00947d8SCraig Rodrigues vref(rtdvp); 1243d00947d8SCraig Rodrigues 1244d00947d8SCraig Rodrigues if (tdvp == tvp) { 1245d00947d8SCraig Rodrigues rtvp = rtdvp; 1246d00947d8SCraig Rodrigues vref(rtvp); 1247d00947d8SCraig Rodrigues } else if (tvp != NULLVP) { 1248d00947d8SCraig Rodrigues unp = VTOUNIONFS(tvp); 1249d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1250d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp); 1251d00947d8SCraig Rodrigues #endif 1252d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) 1253d00947d8SCraig Rodrigues rtvp = NULLVP; 1254d00947d8SCraig Rodrigues else { 1255d00947d8SCraig Rodrigues if (tvp->v_type == VDIR) { 1256d00947d8SCraig Rodrigues error = EINVAL; 1257d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1258d00947d8SCraig Rodrigues } 1259d00947d8SCraig Rodrigues rtvp = unp->un_uppervp; 1260d00947d8SCraig Rodrigues ltvp = unp->un_lowervp; 1261d00947d8SCraig Rodrigues vref(rtvp); 1262df8bae1dSRodney W. Grimes } 12632a31267eSMatthew Dillon } 1264df8bae1dSRodney W. Grimes 12655307411cSDaichi GOTO if (rfvp == rtvp) 12665307411cSDaichi GOTO goto unionfs_rename_abort; 12675307411cSDaichi GOTO 1268d00947d8SCraig Rodrigues if (needrelookup != 0) { 1269cb05b60aSAttilio Rao if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1270d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1271d00947d8SCraig Rodrigues error = unionfs_relookup_for_delete(fdvp, fcnp, td); 127222db15c0SAttilio Rao VOP_UNLOCK(fdvp, 0); 1273d00947d8SCraig Rodrigues if (error != 0) 1274d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1275d00947d8SCraig Rodrigues 1276d00947d8SCraig Rodrigues /* Locke of tvp is canceled in order to avoid recursive lock. */ 1277d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 127822db15c0SAttilio Rao VOP_UNLOCK(tvp, 0); 1279d00947d8SCraig Rodrigues error = unionfs_relookup_for_rename(tdvp, tcnp, td); 1280d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 1281cb05b60aSAttilio Rao vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1282d00947d8SCraig Rodrigues if (error != 0) 1283d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1284df8bae1dSRodney W. Grimes } 1285df8bae1dSRodney W. Grimes 1286d00947d8SCraig Rodrigues error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 12872a31267eSMatthew Dillon 1288dc2dd185SDaichi GOTO if (error == 0) { 1289dc2dd185SDaichi GOTO if (rtvp != NULLVP && rtvp->v_type == VDIR) 1290dc2dd185SDaichi GOTO cache_purge(tdvp); 1291dc2dd185SDaichi GOTO if (fvp->v_type == VDIR && fdvp != tdvp) 1292dc2dd185SDaichi GOTO cache_purge(fdvp); 1293dc2dd185SDaichi GOTO } 1294dc2dd185SDaichi GOTO 12957e0c8995SDaichi GOTO if (ltdvp != NULLVP) 129622db15c0SAttilio Rao VOP_UNLOCK(ltdvp, 0); 1297d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1298d00947d8SCraig Rodrigues vrele(tdvp); 12997e0c8995SDaichi GOTO if (ltvp != NULLVP) 130022db15c0SAttilio Rao VOP_UNLOCK(ltvp, 0); 1301d00947d8SCraig Rodrigues if (tvp != rtvp && tvp != NULLVP) { 1302d00947d8SCraig Rodrigues if (rtvp == NULLVP) 1303df8bae1dSRodney W. Grimes vput(tvp); 13042a31267eSMatthew Dillon else 13052a31267eSMatthew Dillon vrele(tvp); 13062a31267eSMatthew Dillon } 13075307411cSDaichi GOTO if (fdvp != rfdvp) 13085307411cSDaichi GOTO vrele(fdvp); 13095307411cSDaichi GOTO if (fvp != rfvp) 13105307411cSDaichi GOTO vrele(fvp); 1311d00947d8SCraig Rodrigues 1312d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1313d00947d8SCraig Rodrigues 1314d00947d8SCraig Rodrigues return (error); 1315d00947d8SCraig Rodrigues 1316d00947d8SCraig Rodrigues unionfs_rename_abort: 13175307411cSDaichi GOTO vput(tdvp); 1318d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1319d00947d8SCraig Rodrigues vrele(rtdvp); 1320d00947d8SCraig Rodrigues if (tvp != NULLVP) { 1321d00947d8SCraig Rodrigues if (tdvp != tvp) 1322d00947d8SCraig Rodrigues vput(tvp); 1323d00947d8SCraig Rodrigues else 1324d00947d8SCraig Rodrigues vrele(tvp); 1325d00947d8SCraig Rodrigues } 13265307411cSDaichi GOTO if (tvp != rtvp && rtvp != NULLVP) 13275307411cSDaichi GOTO vrele(rtvp); 13285307411cSDaichi GOTO if (fdvp != rfdvp) 13295307411cSDaichi GOTO vrele(rfdvp); 13305307411cSDaichi GOTO if (fvp != rfvp) 13315307411cSDaichi GOTO vrele(rfvp); 1332d00947d8SCraig Rodrigues vrele(fdvp); 1333d00947d8SCraig Rodrigues vrele(fvp); 1334d00947d8SCraig Rodrigues 1335d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1336d00947d8SCraig Rodrigues 1337df8bae1dSRodney W. Grimes return (error); 1338df8bae1dSRodney W. Grimes } 1339df8bae1dSRodney W. Grimes 1340c9bf0111SKATO Takenori static int 1341d00947d8SCraig Rodrigues unionfs_mkdir(struct vop_mkdir_args *ap) 1342df8bae1dSRodney W. Grimes { 1343d00947d8SCraig Rodrigues int error; 134498155f1fSCraig Rodrigues int lkflags; 1345d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1346d00947d8SCraig Rodrigues struct componentname *cnp; 1347d00947d8SCraig Rodrigues struct thread *td; 1348d00947d8SCraig Rodrigues struct vnode *udvp; 1349d00947d8SCraig Rodrigues struct vnode *uvp; 1350d00947d8SCraig Rodrigues struct vattr va; 1351df8bae1dSRodney W. Grimes 1352d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1353d00947d8SCraig Rodrigues 13541e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 13551e5da15aSDaichi GOTO 1356d00947d8SCraig Rodrigues error = EROFS; 1357d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1358d00947d8SCraig Rodrigues cnp = ap->a_cnp; 135998155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1360d00947d8SCraig Rodrigues td = curthread; 1361d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1362d00947d8SCraig Rodrigues 1363d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1364d00947d8SCraig Rodrigues /* check opaque */ 1365d00947d8SCraig Rodrigues if (!(cnp->cn_flags & ISWHITEOUT)) { 13660359a12eSAttilio Rao error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1367d00947d8SCraig Rodrigues if (error != 0) 1368d00947d8SCraig Rodrigues return (error); 1369d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 1370d00947d8SCraig Rodrigues cnp->cn_flags |= ISWHITEOUT; 1371d00947d8SCraig Rodrigues } 1372d00947d8SCraig Rodrigues 1373d00947d8SCraig Rodrigues if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 137422db15c0SAttilio Rao VOP_UNLOCK(uvp, 0); 137598155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1376d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1377d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 137898155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1379d00947d8SCraig Rodrigues vrele(uvp); 1380d00947d8SCraig Rodrigues } 1381d00947d8SCraig Rodrigues } 1382d00947d8SCraig Rodrigues 1383d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1384d00947d8SCraig Rodrigues 1385d00947d8SCraig Rodrigues return (error); 1386d00947d8SCraig Rodrigues } 1387d00947d8SCraig Rodrigues 1388d00947d8SCraig Rodrigues static int 1389d00947d8SCraig Rodrigues unionfs_rmdir(struct vop_rmdir_args *ap) 1390d00947d8SCraig Rodrigues { 1391d00947d8SCraig Rodrigues int error; 1392d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1393d00947d8SCraig Rodrigues struct unionfs_node *unp; 139420885defSDaichi GOTO struct unionfs_mount *ump; 1395d00947d8SCraig Rodrigues struct componentname *cnp; 1396d00947d8SCraig Rodrigues struct thread *td; 1397d00947d8SCraig Rodrigues struct vnode *udvp; 1398d00947d8SCraig Rodrigues struct vnode *uvp; 1399d00947d8SCraig Rodrigues struct vnode *lvp; 1400d00947d8SCraig Rodrigues 1401d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1402d00947d8SCraig Rodrigues 14031e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 14041e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 14051e5da15aSDaichi GOTO 1406d00947d8SCraig Rodrigues error = 0; 1407d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1408d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1409d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1410d00947d8SCraig Rodrigues td = curthread; 1411d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1412d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1413d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1414d00947d8SCraig Rodrigues 1415d00947d8SCraig Rodrigues if (udvp == NULLVP) 1416d00947d8SCraig Rodrigues return (EROFS); 1417d00947d8SCraig Rodrigues 1418d00947d8SCraig Rodrigues if (udvp == uvp) 1419d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1420d00947d8SCraig Rodrigues 1421d00947d8SCraig Rodrigues if (uvp != NULLVP) { 1422d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1423d00947d8SCraig Rodrigues error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td); 1424d00947d8SCraig Rodrigues if (error != 0) 1425d00947d8SCraig Rodrigues return (error); 1426d00947d8SCraig Rodrigues } 142720885defSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 142820885defSDaichi GOTO if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1429d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1430d00947d8SCraig Rodrigues error = VOP_RMDIR(udvp, uvp, cnp); 1431d00947d8SCraig Rodrigues } 1432d00947d8SCraig Rodrigues else if (lvp != NULLVP) 1433d00947d8SCraig Rodrigues error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path); 1434d00947d8SCraig Rodrigues 1435dc2dd185SDaichi GOTO if (error == 0) { 1436dc2dd185SDaichi GOTO cache_purge(ap->a_dvp); 1437dc2dd185SDaichi GOTO cache_purge(ap->a_vp); 1438dc2dd185SDaichi GOTO } 1439dc2dd185SDaichi GOTO 1440d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1441d00947d8SCraig Rodrigues 1442d00947d8SCraig Rodrigues return (error); 1443d00947d8SCraig Rodrigues } 1444d00947d8SCraig Rodrigues 1445d00947d8SCraig Rodrigues static int 1446d00947d8SCraig Rodrigues unionfs_symlink(struct vop_symlink_args *ap) 1447d00947d8SCraig Rodrigues { 1448d00947d8SCraig Rodrigues int error; 144998155f1fSCraig Rodrigues int lkflags; 1450d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1451d00947d8SCraig Rodrigues struct componentname *cnp; 1452d00947d8SCraig Rodrigues struct thread *td; 1453d00947d8SCraig Rodrigues struct vnode *udvp; 1454d00947d8SCraig Rodrigues struct vnode *uvp; 1455d00947d8SCraig Rodrigues 1456d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1457d00947d8SCraig Rodrigues 14581e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 14591e5da15aSDaichi GOTO 1460d00947d8SCraig Rodrigues error = EROFS; 1461d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1462d00947d8SCraig Rodrigues cnp = ap->a_cnp; 146398155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1464d00947d8SCraig Rodrigues td = curthread; 1465d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1466d00947d8SCraig Rodrigues 1467d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1468d00947d8SCraig Rodrigues error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1469d00947d8SCraig Rodrigues if (error == 0) { 147022db15c0SAttilio Rao VOP_UNLOCK(uvp, 0); 147198155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1472d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1473d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 147498155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1475d00947d8SCraig Rodrigues vrele(uvp); 1476d00947d8SCraig Rodrigues } 1477d00947d8SCraig Rodrigues } 1478d00947d8SCraig Rodrigues 1479d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1480d00947d8SCraig Rodrigues 1481d00947d8SCraig Rodrigues return (error); 1482d00947d8SCraig Rodrigues } 1483d00947d8SCraig Rodrigues 1484d00947d8SCraig Rodrigues static int 1485d00947d8SCraig Rodrigues unionfs_readdir(struct vop_readdir_args *ap) 1486d00947d8SCraig Rodrigues { 1487d00947d8SCraig Rodrigues int error; 1488d00947d8SCraig Rodrigues int eofflag; 148998155f1fSCraig Rodrigues int locked; 1490d00947d8SCraig Rodrigues struct unionfs_node *unp; 1491d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 1492d00947d8SCraig Rodrigues struct uio *uio; 1493d00947d8SCraig Rodrigues struct vnode *uvp; 1494d00947d8SCraig Rodrigues struct vnode *lvp; 1495d00947d8SCraig Rodrigues struct thread *td; 1496d00947d8SCraig Rodrigues struct vattr va; 1497d00947d8SCraig Rodrigues 1498d00947d8SCraig Rodrigues int ncookies_bk; 1499d00947d8SCraig Rodrigues u_long *cookies_bk; 1500d00947d8SCraig Rodrigues 1501d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1502d00947d8SCraig Rodrigues 15031e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 15041e5da15aSDaichi GOTO 1505d00947d8SCraig Rodrigues error = 0; 1506d00947d8SCraig Rodrigues eofflag = 0; 150798155f1fSCraig Rodrigues locked = 0; 1508d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1509d00947d8SCraig Rodrigues uio = ap->a_uio; 1510d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1511d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1512d00947d8SCraig Rodrigues td = uio->uio_td; 1513d00947d8SCraig Rodrigues ncookies_bk = 0; 1514d00947d8SCraig Rodrigues cookies_bk = NULL; 1515d00947d8SCraig Rodrigues 1516d00947d8SCraig Rodrigues if (ap->a_vp->v_type != VDIR) 1517d00947d8SCraig Rodrigues return (ENOTDIR); 1518d00947d8SCraig Rodrigues 1519d00947d8SCraig Rodrigues /* check opaque */ 1520d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP) { 15210359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 15225adc4080SDaichi GOTO goto unionfs_readdir_exit; 1523d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 1524d00947d8SCraig Rodrigues lvp = NULLVP; 1525d00947d8SCraig Rodrigues } 1526d00947d8SCraig Rodrigues 15275adc4080SDaichi GOTO /* check the open count. unionfs needs to open before readdir. */ 152881c794f9SAttilio Rao if (VOP_ISLOCKED(ap->a_vp) != LK_EXCLUSIVE) { 1529cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_UPGRADE | LK_RETRY); 153098155f1fSCraig Rodrigues locked = 1; 153198155f1fSCraig Rodrigues } 15325adc4080SDaichi GOTO unionfs_get_node_status(unp, td, &unsp); 15335adc4080SDaichi GOTO if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 15345adc4080SDaichi GOTO (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1535fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 15365adc4080SDaichi GOTO error = EBADF; 15375adc4080SDaichi GOTO } 153898155f1fSCraig Rodrigues if (locked == 1) 1539cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_DOWNGRADE | LK_RETRY); 15405adc4080SDaichi GOTO if (error != 0) 15415adc4080SDaichi GOTO goto unionfs_readdir_exit; 1542d00947d8SCraig Rodrigues 1543d00947d8SCraig Rodrigues /* upper only */ 1544d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp == NULLVP) { 1545d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1546d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1547d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1548d00947d8SCraig Rodrigues 1549d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1550d00947d8SCraig Rodrigues } 1551d00947d8SCraig Rodrigues 1552d00947d8SCraig Rodrigues /* lower only */ 1553d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp != NULLVP) { 1554d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1555d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1556d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1557d00947d8SCraig Rodrigues 1558d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1559d00947d8SCraig Rodrigues } 1560d00947d8SCraig Rodrigues 1561d00947d8SCraig Rodrigues /* 1562d00947d8SCraig Rodrigues * readdir upper and lower 1563d00947d8SCraig Rodrigues */ 15646c98d0e9SDaichi GOTO KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp")); 15656c98d0e9SDaichi GOTO KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp")); 1566d00947d8SCraig Rodrigues if (uio->uio_offset == 0) 1567d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1568d00947d8SCraig Rodrigues 1569d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 0) { 1570d00947d8SCraig Rodrigues /* read upper */ 1571d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1572d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1573d00947d8SCraig Rodrigues 15745adc4080SDaichi GOTO if (error != 0 || eofflag == 0) 15755adc4080SDaichi GOTO goto unionfs_readdir_exit; 1576d00947d8SCraig Rodrigues unsp->uns_readdir_status = 1; 1577d00947d8SCraig Rodrigues 1578d00947d8SCraig Rodrigues /* 1579d00947d8SCraig Rodrigues * ufs(and other fs) needs size of uio_resid larger than 1580d00947d8SCraig Rodrigues * DIRBLKSIZ. 1581d00947d8SCraig Rodrigues * size of DIRBLKSIZ equals DEV_BSIZE. 1582d00947d8SCraig Rodrigues * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1583d00947d8SCraig Rodrigues */ 15845adc4080SDaichi GOTO if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 15855adc4080SDaichi GOTO goto unionfs_readdir_exit; 1586d00947d8SCraig Rodrigues 1587d00947d8SCraig Rodrigues /* 1588d00947d8SCraig Rodrigues * backup cookies 1589d00947d8SCraig Rodrigues * It prepares to readdir in lower. 1590d00947d8SCraig Rodrigues */ 1591d00947d8SCraig Rodrigues if (ap->a_ncookies != NULL) { 1592d00947d8SCraig Rodrigues ncookies_bk = *(ap->a_ncookies); 1593d00947d8SCraig Rodrigues *(ap->a_ncookies) = 0; 1594d00947d8SCraig Rodrigues } 1595d00947d8SCraig Rodrigues if (ap->a_cookies != NULL) { 1596d00947d8SCraig Rodrigues cookies_bk = *(ap->a_cookies); 1597d00947d8SCraig Rodrigues *(ap->a_cookies) = NULL; 1598d00947d8SCraig Rodrigues } 1599d00947d8SCraig Rodrigues } 1600d00947d8SCraig Rodrigues 1601d00947d8SCraig Rodrigues /* initialize for readdir in lower */ 1602d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 1) { 1603d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1604d00947d8SCraig Rodrigues uio->uio_offset = 0; 1605d00947d8SCraig Rodrigues } 1606d00947d8SCraig Rodrigues 1607b16f4eecSCraig Rodrigues if (lvp == NULLVP) { 1608b16f4eecSCraig Rodrigues error = EBADF; 1609b16f4eecSCraig Rodrigues goto unionfs_readdir_exit; 1610b16f4eecSCraig Rodrigues } 1611d00947d8SCraig Rodrigues /* read lower */ 1612d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1613d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1614d00947d8SCraig Rodrigues 1615d00947d8SCraig Rodrigues if (cookies_bk != NULL) { 1616d00947d8SCraig Rodrigues /* merge cookies */ 1617d00947d8SCraig Rodrigues int size; 1618d00947d8SCraig Rodrigues u_long *newcookies, *pos; 1619d00947d8SCraig Rodrigues 1620d00947d8SCraig Rodrigues size = *(ap->a_ncookies) + ncookies_bk; 1621d00947d8SCraig Rodrigues newcookies = (u_long *) malloc(size * sizeof(u_long), 1622d00947d8SCraig Rodrigues M_TEMP, M_WAITOK); 1623d00947d8SCraig Rodrigues pos = newcookies; 1624d00947d8SCraig Rodrigues 1625d00947d8SCraig Rodrigues memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long)); 1626d00947d8SCraig Rodrigues pos += ncookies_bk * sizeof(u_long); 1627d00947d8SCraig Rodrigues memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long)); 1628d00947d8SCraig Rodrigues free(cookies_bk, M_TEMP); 1629d00947d8SCraig Rodrigues free(*(ap->a_cookies), M_TEMP); 1630d00947d8SCraig Rodrigues *(ap->a_ncookies) = size; 1631d00947d8SCraig Rodrigues *(ap->a_cookies) = newcookies; 1632d00947d8SCraig Rodrigues } 1633d00947d8SCraig Rodrigues 1634d00947d8SCraig Rodrigues unionfs_readdir_exit: 16355adc4080SDaichi GOTO if (error != 0 && ap->a_eofflag != NULL) 16365adc4080SDaichi GOTO *(ap->a_eofflag) = 1; 16375adc4080SDaichi GOTO 1638d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1639d00947d8SCraig Rodrigues 1640d00947d8SCraig Rodrigues return (error); 1641d00947d8SCraig Rodrigues } 1642d00947d8SCraig Rodrigues 1643d00947d8SCraig Rodrigues static int 1644d00947d8SCraig Rodrigues unionfs_readlink(struct vop_readlink_args *ap) 1645d00947d8SCraig Rodrigues { 1646d00947d8SCraig Rodrigues int error; 1647d00947d8SCraig Rodrigues struct unionfs_node *unp; 1648df8bae1dSRodney W. Grimes struct vnode *vp; 1649df8bae1dSRodney W. Grimes 1650d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 16512a31267eSMatthew Dillon 16521e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 16531e5da15aSDaichi GOTO 1654d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1655d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1656d00947d8SCraig Rodrigues 1657d00947d8SCraig Rodrigues error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1658d00947d8SCraig Rodrigues 1659d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1660d00947d8SCraig Rodrigues 16612a31267eSMatthew Dillon return (error); 1662df8bae1dSRodney W. Grimes } 1663df8bae1dSRodney W. Grimes 1664c9bf0111SKATO Takenori static int 1665d00947d8SCraig Rodrigues unionfs_getwritemount(struct vop_getwritemount_args *ap) 1666df8bae1dSRodney W. Grimes { 16677be2d300SMike Smith int error; 1668d00947d8SCraig Rodrigues struct vnode *uvp; 1669d00947d8SCraig Rodrigues struct vnode *vp; 1670df8bae1dSRodney W. Grimes 1671d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); 1672996c772fSJohn Dyson 1673d00947d8SCraig Rodrigues error = 0; 1674d00947d8SCraig Rodrigues vp = ap->a_vp; 1675d00947d8SCraig Rodrigues 1676d00947d8SCraig Rodrigues if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) 1677d00947d8SCraig Rodrigues return (EACCES); 1678d00947d8SCraig Rodrigues 16791e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(vp); 16801e5da15aSDaichi GOTO 1681d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(vp); 1682d00947d8SCraig Rodrigues if (uvp == NULLVP && VREG == vp->v_type) 1683d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); 1684d00947d8SCraig Rodrigues 1685d00947d8SCraig Rodrigues if (uvp != NULLVP) 1686d00947d8SCraig Rodrigues error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); 1687d00947d8SCraig Rodrigues else { 1688d00947d8SCraig Rodrigues VI_LOCK(vp); 1689d00947d8SCraig Rodrigues if (vp->v_iflag & VI_FREE) 16906d8e1f82SBrian Feldman error = EOPNOTSUPP; 16916d8e1f82SBrian Feldman else 1692d00947d8SCraig Rodrigues error = EACCES; 1693d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1694df8bae1dSRodney W. Grimes } 1695d00947d8SCraig Rodrigues 1696d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error); 1697d00947d8SCraig Rodrigues 1698df8bae1dSRodney W. Grimes return (error); 1699df8bae1dSRodney W. Grimes } 1700df8bae1dSRodney W. Grimes 1701c9bf0111SKATO Takenori static int 1702d00947d8SCraig Rodrigues unionfs_inactive(struct vop_inactive_args *ap) 1703df8bae1dSRodney W. Grimes { 1704dc2dd185SDaichi GOTO ap->a_vp->v_object = NULL; 1705dc2dd185SDaichi GOTO vrecycle(ap->a_vp, ap->a_td); 1706d00947d8SCraig Rodrigues return (0); 1707df8bae1dSRodney W. Grimes } 1708df8bae1dSRodney W. Grimes 1709c9bf0111SKATO Takenori static int 1710d00947d8SCraig Rodrigues unionfs_reclaim(struct vop_reclaim_args *ap) 1711df8bae1dSRodney W. Grimes { 1712d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1713d00947d8SCraig Rodrigues 1714dc2dd185SDaichi GOTO unionfs_noderem(ap->a_vp, ap->a_td); 1715d00947d8SCraig Rodrigues 1716d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1717d00947d8SCraig Rodrigues 1718d00947d8SCraig Rodrigues return (0); 1719d00947d8SCraig Rodrigues } 1720d00947d8SCraig Rodrigues 1721d00947d8SCraig Rodrigues static int 1722d00947d8SCraig Rodrigues unionfs_print(struct vop_print_args *ap) 1723d00947d8SCraig Rodrigues { 1724d00947d8SCraig Rodrigues struct unionfs_node *unp; 1725d00947d8SCraig Rodrigues /* struct unionfs_node_status *unsp; */ 1726d00947d8SCraig Rodrigues 1727d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1728d00947d8SCraig Rodrigues /* unionfs_get_node_status(unp, curthread, &unsp); */ 1729d00947d8SCraig Rodrigues 1730d00947d8SCraig Rodrigues printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1731d00947d8SCraig Rodrigues ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1732d00947d8SCraig Rodrigues /* 1733d00947d8SCraig Rodrigues printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1734d00947d8SCraig Rodrigues unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1735d00947d8SCraig Rodrigues */ 1736d00947d8SCraig Rodrigues 1737d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 1738d00947d8SCraig Rodrigues vprint("unionfs: upper", unp->un_uppervp); 1739d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1740d00947d8SCraig Rodrigues vprint("unionfs: lower", unp->un_lowervp); 1741d00947d8SCraig Rodrigues 1742d00947d8SCraig Rodrigues return (0); 1743d00947d8SCraig Rodrigues } 1744d00947d8SCraig Rodrigues 1745d00947d8SCraig Rodrigues static int 1746d00947d8SCraig Rodrigues unionfs_get_llt_revlock(int flags) 1747d00947d8SCraig Rodrigues { 1748d00947d8SCraig Rodrigues int count; 1749d00947d8SCraig Rodrigues 1750d00947d8SCraig Rodrigues flags &= LK_TYPE_MASK; 1751d00947d8SCraig Rodrigues for (count = 0; un_llt[count].lock != 0; count++) { 1752d00947d8SCraig Rodrigues if (flags == un_llt[count].lock) { 1753d00947d8SCraig Rodrigues return un_llt[count].revlock; 1754d00947d8SCraig Rodrigues } 1755d00947d8SCraig Rodrigues } 1756d00947d8SCraig Rodrigues 1757d00947d8SCraig Rodrigues return 0; 1758d00947d8SCraig Rodrigues } 1759d00947d8SCraig Rodrigues 1760d00947d8SCraig Rodrigues static int 1761d413d210SKonstantin Belousov unionfs_lock(struct vop_lock1_args *ap) 1762d00947d8SCraig Rodrigues { 1763d00947d8SCraig Rodrigues int error; 1764d00947d8SCraig Rodrigues int flags; 1765d00947d8SCraig Rodrigues int revlock; 1766d00947d8SCraig Rodrigues int uhold; 176757821163SDaichi GOTO struct mount *mp; 1768d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1769d00947d8SCraig Rodrigues struct unionfs_node *unp; 1770d00947d8SCraig Rodrigues struct vnode *vp; 17712a31267eSMatthew Dillon struct vnode *uvp; 1772d00947d8SCraig Rodrigues struct vnode *lvp; 1773df8bae1dSRodney W. Grimes 17741e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 17751e5da15aSDaichi GOTO 1776d00947d8SCraig Rodrigues error = 0; 1777d00947d8SCraig Rodrigues uhold = 0; 1778d00947d8SCraig Rodrigues flags = ap->a_flags; 1779d00947d8SCraig Rodrigues vp = ap->a_vp; 1780df8bae1dSRodney W. Grimes 1781d00947d8SCraig Rodrigues if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK)) 178222db15c0SAttilio Rao return (VOP_UNLOCK(vp, flags)); 1783df8bae1dSRodney W. Grimes 1784d00947d8SCraig Rodrigues if ((revlock = unionfs_get_llt_revlock(flags)) == 0) 1785d00947d8SCraig Rodrigues panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); 17862a31267eSMatthew Dillon 178757821163SDaichi GOTO if ((flags & LK_INTERLOCK) == 0) 1788f3d1ec67SBoris Popov VI_LOCK(vp); 1789d00947d8SCraig Rodrigues 179057821163SDaichi GOTO mp = vp->v_mount; 179157821163SDaichi GOTO if (mp == NULL) 179257821163SDaichi GOTO goto unionfs_lock_null_vnode; 179357821163SDaichi GOTO 179457821163SDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(mp); 1795d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 179657821163SDaichi GOTO if (ump == NULL || unp == NULL) 1797d00947d8SCraig Rodrigues goto unionfs_lock_null_vnode; 1798d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1799d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1800f2a2857bSKirk McKusick 180157821163SDaichi GOTO if ((mp->mnt_kern_flag & MNTK_MPSAFE) != 0 && 180257821163SDaichi GOTO (vp->v_iflag & VI_OWEINACT) != 0) 180357821163SDaichi GOTO flags |= LK_NOWAIT; 180457821163SDaichi GOTO 18052a31267eSMatthew Dillon /* 1806d00947d8SCraig Rodrigues * Sometimes, lower or upper is already exclusive locked. 1807d00947d8SCraig Rodrigues * (ex. vfs_domount: mounted vnode is already locked.) 18082a31267eSMatthew Dillon */ 1809d00947d8SCraig Rodrigues if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1810d00947d8SCraig Rodrigues vp == ump->um_rootvp) 1811d00947d8SCraig Rodrigues flags |= LK_CANRECURSE; 18122a31267eSMatthew Dillon 1813d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1814d00947d8SCraig Rodrigues VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1815d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1816d00947d8SCraig Rodrigues vholdl(lvp); 1817df8bae1dSRodney W. Grimes 1818d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1819d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1820df8bae1dSRodney W. Grimes 182122db15c0SAttilio Rao error = VOP_LOCK(lvp, flags); 1822df8bae1dSRodney W. Grimes 1823d00947d8SCraig Rodrigues VI_LOCK(vp); 1824d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1825d00947d8SCraig Rodrigues if (unp == NULL) { 182657821163SDaichi GOTO VI_UNLOCK(vp); 1827d00947d8SCraig Rodrigues if (error == 0) 182822db15c0SAttilio Rao VOP_UNLOCK(lvp, 0); 1829d00947d8SCraig Rodrigues vdrop(lvp); 1830d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 18312a31267eSMatthew Dillon } 1832df8bae1dSRodney W. Grimes } 1833df8bae1dSRodney W. Grimes 1834d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 1835d00947d8SCraig Rodrigues VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1836d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1837d00947d8SCraig Rodrigues vholdl(uvp); 1838d00947d8SCraig Rodrigues uhold = 1; 1839df8bae1dSRodney W. Grimes 1840d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1841d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1842d00947d8SCraig Rodrigues 184322db15c0SAttilio Rao error = VOP_LOCK(uvp, flags); 1844d00947d8SCraig Rodrigues 1845d00947d8SCraig Rodrigues VI_LOCK(vp); 1846d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1847d00947d8SCraig Rodrigues if (unp == NULL) { 184857821163SDaichi GOTO VI_UNLOCK(vp); 1849d00947d8SCraig Rodrigues if (error == 0) { 185022db15c0SAttilio Rao VOP_UNLOCK(uvp, 0); 1851d00947d8SCraig Rodrigues if (lvp != NULLVP) 185222db15c0SAttilio Rao VOP_UNLOCK(lvp, 0); 1853d00947d8SCraig Rodrigues } 1854d00947d8SCraig Rodrigues if (lvp != NULLVP) 1855d00947d8SCraig Rodrigues vdrop(lvp); 1856d00947d8SCraig Rodrigues vdrop(uvp); 1857d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1858df8bae1dSRodney W. Grimes } 1859df8bae1dSRodney W. Grimes 186057821163SDaichi GOTO if (error != 0 && lvp != NULLVP) { 186157821163SDaichi GOTO VI_UNLOCK(vp); 186257821163SDaichi GOTO if ((revlock & LK_TYPE_MASK) == LK_RELEASE) 186322db15c0SAttilio Rao VOP_UNLOCK(lvp, revlock); 186457821163SDaichi GOTO else 1865cb05b60aSAttilio Rao vn_lock(lvp, revlock | LK_RETRY); 186657821163SDaichi GOTO goto unionfs_lock_abort; 186757821163SDaichi GOTO } 1868df8bae1dSRodney W. Grimes } 1869df8bae1dSRodney W. Grimes 1870d00947d8SCraig Rodrigues VI_UNLOCK(vp); 187157821163SDaichi GOTO unionfs_lock_abort: 1872d00947d8SCraig Rodrigues if (lvp != NULLVP) 1873d00947d8SCraig Rodrigues vdrop(lvp); 1874d00947d8SCraig Rodrigues if (uhold != 0) 1875d00947d8SCraig Rodrigues vdrop(uvp); 1876df8bae1dSRodney W. Grimes 1877df8bae1dSRodney W. Grimes return (error); 1878d00947d8SCraig Rodrigues 1879d00947d8SCraig Rodrigues unionfs_lock_null_vnode: 1880d00947d8SCraig Rodrigues ap->a_flags |= LK_INTERLOCK; 1881d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1882df8bae1dSRodney W. Grimes } 1883df8bae1dSRodney W. Grimes 1884c9bf0111SKATO Takenori static int 1885d00947d8SCraig Rodrigues unionfs_unlock(struct vop_unlock_args *ap) 1886df8bae1dSRodney W. Grimes { 1887d00947d8SCraig Rodrigues int error; 1888d00947d8SCraig Rodrigues int flags; 1889d00947d8SCraig Rodrigues int mtxlkflag; 1890d00947d8SCraig Rodrigues int uhold; 1891d00947d8SCraig Rodrigues struct vnode *vp; 1892d00947d8SCraig Rodrigues struct vnode *lvp; 1893d00947d8SCraig Rodrigues struct vnode *uvp; 1894d00947d8SCraig Rodrigues struct unionfs_node *unp; 1895df8bae1dSRodney W. Grimes 18961e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 18971e5da15aSDaichi GOTO 1898d00947d8SCraig Rodrigues error = 0; 1899d00947d8SCraig Rodrigues mtxlkflag = 0; 1900d00947d8SCraig Rodrigues uhold = 0; 1901d00947d8SCraig Rodrigues flags = ap->a_flags | LK_RELEASE; 1902d00947d8SCraig Rodrigues vp = ap->a_vp; 1903d00947d8SCraig Rodrigues 190457821163SDaichi GOTO if ((flags & LK_INTERLOCK) != 0) 1905d00947d8SCraig Rodrigues mtxlkflag = 1; 1906d00947d8SCraig Rodrigues else if (mtx_owned(VI_MTX(vp)) == 0) { 1907d00947d8SCraig Rodrigues VI_LOCK(vp); 1908d00947d8SCraig Rodrigues mtxlkflag = 2; 1909df8bae1dSRodney W. Grimes } 1910df8bae1dSRodney W. Grimes 1911d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1912d00947d8SCraig Rodrigues if (unp == NULL) 1913d00947d8SCraig Rodrigues goto unionfs_unlock_null_vnode; 1914d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1915d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1916df8bae1dSRodney W. Grimes 1917d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1918d00947d8SCraig Rodrigues VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1919d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1920d00947d8SCraig Rodrigues vholdl(lvp); 1921d00947d8SCraig Rodrigues 1922d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1923d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1924d00947d8SCraig Rodrigues 192522db15c0SAttilio Rao error = VOP_UNLOCK(lvp, flags); 1926d00947d8SCraig Rodrigues 1927d00947d8SCraig Rodrigues VI_LOCK(vp); 1928d00947d8SCraig Rodrigues } 1929d00947d8SCraig Rodrigues 1930d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 1931d00947d8SCraig Rodrigues VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1932d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1933d00947d8SCraig Rodrigues vholdl(uvp); 1934d00947d8SCraig Rodrigues uhold = 1; 1935d00947d8SCraig Rodrigues 1936d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1937d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1938d00947d8SCraig Rodrigues 193922db15c0SAttilio Rao error = VOP_UNLOCK(uvp, flags); 1940d00947d8SCraig Rodrigues 1941d00947d8SCraig Rodrigues VI_LOCK(vp); 1942d00947d8SCraig Rodrigues } 1943d00947d8SCraig Rodrigues 1944d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1945d00947d8SCraig Rodrigues if (lvp != NULLVP) 1946d00947d8SCraig Rodrigues vdrop(lvp); 1947d00947d8SCraig Rodrigues if (uhold != 0) 1948d00947d8SCraig Rodrigues vdrop(uvp); 1949d00947d8SCraig Rodrigues if (mtxlkflag == 0) 1950d00947d8SCraig Rodrigues VI_LOCK(vp); 1951d00947d8SCraig Rodrigues 1952d00947d8SCraig Rodrigues return error; 1953d00947d8SCraig Rodrigues 1954d00947d8SCraig Rodrigues unionfs_unlock_null_vnode: 1955d00947d8SCraig Rodrigues if (mtxlkflag == 2) 1956d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1957d00947d8SCraig Rodrigues return (vop_stdunlock(ap)); 1958d00947d8SCraig Rodrigues } 1959d00947d8SCraig Rodrigues 1960c9bf0111SKATO Takenori static int 1961d00947d8SCraig Rodrigues unionfs_pathconf(struct vop_pathconf_args *ap) 1962df8bae1dSRodney W. Grimes { 1963d00947d8SCraig Rodrigues struct unionfs_node *unp; 1964d00947d8SCraig Rodrigues struct vnode *vp; 1965d00947d8SCraig Rodrigues 19661e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 19671e5da15aSDaichi GOTO 1968d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1969d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1970d00947d8SCraig Rodrigues 1971d00947d8SCraig Rodrigues return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 1972d00947d8SCraig Rodrigues } 1973d00947d8SCraig Rodrigues 1974d00947d8SCraig Rodrigues static int 1975d00947d8SCraig Rodrigues unionfs_advlock(struct vop_advlock_args *ap) 1976d00947d8SCraig Rodrigues { 1977d00947d8SCraig Rodrigues int error; 1978d00947d8SCraig Rodrigues struct unionfs_node *unp; 1979d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 1980d00947d8SCraig Rodrigues struct vnode *vp; 1981d00947d8SCraig Rodrigues struct vnode *uvp; 1982d00947d8SCraig Rodrigues struct thread *td; 1983d00947d8SCraig Rodrigues 1984d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 1985d00947d8SCraig Rodrigues 19861e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 19871e5da15aSDaichi GOTO 1988d00947d8SCraig Rodrigues vp = ap->a_vp; 1989d00947d8SCraig Rodrigues td = curthread; 1990d00947d8SCraig Rodrigues 1991cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1992d00947d8SCraig Rodrigues 1993d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1994d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1995d00947d8SCraig Rodrigues 1996d00947d8SCraig Rodrigues if (uvp == NULLVP) { 1997d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, td->td_ucred, td); 1998d00947d8SCraig Rodrigues if (error != 0) 1999d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2000d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2001d00947d8SCraig Rodrigues 2002d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 2003d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) { 2004d00947d8SCraig Rodrigues /* try reopen the vnode */ 20059e223287SKonstantin Belousov error = VOP_OPEN(uvp, unsp->uns_lower_openmode, 20069e223287SKonstantin Belousov td->td_ucred, td, NULL); 2007d00947d8SCraig Rodrigues if (error) 2008d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2009d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 2010d00947d8SCraig Rodrigues VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td); 2011d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 2012b2b0db08SDaichi GOTO } else 2013fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 2014d00947d8SCraig Rodrigues } 2015d00947d8SCraig Rodrigues 201622db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2017d00947d8SCraig Rodrigues 2018d00947d8SCraig Rodrigues error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 2019d00947d8SCraig Rodrigues 2020d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2021d00947d8SCraig Rodrigues 2022d00947d8SCraig Rodrigues return error; 2023d00947d8SCraig Rodrigues 2024d00947d8SCraig Rodrigues unionfs_advlock_abort: 202522db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 2026d00947d8SCraig Rodrigues 2027d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2028d00947d8SCraig Rodrigues 2029d00947d8SCraig Rodrigues return error; 2030d00947d8SCraig Rodrigues } 2031d00947d8SCraig Rodrigues 2032d00947d8SCraig Rodrigues static int 2033d00947d8SCraig Rodrigues unionfs_strategy(struct vop_strategy_args *ap) 2034d00947d8SCraig Rodrigues { 2035d00947d8SCraig Rodrigues struct unionfs_node *unp; 2036d00947d8SCraig Rodrigues struct vnode *vp; 2037d00947d8SCraig Rodrigues 20381e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20391e5da15aSDaichi GOTO 2040d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2041d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2042df8bae1dSRodney W. Grimes 2043df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 2044d00947d8SCraig Rodrigues if (vp == NULLVP) 2045d00947d8SCraig Rodrigues panic("unionfs_strategy: nullvp"); 2046d00947d8SCraig Rodrigues 2047d00947d8SCraig Rodrigues if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 2048d00947d8SCraig Rodrigues panic("unionfs_strategy: writing to lowervp"); 2049df8bae1dSRodney W. Grimes #endif 2050d00947d8SCraig Rodrigues 2051d00947d8SCraig Rodrigues return (VOP_STRATEGY(vp, ap->a_bp)); 2052df8bae1dSRodney W. Grimes } 2053df8bae1dSRodney W. Grimes 205400fff2c7STim J. Robbins static int 2055d00947d8SCraig Rodrigues unionfs_getacl(struct vop_getacl_args *ap) 205600fff2c7STim J. Robbins { 205700fff2c7STim J. Robbins int error; 2058d00947d8SCraig Rodrigues struct unionfs_node *unp; 205900fff2c7STim J. Robbins struct vnode *vp; 206000fff2c7STim J. Robbins 20611e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20621e5da15aSDaichi GOTO 2063d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2064d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2065d00947d8SCraig Rodrigues 2066d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 2067d00947d8SCraig Rodrigues 2068d00947d8SCraig Rodrigues error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2069d00947d8SCraig Rodrigues 2070d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 207100fff2c7STim J. Robbins 207200fff2c7STim J. Robbins return (error); 207300fff2c7STim J. Robbins } 207400fff2c7STim J. Robbins 207500fff2c7STim J. Robbins static int 2076d00947d8SCraig Rodrigues unionfs_setacl(struct vop_setacl_args *ap) 207700fff2c7STim J. Robbins { 207800fff2c7STim J. Robbins int error; 2079d00947d8SCraig Rodrigues struct unionfs_node *unp; 2080d00947d8SCraig Rodrigues struct vnode *uvp; 2081d00947d8SCraig Rodrigues struct vnode *lvp; 2082d00947d8SCraig Rodrigues struct thread *td; 208300fff2c7STim J. Robbins 2084d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 2085d00947d8SCraig Rodrigues 20861e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20871e5da15aSDaichi GOTO 2088d00947d8SCraig Rodrigues error = EROFS; 2089d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2090d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2091d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2092d00947d8SCraig Rodrigues td = ap->a_td; 2093d00947d8SCraig Rodrigues 2094d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2095d00947d8SCraig Rodrigues return (EROFS); 2096d00947d8SCraig Rodrigues 2097d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2098d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2099d00947d8SCraig Rodrigues return (error); 2100d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2101d00947d8SCraig Rodrigues } 2102d00947d8SCraig Rodrigues 2103d00947d8SCraig Rodrigues if (uvp != NULLVP) 2104d00947d8SCraig Rodrigues error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 2105d00947d8SCraig Rodrigues 2106d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 210700fff2c7STim J. Robbins 210800fff2c7STim J. Robbins return (error); 210900fff2c7STim J. Robbins } 211000fff2c7STim J. Robbins 211100fff2c7STim J. Robbins static int 2112d00947d8SCraig Rodrigues unionfs_aclcheck(struct vop_aclcheck_args *ap) 211300fff2c7STim J. Robbins { 211400fff2c7STim J. Robbins int error; 2115d00947d8SCraig Rodrigues struct unionfs_node *unp; 211600fff2c7STim J. Robbins struct vnode *vp; 211700fff2c7STim J. Robbins 2118d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 2119d00947d8SCraig Rodrigues 21201e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21211e5da15aSDaichi GOTO 2122d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2123d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2124d00947d8SCraig Rodrigues 2125d00947d8SCraig Rodrigues error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2126d00947d8SCraig Rodrigues 2127d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 212800fff2c7STim J. Robbins 212900fff2c7STim J. Robbins return (error); 213000fff2c7STim J. Robbins } 213100fff2c7STim J. Robbins 213200fff2c7STim J. Robbins static int 2133d00947d8SCraig Rodrigues unionfs_openextattr(struct vop_openextattr_args *ap) 213400fff2c7STim J. Robbins { 213500fff2c7STim J. Robbins int error; 2136d00947d8SCraig Rodrigues struct unionfs_node *unp; 213700fff2c7STim J. Robbins struct vnode *vp; 213857821163SDaichi GOTO struct vnode *tvp; 213900fff2c7STim J. Robbins 21401e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21411e5da15aSDaichi GOTO 214257821163SDaichi GOTO vp = ap->a_vp; 214357821163SDaichi GOTO unp = VTOUNIONFS(vp); 214457821163SDaichi GOTO tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2145d00947d8SCraig Rodrigues 214657821163SDaichi GOTO if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 214757821163SDaichi GOTO (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 2148d00947d8SCraig Rodrigues return (EBUSY); 2149d00947d8SCraig Rodrigues 215057821163SDaichi GOTO error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td); 2151d00947d8SCraig Rodrigues 2152d00947d8SCraig Rodrigues if (error == 0) { 2153cb05b60aSAttilio Rao vn_lock(vp, LK_UPGRADE | LK_RETRY); 215457821163SDaichi GOTO if (tvp == unp->un_uppervp) 2155d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2156d00947d8SCraig Rodrigues else 2157d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTL; 2158cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2159d00947d8SCraig Rodrigues } 216000fff2c7STim J. Robbins 216100fff2c7STim J. Robbins return (error); 216200fff2c7STim J. Robbins } 216300fff2c7STim J. Robbins 216400fff2c7STim J. Robbins static int 2165d00947d8SCraig Rodrigues unionfs_closeextattr(struct vop_closeextattr_args *ap) 216600fff2c7STim J. Robbins { 216700fff2c7STim J. Robbins int error; 2168d00947d8SCraig Rodrigues struct unionfs_node *unp; 216900fff2c7STim J. Robbins struct vnode *vp; 217057821163SDaichi GOTO struct vnode *tvp; 217100fff2c7STim J. Robbins 21721e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21731e5da15aSDaichi GOTO 217457821163SDaichi GOTO vp = ap->a_vp; 217557821163SDaichi GOTO unp = VTOUNIONFS(vp); 217657821163SDaichi GOTO tvp = NULLVP; 2177d00947d8SCraig Rodrigues 2178d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 217957821163SDaichi GOTO tvp = unp->un_uppervp; 2180d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 218157821163SDaichi GOTO tvp = unp->un_lowervp; 2182d00947d8SCraig Rodrigues 218357821163SDaichi GOTO if (tvp == NULLVP) 2184d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2185d00947d8SCraig Rodrigues 218657821163SDaichi GOTO error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td); 2187d00947d8SCraig Rodrigues 2188d00947d8SCraig Rodrigues if (error == 0) { 2189cb05b60aSAttilio Rao vn_lock(vp, LK_UPGRADE | LK_RETRY); 219057821163SDaichi GOTO if (tvp == unp->un_uppervp) 2191d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTU; 2192d00947d8SCraig Rodrigues else 2193d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2194cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2195d00947d8SCraig Rodrigues } 219600fff2c7STim J. Robbins 219700fff2c7STim J. Robbins return (error); 219800fff2c7STim J. Robbins } 219900fff2c7STim J. Robbins 220000fff2c7STim J. Robbins static int 2201d00947d8SCraig Rodrigues unionfs_getextattr(struct vop_getextattr_args *ap) 220200fff2c7STim J. Robbins { 2203d00947d8SCraig Rodrigues struct unionfs_node *unp; 220400fff2c7STim J. Robbins struct vnode *vp; 220500fff2c7STim J. Robbins 22061e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22071e5da15aSDaichi GOTO 2208d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2209d00947d8SCraig Rodrigues vp = NULLVP; 2210d00947d8SCraig Rodrigues 2211d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2212d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2213d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2214d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2215d00947d8SCraig Rodrigues 2216d00947d8SCraig Rodrigues if (vp == NULLVP) 2217d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2218d00947d8SCraig Rodrigues 2219d00947d8SCraig Rodrigues return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2220d00947d8SCraig Rodrigues ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2221d00947d8SCraig Rodrigues } 2222d00947d8SCraig Rodrigues 2223d00947d8SCraig Rodrigues static int 2224d00947d8SCraig Rodrigues unionfs_setextattr(struct vop_setextattr_args *ap) 2225d00947d8SCraig Rodrigues { 2226d00947d8SCraig Rodrigues int error; 2227d00947d8SCraig Rodrigues struct unionfs_node *unp; 2228d00947d8SCraig Rodrigues struct vnode *uvp; 2229d00947d8SCraig Rodrigues struct vnode *lvp; 2230d00947d8SCraig Rodrigues struct vnode *ovp; 2231d00947d8SCraig Rodrigues struct ucred *cred; 2232d00947d8SCraig Rodrigues struct thread *td; 2233d00947d8SCraig Rodrigues 22341e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22351e5da15aSDaichi GOTO 2236d00947d8SCraig Rodrigues error = EROFS; 2237d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2238d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2239d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2240d00947d8SCraig Rodrigues ovp = NULLVP; 2241d00947d8SCraig Rodrigues cred = ap->a_cred; 2242d00947d8SCraig Rodrigues td = ap->a_td; 2243d00947d8SCraig Rodrigues 2244d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag); 2245d00947d8SCraig Rodrigues 2246d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2247d00947d8SCraig Rodrigues return (EROFS); 2248d00947d8SCraig Rodrigues 2249d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2250d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2251d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2252d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2253d00947d8SCraig Rodrigues 2254d00947d8SCraig Rodrigues if (ovp == NULLVP) 2255d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2256d00947d8SCraig Rodrigues 2257d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2258d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2259d00947d8SCraig Rodrigues if (uvp == NULLVP && 2260d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2261d00947d8SCraig Rodrigues unionfs_setextattr_reopen: 2262d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2263d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2264d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2265d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2266d00947d8SCraig Rodrigues #endif 2267d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2268d00947d8SCraig Rodrigues } 2269d00947d8SCraig Rodrigues goto unionfs_setextattr_abort; 2270d00947d8SCraig Rodrigues } 2271d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2272d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2273d00947d8SCraig Rodrigues goto unionfs_setextattr_reopen; 2274d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2275d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2276d00947d8SCraig Rodrigues ovp = uvp; 2277d00947d8SCraig Rodrigues } 2278d00947d8SCraig Rodrigues 2279d00947d8SCraig Rodrigues if (ovp == uvp) 2280d00947d8SCraig Rodrigues error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2281d00947d8SCraig Rodrigues ap->a_uio, cred, td); 2282d00947d8SCraig Rodrigues 2283d00947d8SCraig Rodrigues unionfs_setextattr_abort: 2284d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 228500fff2c7STim J. Robbins 228600fff2c7STim J. Robbins return (error); 228700fff2c7STim J. Robbins } 228800fff2c7STim J. Robbins 228900fff2c7STim J. Robbins static int 2290d00947d8SCraig Rodrigues unionfs_listextattr(struct vop_listextattr_args *ap) 229100fff2c7STim J. Robbins { 2292d00947d8SCraig Rodrigues struct unionfs_node *unp; 229300fff2c7STim J. Robbins struct vnode *vp; 229400fff2c7STim J. Robbins 22951e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22961e5da15aSDaichi GOTO 2297d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2298d00947d8SCraig Rodrigues vp = NULLVP; 2299d00947d8SCraig Rodrigues 2300d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2301d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2302d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2303d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2304d00947d8SCraig Rodrigues 2305d00947d8SCraig Rodrigues if (vp == NULLVP) 2306d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2307d00947d8SCraig Rodrigues 2308d00947d8SCraig Rodrigues return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2309d00947d8SCraig Rodrigues ap->a_size, ap->a_cred, ap->a_td)); 2310d00947d8SCraig Rodrigues } 2311d00947d8SCraig Rodrigues 2312d00947d8SCraig Rodrigues static int 2313d00947d8SCraig Rodrigues unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2314d00947d8SCraig Rodrigues { 2315d00947d8SCraig Rodrigues int error; 2316d00947d8SCraig Rodrigues struct unionfs_node *unp; 2317d00947d8SCraig Rodrigues struct vnode *uvp; 2318d00947d8SCraig Rodrigues struct vnode *lvp; 2319d00947d8SCraig Rodrigues struct vnode *ovp; 2320d00947d8SCraig Rodrigues struct ucred *cred; 2321d00947d8SCraig Rodrigues struct thread *td; 2322d00947d8SCraig Rodrigues 23231e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23241e5da15aSDaichi GOTO 2325d00947d8SCraig Rodrigues error = EROFS; 2326d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2327d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2328d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2329d00947d8SCraig Rodrigues ovp = NULLVP; 2330d00947d8SCraig Rodrigues cred = ap->a_cred; 2331d00947d8SCraig Rodrigues td = ap->a_td; 2332d00947d8SCraig Rodrigues 2333d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag); 2334d00947d8SCraig Rodrigues 2335d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2336d00947d8SCraig Rodrigues return (EROFS); 2337d00947d8SCraig Rodrigues 2338d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2339d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2340d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2341d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2342d00947d8SCraig Rodrigues 2343d00947d8SCraig Rodrigues if (ovp == NULLVP) 2344d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2345d00947d8SCraig Rodrigues 2346d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2347d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2348d00947d8SCraig Rodrigues if (uvp == NULLVP && 2349d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2350d00947d8SCraig Rodrigues unionfs_deleteextattr_reopen: 2351d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2352d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2353d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2354d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2355d00947d8SCraig Rodrigues #endif 2356d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2357d00947d8SCraig Rodrigues } 2358d00947d8SCraig Rodrigues goto unionfs_deleteextattr_abort; 2359d00947d8SCraig Rodrigues } 2360d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2361d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2362d00947d8SCraig Rodrigues goto unionfs_deleteextattr_reopen; 2363d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2364d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2365d00947d8SCraig Rodrigues ovp = uvp; 2366d00947d8SCraig Rodrigues } 2367d00947d8SCraig Rodrigues 2368d00947d8SCraig Rodrigues if (ovp == uvp) 2369d00947d8SCraig Rodrigues error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2370d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 2371d00947d8SCraig Rodrigues 2372d00947d8SCraig Rodrigues unionfs_deleteextattr_abort: 2373d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 237400fff2c7STim J. Robbins 237500fff2c7STim J. Robbins return (error); 237600fff2c7STim J. Robbins } 237700fff2c7STim J. Robbins 237800fff2c7STim J. Robbins static int 2379d00947d8SCraig Rodrigues unionfs_setlabel(struct vop_setlabel_args *ap) 238000fff2c7STim J. Robbins { 238100fff2c7STim J. Robbins int error; 2382d00947d8SCraig Rodrigues struct unionfs_node *unp; 2383d00947d8SCraig Rodrigues struct vnode *uvp; 2384d00947d8SCraig Rodrigues struct vnode *lvp; 2385d00947d8SCraig Rodrigues struct thread *td; 238600fff2c7STim J. Robbins 2387d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2388d00947d8SCraig Rodrigues 23891e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23901e5da15aSDaichi GOTO 2391d00947d8SCraig Rodrigues error = EROFS; 2392d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2393d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2394d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2395d00947d8SCraig Rodrigues td = ap->a_td; 2396d00947d8SCraig Rodrigues 2397d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2398d00947d8SCraig Rodrigues return (EROFS); 2399d00947d8SCraig Rodrigues 2400d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2401d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2402d00947d8SCraig Rodrigues return (error); 2403d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2404d00947d8SCraig Rodrigues } 2405d00947d8SCraig Rodrigues 2406d00947d8SCraig Rodrigues if (uvp != NULLVP) 2407d00947d8SCraig Rodrigues error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2408d00947d8SCraig Rodrigues 2409d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 241000fff2c7STim J. Robbins 241100fff2c7STim J. Robbins return (error); 241200fff2c7STim J. Robbins } 241300fff2c7STim J. Robbins 241410bcafe9SPawel Jakub Dawidek static int 241510bcafe9SPawel Jakub Dawidek unionfs_vptofh(struct vop_vptofh_args *ap) 241610bcafe9SPawel Jakub Dawidek { 241710bcafe9SPawel Jakub Dawidek return (EOPNOTSUPP); 241810bcafe9SPawel Jakub Dawidek } 241910bcafe9SPawel Jakub Dawidek 2420d00947d8SCraig Rodrigues struct vop_vector unionfs_vnodeops = { 2421aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 242283c64397SPoul-Henning Kamp 2423d00947d8SCraig Rodrigues .vop_access = unionfs_access, 2424d00947d8SCraig Rodrigues .vop_aclcheck = unionfs_aclcheck, 2425d00947d8SCraig Rodrigues .vop_advlock = unionfs_advlock, 2426aec0fb7bSPoul-Henning Kamp .vop_bmap = VOP_EOPNOTSUPP, 2427dc2dd185SDaichi GOTO .vop_cachedlookup = unionfs_lookup, 2428d00947d8SCraig Rodrigues .vop_close = unionfs_close, 2429d00947d8SCraig Rodrigues .vop_closeextattr = unionfs_closeextattr, 2430d00947d8SCraig Rodrigues .vop_create = unionfs_create, 2431d00947d8SCraig Rodrigues .vop_deleteextattr = unionfs_deleteextattr, 2432d00947d8SCraig Rodrigues .vop_fsync = unionfs_fsync, 2433d00947d8SCraig Rodrigues .vop_getacl = unionfs_getacl, 2434d00947d8SCraig Rodrigues .vop_getattr = unionfs_getattr, 2435d00947d8SCraig Rodrigues .vop_getextattr = unionfs_getextattr, 2436d00947d8SCraig Rodrigues .vop_getwritemount = unionfs_getwritemount, 2437d00947d8SCraig Rodrigues .vop_inactive = unionfs_inactive, 2438d00947d8SCraig Rodrigues .vop_ioctl = unionfs_ioctl, 2439d00947d8SCraig Rodrigues .vop_link = unionfs_link, 2440d00947d8SCraig Rodrigues .vop_listextattr = unionfs_listextattr, 2441d413d210SKonstantin Belousov .vop_lock1 = unionfs_lock, 2442dc2dd185SDaichi GOTO .vop_lookup = vfs_cache_lookup, 2443d00947d8SCraig Rodrigues .vop_mkdir = unionfs_mkdir, 2444d00947d8SCraig Rodrigues .vop_mknod = unionfs_mknod, 2445d00947d8SCraig Rodrigues .vop_open = unionfs_open, 2446d00947d8SCraig Rodrigues .vop_openextattr = unionfs_openextattr, 2447d00947d8SCraig Rodrigues .vop_pathconf = unionfs_pathconf, 2448d00947d8SCraig Rodrigues .vop_poll = unionfs_poll, 2449d00947d8SCraig Rodrigues .vop_print = unionfs_print, 2450d00947d8SCraig Rodrigues .vop_read = unionfs_read, 2451d00947d8SCraig Rodrigues .vop_readdir = unionfs_readdir, 2452d00947d8SCraig Rodrigues .vop_readlink = unionfs_readlink, 2453d00947d8SCraig Rodrigues .vop_reclaim = unionfs_reclaim, 2454d00947d8SCraig Rodrigues .vop_remove = unionfs_remove, 2455d00947d8SCraig Rodrigues .vop_rename = unionfs_rename, 2456d00947d8SCraig Rodrigues .vop_rmdir = unionfs_rmdir, 2457d00947d8SCraig Rodrigues .vop_setacl = unionfs_setacl, 2458d00947d8SCraig Rodrigues .vop_setattr = unionfs_setattr, 2459d00947d8SCraig Rodrigues .vop_setextattr = unionfs_setextattr, 2460d00947d8SCraig Rodrigues .vop_setlabel = unionfs_setlabel, 2461d00947d8SCraig Rodrigues .vop_strategy = unionfs_strategy, 2462d00947d8SCraig Rodrigues .vop_symlink = unionfs_symlink, 2463d00947d8SCraig Rodrigues .vop_unlock = unionfs_unlock, 2464d00947d8SCraig Rodrigues .vop_whiteout = unionfs_whiteout, 2465d00947d8SCraig Rodrigues .vop_write = unionfs_write, 246610bcafe9SPawel Jakub Dawidek .vop_vptofh = unionfs_vptofh, 2467df8bae1dSRodney W. Grimes }; 2468