1d167cf6fSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. 5996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 6d00947d8SCraig Rodrigues * The Regents of the University of California. 7cb5736b7SDaichi GOTO * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 8cb5736b7SDaichi GOTO * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org> 9d00947d8SCraig Rodrigues * All rights reserved. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 12df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 13df8bae1dSRodney W. Grimes * 14df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 15df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 16df8bae1dSRodney W. Grimes * are met: 17df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 19df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 20df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 21df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 22fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38996c772fSJohn Dyson * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 39c3aac50fSPeter Wemm * $FreeBSD$ 40d00947d8SCraig Rodrigues * 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes #include <sys/param.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 45d00947d8SCraig Rodrigues #include <sys/conf.h> 46d00947d8SCraig Rodrigues #include <sys/kernel.h> 47d00947d8SCraig Rodrigues #include <sys/lock.h> 48d00947d8SCraig Rodrigues #include <sys/malloc.h> 49d00947d8SCraig Rodrigues #include <sys/mount.h> 50d00947d8SCraig Rodrigues #include <sys/mutex.h> 51d00947d8SCraig Rodrigues #include <sys/namei.h> 52d00947d8SCraig Rodrigues #include <sys/sysctl.h> 53d00947d8SCraig Rodrigues #include <sys/vnode.h> 54d00947d8SCraig Rodrigues #include <sys/kdb.h> 553ac4d1efSBruce Evans #include <sys/fcntl.h> 56996c772fSJohn Dyson #include <sys/stat.h> 57d00947d8SCraig Rodrigues #include <sys/dirent.h> 58d00947d8SCraig Rodrigues #include <sys/proc.h> 593d253c11SCraig Rodrigues #include <sys/bio.h> 603d253c11SCraig Rodrigues #include <sys/buf.h> 61d00947d8SCraig Rodrigues 6299d300a1SRuslan Ermilov #include <fs/unionfs/union.h> 63df8bae1dSRodney W. Grimes 642a31267eSMatthew Dillon #include <vm/vm.h> 65d00947d8SCraig Rodrigues #include <vm/vm_extern.h> 66d00947d8SCraig Rodrigues #include <vm/vm_object.h> 672a31267eSMatthew Dillon #include <vm/vnode_pager.h> 682a31267eSMatthew Dillon 69d00947d8SCraig Rodrigues #if 0 70d00947d8SCraig Rodrigues #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) 71d00947d8SCraig Rodrigues #define UNIONFS_IDBG_RENAME 722a31267eSMatthew Dillon #else 73d00947d8SCraig Rodrigues #define UNIONFS_INTERNAL_DEBUG(msg, args...) 742a31267eSMatthew Dillon #endif 75df8bae1dSRodney W. Grimes 761e5da15aSDaichi GOTO #define KASSERT_UNIONFS_VNODE(vp) \ 771e5da15aSDaichi GOTO KASSERT(((vp)->v_op == &unionfs_vnodeops), \ 781e5da15aSDaichi GOTO ("unionfs: it is not unionfs-vnode")) 791e5da15aSDaichi GOTO 80df8bae1dSRodney W. Grimes static int 81dc2dd185SDaichi GOTO unionfs_lookup(struct vop_cachedlookup_args *ap) 82df8bae1dSRodney W. Grimes { 83d00947d8SCraig Rodrigues int iswhiteout; 84d00947d8SCraig Rodrigues int lockflag; 85d00947d8SCraig Rodrigues int error , uerror, lerror; 86d00947d8SCraig Rodrigues u_long nameiop; 87d00947d8SCraig Rodrigues u_long cnflags, cnflagsbk; 88d00947d8SCraig Rodrigues struct unionfs_node *dunp; 89d00947d8SCraig Rodrigues struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp; 90d00947d8SCraig Rodrigues struct vattr va; 91d00947d8SCraig Rodrigues struct componentname *cnp; 92d00947d8SCraig Rodrigues struct thread *td; 93d00947d8SCraig Rodrigues 94d00947d8SCraig Rodrigues iswhiteout = 0; 95d00947d8SCraig Rodrigues lockflag = 0; 96d00947d8SCraig Rodrigues error = uerror = lerror = ENOENT; 97d00947d8SCraig Rodrigues cnp = ap->a_cnp; 98d00947d8SCraig Rodrigues nameiop = cnp->cn_nameiop; 99d00947d8SCraig Rodrigues cnflags = cnp->cn_flags; 100d00947d8SCraig Rodrigues dvp = ap->a_dvp; 101d00947d8SCraig Rodrigues dunp = VTOUNIONFS(dvp); 102d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 103d00947d8SCraig Rodrigues ldvp = dunp->un_lowervp; 104d00947d8SCraig Rodrigues vp = uvp = lvp = NULLVP; 105d00947d8SCraig Rodrigues td = curthread; 106d00947d8SCraig Rodrigues *(ap->a_vpp) = NULLVP; 107d00947d8SCraig Rodrigues 108d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr); 109d00947d8SCraig Rodrigues 110d00947d8SCraig Rodrigues if (dvp->v_type != VDIR) 111d00947d8SCraig Rodrigues return (ENOTDIR); 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes /* 114d00947d8SCraig Rodrigues * If read-only and op is not LOOKUP, will return EROFS. 115df8bae1dSRodney W. Grimes */ 116d00947d8SCraig Rodrigues if ((cnflags & ISLASTCN) && 117d00947d8SCraig Rodrigues (dvp->v_mount->mnt_flag & MNT_RDONLY) && 118d00947d8SCraig Rodrigues LOOKUP != nameiop) 119d00947d8SCraig Rodrigues return (EROFS); 120d00947d8SCraig Rodrigues 121df8bae1dSRodney W. Grimes /* 122d00947d8SCraig Rodrigues * lookup dotdot 123df8bae1dSRodney W. Grimes */ 124d00947d8SCraig Rodrigues if (cnflags & ISDOTDOT) { 125d00947d8SCraig Rodrigues if (LOOKUP != nameiop && udvp == NULLVP) 126d00947d8SCraig Rodrigues return (EROFS); 127d00947d8SCraig Rodrigues 128d00947d8SCraig Rodrigues if (udvp != NULLVP) { 129d00947d8SCraig Rodrigues dtmpvp = udvp; 130d00947d8SCraig Rodrigues if (ldvp != NULLVP) 131cb5736b7SDaichi GOTO VOP_UNLOCK(ldvp, LK_RELEASE); 132d00947d8SCraig Rodrigues } 133d00947d8SCraig Rodrigues else 134d00947d8SCraig Rodrigues dtmpvp = ldvp; 135d00947d8SCraig Rodrigues 136d00947d8SCraig Rodrigues error = VOP_LOOKUP(dtmpvp, &vp, cnp); 137d00947d8SCraig Rodrigues 138d00947d8SCraig Rodrigues if (dtmpvp == udvp && ldvp != NULLVP) { 139cb5736b7SDaichi GOTO VOP_UNLOCK(udvp, LK_RELEASE); 140cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 141df8bae1dSRodney W. Grimes } 142df8bae1dSRodney W. Grimes 1432a31267eSMatthew Dillon if (error == 0) { 144d00947d8SCraig Rodrigues /* 145d00947d8SCraig Rodrigues * Exchange lock and reference from vp to 146d00947d8SCraig Rodrigues * dunp->un_dvp. vp is upper/lower vnode, but it 147d00947d8SCraig Rodrigues * will need to return the unionfs vnode. 148d00947d8SCraig Rodrigues */ 149d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 150d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 151cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 152d00947d8SCraig Rodrigues vrele(vp); 153d00947d8SCraig Rodrigues 154cb5736b7SDaichi GOTO VOP_UNLOCK(dvp, LK_RELEASE); 155d00947d8SCraig Rodrigues *(ap->a_vpp) = dunp->un_dvp; 156d00947d8SCraig Rodrigues vref(dunp->un_dvp); 157d00947d8SCraig Rodrigues 158d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME) 159cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY); 160d00947d8SCraig Rodrigues else if (cnp->cn_lkflags & LK_TYPE_MASK) 161cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, cnp->cn_lkflags | 162cb05b60aSAttilio Rao LK_RETRY); 163d00947d8SCraig Rodrigues 164cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1656c21f6edSKonstantin Belousov } else if (error == ENOENT && (cnflags & MAKEENTRY) != 0) 166dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 167d00947d8SCraig Rodrigues 168d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 169d00947d8SCraig Rodrigues 170d00947d8SCraig Rodrigues return (error); 1712a31267eSMatthew Dillon } 172d00947d8SCraig Rodrigues 173d00947d8SCraig Rodrigues /* 174d00947d8SCraig Rodrigues * lookup upper layer 175d00947d8SCraig Rodrigues */ 176d00947d8SCraig Rodrigues if (udvp != NULLVP) { 177d00947d8SCraig Rodrigues uerror = VOP_LOOKUP(udvp, &uvp, cnp); 178d00947d8SCraig Rodrigues 179d00947d8SCraig Rodrigues if (uerror == 0) { 180d00947d8SCraig Rodrigues if (udvp == uvp) { /* is dot */ 181d00947d8SCraig Rodrigues vrele(uvp); 182d00947d8SCraig Rodrigues *(ap->a_vpp) = dvp; 183d00947d8SCraig Rodrigues vref(dvp); 184d00947d8SCraig Rodrigues 185d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror); 186d00947d8SCraig Rodrigues 187d00947d8SCraig Rodrigues return (uerror); 188d00947d8SCraig Rodrigues } 189d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 190d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 191cb5736b7SDaichi GOTO VOP_UNLOCK(uvp, LK_RELEASE); 192d00947d8SCraig Rodrigues } 193d00947d8SCraig Rodrigues 194d00947d8SCraig Rodrigues /* check whiteout */ 195d00947d8SCraig Rodrigues if (uerror == ENOENT || uerror == EJUSTRETURN) 196d00947d8SCraig Rodrigues if (cnp->cn_flags & ISWHITEOUT) 197d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 198d00947d8SCraig Rodrigues if (iswhiteout == 0 && ldvp != NULLVP) 1990359a12eSAttilio Rao if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) && 200d00947d8SCraig Rodrigues (va.va_flags & OPAQUE)) 201d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 202d00947d8SCraig Rodrigues #if 0 203d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr); 204d00947d8SCraig Rodrigues #endif 205d00947d8SCraig Rodrigues } 206d00947d8SCraig Rodrigues 207d00947d8SCraig Rodrigues /* 208d00947d8SCraig Rodrigues * lookup lower layer 209d00947d8SCraig Rodrigues */ 210d00947d8SCraig Rodrigues if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) { 211d00947d8SCraig Rodrigues /* always op is LOOKUP */ 212d00947d8SCraig Rodrigues cnp->cn_nameiop = LOOKUP; 213d00947d8SCraig Rodrigues cnflagsbk = cnp->cn_flags; 214d00947d8SCraig Rodrigues cnp->cn_flags = cnflags; 215d00947d8SCraig Rodrigues 216d00947d8SCraig Rodrigues lerror = VOP_LOOKUP(ldvp, &lvp, cnp); 217d00947d8SCraig Rodrigues 218d00947d8SCraig Rodrigues cnp->cn_nameiop = nameiop; 219d00947d8SCraig Rodrigues if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) 220d00947d8SCraig Rodrigues cnp->cn_flags = cnflagsbk; 221d00947d8SCraig Rodrigues 222d00947d8SCraig Rodrigues if (lerror == 0) { 223d00947d8SCraig Rodrigues if (ldvp == lvp) { /* is dot */ 224d00947d8SCraig Rodrigues if (uvp != NULLVP) 225d00947d8SCraig Rodrigues vrele(uvp); /* no need? */ 226d00947d8SCraig Rodrigues vrele(lvp); 227d00947d8SCraig Rodrigues *(ap->a_vpp) = dvp; 228d00947d8SCraig Rodrigues vref(dvp); 229d00947d8SCraig Rodrigues 230d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror); 231d00947d8SCraig Rodrigues 232d00947d8SCraig Rodrigues return (lerror); 233d00947d8SCraig Rodrigues } 234d00947d8SCraig Rodrigues if (cnp->cn_lkflags & LK_TYPE_MASK) 235cb5736b7SDaichi GOTO VOP_UNLOCK(lvp, LK_RELEASE); 236d00947d8SCraig Rodrigues } 237d00947d8SCraig Rodrigues } 238d00947d8SCraig Rodrigues 239d00947d8SCraig Rodrigues /* 240d00947d8SCraig Rodrigues * check lookup result 241d00947d8SCraig Rodrigues */ 242d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp == NULLVP) { 243d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", 244d00947d8SCraig Rodrigues (udvp != NULLVP ? uerror : lerror)); 245d00947d8SCraig Rodrigues return (udvp != NULLVP ? uerror : lerror); 246d00947d8SCraig Rodrigues } 247d00947d8SCraig Rodrigues 248d00947d8SCraig Rodrigues /* 249d00947d8SCraig Rodrigues * check vnode type 250d00947d8SCraig Rodrigues */ 251d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) { 252d00947d8SCraig Rodrigues vrele(lvp); 253d00947d8SCraig Rodrigues lvp = NULLVP; 254d00947d8SCraig Rodrigues } 255d00947d8SCraig Rodrigues 256d00947d8SCraig Rodrigues /* 257d00947d8SCraig Rodrigues * check shadow dir 258d00947d8SCraig Rodrigues */ 259d00947d8SCraig Rodrigues if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP && 260d00947d8SCraig Rodrigues lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR && 261d00947d8SCraig Rodrigues !(dvp->v_mount->mnt_flag & MNT_RDONLY) && 262d00947d8SCraig Rodrigues (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) { 263d00947d8SCraig Rodrigues /* get unionfs vnode in order to create a new shadow dir. */ 264d00947d8SCraig Rodrigues error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp, 265d00947d8SCraig Rodrigues cnp, td); 266d00947d8SCraig Rodrigues if (error != 0) 267d00947d8SCraig Rodrigues goto unionfs_lookup_out; 268d00947d8SCraig Rodrigues 269d00947d8SCraig Rodrigues if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK)) 270cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 27181c794f9SAttilio Rao if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) { 272cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 273d00947d8SCraig Rodrigues lockflag = 1; 274d00947d8SCraig Rodrigues } 275d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), 276d00947d8SCraig Rodrigues udvp, VTOUNIONFS(vp), cnp, td); 277d00947d8SCraig Rodrigues if (lockflag != 0) 278cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 279d00947d8SCraig Rodrigues if (error != 0) { 280d00947d8SCraig Rodrigues UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir."); 281d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) 282d00947d8SCraig Rodrigues vput(vp); 283d00947d8SCraig Rodrigues else 284d00947d8SCraig Rodrigues vrele(vp); 285d00947d8SCraig Rodrigues goto unionfs_lookup_out; 286d00947d8SCraig Rodrigues } 287d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED) 288cb05b60aSAttilio Rao vn_lock(vp, LK_SHARED | LK_RETRY); 289d00947d8SCraig Rodrigues } 290d00947d8SCraig Rodrigues /* 291d00947d8SCraig Rodrigues * get unionfs vnode. 292d00947d8SCraig Rodrigues */ 293d00947d8SCraig Rodrigues else { 294d00947d8SCraig Rodrigues if (uvp != NULLVP) 295d00947d8SCraig Rodrigues error = uerror; 296d00947d8SCraig Rodrigues else 297d00947d8SCraig Rodrigues error = lerror; 298d00947d8SCraig Rodrigues if (error != 0) 299d00947d8SCraig Rodrigues goto unionfs_lookup_out; 3001e5da15aSDaichi GOTO /* 3011e5da15aSDaichi GOTO * get socket vnode. 3021e5da15aSDaichi GOTO */ 3031e5da15aSDaichi GOTO if (uvp != NULLVP && uvp->v_type == VSOCK) { 3041e5da15aSDaichi GOTO vp = uvp; 3051e5da15aSDaichi GOTO vref(vp); 3061e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3071e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3081e5da15aSDaichi GOTO } 3091e5da15aSDaichi GOTO else if (lvp != NULLVP && lvp->v_type == VSOCK) { 3101e5da15aSDaichi GOTO vp = lvp; 3111e5da15aSDaichi GOTO vref(vp); 3121e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3131e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3141e5da15aSDaichi GOTO } 3151e5da15aSDaichi GOTO /* 3161e5da15aSDaichi GOTO * get unionfs vnode. 3171e5da15aSDaichi GOTO */ 3181e5da15aSDaichi GOTO else 3191e5da15aSDaichi GOTO error = unionfs_nodeget(dvp->v_mount, uvp, lvp, 3201e5da15aSDaichi GOTO dvp, &vp, cnp, td); 321d00947d8SCraig Rodrigues if (error != 0) { 322d00947d8SCraig Rodrigues UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode."); 323d00947d8SCraig Rodrigues goto unionfs_lookup_out; 324d00947d8SCraig Rodrigues } 325d00947d8SCraig Rodrigues if ((nameiop == DELETE || nameiop == RENAME) && 326d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK) == 0) 327cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 328d00947d8SCraig Rodrigues } 329d00947d8SCraig Rodrigues 330d00947d8SCraig Rodrigues *(ap->a_vpp) = vp; 331d00947d8SCraig Rodrigues 3321e5da15aSDaichi GOTO if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK) 333dc2dd185SDaichi GOTO cache_enter(dvp, vp, cnp); 334dc2dd185SDaichi GOTO 335d00947d8SCraig Rodrigues unionfs_lookup_out: 336d00947d8SCraig Rodrigues if (uvp != NULLVP) 337d00947d8SCraig Rodrigues vrele(uvp); 338d00947d8SCraig Rodrigues if (lvp != NULLVP) 339d00947d8SCraig Rodrigues vrele(lvp); 340d00947d8SCraig Rodrigues 3416c21f6edSKonstantin Belousov if (error == ENOENT && (cnflags & MAKEENTRY) != 0) 342dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 343dc2dd185SDaichi GOTO 344d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 345d00947d8SCraig Rodrigues 3462a31267eSMatthew Dillon return (error); 347df8bae1dSRodney W. Grimes } 348df8bae1dSRodney W. Grimes 349c9bf0111SKATO Takenori static int 350d00947d8SCraig Rodrigues unionfs_create(struct vop_create_args *ap) 351996c772fSJohn Dyson { 352d00947d8SCraig Rodrigues struct unionfs_node *dunp; 353d00947d8SCraig Rodrigues struct componentname *cnp; 354d00947d8SCraig Rodrigues struct vnode *udvp; 355d00947d8SCraig Rodrigues struct vnode *vp; 3563bb3827fSDavid Schultz int error; 357996c772fSJohn Dyson 358d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n"); 359d00947d8SCraig Rodrigues 3601e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 3611e5da15aSDaichi GOTO 362d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 363d00947d8SCraig Rodrigues cnp = ap->a_cnp; 364d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 365d00947d8SCraig Rodrigues error = EROFS; 366d00947d8SCraig Rodrigues 367d00947d8SCraig Rodrigues if (udvp != NULLVP) { 3681e5da15aSDaichi GOTO error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap); 3691e5da15aSDaichi GOTO if (error != 0) 3701e5da15aSDaichi GOTO goto unionfs_create_abort; 3711e5da15aSDaichi GOTO 3721e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 3731e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 3741e5da15aSDaichi GOTO else { 375cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 376d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 37722db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 378d00947d8SCraig Rodrigues vrele(vp); 379d00947d8SCraig Rodrigues } 380d00947d8SCraig Rodrigues } 381d00947d8SCraig Rodrigues 3821e5da15aSDaichi GOTO unionfs_create_abort: 383d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error); 384d00947d8SCraig Rodrigues 385d00947d8SCraig Rodrigues return (error); 386d00947d8SCraig Rodrigues } 387d00947d8SCraig Rodrigues 388d00947d8SCraig Rodrigues static int 389d00947d8SCraig Rodrigues unionfs_whiteout(struct vop_whiteout_args *ap) 390d00947d8SCraig Rodrigues { 391d00947d8SCraig Rodrigues struct unionfs_node *dunp; 392d00947d8SCraig Rodrigues struct componentname *cnp; 393d00947d8SCraig Rodrigues struct vnode *udvp; 394d00947d8SCraig Rodrigues int error; 395d00947d8SCraig Rodrigues 396d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n"); 397d00947d8SCraig Rodrigues 3981e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 3991e5da15aSDaichi GOTO 400d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 401d00947d8SCraig Rodrigues cnp = ap->a_cnp; 402d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 403d00947d8SCraig Rodrigues error = EOPNOTSUPP; 404d00947d8SCraig Rodrigues 405d00947d8SCraig Rodrigues if (udvp != NULLVP) { 406ac092fb3SDavid Schultz switch (ap->a_flags) { 407ac092fb3SDavid Schultz case CREATE: 408ac092fb3SDavid Schultz case DELETE: 4093bb3827fSDavid Schultz case LOOKUP: 410d00947d8SCraig Rodrigues error = VOP_WHITEOUT(udvp, cnp, ap->a_flags); 411ac092fb3SDavid Schultz break; 412ac092fb3SDavid Schultz default: 413d00947d8SCraig Rodrigues error = EINVAL; 414d00947d8SCraig Rodrigues break; 415ac092fb3SDavid Schultz } 416d00947d8SCraig Rodrigues } 417d00947d8SCraig Rodrigues 418d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error); 419d00947d8SCraig Rodrigues 4202a31267eSMatthew Dillon return (error); 4212a31267eSMatthew Dillon } 4222a31267eSMatthew Dillon 423c9bf0111SKATO Takenori static int 424d00947d8SCraig Rodrigues unionfs_mknod(struct vop_mknod_args *ap) 425df8bae1dSRodney W. Grimes { 426d00947d8SCraig Rodrigues struct unionfs_node *dunp; 427d00947d8SCraig Rodrigues struct componentname *cnp; 428d00947d8SCraig Rodrigues struct vnode *udvp; 429df8bae1dSRodney W. Grimes struct vnode *vp; 430d00947d8SCraig Rodrigues int error; 431df8bae1dSRodney W. Grimes 432d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n"); 433d00947d8SCraig Rodrigues 4341e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 4351e5da15aSDaichi GOTO 436d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 437d00947d8SCraig Rodrigues cnp = ap->a_cnp; 438d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 439d00947d8SCraig Rodrigues error = EROFS; 440d00947d8SCraig Rodrigues 441d00947d8SCraig Rodrigues if (udvp != NULLVP) { 4421e5da15aSDaichi GOTO error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap); 4431e5da15aSDaichi GOTO if (error != 0) 4441e5da15aSDaichi GOTO goto unionfs_mknod_abort; 4451e5da15aSDaichi GOTO 4461e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 4471e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 4481e5da15aSDaichi GOTO else { 449cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 450d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 45122db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 452d00947d8SCraig Rodrigues vrele(vp); 453d00947d8SCraig Rodrigues } 454d00947d8SCraig Rodrigues } 455d00947d8SCraig Rodrigues 4561e5da15aSDaichi GOTO unionfs_mknod_abort: 457d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error); 458d00947d8SCraig Rodrigues 459d00947d8SCraig Rodrigues return (error); 460d00947d8SCraig Rodrigues } 461d00947d8SCraig Rodrigues 462d00947d8SCraig Rodrigues static int 463d00947d8SCraig Rodrigues unionfs_open(struct vop_open_args *ap) 464d00947d8SCraig Rodrigues { 465d00947d8SCraig Rodrigues int error; 466d00947d8SCraig Rodrigues struct unionfs_node *unp; 467d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 468d00947d8SCraig Rodrigues struct vnode *uvp; 469d00947d8SCraig Rodrigues struct vnode *lvp; 470d00947d8SCraig Rodrigues struct vnode *targetvp; 471d00947d8SCraig Rodrigues struct ucred *cred; 472d00947d8SCraig Rodrigues struct thread *td; 473d00947d8SCraig Rodrigues 474d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n"); 475d00947d8SCraig Rodrigues 4761e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 4771e5da15aSDaichi GOTO 478d00947d8SCraig Rodrigues error = 0; 479d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 480d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 481d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 482d00947d8SCraig Rodrigues targetvp = NULLVP; 483d00947d8SCraig Rodrigues cred = ap->a_cred; 484d00947d8SCraig Rodrigues td = ap->a_td; 485d00947d8SCraig Rodrigues 486d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 487d00947d8SCraig Rodrigues 488d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) { 489d00947d8SCraig Rodrigues /* vnode is already opend. */ 490d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt > 0) 491d00947d8SCraig Rodrigues targetvp = uvp; 492d00947d8SCraig Rodrigues else 493d00947d8SCraig Rodrigues targetvp = lvp; 494d00947d8SCraig Rodrigues 495d00947d8SCraig Rodrigues if (targetvp == lvp && 496d00947d8SCraig Rodrigues (ap->a_mode & FWRITE) && lvp->v_type == VREG) 497d00947d8SCraig Rodrigues targetvp = NULLVP; 498d00947d8SCraig Rodrigues } 499d00947d8SCraig Rodrigues if (targetvp == NULLVP) { 500d00947d8SCraig Rodrigues if (uvp == NULLVP) { 501d00947d8SCraig Rodrigues if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) { 502d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 503d00947d8SCraig Rodrigues !(ap->a_mode & O_TRUNC), cred, td); 504d00947d8SCraig Rodrigues if (error != 0) 505d00947d8SCraig Rodrigues goto unionfs_open_abort; 506d00947d8SCraig Rodrigues targetvp = uvp = unp->un_uppervp; 507d00947d8SCraig Rodrigues } else 508d00947d8SCraig Rodrigues targetvp = lvp; 509d00947d8SCraig Rodrigues } else 510d00947d8SCraig Rodrigues targetvp = uvp; 511d00947d8SCraig Rodrigues } 512d00947d8SCraig Rodrigues 5139e223287SKonstantin Belousov error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp); 514d00947d8SCraig Rodrigues if (error == 0) { 515d00947d8SCraig Rodrigues if (targetvp == uvp) { 516d00947d8SCraig Rodrigues if (uvp->v_type == VDIR && lvp != NULLVP && 517d00947d8SCraig Rodrigues unsp->uns_lower_opencnt <= 0) { 518d00947d8SCraig Rodrigues /* open lower for readdir */ 5199e223287SKonstantin Belousov error = VOP_OPEN(lvp, FREAD, cred, td, NULL); 520d00947d8SCraig Rodrigues if (error != 0) { 521d00947d8SCraig Rodrigues VOP_CLOSE(uvp, ap->a_mode, cred, td); 522d00947d8SCraig Rodrigues goto unionfs_open_abort; 523d00947d8SCraig Rodrigues } 524d00947d8SCraig Rodrigues unsp->uns_node_flag |= UNS_OPENL_4_READDIR; 525d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 526d00947d8SCraig Rodrigues } 527d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 528d00947d8SCraig Rodrigues } else { 529d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 530d00947d8SCraig Rodrigues unsp->uns_lower_openmode = ap->a_mode; 531d00947d8SCraig Rodrigues } 532d00947d8SCraig Rodrigues ap->a_vp->v_object = targetvp->v_object; 533d00947d8SCraig Rodrigues } 534d00947d8SCraig Rodrigues 535d00947d8SCraig Rodrigues unionfs_open_abort: 536d00947d8SCraig Rodrigues if (error != 0) 537fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 538d00947d8SCraig Rodrigues 539d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error); 540d00947d8SCraig Rodrigues 541d00947d8SCraig Rodrigues return (error); 542d00947d8SCraig Rodrigues } 543d00947d8SCraig Rodrigues 544d00947d8SCraig Rodrigues static int 545d00947d8SCraig Rodrigues unionfs_close(struct vop_close_args *ap) 546d00947d8SCraig Rodrigues { 547d00947d8SCraig Rodrigues int error; 548d00947d8SCraig Rodrigues int locked; 549d00947d8SCraig Rodrigues struct unionfs_node *unp; 550d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 551d00947d8SCraig Rodrigues struct ucred *cred; 552d00947d8SCraig Rodrigues struct thread *td; 553cb5736b7SDaichi GOTO struct vnode *vp; 554d00947d8SCraig Rodrigues struct vnode *ovp; 555d00947d8SCraig Rodrigues 556d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 557d00947d8SCraig Rodrigues 5581e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 5591e5da15aSDaichi GOTO 560d00947d8SCraig Rodrigues locked = 0; 561cb5736b7SDaichi GOTO vp = ap->a_vp; 562cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 563d00947d8SCraig Rodrigues cred = ap->a_cred; 564d00947d8SCraig Rodrigues td = ap->a_td; 565d00947d8SCraig Rodrigues 566cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 567cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 568cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 569d00947d8SCraig Rodrigues locked = 1; 570d00947d8SCraig Rodrigues } 571d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 572d00947d8SCraig Rodrigues 573d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 574d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 575d00947d8SCraig Rodrigues printf("unionfs_close: warning: open count is 0\n"); 576df8bae1dSRodney W. Grimes #endif 577d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 578d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 579d00947d8SCraig Rodrigues else 580d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 581d00947d8SCraig Rodrigues } else if (unsp->uns_upper_opencnt > 0) 582d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 583d00947d8SCraig Rodrigues else 584d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 585d00947d8SCraig Rodrigues 586d00947d8SCraig Rodrigues error = VOP_CLOSE(ovp, ap->a_fflag, cred, td); 587d00947d8SCraig Rodrigues 588d00947d8SCraig Rodrigues if (error != 0) 589d00947d8SCraig Rodrigues goto unionfs_close_abort; 590d00947d8SCraig Rodrigues 591cb5736b7SDaichi GOTO vp->v_object = ovp->v_object; 592d00947d8SCraig Rodrigues 593d00947d8SCraig Rodrigues if (ovp == unp->un_uppervp) { 594d00947d8SCraig Rodrigues unsp->uns_upper_opencnt--; 595d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt == 0) { 596d00947d8SCraig Rodrigues if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 597d00947d8SCraig Rodrigues VOP_CLOSE(unp->un_lowervp, FREAD, cred, td); 598d00947d8SCraig Rodrigues unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 599d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 600df8bae1dSRodney W. Grimes } 601d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) 602cb5736b7SDaichi GOTO vp->v_object = unp->un_lowervp->v_object; 603d00947d8SCraig Rodrigues } 604d00947d8SCraig Rodrigues } else 605d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 606d00947d8SCraig Rodrigues 607d00947d8SCraig Rodrigues unionfs_close_abort: 608fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 609d00947d8SCraig Rodrigues 610d00947d8SCraig Rodrigues if (locked != 0) 611cb5736b7SDaichi GOTO vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 612d00947d8SCraig Rodrigues 613d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 614d00947d8SCraig Rodrigues 615d00947d8SCraig Rodrigues return (error); 616df8bae1dSRodney W. Grimes } 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes /* 619d00947d8SCraig Rodrigues * Check the access mode toward shadow file/dir. 620df8bae1dSRodney W. Grimes */ 621c9bf0111SKATO Takenori static int 62215bc6b2bSEdward Tomasz Napierala unionfs_check_corrected_access(accmode_t accmode, 623d00947d8SCraig Rodrigues struct vattr *va, 624d00947d8SCraig Rodrigues struct ucred *cred) 625df8bae1dSRodney W. Grimes { 626d00947d8SCraig Rodrigues int count; 627d00947d8SCraig Rodrigues uid_t uid; /* upper side vnode's uid */ 628d00947d8SCraig Rodrigues gid_t gid; /* upper side vnode's gid */ 629d00947d8SCraig Rodrigues u_short vmode; /* upper side vnode's mode */ 630d00947d8SCraig Rodrigues u_short mask; 631df8bae1dSRodney W. Grimes 632d00947d8SCraig Rodrigues mask = 0; 633d00947d8SCraig Rodrigues uid = va->va_uid; 634d00947d8SCraig Rodrigues gid = va->va_gid; 635d00947d8SCraig Rodrigues vmode = va->va_mode; 636d00947d8SCraig Rodrigues 637d00947d8SCraig Rodrigues /* check owner */ 638d00947d8SCraig Rodrigues if (cred->cr_uid == uid) { 63915bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 640d00947d8SCraig Rodrigues mask |= S_IXUSR; 64115bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 642d00947d8SCraig Rodrigues mask |= S_IRUSR; 64315bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 644d00947d8SCraig Rodrigues mask |= S_IWUSR; 645d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 646d00947d8SCraig Rodrigues } 647d00947d8SCraig Rodrigues 648d00947d8SCraig Rodrigues /* check group */ 649d00947d8SCraig Rodrigues count = 0; 650838d9858SBrooks Davis if (groupmember(gid, cred)) { 65115bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 652d00947d8SCraig Rodrigues mask |= S_IXGRP; 65315bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 654d00947d8SCraig Rodrigues mask |= S_IRGRP; 65515bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 656d00947d8SCraig Rodrigues mask |= S_IWGRP; 657d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 658d00947d8SCraig Rodrigues } 659d00947d8SCraig Rodrigues 660d00947d8SCraig Rodrigues /* check other */ 66115bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 662d00947d8SCraig Rodrigues mask |= S_IXOTH; 66315bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 664d00947d8SCraig Rodrigues mask |= S_IROTH; 66515bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 666d00947d8SCraig Rodrigues mask |= S_IWOTH; 667d00947d8SCraig Rodrigues 668d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 669d00947d8SCraig Rodrigues } 670d00947d8SCraig Rodrigues 671d00947d8SCraig Rodrigues static int 672d00947d8SCraig Rodrigues unionfs_access(struct vop_access_args *ap) 673d00947d8SCraig Rodrigues { 674d00947d8SCraig Rodrigues struct unionfs_mount *ump; 675d00947d8SCraig Rodrigues struct unionfs_node *unp; 676d00947d8SCraig Rodrigues struct vnode *uvp; 677d00947d8SCraig Rodrigues struct vnode *lvp; 678d00947d8SCraig Rodrigues struct thread *td; 679d00947d8SCraig Rodrigues struct vattr va; 68015bc6b2bSEdward Tomasz Napierala accmode_t accmode; 681d00947d8SCraig Rodrigues int error; 682d00947d8SCraig Rodrigues 683d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 684d00947d8SCraig Rodrigues 6851e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 6861e5da15aSDaichi GOTO 687d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 688d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 689d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 690d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 691d00947d8SCraig Rodrigues td = ap->a_td; 69215bc6b2bSEdward Tomasz Napierala accmode = ap->a_accmode; 693d00947d8SCraig Rodrigues error = EACCES; 694d00947d8SCraig Rodrigues 69515bc6b2bSEdward Tomasz Napierala if ((accmode & VWRITE) && 6962a31267eSMatthew Dillon (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 6976ca02614SKATO Takenori switch (ap->a_vp->v_type) { 698831a80b0SMatthew Dillon case VREG: 699831a80b0SMatthew Dillon case VDIR: 700831a80b0SMatthew Dillon case VLNK: 7016ca02614SKATO Takenori return (EROFS); 702831a80b0SMatthew Dillon default: 703831a80b0SMatthew Dillon break; 7046ca02614SKATO Takenori } 7056ca02614SKATO Takenori } 7062a31267eSMatthew Dillon 707d00947d8SCraig Rodrigues if (uvp != NULLVP) { 70815bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(uvp, accmode, ap->a_cred, td); 709d00947d8SCraig Rodrigues 710d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 711d00947d8SCraig Rodrigues 7122a31267eSMatthew Dillon return (error); 713df8bae1dSRodney W. Grimes } 714df8bae1dSRodney W. Grimes 715d00947d8SCraig Rodrigues if (lvp != NULLVP) { 71615bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) { 717d00947d8SCraig Rodrigues if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 718d00947d8SCraig Rodrigues switch (ap->a_vp->v_type) { 719d00947d8SCraig Rodrigues case VREG: 720d00947d8SCraig Rodrigues case VDIR: 721d00947d8SCraig Rodrigues case VLNK: 722d00947d8SCraig Rodrigues return (EROFS); 723d00947d8SCraig Rodrigues default: 724d00947d8SCraig Rodrigues break; 725df8bae1dSRodney W. Grimes } 726d00947d8SCraig Rodrigues } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 727d00947d8SCraig Rodrigues /* check shadow file/dir */ 728d00947d8SCraig Rodrigues if (ump->um_copymode != UNIONFS_TRANSPARENT) { 729d00947d8SCraig Rodrigues error = unionfs_create_uppervattr(ump, 730d00947d8SCraig Rodrigues lvp, &va, ap->a_cred, td); 731d00947d8SCraig Rodrigues if (error != 0) 732d00947d8SCraig Rodrigues return (error); 733d00947d8SCraig Rodrigues 734d00947d8SCraig Rodrigues error = unionfs_check_corrected_access( 73515bc6b2bSEdward Tomasz Napierala accmode, &va, ap->a_cred); 736d00947d8SCraig Rodrigues if (error != 0) 737df8bae1dSRodney W. Grimes return (error); 738df8bae1dSRodney W. Grimes } 739d00947d8SCraig Rodrigues } 7405c0c5a18SEdward Tomasz Napierala accmode &= ~(VWRITE | VAPPEND); 74115bc6b2bSEdward Tomasz Napierala accmode |= VREAD; /* will copy to upper */ 742d00947d8SCraig Rodrigues } 74315bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(lvp, accmode, ap->a_cred, td); 744d00947d8SCraig Rodrigues } 745df8bae1dSRodney W. Grimes 746d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 747d00947d8SCraig Rodrigues 748d00947d8SCraig Rodrigues return (error); 749d00947d8SCraig Rodrigues } 7502a31267eSMatthew Dillon 751c9bf0111SKATO Takenori static int 752d00947d8SCraig Rodrigues unionfs_getattr(struct vop_getattr_args *ap) 753df8bae1dSRodney W. Grimes { 754df8bae1dSRodney W. Grimes int error; 755d00947d8SCraig Rodrigues struct unionfs_node *unp; 756d00947d8SCraig Rodrigues struct unionfs_mount *ump; 757d00947d8SCraig Rodrigues struct vnode *uvp; 758d00947d8SCraig Rodrigues struct vnode *lvp; 759d00947d8SCraig Rodrigues struct thread *td; 760df8bae1dSRodney W. Grimes struct vattr va; 761df8bae1dSRodney W. Grimes 762d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 763df8bae1dSRodney W. Grimes 7641e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 7651e5da15aSDaichi GOTO 766d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 767d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 768d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 769d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 7700359a12eSAttilio Rao td = curthread; 771df8bae1dSRodney W. Grimes 772d00947d8SCraig Rodrigues if (uvp != NULLVP) { 7730359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 7746e4c3467STakanori Watanabe ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 775d354520eSTakanori Watanabe 776d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 777d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, 778d00947d8SCraig Rodrigues ap->a_vap->va_gid, error); 779d00947d8SCraig Rodrigues 780d00947d8SCraig Rodrigues return (error); 781d00947d8SCraig Rodrigues } 782d00947d8SCraig Rodrigues 7830359a12eSAttilio Rao error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 784d00947d8SCraig Rodrigues 785d00947d8SCraig Rodrigues if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 786d00947d8SCraig Rodrigues /* correct the attr toward shadow file/dir. */ 787d00947d8SCraig Rodrigues if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 788d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); 789d00947d8SCraig Rodrigues ap->a_vap->va_mode = va.va_mode; 790d00947d8SCraig Rodrigues ap->a_vap->va_uid = va.va_uid; 791d00947d8SCraig Rodrigues ap->a_vap->va_gid = va.va_gid; 792d00947d8SCraig Rodrigues } 793d00947d8SCraig Rodrigues } 794d00947d8SCraig Rodrigues 795d00947d8SCraig Rodrigues if (error == 0) 796d00947d8SCraig Rodrigues ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 797d00947d8SCraig Rodrigues 798d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 799d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 800d00947d8SCraig Rodrigues 801d00947d8SCraig Rodrigues return (error); 802df8bae1dSRodney W. Grimes } 803df8bae1dSRodney W. Grimes 804c9bf0111SKATO Takenori static int 805d00947d8SCraig Rodrigues unionfs_setattr(struct vop_setattr_args *ap) 806df8bae1dSRodney W. Grimes { 807df8bae1dSRodney W. Grimes int error; 808d00947d8SCraig Rodrigues struct unionfs_node *unp; 809d00947d8SCraig Rodrigues struct vnode *uvp; 810d00947d8SCraig Rodrigues struct vnode *lvp; 811d00947d8SCraig Rodrigues struct thread *td; 812d00947d8SCraig Rodrigues struct vattr *vap; 813df8bae1dSRodney W. Grimes 814d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 815d00947d8SCraig Rodrigues 8161e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8171e5da15aSDaichi GOTO 818d00947d8SCraig Rodrigues error = EROFS; 819d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 820d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 821d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 8220359a12eSAttilio Rao td = curthread; 823d00947d8SCraig Rodrigues vap = ap->a_vap; 824d00947d8SCraig Rodrigues 8256ca02614SKATO Takenori if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 8266ca02614SKATO Takenori (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 8276ca02614SKATO Takenori vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 828d00947d8SCraig Rodrigues vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 8296ca02614SKATO Takenori return (EROFS); 8306ca02614SKATO Takenori 831d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 832d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, (vap->va_size != 0), 833d00947d8SCraig Rodrigues ap->a_cred, td); 834d00947d8SCraig Rodrigues if (error != 0) 835df8bae1dSRodney W. Grimes return (error); 836d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 837df8bae1dSRodney W. Grimes } 838df8bae1dSRodney W. Grimes 839d00947d8SCraig Rodrigues if (uvp != NULLVP) 8400359a12eSAttilio Rao error = VOP_SETATTR(uvp, vap, ap->a_cred); 841d00947d8SCraig Rodrigues 842d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 843d00947d8SCraig Rodrigues 8442a31267eSMatthew Dillon return (error); 845df8bae1dSRodney W. Grimes } 846df8bae1dSRodney W. Grimes 847c9bf0111SKATO Takenori static int 848d00947d8SCraig Rodrigues unionfs_read(struct vop_read_args *ap) 849df8bae1dSRodney W. Grimes { 8502a31267eSMatthew Dillon int error; 851d00947d8SCraig Rodrigues struct unionfs_node *unp; 852d00947d8SCraig Rodrigues struct vnode *tvp; 853df8bae1dSRodney W. Grimes 854d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 8552a31267eSMatthew Dillon 8561e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8571e5da15aSDaichi GOTO 858d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 859d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 860996c772fSJohn Dyson 861d00947d8SCraig Rodrigues error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 862996c772fSJohn Dyson 863d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 864d00947d8SCraig Rodrigues 865df8bae1dSRodney W. Grimes return (error); 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes 868c9bf0111SKATO Takenori static int 869d00947d8SCraig Rodrigues unionfs_write(struct vop_write_args *ap) 870df8bae1dSRodney W. Grimes { 8712a31267eSMatthew Dillon int error; 872d00947d8SCraig Rodrigues struct unionfs_node *unp; 873d00947d8SCraig Rodrigues struct vnode *tvp; 874df8bae1dSRodney W. Grimes 875d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 876996c772fSJohn Dyson 8771e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8781e5da15aSDaichi GOTO 879d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 880d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 881996c772fSJohn Dyson 882d00947d8SCraig Rodrigues error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 883996c772fSJohn Dyson 884d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 885df8bae1dSRodney W. Grimes 886df8bae1dSRodney W. Grimes return (error); 887df8bae1dSRodney W. Grimes } 888df8bae1dSRodney W. Grimes 889c9bf0111SKATO Takenori static int 890d00947d8SCraig Rodrigues unionfs_ioctl(struct vop_ioctl_args *ap) 891df8bae1dSRodney W. Grimes { 892df8bae1dSRodney W. Grimes int error; 893d00947d8SCraig Rodrigues struct unionfs_node *unp; 894d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 895d00947d8SCraig Rodrigues struct vnode *ovp; 896df8bae1dSRodney W. Grimes 897d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 8982a31267eSMatthew Dillon 8991e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9001e5da15aSDaichi GOTO 901cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 902d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 903d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 904d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 905fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 906cb5736b7SDaichi GOTO VOP_UNLOCK(ap->a_vp, LK_RELEASE); 907d00947d8SCraig Rodrigues 908d00947d8SCraig Rodrigues if (ovp == NULLVP) 909d00947d8SCraig Rodrigues return (EBADF); 910d00947d8SCraig Rodrigues 911d00947d8SCraig Rodrigues error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 912d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 913d00947d8SCraig Rodrigues 914885868cdSRobert Watson UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error); 915d00947d8SCraig Rodrigues 916d00947d8SCraig Rodrigues return (error); 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes 919d00947d8SCraig Rodrigues static int 920d00947d8SCraig Rodrigues unionfs_poll(struct vop_poll_args *ap) 921d00947d8SCraig Rodrigues { 922d00947d8SCraig Rodrigues struct unionfs_node *unp; 923d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 924d00947d8SCraig Rodrigues struct vnode *ovp; 9252a31267eSMatthew Dillon 9261e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9271e5da15aSDaichi GOTO 928cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 929d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 930d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 931d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 932fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 933cb5736b7SDaichi GOTO VOP_UNLOCK(ap->a_vp, LK_RELEASE); 934d00947d8SCraig Rodrigues 935d00947d8SCraig Rodrigues if (ovp == NULLVP) 936d00947d8SCraig Rodrigues return (EBADF); 937d00947d8SCraig Rodrigues 938d00947d8SCraig Rodrigues return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td)); 939d00947d8SCraig Rodrigues } 940d00947d8SCraig Rodrigues 941d00947d8SCraig Rodrigues static int 942d00947d8SCraig Rodrigues unionfs_fsync(struct vop_fsync_args *ap) 943d00947d8SCraig Rodrigues { 944d00947d8SCraig Rodrigues struct unionfs_node *unp; 945d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 946d00947d8SCraig Rodrigues struct vnode *ovp; 947d00947d8SCraig Rodrigues 9481e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9491e5da15aSDaichi GOTO 950d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 951d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 952d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 953fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 954d00947d8SCraig Rodrigues 955d00947d8SCraig Rodrigues if (ovp == NULLVP) 956d00947d8SCraig Rodrigues return (EBADF); 957d00947d8SCraig Rodrigues 958d00947d8SCraig Rodrigues return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td)); 959d00947d8SCraig Rodrigues } 960d00947d8SCraig Rodrigues 961d00947d8SCraig Rodrigues static int 962d00947d8SCraig Rodrigues unionfs_remove(struct vop_remove_args *ap) 963d00947d8SCraig Rodrigues { 964d00947d8SCraig Rodrigues int error; 9651e5da15aSDaichi GOTO char *path; 966d00947d8SCraig Rodrigues struct unionfs_node *dunp; 967d00947d8SCraig Rodrigues struct unionfs_node *unp; 96820885defSDaichi GOTO struct unionfs_mount *ump; 969d00947d8SCraig Rodrigues struct vnode *udvp; 970d00947d8SCraig Rodrigues struct vnode *uvp; 971d00947d8SCraig Rodrigues struct vnode *lvp; 9721e5da15aSDaichi GOTO struct vnode *vp; 973d00947d8SCraig Rodrigues struct componentname *cnp; 9741e5da15aSDaichi GOTO struct componentname cn; 975d00947d8SCraig Rodrigues struct thread *td; 976d00947d8SCraig Rodrigues 977d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 978d00947d8SCraig Rodrigues 9791e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 9801e5da15aSDaichi GOTO 981d00947d8SCraig Rodrigues error = 0; 982d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 983d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 984d00947d8SCraig Rodrigues cnp = ap->a_cnp; 985d00947d8SCraig Rodrigues td = curthread; 986d00947d8SCraig Rodrigues 9871e5da15aSDaichi GOTO if (ap->a_vp->v_op != &unionfs_vnodeops) { 9881e5da15aSDaichi GOTO if (ap->a_vp->v_type != VSOCK) 9891e5da15aSDaichi GOTO return (EINVAL); 9901e5da15aSDaichi GOTO ump = NULL; 9911e5da15aSDaichi GOTO vp = uvp = lvp = NULLVP; 9921e5da15aSDaichi GOTO /* search vnode */ 993cb5736b7SDaichi GOTO VOP_UNLOCK(ap->a_vp, LK_RELEASE); 9941e5da15aSDaichi GOTO error = unionfs_relookup(udvp, &vp, cnp, &cn, td, 9951e5da15aSDaichi GOTO cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE); 9961e5da15aSDaichi GOTO if (error != 0 && error != ENOENT) { 9971e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 9981e5da15aSDaichi GOTO return (error); 9991e5da15aSDaichi GOTO } 10001e5da15aSDaichi GOTO 10011e5da15aSDaichi GOTO if (error == 0 && vp == ap->a_vp) { 10021e5da15aSDaichi GOTO /* target vnode in upper */ 10031e5da15aSDaichi GOTO uvp = vp; 10041e5da15aSDaichi GOTO vrele(vp); 10051e5da15aSDaichi GOTO path = NULL; 10061e5da15aSDaichi GOTO } else { 10071e5da15aSDaichi GOTO /* target vnode in lower */ 10081e5da15aSDaichi GOTO if (vp != NULLVP) { 10091e5da15aSDaichi GOTO if (udvp == vp) 10101e5da15aSDaichi GOTO vrele(vp); 10111e5da15aSDaichi GOTO else 10121e5da15aSDaichi GOTO vput(vp); 10131e5da15aSDaichi GOTO } 10141e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 10151e5da15aSDaichi GOTO lvp = ap->a_vp; 10161e5da15aSDaichi GOTO path = ap->a_cnp->cn_nameptr; 10171e5da15aSDaichi GOTO } 10181e5da15aSDaichi GOTO } else { 10191e5da15aSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 10201e5da15aSDaichi GOTO unp = VTOUNIONFS(ap->a_vp); 10211e5da15aSDaichi GOTO uvp = unp->un_uppervp; 10221e5da15aSDaichi GOTO lvp = unp->un_lowervp; 10231e5da15aSDaichi GOTO path = unp->un_path; 10241e5da15aSDaichi GOTO } 10251e5da15aSDaichi GOTO 1026d00947d8SCraig Rodrigues if (udvp == NULLVP) 1027d00947d8SCraig Rodrigues return (EROFS); 1028d00947d8SCraig Rodrigues 1029d00947d8SCraig Rodrigues if (uvp != NULLVP) { 10301e5da15aSDaichi GOTO /* 10311e5da15aSDaichi GOTO * XXX: if the vnode type is VSOCK, it will create whiteout 10321e5da15aSDaichi GOTO * after remove. 10331e5da15aSDaichi GOTO */ 10341e5da15aSDaichi GOTO if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS || 10351e5da15aSDaichi GOTO lvp != NULLVP) 1036d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1037d00947d8SCraig Rodrigues error = VOP_REMOVE(udvp, uvp, cnp); 1038d00947d8SCraig Rodrigues } else if (lvp != NULLVP) 10391e5da15aSDaichi GOTO error = unionfs_mkwhiteout(udvp, cnp, td, path); 1040d00947d8SCraig Rodrigues 1041d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 1042d00947d8SCraig Rodrigues 1043d00947d8SCraig Rodrigues return (error); 1044d00947d8SCraig Rodrigues } 1045d00947d8SCraig Rodrigues 1046d00947d8SCraig Rodrigues static int 1047d00947d8SCraig Rodrigues unionfs_link(struct vop_link_args *ap) 1048d00947d8SCraig Rodrigues { 1049d00947d8SCraig Rodrigues int error; 1050d00947d8SCraig Rodrigues int needrelookup; 1051d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1052d00947d8SCraig Rodrigues struct unionfs_node *unp; 1053d00947d8SCraig Rodrigues struct vnode *udvp; 1054d00947d8SCraig Rodrigues struct vnode *uvp; 1055d00947d8SCraig Rodrigues struct componentname *cnp; 1056d00947d8SCraig Rodrigues struct thread *td; 1057d00947d8SCraig Rodrigues 1058d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 1059d00947d8SCraig Rodrigues 10601e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_tdvp); 10611e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 10621e5da15aSDaichi GOTO 1063d00947d8SCraig Rodrigues error = 0; 1064d00947d8SCraig Rodrigues needrelookup = 0; 1065d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_tdvp); 1066d00947d8SCraig Rodrigues unp = NULL; 1067d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1068d00947d8SCraig Rodrigues uvp = NULLVP; 1069d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1070d00947d8SCraig Rodrigues td = curthread; 1071d00947d8SCraig Rodrigues 1072d00947d8SCraig Rodrigues if (udvp == NULLVP) 1073d00947d8SCraig Rodrigues return (EROFS); 1074d00947d8SCraig Rodrigues 1075d00947d8SCraig Rodrigues if (ap->a_vp->v_op != &unionfs_vnodeops) 1076d00947d8SCraig Rodrigues uvp = ap->a_vp; 1077d00947d8SCraig Rodrigues else { 1078d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1079d00947d8SCraig Rodrigues 1080d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1081d00947d8SCraig Rodrigues if (ap->a_vp->v_type != VREG) 1082d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1083d00947d8SCraig Rodrigues 1084d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, cnp->cn_cred, td); 1085d00947d8SCraig Rodrigues if (error != 0) 1086d00947d8SCraig Rodrigues return (error); 1087d00947d8SCraig Rodrigues needrelookup = 1; 1088d00947d8SCraig Rodrigues } 1089d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1090d00947d8SCraig Rodrigues } 1091d00947d8SCraig Rodrigues 1092d00947d8SCraig Rodrigues if (needrelookup != 0) 1093d00947d8SCraig Rodrigues error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td); 1094d00947d8SCraig Rodrigues 1095d00947d8SCraig Rodrigues if (error == 0) 1096d00947d8SCraig Rodrigues error = VOP_LINK(udvp, uvp, cnp); 1097d00947d8SCraig Rodrigues 1098d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 1099d00947d8SCraig Rodrigues 1100d00947d8SCraig Rodrigues return (error); 1101d00947d8SCraig Rodrigues } 1102d00947d8SCraig Rodrigues 1103d00947d8SCraig Rodrigues static int 1104d00947d8SCraig Rodrigues unionfs_rename(struct vop_rename_args *ap) 1105d00947d8SCraig Rodrigues { 1106d00947d8SCraig Rodrigues int error; 1107d00947d8SCraig Rodrigues struct vnode *fdvp; 1108d00947d8SCraig Rodrigues struct vnode *fvp; 1109d00947d8SCraig Rodrigues struct componentname *fcnp; 1110d00947d8SCraig Rodrigues struct vnode *tdvp; 1111d00947d8SCraig Rodrigues struct vnode *tvp; 1112d00947d8SCraig Rodrigues struct componentname *tcnp; 1113d00947d8SCraig Rodrigues struct vnode *ltdvp; 1114d00947d8SCraig Rodrigues struct vnode *ltvp; 1115d00947d8SCraig Rodrigues struct thread *td; 1116d00947d8SCraig Rodrigues 1117d00947d8SCraig Rodrigues /* rename target vnodes */ 1118d00947d8SCraig Rodrigues struct vnode *rfdvp; 1119d00947d8SCraig Rodrigues struct vnode *rfvp; 1120d00947d8SCraig Rodrigues struct vnode *rtdvp; 1121d00947d8SCraig Rodrigues struct vnode *rtvp; 1122d00947d8SCraig Rodrigues 1123d00947d8SCraig Rodrigues int needrelookup; 1124d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1125d00947d8SCraig Rodrigues struct unionfs_node *unp; 1126d00947d8SCraig Rodrigues 1127d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 1128d00947d8SCraig Rodrigues 1129d00947d8SCraig Rodrigues error = 0; 1130d00947d8SCraig Rodrigues fdvp = ap->a_fdvp; 1131d00947d8SCraig Rodrigues fvp = ap->a_fvp; 1132d00947d8SCraig Rodrigues fcnp = ap->a_fcnp; 1133d00947d8SCraig Rodrigues tdvp = ap->a_tdvp; 1134d00947d8SCraig Rodrigues tvp = ap->a_tvp; 1135d00947d8SCraig Rodrigues tcnp = ap->a_tcnp; 1136d00947d8SCraig Rodrigues ltdvp = NULLVP; 1137d00947d8SCraig Rodrigues ltvp = NULLVP; 1138d00947d8SCraig Rodrigues td = curthread; 1139d00947d8SCraig Rodrigues rfdvp = fdvp; 1140d00947d8SCraig Rodrigues rfvp = fvp; 1141d00947d8SCraig Rodrigues rtdvp = tdvp; 1142d00947d8SCraig Rodrigues rtvp = tvp; 1143d00947d8SCraig Rodrigues needrelookup = 0; 1144d00947d8SCraig Rodrigues 1145d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 1146d00947d8SCraig Rodrigues if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1147d00947d8SCraig Rodrigues panic("unionfs_rename: no name"); 11482a31267eSMatthew Dillon #endif 11492a31267eSMatthew Dillon 1150d00947d8SCraig Rodrigues /* check for cross device rename */ 1151d00947d8SCraig Rodrigues if (fvp->v_mount != tdvp->v_mount || 1152d00947d8SCraig Rodrigues (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 11531e5da15aSDaichi GOTO if (fvp->v_op != &unionfs_vnodeops) 11541e5da15aSDaichi GOTO error = ENODEV; 11551e5da15aSDaichi GOTO else 1156d00947d8SCraig Rodrigues error = EXDEV; 1157d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1158d00947d8SCraig Rodrigues } 1159d00947d8SCraig Rodrigues 1160d00947d8SCraig Rodrigues /* Renaming a file to itself has no effect. */ 1161d00947d8SCraig Rodrigues if (fvp == tvp) 1162d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1163d00947d8SCraig Rodrigues 1164d00947d8SCraig Rodrigues /* 1165d00947d8SCraig Rodrigues * from/to vnode is unionfs node. 1166d00947d8SCraig Rodrigues */ 1167d00947d8SCraig Rodrigues 11681e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fdvp); 11691e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fvp); 11701e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tdvp); 11711e5da15aSDaichi GOTO if (tvp != NULLVP) 11721e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tvp); 11731e5da15aSDaichi GOTO 1174d00947d8SCraig Rodrigues unp = VTOUNIONFS(fdvp); 1175d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1176d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp); 1177d00947d8SCraig Rodrigues #endif 1178d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1179d00947d8SCraig Rodrigues error = ENODEV; 1180d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1181d00947d8SCraig Rodrigues } 1182d00947d8SCraig Rodrigues rfdvp = unp->un_uppervp; 1183d00947d8SCraig Rodrigues vref(rfdvp); 1184d00947d8SCraig Rodrigues 1185d00947d8SCraig Rodrigues unp = VTOUNIONFS(fvp); 1186d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1187d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp); 1188d00947d8SCraig Rodrigues #endif 1189d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1190d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 11912a31267eSMatthew Dillon switch (fvp->v_type) { 11922a31267eSMatthew Dillon case VREG: 1193cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1194d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1195d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td); 1196cb5736b7SDaichi GOTO VOP_UNLOCK(fvp, LK_RELEASE); 1197d00947d8SCraig Rodrigues if (error != 0) 1198d00947d8SCraig Rodrigues goto unionfs_rename_abort; 11992a31267eSMatthew Dillon break; 12002a31267eSMatthew Dillon case VDIR: 1201cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1202d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1203d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td); 1204cb5736b7SDaichi GOTO VOP_UNLOCK(fvp, LK_RELEASE); 1205d00947d8SCraig Rodrigues if (error != 0) 1206d00947d8SCraig Rodrigues goto unionfs_rename_abort; 12072a31267eSMatthew Dillon break; 12082a31267eSMatthew Dillon default: 1209d00947d8SCraig Rodrigues error = ENODEV; 1210d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1211d00947d8SCraig Rodrigues } 1212d00947d8SCraig Rodrigues 1213d00947d8SCraig Rodrigues needrelookup = 1; 1214d00947d8SCraig Rodrigues } 1215d00947d8SCraig Rodrigues 1216d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1217d00947d8SCraig Rodrigues fcnp->cn_flags |= DOWHITEOUT; 1218d00947d8SCraig Rodrigues rfvp = unp->un_uppervp; 1219d00947d8SCraig Rodrigues vref(rfvp); 1220d00947d8SCraig Rodrigues 1221d00947d8SCraig Rodrigues unp = VTOUNIONFS(tdvp); 1222d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1223d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp); 1224d00947d8SCraig Rodrigues #endif 1225d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1226d00947d8SCraig Rodrigues error = ENODEV; 1227d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1228d00947d8SCraig Rodrigues } 1229d00947d8SCraig Rodrigues rtdvp = unp->un_uppervp; 1230d00947d8SCraig Rodrigues ltdvp = unp->un_lowervp; 1231d00947d8SCraig Rodrigues vref(rtdvp); 1232d00947d8SCraig Rodrigues 1233d00947d8SCraig Rodrigues if (tdvp == tvp) { 1234d00947d8SCraig Rodrigues rtvp = rtdvp; 1235d00947d8SCraig Rodrigues vref(rtvp); 1236d00947d8SCraig Rodrigues } else if (tvp != NULLVP) { 1237d00947d8SCraig Rodrigues unp = VTOUNIONFS(tvp); 1238d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1239d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp); 1240d00947d8SCraig Rodrigues #endif 1241d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) 1242d00947d8SCraig Rodrigues rtvp = NULLVP; 1243d00947d8SCraig Rodrigues else { 1244d00947d8SCraig Rodrigues if (tvp->v_type == VDIR) { 1245d00947d8SCraig Rodrigues error = EINVAL; 1246d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1247d00947d8SCraig Rodrigues } 1248d00947d8SCraig Rodrigues rtvp = unp->un_uppervp; 1249d00947d8SCraig Rodrigues ltvp = unp->un_lowervp; 1250d00947d8SCraig Rodrigues vref(rtvp); 1251df8bae1dSRodney W. Grimes } 12522a31267eSMatthew Dillon } 1253df8bae1dSRodney W. Grimes 12545307411cSDaichi GOTO if (rfvp == rtvp) 12555307411cSDaichi GOTO goto unionfs_rename_abort; 12565307411cSDaichi GOTO 1257d00947d8SCraig Rodrigues if (needrelookup != 0) { 1258cb05b60aSAttilio Rao if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1259d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1260d00947d8SCraig Rodrigues error = unionfs_relookup_for_delete(fdvp, fcnp, td); 1261cb5736b7SDaichi GOTO VOP_UNLOCK(fdvp, LK_RELEASE); 1262d00947d8SCraig Rodrigues if (error != 0) 1263d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1264d00947d8SCraig Rodrigues 1265d00947d8SCraig Rodrigues /* Locke of tvp is canceled in order to avoid recursive lock. */ 1266d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 1267cb5736b7SDaichi GOTO VOP_UNLOCK(tvp, LK_RELEASE); 1268d00947d8SCraig Rodrigues error = unionfs_relookup_for_rename(tdvp, tcnp, td); 1269d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 1270cb05b60aSAttilio Rao vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1271d00947d8SCraig Rodrigues if (error != 0) 1272d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1273df8bae1dSRodney W. Grimes } 1274df8bae1dSRodney W. Grimes 1275d00947d8SCraig Rodrigues error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 12762a31267eSMatthew Dillon 1277dc2dd185SDaichi GOTO if (error == 0) { 1278dc2dd185SDaichi GOTO if (rtvp != NULLVP && rtvp->v_type == VDIR) 1279dc2dd185SDaichi GOTO cache_purge(tdvp); 1280dc2dd185SDaichi GOTO if (fvp->v_type == VDIR && fdvp != tdvp) 1281dc2dd185SDaichi GOTO cache_purge(fdvp); 1282dc2dd185SDaichi GOTO } 1283dc2dd185SDaichi GOTO 12847e0c8995SDaichi GOTO if (ltdvp != NULLVP) 1285cb5736b7SDaichi GOTO VOP_UNLOCK(ltdvp, LK_RELEASE); 1286d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1287d00947d8SCraig Rodrigues vrele(tdvp); 12887e0c8995SDaichi GOTO if (ltvp != NULLVP) 1289cb5736b7SDaichi GOTO VOP_UNLOCK(ltvp, LK_RELEASE); 1290d00947d8SCraig Rodrigues if (tvp != rtvp && tvp != NULLVP) { 1291d00947d8SCraig Rodrigues if (rtvp == NULLVP) 1292df8bae1dSRodney W. Grimes vput(tvp); 12932a31267eSMatthew Dillon else 12942a31267eSMatthew Dillon vrele(tvp); 12952a31267eSMatthew Dillon } 12965307411cSDaichi GOTO if (fdvp != rfdvp) 12975307411cSDaichi GOTO vrele(fdvp); 12985307411cSDaichi GOTO if (fvp != rfvp) 12995307411cSDaichi GOTO vrele(fvp); 1300d00947d8SCraig Rodrigues 1301d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1302d00947d8SCraig Rodrigues 1303d00947d8SCraig Rodrigues return (error); 1304d00947d8SCraig Rodrigues 1305d00947d8SCraig Rodrigues unionfs_rename_abort: 13065307411cSDaichi GOTO vput(tdvp); 1307d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1308d00947d8SCraig Rodrigues vrele(rtdvp); 1309d00947d8SCraig Rodrigues if (tvp != NULLVP) { 1310d00947d8SCraig Rodrigues if (tdvp != tvp) 1311d00947d8SCraig Rodrigues vput(tvp); 1312d00947d8SCraig Rodrigues else 1313d00947d8SCraig Rodrigues vrele(tvp); 1314d00947d8SCraig Rodrigues } 13155307411cSDaichi GOTO if (tvp != rtvp && rtvp != NULLVP) 13165307411cSDaichi GOTO vrele(rtvp); 13175307411cSDaichi GOTO if (fdvp != rfdvp) 13185307411cSDaichi GOTO vrele(rfdvp); 13195307411cSDaichi GOTO if (fvp != rfvp) 13205307411cSDaichi GOTO vrele(rfvp); 1321d00947d8SCraig Rodrigues vrele(fdvp); 1322d00947d8SCraig Rodrigues vrele(fvp); 1323d00947d8SCraig Rodrigues 1324d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1325d00947d8SCraig Rodrigues 1326df8bae1dSRodney W. Grimes return (error); 1327df8bae1dSRodney W. Grimes } 1328df8bae1dSRodney W. Grimes 1329c9bf0111SKATO Takenori static int 1330d00947d8SCraig Rodrigues unionfs_mkdir(struct vop_mkdir_args *ap) 1331df8bae1dSRodney W. Grimes { 1332d00947d8SCraig Rodrigues int error; 133398155f1fSCraig Rodrigues int lkflags; 1334d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1335d00947d8SCraig Rodrigues struct componentname *cnp; 1336d00947d8SCraig Rodrigues struct thread *td; 1337d00947d8SCraig Rodrigues struct vnode *udvp; 1338d00947d8SCraig Rodrigues struct vnode *uvp; 1339d00947d8SCraig Rodrigues struct vattr va; 1340df8bae1dSRodney W. Grimes 1341d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1342d00947d8SCraig Rodrigues 13431e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 13441e5da15aSDaichi GOTO 1345d00947d8SCraig Rodrigues error = EROFS; 1346d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1347d00947d8SCraig Rodrigues cnp = ap->a_cnp; 134898155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1349d00947d8SCraig Rodrigues td = curthread; 1350d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1351d00947d8SCraig Rodrigues 1352d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1353d00947d8SCraig Rodrigues /* check opaque */ 1354d00947d8SCraig Rodrigues if (!(cnp->cn_flags & ISWHITEOUT)) { 13550359a12eSAttilio Rao error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1356d00947d8SCraig Rodrigues if (error != 0) 1357d00947d8SCraig Rodrigues return (error); 1358d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 1359d00947d8SCraig Rodrigues cnp->cn_flags |= ISWHITEOUT; 1360d00947d8SCraig Rodrigues } 1361d00947d8SCraig Rodrigues 1362d00947d8SCraig Rodrigues if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1363cb5736b7SDaichi GOTO VOP_UNLOCK(uvp, LK_RELEASE); 136498155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1365d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1366d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 136798155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1368d00947d8SCraig Rodrigues vrele(uvp); 1369d00947d8SCraig Rodrigues } 1370d00947d8SCraig Rodrigues } 1371d00947d8SCraig Rodrigues 1372d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1373d00947d8SCraig Rodrigues 1374d00947d8SCraig Rodrigues return (error); 1375d00947d8SCraig Rodrigues } 1376d00947d8SCraig Rodrigues 1377d00947d8SCraig Rodrigues static int 1378d00947d8SCraig Rodrigues unionfs_rmdir(struct vop_rmdir_args *ap) 1379d00947d8SCraig Rodrigues { 1380d00947d8SCraig Rodrigues int error; 1381d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1382d00947d8SCraig Rodrigues struct unionfs_node *unp; 138320885defSDaichi GOTO struct unionfs_mount *ump; 1384d00947d8SCraig Rodrigues struct componentname *cnp; 1385d00947d8SCraig Rodrigues struct thread *td; 1386d00947d8SCraig Rodrigues struct vnode *udvp; 1387d00947d8SCraig Rodrigues struct vnode *uvp; 1388d00947d8SCraig Rodrigues struct vnode *lvp; 1389d00947d8SCraig Rodrigues 1390d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1391d00947d8SCraig Rodrigues 13921e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 13931e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 13941e5da15aSDaichi GOTO 1395d00947d8SCraig Rodrigues error = 0; 1396d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1397d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1398d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1399d00947d8SCraig Rodrigues td = curthread; 1400d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1401d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1402d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1403d00947d8SCraig Rodrigues 1404d00947d8SCraig Rodrigues if (udvp == NULLVP) 1405d00947d8SCraig Rodrigues return (EROFS); 1406d00947d8SCraig Rodrigues 1407d00947d8SCraig Rodrigues if (udvp == uvp) 1408d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1409d00947d8SCraig Rodrigues 1410d00947d8SCraig Rodrigues if (uvp != NULLVP) { 1411d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1412d00947d8SCraig Rodrigues error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td); 1413d00947d8SCraig Rodrigues if (error != 0) 1414d00947d8SCraig Rodrigues return (error); 1415d00947d8SCraig Rodrigues } 141620885defSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 141720885defSDaichi GOTO if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1418d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1419cb5736b7SDaichi GOTO error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td); 1420cb5736b7SDaichi GOTO if (!error) 1421d00947d8SCraig Rodrigues error = VOP_RMDIR(udvp, uvp, cnp); 1422d00947d8SCraig Rodrigues } 1423d00947d8SCraig Rodrigues else if (lvp != NULLVP) 1424d00947d8SCraig Rodrigues error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path); 1425d00947d8SCraig Rodrigues 1426dc2dd185SDaichi GOTO if (error == 0) { 1427dc2dd185SDaichi GOTO cache_purge(ap->a_dvp); 1428dc2dd185SDaichi GOTO cache_purge(ap->a_vp); 1429dc2dd185SDaichi GOTO } 1430dc2dd185SDaichi GOTO 1431d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1432d00947d8SCraig Rodrigues 1433d00947d8SCraig Rodrigues return (error); 1434d00947d8SCraig Rodrigues } 1435d00947d8SCraig Rodrigues 1436d00947d8SCraig Rodrigues static int 1437d00947d8SCraig Rodrigues unionfs_symlink(struct vop_symlink_args *ap) 1438d00947d8SCraig Rodrigues { 1439d00947d8SCraig Rodrigues int error; 144098155f1fSCraig Rodrigues int lkflags; 1441d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1442d00947d8SCraig Rodrigues struct componentname *cnp; 1443d00947d8SCraig Rodrigues struct thread *td; 1444d00947d8SCraig Rodrigues struct vnode *udvp; 1445d00947d8SCraig Rodrigues struct vnode *uvp; 1446d00947d8SCraig Rodrigues 1447d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1448d00947d8SCraig Rodrigues 14491e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 14501e5da15aSDaichi GOTO 1451d00947d8SCraig Rodrigues error = EROFS; 1452d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1453d00947d8SCraig Rodrigues cnp = ap->a_cnp; 145498155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1455d00947d8SCraig Rodrigues td = curthread; 1456d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1457d00947d8SCraig Rodrigues 1458d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1459d00947d8SCraig Rodrigues error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1460d00947d8SCraig Rodrigues if (error == 0) { 1461cb5736b7SDaichi GOTO VOP_UNLOCK(uvp, LK_RELEASE); 146298155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1463d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1464d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 146598155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1466d00947d8SCraig Rodrigues vrele(uvp); 1467d00947d8SCraig Rodrigues } 1468d00947d8SCraig Rodrigues } 1469d00947d8SCraig Rodrigues 1470d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1471d00947d8SCraig Rodrigues 1472d00947d8SCraig Rodrigues return (error); 1473d00947d8SCraig Rodrigues } 1474d00947d8SCraig Rodrigues 1475d00947d8SCraig Rodrigues static int 1476d00947d8SCraig Rodrigues unionfs_readdir(struct vop_readdir_args *ap) 1477d00947d8SCraig Rodrigues { 1478d00947d8SCraig Rodrigues int error; 1479d00947d8SCraig Rodrigues int eofflag; 148098155f1fSCraig Rodrigues int locked; 1481cb5736b7SDaichi GOTO int uio_offset_bk; 1482d00947d8SCraig Rodrigues struct unionfs_node *unp; 1483d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 1484d00947d8SCraig Rodrigues struct uio *uio; 1485cb5736b7SDaichi GOTO struct vnode *vp; 1486d00947d8SCraig Rodrigues struct vnode *uvp; 1487d00947d8SCraig Rodrigues struct vnode *lvp; 1488d00947d8SCraig Rodrigues struct thread *td; 1489d00947d8SCraig Rodrigues struct vattr va; 1490d00947d8SCraig Rodrigues 1491d00947d8SCraig Rodrigues int ncookies_bk; 1492d00947d8SCraig Rodrigues u_long *cookies_bk; 1493d00947d8SCraig Rodrigues 1494d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1495d00947d8SCraig Rodrigues 14961e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 14971e5da15aSDaichi GOTO 1498d00947d8SCraig Rodrigues error = 0; 1499d00947d8SCraig Rodrigues eofflag = 0; 150098155f1fSCraig Rodrigues locked = 0; 1501cb5736b7SDaichi GOTO uio_offset_bk = 0; 1502d00947d8SCraig Rodrigues uio = ap->a_uio; 1503cb5736b7SDaichi GOTO uvp = NULLVP; 1504cb5736b7SDaichi GOTO lvp = NULLVP; 1505d00947d8SCraig Rodrigues td = uio->uio_td; 1506d00947d8SCraig Rodrigues ncookies_bk = 0; 1507d00947d8SCraig Rodrigues cookies_bk = NULL; 1508d00947d8SCraig Rodrigues 1509cb5736b7SDaichi GOTO vp = ap->a_vp; 1510cb5736b7SDaichi GOTO if (vp->v_type != VDIR) 1511d00947d8SCraig Rodrigues return (ENOTDIR); 1512d00947d8SCraig Rodrigues 1513cb5736b7SDaichi GOTO /* check the open count. unionfs needs to open before readdir. */ 1514cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 1515cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 1516cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1517cb5736b7SDaichi GOTO locked = 1; 1518cb5736b7SDaichi GOTO } 1519cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 1520cb5736b7SDaichi GOTO if (unp == NULL) 1521cb5736b7SDaichi GOTO error = EBADF; 1522cb5736b7SDaichi GOTO else { 1523cb5736b7SDaichi GOTO uvp = unp->un_uppervp; 1524cb5736b7SDaichi GOTO lvp = unp->un_lowervp; 1525cb5736b7SDaichi GOTO unionfs_get_node_status(unp, td, &unsp); 1526cb5736b7SDaichi GOTO if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 1527cb5736b7SDaichi GOTO (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1528cb5736b7SDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 1529cb5736b7SDaichi GOTO error = EBADF; 1530cb5736b7SDaichi GOTO } 1531cb5736b7SDaichi GOTO } 1532cb5736b7SDaichi GOTO if (locked) 1533cb5736b7SDaichi GOTO vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 1534cb5736b7SDaichi GOTO if (error != 0) 1535cb5736b7SDaichi GOTO goto unionfs_readdir_exit; 1536cb5736b7SDaichi GOTO 1537d00947d8SCraig Rodrigues /* check opaque */ 1538d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP) { 15390359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 15405adc4080SDaichi GOTO goto unionfs_readdir_exit; 1541d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 1542d00947d8SCraig Rodrigues lvp = NULLVP; 1543d00947d8SCraig Rodrigues } 1544d00947d8SCraig Rodrigues 1545d00947d8SCraig Rodrigues /* upper only */ 1546d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp == NULLVP) { 1547d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1548d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1549d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1550d00947d8SCraig Rodrigues 1551d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1552d00947d8SCraig Rodrigues } 1553d00947d8SCraig Rodrigues 1554d00947d8SCraig Rodrigues /* lower only */ 1555d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp != NULLVP) { 1556d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1557d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1558d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1559d00947d8SCraig Rodrigues 1560d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1561d00947d8SCraig Rodrigues } 1562d00947d8SCraig Rodrigues 1563d00947d8SCraig Rodrigues /* 1564d00947d8SCraig Rodrigues * readdir upper and lower 1565d00947d8SCraig Rodrigues */ 15666c98d0e9SDaichi GOTO KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp")); 15676c98d0e9SDaichi GOTO KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp")); 1568d00947d8SCraig Rodrigues if (uio->uio_offset == 0) 1569d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1570d00947d8SCraig Rodrigues 1571d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 0) { 1572d00947d8SCraig Rodrigues /* read upper */ 1573d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1574d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1575d00947d8SCraig Rodrigues 15765adc4080SDaichi GOTO if (error != 0 || eofflag == 0) 15775adc4080SDaichi GOTO goto unionfs_readdir_exit; 1578d00947d8SCraig Rodrigues unsp->uns_readdir_status = 1; 1579d00947d8SCraig Rodrigues 1580d00947d8SCraig Rodrigues /* 1581cb5736b7SDaichi GOTO * UFS(and other FS) needs size of uio_resid larger than 1582d00947d8SCraig Rodrigues * DIRBLKSIZ. 1583d00947d8SCraig Rodrigues * size of DIRBLKSIZ equals DEV_BSIZE. 1584d00947d8SCraig Rodrigues * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1585d00947d8SCraig Rodrigues */ 15865adc4080SDaichi GOTO if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 15875adc4080SDaichi GOTO goto unionfs_readdir_exit; 1588d00947d8SCraig Rodrigues 1589d00947d8SCraig Rodrigues /* 1590cb5736b7SDaichi GOTO * Backup cookies. 1591d00947d8SCraig Rodrigues * It prepares to readdir in lower. 1592d00947d8SCraig Rodrigues */ 1593d00947d8SCraig Rodrigues if (ap->a_ncookies != NULL) { 1594d00947d8SCraig Rodrigues ncookies_bk = *(ap->a_ncookies); 1595d00947d8SCraig Rodrigues *(ap->a_ncookies) = 0; 1596d00947d8SCraig Rodrigues } 1597d00947d8SCraig Rodrigues if (ap->a_cookies != NULL) { 1598d00947d8SCraig Rodrigues cookies_bk = *(ap->a_cookies); 1599d00947d8SCraig Rodrigues *(ap->a_cookies) = NULL; 1600d00947d8SCraig Rodrigues } 1601d00947d8SCraig Rodrigues } 1602d00947d8SCraig Rodrigues 1603d00947d8SCraig Rodrigues /* initialize for readdir in lower */ 1604d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 1) { 1605d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1606cb5736b7SDaichi GOTO /* 1607cb5736b7SDaichi GOTO * Backup uio_offset. See the comment after the 1608cb5736b7SDaichi GOTO * VOP_READDIR call on the lower layer. 1609cb5736b7SDaichi GOTO */ 1610cb5736b7SDaichi GOTO uio_offset_bk = uio->uio_offset; 1611d00947d8SCraig Rodrigues uio->uio_offset = 0; 1612d00947d8SCraig Rodrigues } 1613d00947d8SCraig Rodrigues 1614b16f4eecSCraig Rodrigues if (lvp == NULLVP) { 1615b16f4eecSCraig Rodrigues error = EBADF; 1616b16f4eecSCraig Rodrigues goto unionfs_readdir_exit; 1617b16f4eecSCraig Rodrigues } 1618d00947d8SCraig Rodrigues /* read lower */ 1619d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1620d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1621d00947d8SCraig Rodrigues 1622cb5736b7SDaichi GOTO /* 1623cb5736b7SDaichi GOTO * We can't return an uio_offset of 0: this would trigger an 1624cb5736b7SDaichi GOTO * infinite loop, because the next call to unionfs_readdir would 1625cb5736b7SDaichi GOTO * always restart with the upper layer (uio_offset == 0) and 1626cb5736b7SDaichi GOTO * always return some data. 1627cb5736b7SDaichi GOTO * 1628cb5736b7SDaichi GOTO * This happens when the lower layer root directory is removed. 1629cb5736b7SDaichi GOTO * (A root directory deleting of unionfs should not be permitted. 1630cb5736b7SDaichi GOTO * But current VFS can not do it.) 1631cb5736b7SDaichi GOTO */ 1632cb5736b7SDaichi GOTO if (uio->uio_offset == 0) 1633cb5736b7SDaichi GOTO uio->uio_offset = uio_offset_bk; 1634cb5736b7SDaichi GOTO 1635d00947d8SCraig Rodrigues if (cookies_bk != NULL) { 1636d00947d8SCraig Rodrigues /* merge cookies */ 1637d00947d8SCraig Rodrigues int size; 1638d00947d8SCraig Rodrigues u_long *newcookies, *pos; 1639d00947d8SCraig Rodrigues 1640d00947d8SCraig Rodrigues size = *(ap->a_ncookies) + ncookies_bk; 1641d00947d8SCraig Rodrigues newcookies = (u_long *) malloc(size * sizeof(u_long), 1642d00947d8SCraig Rodrigues M_TEMP, M_WAITOK); 1643d00947d8SCraig Rodrigues pos = newcookies; 1644d00947d8SCraig Rodrigues 1645d00947d8SCraig Rodrigues memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long)); 1646508a31f1SDaichi GOTO pos += ncookies_bk; 1647d00947d8SCraig Rodrigues memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long)); 1648d00947d8SCraig Rodrigues free(cookies_bk, M_TEMP); 1649d00947d8SCraig Rodrigues free(*(ap->a_cookies), M_TEMP); 1650d00947d8SCraig Rodrigues *(ap->a_ncookies) = size; 1651d00947d8SCraig Rodrigues *(ap->a_cookies) = newcookies; 1652d00947d8SCraig Rodrigues } 1653d00947d8SCraig Rodrigues 1654d00947d8SCraig Rodrigues unionfs_readdir_exit: 16555adc4080SDaichi GOTO if (error != 0 && ap->a_eofflag != NULL) 16565adc4080SDaichi GOTO *(ap->a_eofflag) = 1; 16575adc4080SDaichi GOTO 1658d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1659d00947d8SCraig Rodrigues 1660d00947d8SCraig Rodrigues return (error); 1661d00947d8SCraig Rodrigues } 1662d00947d8SCraig Rodrigues 1663d00947d8SCraig Rodrigues static int 1664d00947d8SCraig Rodrigues unionfs_readlink(struct vop_readlink_args *ap) 1665d00947d8SCraig Rodrigues { 1666d00947d8SCraig Rodrigues int error; 1667d00947d8SCraig Rodrigues struct unionfs_node *unp; 1668df8bae1dSRodney W. Grimes struct vnode *vp; 1669df8bae1dSRodney W. Grimes 1670d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 16712a31267eSMatthew Dillon 16721e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 16731e5da15aSDaichi GOTO 1674d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1675d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1676d00947d8SCraig Rodrigues 1677d00947d8SCraig Rodrigues error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1678d00947d8SCraig Rodrigues 1679d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1680d00947d8SCraig Rodrigues 16812a31267eSMatthew Dillon return (error); 1682df8bae1dSRodney W. Grimes } 1683df8bae1dSRodney W. Grimes 1684c9bf0111SKATO Takenori static int 1685d00947d8SCraig Rodrigues unionfs_getwritemount(struct vop_getwritemount_args *ap) 1686df8bae1dSRodney W. Grimes { 16877be2d300SMike Smith int error; 1688d00947d8SCraig Rodrigues struct vnode *uvp; 1689d00947d8SCraig Rodrigues struct vnode *vp; 1690df8bae1dSRodney W. Grimes 1691d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); 1692996c772fSJohn Dyson 1693d00947d8SCraig Rodrigues error = 0; 1694d00947d8SCraig Rodrigues vp = ap->a_vp; 1695d00947d8SCraig Rodrigues 1696d00947d8SCraig Rodrigues if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) 1697d00947d8SCraig Rodrigues return (EACCES); 1698d00947d8SCraig Rodrigues 16991e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(vp); 17001e5da15aSDaichi GOTO 1701d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(vp); 1702d00947d8SCraig Rodrigues if (uvp == NULLVP && VREG == vp->v_type) 1703d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); 1704d00947d8SCraig Rodrigues 1705d00947d8SCraig Rodrigues if (uvp != NULLVP) 1706d00947d8SCraig Rodrigues error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); 1707d00947d8SCraig Rodrigues else { 1708d00947d8SCraig Rodrigues VI_LOCK(vp); 1709d00947d8SCraig Rodrigues if (vp->v_iflag & VI_FREE) 17106d8e1f82SBrian Feldman error = EOPNOTSUPP; 17116d8e1f82SBrian Feldman else 1712d00947d8SCraig Rodrigues error = EACCES; 1713d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1714df8bae1dSRodney W. Grimes } 1715d00947d8SCraig Rodrigues 1716d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error); 1717d00947d8SCraig Rodrigues 1718df8bae1dSRodney W. Grimes return (error); 1719df8bae1dSRodney W. Grimes } 1720df8bae1dSRodney W. Grimes 1721c9bf0111SKATO Takenori static int 1722d00947d8SCraig Rodrigues unionfs_inactive(struct vop_inactive_args *ap) 1723df8bae1dSRodney W. Grimes { 1724dc2dd185SDaichi GOTO ap->a_vp->v_object = NULL; 1725af6e6b87SEdward Tomasz Napierala vrecycle(ap->a_vp); 1726d00947d8SCraig Rodrigues return (0); 1727df8bae1dSRodney W. Grimes } 1728df8bae1dSRodney W. Grimes 1729c9bf0111SKATO Takenori static int 1730d00947d8SCraig Rodrigues unionfs_reclaim(struct vop_reclaim_args *ap) 1731df8bae1dSRodney W. Grimes { 1732d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1733d00947d8SCraig Rodrigues 1734dc2dd185SDaichi GOTO unionfs_noderem(ap->a_vp, ap->a_td); 1735d00947d8SCraig Rodrigues 1736d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1737d00947d8SCraig Rodrigues 1738d00947d8SCraig Rodrigues return (0); 1739d00947d8SCraig Rodrigues } 1740d00947d8SCraig Rodrigues 1741d00947d8SCraig Rodrigues static int 1742d00947d8SCraig Rodrigues unionfs_print(struct vop_print_args *ap) 1743d00947d8SCraig Rodrigues { 1744d00947d8SCraig Rodrigues struct unionfs_node *unp; 1745d00947d8SCraig Rodrigues /* struct unionfs_node_status *unsp; */ 1746d00947d8SCraig Rodrigues 1747d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1748d00947d8SCraig Rodrigues /* unionfs_get_node_status(unp, curthread, &unsp); */ 1749d00947d8SCraig Rodrigues 1750d00947d8SCraig Rodrigues printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1751d00947d8SCraig Rodrigues ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1752d00947d8SCraig Rodrigues /* 1753d00947d8SCraig Rodrigues printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1754d00947d8SCraig Rodrigues unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1755d00947d8SCraig Rodrigues */ 1756d00947d8SCraig Rodrigues 1757d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 1758411455a8SEdward Tomasz Napierala vn_printf(unp->un_uppervp, "unionfs: upper "); 1759d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1760411455a8SEdward Tomasz Napierala vn_printf(unp->un_lowervp, "unionfs: lower "); 1761d00947d8SCraig Rodrigues 1762d00947d8SCraig Rodrigues return (0); 1763d00947d8SCraig Rodrigues } 1764d00947d8SCraig Rodrigues 1765d00947d8SCraig Rodrigues static int 1766cb5736b7SDaichi GOTO unionfs_islocked(struct vop_islocked_args *ap) 1767d00947d8SCraig Rodrigues { 1768cb5736b7SDaichi GOTO struct unionfs_node *unp; 1769d00947d8SCraig Rodrigues 1770cb5736b7SDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 1771cb5736b7SDaichi GOTO 1772cb5736b7SDaichi GOTO unp = VTOUNIONFS(ap->a_vp); 1773cb5736b7SDaichi GOTO if (unp == NULL) 1774cb5736b7SDaichi GOTO return (vop_stdislocked(ap)); 1775cb5736b7SDaichi GOTO 1776cb5736b7SDaichi GOTO if (unp->un_uppervp != NULLVP) 1777cb5736b7SDaichi GOTO return (VOP_ISLOCKED(unp->un_uppervp)); 1778cb5736b7SDaichi GOTO if (unp->un_lowervp != NULLVP) 1779cb5736b7SDaichi GOTO return (VOP_ISLOCKED(unp->un_lowervp)); 1780cb5736b7SDaichi GOTO return (vop_stdislocked(ap)); 1781d00947d8SCraig Rodrigues } 1782d00947d8SCraig Rodrigues 1783cb5736b7SDaichi GOTO static int 1784cb5736b7SDaichi GOTO unionfs_get_llt_revlock(struct vnode *vp, int flags) 1785cb5736b7SDaichi GOTO { 1786cb5736b7SDaichi GOTO int revlock; 1787cb5736b7SDaichi GOTO 1788cb5736b7SDaichi GOTO revlock = 0; 1789cb5736b7SDaichi GOTO 1790cb5736b7SDaichi GOTO switch (flags & LK_TYPE_MASK) { 1791cb5736b7SDaichi GOTO case LK_SHARED: 1792cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) 1793cb5736b7SDaichi GOTO revlock = LK_UPGRADE; 1794cb5736b7SDaichi GOTO else 1795cb5736b7SDaichi GOTO revlock = LK_RELEASE; 1796cb5736b7SDaichi GOTO break; 1797cb5736b7SDaichi GOTO case LK_EXCLUSIVE: 1798cb5736b7SDaichi GOTO case LK_UPGRADE: 1799cb5736b7SDaichi GOTO revlock = LK_RELEASE; 1800cb5736b7SDaichi GOTO break; 1801cb5736b7SDaichi GOTO case LK_DOWNGRADE: 1802cb5736b7SDaichi GOTO revlock = LK_UPGRADE; 1803cb5736b7SDaichi GOTO break; 1804cb5736b7SDaichi GOTO default: 1805cb5736b7SDaichi GOTO break; 1806cb5736b7SDaichi GOTO } 1807cb5736b7SDaichi GOTO 1808cb5736b7SDaichi GOTO return (revlock); 1809cb5736b7SDaichi GOTO } 1810cb5736b7SDaichi GOTO 1811cb5736b7SDaichi GOTO /* 1812cb5736b7SDaichi GOTO * The state of an acquired lock is adjusted similarly to 1813cb5736b7SDaichi GOTO * the time of error generating. 1814cb5736b7SDaichi GOTO * flags: LK_RELEASE or LK_UPGRADE 1815cb5736b7SDaichi GOTO */ 1816cb5736b7SDaichi GOTO static void 1817cb5736b7SDaichi GOTO unionfs_revlock(struct vnode *vp, int flags) 1818cb5736b7SDaichi GOTO { 1819cb5736b7SDaichi GOTO if (flags & LK_RELEASE) 1820cb5736b7SDaichi GOTO VOP_UNLOCK(vp, flags); 1821cb5736b7SDaichi GOTO else { 1822cb5736b7SDaichi GOTO /* UPGRADE */ 1823cb5736b7SDaichi GOTO if (vn_lock(vp, flags) != 0) 1824cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1825cb5736b7SDaichi GOTO } 1826d00947d8SCraig Rodrigues } 1827d00947d8SCraig Rodrigues 1828d00947d8SCraig Rodrigues static int 1829d413d210SKonstantin Belousov unionfs_lock(struct vop_lock1_args *ap) 1830d00947d8SCraig Rodrigues { 1831d00947d8SCraig Rodrigues int error; 1832d00947d8SCraig Rodrigues int flags; 1833d00947d8SCraig Rodrigues int revlock; 1834cb5736b7SDaichi GOTO int interlock; 1835d00947d8SCraig Rodrigues int uhold; 183657821163SDaichi GOTO struct mount *mp; 1837d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1838d00947d8SCraig Rodrigues struct unionfs_node *unp; 1839d00947d8SCraig Rodrigues struct vnode *vp; 18402a31267eSMatthew Dillon struct vnode *uvp; 1841d00947d8SCraig Rodrigues struct vnode *lvp; 1842df8bae1dSRodney W. Grimes 18431e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 18441e5da15aSDaichi GOTO 1845d00947d8SCraig Rodrigues error = 0; 1846cb5736b7SDaichi GOTO interlock = 1; 1847d00947d8SCraig Rodrigues uhold = 0; 1848d00947d8SCraig Rodrigues flags = ap->a_flags; 1849d00947d8SCraig Rodrigues vp = ap->a_vp; 1850df8bae1dSRodney W. Grimes 1851d00947d8SCraig Rodrigues if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK)) 1852cb5736b7SDaichi GOTO return (VOP_UNLOCK(vp, flags | LK_RELEASE)); 18532a31267eSMatthew Dillon 185457821163SDaichi GOTO if ((flags & LK_INTERLOCK) == 0) 1855f3d1ec67SBoris Popov VI_LOCK(vp); 1856d00947d8SCraig Rodrigues 185757821163SDaichi GOTO mp = vp->v_mount; 185857821163SDaichi GOTO if (mp == NULL) 185957821163SDaichi GOTO goto unionfs_lock_null_vnode; 186057821163SDaichi GOTO 186157821163SDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(mp); 1862d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 186357821163SDaichi GOTO if (ump == NULL || unp == NULL) 1864d00947d8SCraig Rodrigues goto unionfs_lock_null_vnode; 1865d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1866d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1867f2a2857bSKirk McKusick 1868cb5736b7SDaichi GOTO if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0) 1869cb5736b7SDaichi GOTO panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); 1870cb5736b7SDaichi GOTO 1871bc2258daSAttilio Rao if ((vp->v_iflag & VI_OWEINACT) != 0) 187257821163SDaichi GOTO flags |= LK_NOWAIT; 187357821163SDaichi GOTO 18742a31267eSMatthew Dillon /* 1875d00947d8SCraig Rodrigues * Sometimes, lower or upper is already exclusive locked. 1876d00947d8SCraig Rodrigues * (ex. vfs_domount: mounted vnode is already locked.) 18772a31267eSMatthew Dillon */ 1878d00947d8SCraig Rodrigues if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1879d00947d8SCraig Rodrigues vp == ump->um_rootvp) 1880d00947d8SCraig Rodrigues flags |= LK_CANRECURSE; 18812a31267eSMatthew Dillon 1882d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1883cb5736b7SDaichi GOTO if (uvp != NULLVP && flags & LK_UPGRADE) { 1884cb5736b7SDaichi GOTO /* Share Lock is once released and a deadlock is avoided. */ 188548407115SMateusz Guzik vholdnz(uvp); 1886cb5736b7SDaichi GOTO uhold = 1; 188748407115SMateusz Guzik VOP_UNLOCK(uvp, LK_RELEASE); 1888cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 1889cb5736b7SDaichi GOTO if (unp == NULL) { 1890cb5736b7SDaichi GOTO /* vnode is released. */ 1891cb5736b7SDaichi GOTO VI_UNLOCK(vp); 1892cb5736b7SDaichi GOTO VOP_UNLOCK(lvp, LK_RELEASE); 1893cb5736b7SDaichi GOTO vdrop(uvp); 1894cb5736b7SDaichi GOTO return (EBUSY); 1895cb5736b7SDaichi GOTO } 1896cb5736b7SDaichi GOTO } 1897d00947d8SCraig Rodrigues VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1898d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1899d00947d8SCraig Rodrigues vholdl(lvp); 1900df8bae1dSRodney W. Grimes 1901d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1902d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1903df8bae1dSRodney W. Grimes 190422db15c0SAttilio Rao error = VOP_LOCK(lvp, flags); 1905df8bae1dSRodney W. Grimes 1906d00947d8SCraig Rodrigues VI_LOCK(vp); 1907d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1908d00947d8SCraig Rodrigues if (unp == NULL) { 1909cb5736b7SDaichi GOTO /* vnode is released. */ 191057821163SDaichi GOTO VI_UNLOCK(vp); 1911d00947d8SCraig Rodrigues if (error == 0) 1912cb5736b7SDaichi GOTO VOP_UNLOCK(lvp, LK_RELEASE); 1913d00947d8SCraig Rodrigues vdrop(lvp); 1914cb5736b7SDaichi GOTO if (uhold != 0) 1915cb5736b7SDaichi GOTO vdrop(uvp); 1916d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 19172a31267eSMatthew Dillon } 1918df8bae1dSRodney W. Grimes } 1919df8bae1dSRodney W. Grimes 1920d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 1921cb5736b7SDaichi GOTO if (uhold && flags & LK_UPGRADE) { 1922cb5736b7SDaichi GOTO flags &= ~LK_TYPE_MASK; 1923cb5736b7SDaichi GOTO flags |= LK_EXCLUSIVE; 1924cb5736b7SDaichi GOTO } 1925d00947d8SCraig Rodrigues VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1926d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1927cb5736b7SDaichi GOTO if (uhold == 0) { 1928d00947d8SCraig Rodrigues vholdl(uvp); 1929d00947d8SCraig Rodrigues uhold = 1; 1930cb5736b7SDaichi GOTO } 1931df8bae1dSRodney W. Grimes 1932d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1933d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1934d00947d8SCraig Rodrigues 193522db15c0SAttilio Rao error = VOP_LOCK(uvp, flags); 1936d00947d8SCraig Rodrigues 1937d00947d8SCraig Rodrigues VI_LOCK(vp); 1938d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1939d00947d8SCraig Rodrigues if (unp == NULL) { 1940cb5736b7SDaichi GOTO /* vnode is released. */ 194157821163SDaichi GOTO VI_UNLOCK(vp); 1942cb5736b7SDaichi GOTO if (error == 0) 1943cb5736b7SDaichi GOTO VOP_UNLOCK(uvp, LK_RELEASE); 1944d00947d8SCraig Rodrigues vdrop(uvp); 1945cb5736b7SDaichi GOTO if (lvp != NULLVP) { 1946cb5736b7SDaichi GOTO VOP_UNLOCK(lvp, LK_RELEASE); 1947cb5736b7SDaichi GOTO vdrop(lvp); 1948cb5736b7SDaichi GOTO } 1949d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1950df8bae1dSRodney W. Grimes } 195157821163SDaichi GOTO if (error != 0 && lvp != NULLVP) { 1952cb5736b7SDaichi GOTO /* rollback */ 195357821163SDaichi GOTO VI_UNLOCK(vp); 1954cb5736b7SDaichi GOTO unionfs_revlock(lvp, revlock); 1955cb5736b7SDaichi GOTO interlock = 0; 195657821163SDaichi GOTO } 1957df8bae1dSRodney W. Grimes } 1958df8bae1dSRodney W. Grimes 1959cb5736b7SDaichi GOTO if (interlock) 1960d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1961d00947d8SCraig Rodrigues if (lvp != NULLVP) 1962d00947d8SCraig Rodrigues vdrop(lvp); 1963d00947d8SCraig Rodrigues if (uhold != 0) 1964d00947d8SCraig Rodrigues vdrop(uvp); 1965df8bae1dSRodney W. Grimes 1966df8bae1dSRodney W. Grimes return (error); 1967d00947d8SCraig Rodrigues 1968d00947d8SCraig Rodrigues unionfs_lock_null_vnode: 1969d00947d8SCraig Rodrigues ap->a_flags |= LK_INTERLOCK; 1970d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1971df8bae1dSRodney W. Grimes } 1972df8bae1dSRodney W. Grimes 1973c9bf0111SKATO Takenori static int 1974d00947d8SCraig Rodrigues unionfs_unlock(struct vop_unlock_args *ap) 1975df8bae1dSRodney W. Grimes { 1976d00947d8SCraig Rodrigues int error; 1977d00947d8SCraig Rodrigues int flags; 1978d00947d8SCraig Rodrigues int uhold; 1979d00947d8SCraig Rodrigues struct vnode *vp; 1980d00947d8SCraig Rodrigues struct vnode *lvp; 1981d00947d8SCraig Rodrigues struct vnode *uvp; 1982d00947d8SCraig Rodrigues struct unionfs_node *unp; 1983df8bae1dSRodney W. Grimes 19841e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 19851e5da15aSDaichi GOTO 1986d00947d8SCraig Rodrigues error = 0; 1987d00947d8SCraig Rodrigues uhold = 0; 1988d00947d8SCraig Rodrigues flags = ap->a_flags | LK_RELEASE; 1989d00947d8SCraig Rodrigues vp = ap->a_vp; 1990d00947d8SCraig Rodrigues 1991d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1992d00947d8SCraig Rodrigues if (unp == NULL) 1993d00947d8SCraig Rodrigues goto unionfs_unlock_null_vnode; 1994d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1995d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1996df8bae1dSRodney W. Grimes 1997d00947d8SCraig Rodrigues if (lvp != NULLVP) { 199848407115SMateusz Guzik vholdnz(lvp); 199922db15c0SAttilio Rao error = VOP_UNLOCK(lvp, flags); 2000d00947d8SCraig Rodrigues } 2001d00947d8SCraig Rodrigues 2002d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 200348407115SMateusz Guzik vholdnz(uvp); 2004d00947d8SCraig Rodrigues uhold = 1; 200522db15c0SAttilio Rao error = VOP_UNLOCK(uvp, flags); 2006d00947d8SCraig Rodrigues } 2007d00947d8SCraig Rodrigues 2008d00947d8SCraig Rodrigues if (lvp != NULLVP) 2009d00947d8SCraig Rodrigues vdrop(lvp); 2010d00947d8SCraig Rodrigues if (uhold != 0) 2011d00947d8SCraig Rodrigues vdrop(uvp); 2012d00947d8SCraig Rodrigues 2013d00947d8SCraig Rodrigues return error; 2014d00947d8SCraig Rodrigues 2015d00947d8SCraig Rodrigues unionfs_unlock_null_vnode: 2016d00947d8SCraig Rodrigues return (vop_stdunlock(ap)); 2017d00947d8SCraig Rodrigues } 2018d00947d8SCraig Rodrigues 2019c9bf0111SKATO Takenori static int 2020d00947d8SCraig Rodrigues unionfs_pathconf(struct vop_pathconf_args *ap) 2021df8bae1dSRodney W. Grimes { 2022d00947d8SCraig Rodrigues struct unionfs_node *unp; 2023d00947d8SCraig Rodrigues struct vnode *vp; 2024d00947d8SCraig Rodrigues 20251e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20261e5da15aSDaichi GOTO 2027d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2028d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2029d00947d8SCraig Rodrigues 2030d00947d8SCraig Rodrigues return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 2031d00947d8SCraig Rodrigues } 2032d00947d8SCraig Rodrigues 2033d00947d8SCraig Rodrigues static int 2034d00947d8SCraig Rodrigues unionfs_advlock(struct vop_advlock_args *ap) 2035d00947d8SCraig Rodrigues { 2036d00947d8SCraig Rodrigues int error; 2037d00947d8SCraig Rodrigues struct unionfs_node *unp; 2038d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 2039d00947d8SCraig Rodrigues struct vnode *vp; 2040d00947d8SCraig Rodrigues struct vnode *uvp; 2041d00947d8SCraig Rodrigues struct thread *td; 2042d00947d8SCraig Rodrigues 2043d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 2044d00947d8SCraig Rodrigues 20451e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20461e5da15aSDaichi GOTO 2047d00947d8SCraig Rodrigues vp = ap->a_vp; 2048d00947d8SCraig Rodrigues td = curthread; 2049d00947d8SCraig Rodrigues 2050cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2051d00947d8SCraig Rodrigues 2052d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2053d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2054d00947d8SCraig Rodrigues 2055d00947d8SCraig Rodrigues if (uvp == NULLVP) { 2056d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, td->td_ucred, td); 2057d00947d8SCraig Rodrigues if (error != 0) 2058d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2059d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2060d00947d8SCraig Rodrigues 2061d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 2062d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) { 2063d00947d8SCraig Rodrigues /* try reopen the vnode */ 20649e223287SKonstantin Belousov error = VOP_OPEN(uvp, unsp->uns_lower_openmode, 20659e223287SKonstantin Belousov td->td_ucred, td, NULL); 2066d00947d8SCraig Rodrigues if (error) 2067d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2068d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 2069d00947d8SCraig Rodrigues VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td); 2070d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 2071b2b0db08SDaichi GOTO } else 2072fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 2073d00947d8SCraig Rodrigues } 2074d00947d8SCraig Rodrigues 2075cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 2076d00947d8SCraig Rodrigues 2077d00947d8SCraig Rodrigues error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 2078d00947d8SCraig Rodrigues 2079d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2080d00947d8SCraig Rodrigues 2081d00947d8SCraig Rodrigues return error; 2082d00947d8SCraig Rodrigues 2083d00947d8SCraig Rodrigues unionfs_advlock_abort: 2084cb5736b7SDaichi GOTO VOP_UNLOCK(vp, LK_RELEASE); 2085d00947d8SCraig Rodrigues 2086d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2087d00947d8SCraig Rodrigues 2088d00947d8SCraig Rodrigues return error; 2089d00947d8SCraig Rodrigues } 2090d00947d8SCraig Rodrigues 2091d00947d8SCraig Rodrigues static int 2092d00947d8SCraig Rodrigues unionfs_strategy(struct vop_strategy_args *ap) 2093d00947d8SCraig Rodrigues { 2094d00947d8SCraig Rodrigues struct unionfs_node *unp; 2095d00947d8SCraig Rodrigues struct vnode *vp; 2096d00947d8SCraig Rodrigues 20971e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20981e5da15aSDaichi GOTO 2099d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2100d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2101df8bae1dSRodney W. Grimes 2102df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 2103d00947d8SCraig Rodrigues if (vp == NULLVP) 2104d00947d8SCraig Rodrigues panic("unionfs_strategy: nullvp"); 2105d00947d8SCraig Rodrigues 2106d00947d8SCraig Rodrigues if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 2107d00947d8SCraig Rodrigues panic("unionfs_strategy: writing to lowervp"); 2108df8bae1dSRodney W. Grimes #endif 2109d00947d8SCraig Rodrigues 2110d00947d8SCraig Rodrigues return (VOP_STRATEGY(vp, ap->a_bp)); 2111df8bae1dSRodney W. Grimes } 2112df8bae1dSRodney W. Grimes 211300fff2c7STim J. Robbins static int 2114d00947d8SCraig Rodrigues unionfs_getacl(struct vop_getacl_args *ap) 211500fff2c7STim J. Robbins { 211600fff2c7STim J. Robbins int error; 2117d00947d8SCraig Rodrigues struct unionfs_node *unp; 211800fff2c7STim J. Robbins struct vnode *vp; 211900fff2c7STim J. Robbins 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 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 2126d00947d8SCraig Rodrigues 2127d00947d8SCraig Rodrigues error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2128d00947d8SCraig Rodrigues 2129d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 213000fff2c7STim J. Robbins 213100fff2c7STim J. Robbins return (error); 213200fff2c7STim J. Robbins } 213300fff2c7STim J. Robbins 213400fff2c7STim J. Robbins static int 2135d00947d8SCraig Rodrigues unionfs_setacl(struct vop_setacl_args *ap) 213600fff2c7STim J. Robbins { 213700fff2c7STim J. Robbins int error; 2138d00947d8SCraig Rodrigues struct unionfs_node *unp; 2139d00947d8SCraig Rodrigues struct vnode *uvp; 2140d00947d8SCraig Rodrigues struct vnode *lvp; 2141d00947d8SCraig Rodrigues struct thread *td; 214200fff2c7STim J. Robbins 2143d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 2144d00947d8SCraig Rodrigues 21451e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21461e5da15aSDaichi GOTO 2147d00947d8SCraig Rodrigues error = EROFS; 2148d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2149d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2150d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2151d00947d8SCraig Rodrigues td = ap->a_td; 2152d00947d8SCraig Rodrigues 2153d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2154d00947d8SCraig Rodrigues return (EROFS); 2155d00947d8SCraig Rodrigues 2156d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2157d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2158d00947d8SCraig Rodrigues return (error); 2159d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2160d00947d8SCraig Rodrigues } 2161d00947d8SCraig Rodrigues 2162d00947d8SCraig Rodrigues if (uvp != NULLVP) 2163d00947d8SCraig Rodrigues error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 2164d00947d8SCraig Rodrigues 2165d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 216600fff2c7STim J. Robbins 216700fff2c7STim J. Robbins return (error); 216800fff2c7STim J. Robbins } 216900fff2c7STim J. Robbins 217000fff2c7STim J. Robbins static int 2171d00947d8SCraig Rodrigues unionfs_aclcheck(struct vop_aclcheck_args *ap) 217200fff2c7STim J. Robbins { 217300fff2c7STim J. Robbins int error; 2174d00947d8SCraig Rodrigues struct unionfs_node *unp; 217500fff2c7STim J. Robbins struct vnode *vp; 217600fff2c7STim J. Robbins 2177d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 2178d00947d8SCraig Rodrigues 21791e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21801e5da15aSDaichi GOTO 2181d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2182d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2183d00947d8SCraig Rodrigues 2184d00947d8SCraig Rodrigues error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2185d00947d8SCraig Rodrigues 2186d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 218700fff2c7STim J. Robbins 218800fff2c7STim J. Robbins return (error); 218900fff2c7STim J. Robbins } 219000fff2c7STim J. Robbins 219100fff2c7STim J. Robbins static int 2192d00947d8SCraig Rodrigues unionfs_openextattr(struct vop_openextattr_args *ap) 219300fff2c7STim J. Robbins { 219400fff2c7STim J. Robbins int error; 2195d00947d8SCraig Rodrigues struct unionfs_node *unp; 219600fff2c7STim J. Robbins struct vnode *vp; 219757821163SDaichi GOTO struct vnode *tvp; 219800fff2c7STim J. Robbins 21991e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22001e5da15aSDaichi GOTO 220157821163SDaichi GOTO vp = ap->a_vp; 220257821163SDaichi GOTO unp = VTOUNIONFS(vp); 220357821163SDaichi GOTO tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2204d00947d8SCraig Rodrigues 220557821163SDaichi GOTO if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 220657821163SDaichi GOTO (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 2207d00947d8SCraig Rodrigues return (EBUSY); 2208d00947d8SCraig Rodrigues 220957821163SDaichi GOTO error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td); 2210d00947d8SCraig Rodrigues 2211d00947d8SCraig Rodrigues if (error == 0) { 2212cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 2213cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 221457821163SDaichi GOTO if (tvp == unp->un_uppervp) 2215d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2216d00947d8SCraig Rodrigues else 2217d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTL; 2218cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2219d00947d8SCraig Rodrigues } 222000fff2c7STim J. Robbins 222100fff2c7STim J. Robbins return (error); 222200fff2c7STim J. Robbins } 222300fff2c7STim J. Robbins 222400fff2c7STim J. Robbins static int 2225d00947d8SCraig Rodrigues unionfs_closeextattr(struct vop_closeextattr_args *ap) 222600fff2c7STim J. Robbins { 222700fff2c7STim J. Robbins int error; 2228d00947d8SCraig Rodrigues struct unionfs_node *unp; 222900fff2c7STim J. Robbins struct vnode *vp; 223057821163SDaichi GOTO struct vnode *tvp; 223100fff2c7STim J. Robbins 22321e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22331e5da15aSDaichi GOTO 223457821163SDaichi GOTO vp = ap->a_vp; 223557821163SDaichi GOTO unp = VTOUNIONFS(vp); 223657821163SDaichi GOTO tvp = NULLVP; 2237d00947d8SCraig Rodrigues 2238d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 223957821163SDaichi GOTO tvp = unp->un_uppervp; 2240d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 224157821163SDaichi GOTO tvp = unp->un_lowervp; 2242d00947d8SCraig Rodrigues 224357821163SDaichi GOTO if (tvp == NULLVP) 2244d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2245d00947d8SCraig Rodrigues 224657821163SDaichi GOTO error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td); 2247d00947d8SCraig Rodrigues 2248d00947d8SCraig Rodrigues if (error == 0) { 2249cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 2250cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 225157821163SDaichi GOTO if (tvp == unp->un_uppervp) 2252d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTU; 2253d00947d8SCraig Rodrigues else 2254d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2255cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2256d00947d8SCraig Rodrigues } 225700fff2c7STim J. Robbins 225800fff2c7STim J. Robbins return (error); 225900fff2c7STim J. Robbins } 226000fff2c7STim J. Robbins 226100fff2c7STim J. Robbins static int 2262d00947d8SCraig Rodrigues unionfs_getextattr(struct vop_getextattr_args *ap) 226300fff2c7STim J. Robbins { 2264d00947d8SCraig Rodrigues struct unionfs_node *unp; 226500fff2c7STim J. Robbins struct vnode *vp; 226600fff2c7STim J. Robbins 22671e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22681e5da15aSDaichi GOTO 2269d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2270d00947d8SCraig Rodrigues vp = NULLVP; 2271d00947d8SCraig Rodrigues 2272d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2273d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2274d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2275d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2276d00947d8SCraig Rodrigues 2277d00947d8SCraig Rodrigues if (vp == NULLVP) 2278d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2279d00947d8SCraig Rodrigues 2280d00947d8SCraig Rodrigues return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2281d00947d8SCraig Rodrigues ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2282d00947d8SCraig Rodrigues } 2283d00947d8SCraig Rodrigues 2284d00947d8SCraig Rodrigues static int 2285d00947d8SCraig Rodrigues unionfs_setextattr(struct vop_setextattr_args *ap) 2286d00947d8SCraig Rodrigues { 2287d00947d8SCraig Rodrigues int error; 2288d00947d8SCraig Rodrigues struct unionfs_node *unp; 2289d00947d8SCraig Rodrigues struct vnode *uvp; 2290d00947d8SCraig Rodrigues struct vnode *lvp; 2291d00947d8SCraig Rodrigues struct vnode *ovp; 2292d00947d8SCraig Rodrigues struct ucred *cred; 2293d00947d8SCraig Rodrigues struct thread *td; 2294d00947d8SCraig Rodrigues 22951e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22961e5da15aSDaichi GOTO 2297d00947d8SCraig Rodrigues error = EROFS; 2298d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2299d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2300d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2301d00947d8SCraig Rodrigues ovp = NULLVP; 2302d00947d8SCraig Rodrigues cred = ap->a_cred; 2303d00947d8SCraig Rodrigues td = ap->a_td; 2304d00947d8SCraig Rodrigues 2305d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag); 2306d00947d8SCraig Rodrigues 2307d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2308d00947d8SCraig Rodrigues return (EROFS); 2309d00947d8SCraig Rodrigues 2310d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2311d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2312d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2313d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2314d00947d8SCraig Rodrigues 2315d00947d8SCraig Rodrigues if (ovp == NULLVP) 2316d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2317d00947d8SCraig Rodrigues 2318d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2319d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2320d00947d8SCraig Rodrigues if (uvp == NULLVP && 2321d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2322d00947d8SCraig Rodrigues unionfs_setextattr_reopen: 2323d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2324d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2325d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2326d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2327d00947d8SCraig Rodrigues #endif 2328d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2329d00947d8SCraig Rodrigues } 2330d00947d8SCraig Rodrigues goto unionfs_setextattr_abort; 2331d00947d8SCraig Rodrigues } 2332d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2333d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2334d00947d8SCraig Rodrigues goto unionfs_setextattr_reopen; 2335d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2336d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2337d00947d8SCraig Rodrigues ovp = uvp; 2338d00947d8SCraig Rodrigues } 2339d00947d8SCraig Rodrigues 2340d00947d8SCraig Rodrigues if (ovp == uvp) 2341d00947d8SCraig Rodrigues error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2342d00947d8SCraig Rodrigues ap->a_uio, cred, td); 2343d00947d8SCraig Rodrigues 2344d00947d8SCraig Rodrigues unionfs_setextattr_abort: 2345d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 234600fff2c7STim J. Robbins 234700fff2c7STim J. Robbins return (error); 234800fff2c7STim J. Robbins } 234900fff2c7STim J. Robbins 235000fff2c7STim J. Robbins static int 2351d00947d8SCraig Rodrigues unionfs_listextattr(struct vop_listextattr_args *ap) 235200fff2c7STim J. Robbins { 2353d00947d8SCraig Rodrigues struct unionfs_node *unp; 235400fff2c7STim J. Robbins struct vnode *vp; 235500fff2c7STim J. Robbins 23561e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23571e5da15aSDaichi GOTO 2358d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2359d00947d8SCraig Rodrigues vp = NULLVP; 2360d00947d8SCraig Rodrigues 2361d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2362d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2363d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2364d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2365d00947d8SCraig Rodrigues 2366d00947d8SCraig Rodrigues if (vp == NULLVP) 2367d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2368d00947d8SCraig Rodrigues 2369d00947d8SCraig Rodrigues return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2370d00947d8SCraig Rodrigues ap->a_size, ap->a_cred, ap->a_td)); 2371d00947d8SCraig Rodrigues } 2372d00947d8SCraig Rodrigues 2373d00947d8SCraig Rodrigues static int 2374d00947d8SCraig Rodrigues unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2375d00947d8SCraig Rodrigues { 2376d00947d8SCraig Rodrigues int error; 2377d00947d8SCraig Rodrigues struct unionfs_node *unp; 2378d00947d8SCraig Rodrigues struct vnode *uvp; 2379d00947d8SCraig Rodrigues struct vnode *lvp; 2380d00947d8SCraig Rodrigues struct vnode *ovp; 2381d00947d8SCraig Rodrigues struct ucred *cred; 2382d00947d8SCraig Rodrigues struct thread *td; 2383d00947d8SCraig Rodrigues 23841e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23851e5da15aSDaichi GOTO 2386d00947d8SCraig Rodrigues error = EROFS; 2387d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2388d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2389d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2390d00947d8SCraig Rodrigues ovp = NULLVP; 2391d00947d8SCraig Rodrigues cred = ap->a_cred; 2392d00947d8SCraig Rodrigues td = ap->a_td; 2393d00947d8SCraig Rodrigues 2394d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag); 2395d00947d8SCraig Rodrigues 2396d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2397d00947d8SCraig Rodrigues return (EROFS); 2398d00947d8SCraig Rodrigues 2399d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2400d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2401d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2402d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2403d00947d8SCraig Rodrigues 2404d00947d8SCraig Rodrigues if (ovp == NULLVP) 2405d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2406d00947d8SCraig Rodrigues 2407d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2408d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2409d00947d8SCraig Rodrigues if (uvp == NULLVP && 2410d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2411d00947d8SCraig Rodrigues unionfs_deleteextattr_reopen: 2412d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2413d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2414d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2415d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2416d00947d8SCraig Rodrigues #endif 2417d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2418d00947d8SCraig Rodrigues } 2419d00947d8SCraig Rodrigues goto unionfs_deleteextattr_abort; 2420d00947d8SCraig Rodrigues } 2421d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2422d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2423d00947d8SCraig Rodrigues goto unionfs_deleteextattr_reopen; 2424d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2425d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2426d00947d8SCraig Rodrigues ovp = uvp; 2427d00947d8SCraig Rodrigues } 2428d00947d8SCraig Rodrigues 2429d00947d8SCraig Rodrigues if (ovp == uvp) 2430d00947d8SCraig Rodrigues error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2431d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 2432d00947d8SCraig Rodrigues 2433d00947d8SCraig Rodrigues unionfs_deleteextattr_abort: 2434d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 243500fff2c7STim J. Robbins 243600fff2c7STim J. Robbins return (error); 243700fff2c7STim J. Robbins } 243800fff2c7STim J. Robbins 243900fff2c7STim J. Robbins static int 2440d00947d8SCraig Rodrigues unionfs_setlabel(struct vop_setlabel_args *ap) 244100fff2c7STim J. Robbins { 244200fff2c7STim J. Robbins int error; 2443d00947d8SCraig Rodrigues struct unionfs_node *unp; 2444d00947d8SCraig Rodrigues struct vnode *uvp; 2445d00947d8SCraig Rodrigues struct vnode *lvp; 2446d00947d8SCraig Rodrigues struct thread *td; 244700fff2c7STim J. Robbins 2448d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2449d00947d8SCraig Rodrigues 24501e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 24511e5da15aSDaichi GOTO 2452d00947d8SCraig Rodrigues error = EROFS; 2453d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2454d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2455d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2456d00947d8SCraig Rodrigues td = ap->a_td; 2457d00947d8SCraig Rodrigues 2458d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2459d00947d8SCraig Rodrigues return (EROFS); 2460d00947d8SCraig Rodrigues 2461d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2462d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2463d00947d8SCraig Rodrigues return (error); 2464d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2465d00947d8SCraig Rodrigues } 2466d00947d8SCraig Rodrigues 2467d00947d8SCraig Rodrigues if (uvp != NULLVP) 2468d00947d8SCraig Rodrigues error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2469d00947d8SCraig Rodrigues 2470d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 247100fff2c7STim J. Robbins 247200fff2c7STim J. Robbins return (error); 247300fff2c7STim J. Robbins } 247400fff2c7STim J. Robbins 247510bcafe9SPawel Jakub Dawidek static int 247610bcafe9SPawel Jakub Dawidek unionfs_vptofh(struct vop_vptofh_args *ap) 247710bcafe9SPawel Jakub Dawidek { 247810bcafe9SPawel Jakub Dawidek return (EOPNOTSUPP); 247910bcafe9SPawel Jakub Dawidek } 248010bcafe9SPawel Jakub Dawidek 248130d49d53SKonstantin Belousov static int 248230d49d53SKonstantin Belousov unionfs_add_writecount(struct vop_add_writecount_args *ap) 248330d49d53SKonstantin Belousov { 248430d49d53SKonstantin Belousov struct vnode *tvp, *vp; 248530d49d53SKonstantin Belousov struct unionfs_node *unp; 248630d49d53SKonstantin Belousov int error; 248730d49d53SKonstantin Belousov 248830d49d53SKonstantin Belousov vp = ap->a_vp; 248930d49d53SKonstantin Belousov unp = VTOUNIONFS(vp); 249030d49d53SKonstantin Belousov tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp; 249130d49d53SKonstantin Belousov VI_LOCK(vp); 249230d49d53SKonstantin Belousov /* text refs are bypassed to lowervp */ 249330d49d53SKonstantin Belousov VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount")); 249430d49d53SKonstantin Belousov VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp, 249530d49d53SKonstantin Belousov ("wrong writecount inc %d", ap->a_inc)); 249630d49d53SKonstantin Belousov if (tvp != NULL) 249730d49d53SKonstantin Belousov error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc); 249830d49d53SKonstantin Belousov else if (vp->v_writecount < 0) 249930d49d53SKonstantin Belousov error = ETXTBSY; 250030d49d53SKonstantin Belousov else 250130d49d53SKonstantin Belousov error = 0; 250230d49d53SKonstantin Belousov if (error == 0) 250330d49d53SKonstantin Belousov vp->v_writecount += ap->a_inc; 250430d49d53SKonstantin Belousov VI_UNLOCK(vp); 250530d49d53SKonstantin Belousov return (error); 250630d49d53SKonstantin Belousov } 250730d49d53SKonstantin Belousov 2508d00947d8SCraig Rodrigues struct vop_vector unionfs_vnodeops = { 2509aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 251083c64397SPoul-Henning Kamp 2511d00947d8SCraig Rodrigues .vop_access = unionfs_access, 2512d00947d8SCraig Rodrigues .vop_aclcheck = unionfs_aclcheck, 2513d00947d8SCraig Rodrigues .vop_advlock = unionfs_advlock, 2514aec0fb7bSPoul-Henning Kamp .vop_bmap = VOP_EOPNOTSUPP, 2515dc2dd185SDaichi GOTO .vop_cachedlookup = unionfs_lookup, 2516d00947d8SCraig Rodrigues .vop_close = unionfs_close, 2517d00947d8SCraig Rodrigues .vop_closeextattr = unionfs_closeextattr, 2518d00947d8SCraig Rodrigues .vop_create = unionfs_create, 2519d00947d8SCraig Rodrigues .vop_deleteextattr = unionfs_deleteextattr, 2520d00947d8SCraig Rodrigues .vop_fsync = unionfs_fsync, 2521d00947d8SCraig Rodrigues .vop_getacl = unionfs_getacl, 2522d00947d8SCraig Rodrigues .vop_getattr = unionfs_getattr, 2523d00947d8SCraig Rodrigues .vop_getextattr = unionfs_getextattr, 2524d00947d8SCraig Rodrigues .vop_getwritemount = unionfs_getwritemount, 2525d00947d8SCraig Rodrigues .vop_inactive = unionfs_inactive, 25261e2f0cebSMateusz Guzik .vop_need_inactive = vop_stdneed_inactive, 2527cb5736b7SDaichi GOTO .vop_islocked = unionfs_islocked, 2528d00947d8SCraig Rodrigues .vop_ioctl = unionfs_ioctl, 2529d00947d8SCraig Rodrigues .vop_link = unionfs_link, 2530d00947d8SCraig Rodrigues .vop_listextattr = unionfs_listextattr, 2531d413d210SKonstantin Belousov .vop_lock1 = unionfs_lock, 2532dc2dd185SDaichi GOTO .vop_lookup = vfs_cache_lookup, 2533d00947d8SCraig Rodrigues .vop_mkdir = unionfs_mkdir, 2534d00947d8SCraig Rodrigues .vop_mknod = unionfs_mknod, 2535d00947d8SCraig Rodrigues .vop_open = unionfs_open, 2536d00947d8SCraig Rodrigues .vop_openextattr = unionfs_openextattr, 2537d00947d8SCraig Rodrigues .vop_pathconf = unionfs_pathconf, 2538d00947d8SCraig Rodrigues .vop_poll = unionfs_poll, 2539d00947d8SCraig Rodrigues .vop_print = unionfs_print, 2540d00947d8SCraig Rodrigues .vop_read = unionfs_read, 2541d00947d8SCraig Rodrigues .vop_readdir = unionfs_readdir, 2542d00947d8SCraig Rodrigues .vop_readlink = unionfs_readlink, 2543d00947d8SCraig Rodrigues .vop_reclaim = unionfs_reclaim, 2544d00947d8SCraig Rodrigues .vop_remove = unionfs_remove, 2545d00947d8SCraig Rodrigues .vop_rename = unionfs_rename, 2546d00947d8SCraig Rodrigues .vop_rmdir = unionfs_rmdir, 2547d00947d8SCraig Rodrigues .vop_setacl = unionfs_setacl, 2548d00947d8SCraig Rodrigues .vop_setattr = unionfs_setattr, 2549d00947d8SCraig Rodrigues .vop_setextattr = unionfs_setextattr, 2550d00947d8SCraig Rodrigues .vop_setlabel = unionfs_setlabel, 2551d00947d8SCraig Rodrigues .vop_strategy = unionfs_strategy, 2552d00947d8SCraig Rodrigues .vop_symlink = unionfs_symlink, 2553d00947d8SCraig Rodrigues .vop_unlock = unionfs_unlock, 2554d00947d8SCraig Rodrigues .vop_whiteout = unionfs_whiteout, 2555d00947d8SCraig Rodrigues .vop_write = unionfs_write, 255610bcafe9SPawel Jakub Dawidek .vop_vptofh = unionfs_vptofh, 255730d49d53SKonstantin Belousov .vop_add_writecount = unionfs_add_writecount, 2558df8bae1dSRodney W. Grimes }; 2559*6fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops); 2560