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 struct unionfs_node *dunp; 84d00947d8SCraig Rodrigues struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp; 85d00947d8SCraig Rodrigues struct vattr va; 86d00947d8SCraig Rodrigues struct componentname *cnp; 87d00947d8SCraig Rodrigues struct thread *td; 88312d49efSJason A. Harmening u_long nameiop; 89312d49efSJason A. Harmening u_long cnflags, cnflagsbk; 90312d49efSJason A. Harmening int iswhiteout; 91312d49efSJason A. Harmening int lockflag; 92312d49efSJason A. Harmening int error , uerror, lerror; 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 108312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG( 109312d49efSJason A. Harmening "unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", 110312d49efSJason A. Harmening nameiop, cnflags, cnp->cn_nameptr); 111d00947d8SCraig Rodrigues 112d00947d8SCraig Rodrigues if (dvp->v_type != VDIR) 113d00947d8SCraig Rodrigues return (ENOTDIR); 114df8bae1dSRodney W. Grimes 115df8bae1dSRodney W. Grimes /* 116d00947d8SCraig Rodrigues * If read-only and op is not LOOKUP, will return EROFS. 117df8bae1dSRodney W. Grimes */ 118d00947d8SCraig Rodrigues if ((cnflags & ISLASTCN) && 119d00947d8SCraig Rodrigues (dvp->v_mount->mnt_flag & MNT_RDONLY) && 120d00947d8SCraig Rodrigues LOOKUP != nameiop) 121d00947d8SCraig Rodrigues return (EROFS); 122d00947d8SCraig Rodrigues 123df8bae1dSRodney W. Grimes /* 124d00947d8SCraig Rodrigues * lookup dotdot 125df8bae1dSRodney W. Grimes */ 126d00947d8SCraig Rodrigues if (cnflags & ISDOTDOT) { 127d00947d8SCraig Rodrigues if (LOOKUP != nameiop && udvp == NULLVP) 128d00947d8SCraig Rodrigues return (EROFS); 129d00947d8SCraig Rodrigues 130d00947d8SCraig Rodrigues if (udvp != NULLVP) { 131d00947d8SCraig Rodrigues dtmpvp = udvp; 132d00947d8SCraig Rodrigues if (ldvp != NULLVP) 133b249ce48SMateusz Guzik VOP_UNLOCK(ldvp); 134d00947d8SCraig Rodrigues } 135d00947d8SCraig Rodrigues else 136d00947d8SCraig Rodrigues dtmpvp = ldvp; 137d00947d8SCraig Rodrigues 138d00947d8SCraig Rodrigues error = VOP_LOOKUP(dtmpvp, &vp, cnp); 139d00947d8SCraig Rodrigues 140d00947d8SCraig Rodrigues if (dtmpvp == udvp && ldvp != NULLVP) { 141b249ce48SMateusz Guzik VOP_UNLOCK(udvp); 142cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes 1452a31267eSMatthew Dillon if (error == 0) { 146d00947d8SCraig Rodrigues /* 147d00947d8SCraig Rodrigues * Exchange lock and reference from vp to 148d00947d8SCraig Rodrigues * dunp->un_dvp. vp is upper/lower vnode, but it 149d00947d8SCraig Rodrigues * will need to return the unionfs vnode. 150d00947d8SCraig Rodrigues */ 151d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 152d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 153b249ce48SMateusz Guzik VOP_UNLOCK(vp); 154d00947d8SCraig Rodrigues vrele(vp); 155d00947d8SCraig Rodrigues 156b249ce48SMateusz Guzik VOP_UNLOCK(dvp); 157d00947d8SCraig Rodrigues *(ap->a_vpp) = dunp->un_dvp; 158d00947d8SCraig Rodrigues vref(dunp->un_dvp); 159d00947d8SCraig Rodrigues 160d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME) 161cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY); 162d00947d8SCraig Rodrigues else if (cnp->cn_lkflags & LK_TYPE_MASK) 163cb05b60aSAttilio Rao vn_lock(dunp->un_dvp, cnp->cn_lkflags | 164cb05b60aSAttilio Rao LK_RETRY); 165d00947d8SCraig Rodrigues 166cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1676c21f6edSKonstantin Belousov } else if (error == ENOENT && (cnflags & MAKEENTRY) != 0) 168dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 169d00947d8SCraig Rodrigues 170*152c35eeSJason A. Harmening goto unionfs_lookup_return; 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 185*152c35eeSJason A. Harmening error = uerror; 186*152c35eeSJason A. Harmening goto unionfs_lookup_return; 187d00947d8SCraig Rodrigues } 188d00947d8SCraig Rodrigues if (nameiop == DELETE || nameiop == RENAME || 189d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK)) 190b249ce48SMateusz Guzik VOP_UNLOCK(uvp); 191d00947d8SCraig Rodrigues } 192d00947d8SCraig Rodrigues 193d00947d8SCraig Rodrigues /* check whiteout */ 194d00947d8SCraig Rodrigues if (uerror == ENOENT || uerror == EJUSTRETURN) 195d00947d8SCraig Rodrigues if (cnp->cn_flags & ISWHITEOUT) 196d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 197d00947d8SCraig Rodrigues if (iswhiteout == 0 && ldvp != NULLVP) 1980359a12eSAttilio Rao if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) && 199d00947d8SCraig Rodrigues (va.va_flags & OPAQUE)) 200d00947d8SCraig Rodrigues iswhiteout = 1; /* don't lookup lower */ 201d00947d8SCraig Rodrigues #if 0 202312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG( 203312d49efSJason A. Harmening "unionfs_lookup: debug: whiteout=%d, path=%s\n", 204312d49efSJason A. Harmening iswhiteout, cnp->cn_nameptr); 205d00947d8SCraig Rodrigues #endif 206d00947d8SCraig Rodrigues } 207d00947d8SCraig Rodrigues 208d00947d8SCraig Rodrigues /* 209d00947d8SCraig Rodrigues * lookup lower layer 210d00947d8SCraig Rodrigues */ 211d00947d8SCraig Rodrigues if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) { 212d00947d8SCraig Rodrigues /* always op is LOOKUP */ 213d00947d8SCraig Rodrigues cnp->cn_nameiop = LOOKUP; 214d00947d8SCraig Rodrigues cnflagsbk = cnp->cn_flags; 215d00947d8SCraig Rodrigues cnp->cn_flags = cnflags; 216d00947d8SCraig Rodrigues 217d00947d8SCraig Rodrigues lerror = VOP_LOOKUP(ldvp, &lvp, cnp); 218d00947d8SCraig Rodrigues 219d00947d8SCraig Rodrigues cnp->cn_nameiop = nameiop; 220d00947d8SCraig Rodrigues if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) 221d00947d8SCraig Rodrigues cnp->cn_flags = cnflagsbk; 222d00947d8SCraig Rodrigues 223d00947d8SCraig Rodrigues if (lerror == 0) { 224d00947d8SCraig Rodrigues if (ldvp == lvp) { /* is dot */ 225d00947d8SCraig Rodrigues if (uvp != NULLVP) 226d00947d8SCraig Rodrigues vrele(uvp); /* no need? */ 227d00947d8SCraig Rodrigues vrele(lvp); 228d00947d8SCraig Rodrigues *(ap->a_vpp) = dvp; 229d00947d8SCraig Rodrigues vref(dvp); 230d00947d8SCraig Rodrigues 231312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG( 232312d49efSJason A. Harmening "unionfs_lookup: leave (%d)\n", lerror); 233d00947d8SCraig Rodrigues 234d00947d8SCraig Rodrigues return (lerror); 235d00947d8SCraig Rodrigues } 236d00947d8SCraig Rodrigues if (cnp->cn_lkflags & LK_TYPE_MASK) 237b249ce48SMateusz Guzik VOP_UNLOCK(lvp); 238d00947d8SCraig Rodrigues } 239d00947d8SCraig Rodrigues } 240d00947d8SCraig Rodrigues 241d00947d8SCraig Rodrigues /* 242d00947d8SCraig Rodrigues * check lookup result 243d00947d8SCraig Rodrigues */ 244d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp == NULLVP) { 245*152c35eeSJason A. Harmening error = (udvp != NULLVP ? uerror : lerror); 246*152c35eeSJason A. Harmening goto unionfs_lookup_return; 247d00947d8SCraig Rodrigues } 248d00947d8SCraig Rodrigues 249d00947d8SCraig Rodrigues /* 250d00947d8SCraig Rodrigues * check vnode type 251d00947d8SCraig Rodrigues */ 252d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) { 253d00947d8SCraig Rodrigues vrele(lvp); 254d00947d8SCraig Rodrigues lvp = NULLVP; 255d00947d8SCraig Rodrigues } 256d00947d8SCraig Rodrigues 257d00947d8SCraig Rodrigues /* 258d00947d8SCraig Rodrigues * check shadow dir 259d00947d8SCraig Rodrigues */ 260d00947d8SCraig Rodrigues if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP && 261d00947d8SCraig Rodrigues lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR && 262d00947d8SCraig Rodrigues !(dvp->v_mount->mnt_flag & MNT_RDONLY) && 263d00947d8SCraig Rodrigues (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) { 264d00947d8SCraig Rodrigues /* get unionfs vnode in order to create a new shadow dir. */ 265d00947d8SCraig Rodrigues error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp, 266d00947d8SCraig Rodrigues cnp, td); 267d00947d8SCraig Rodrigues if (error != 0) 268*152c35eeSJason A. Harmening goto unionfs_lookup_cleanup; 269d00947d8SCraig Rodrigues 270d00947d8SCraig Rodrigues if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK)) 271b249ce48SMateusz Guzik VOP_UNLOCK(vp); 27281c794f9SAttilio Rao if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) { 273cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 274d00947d8SCraig Rodrigues lockflag = 1; 275d00947d8SCraig Rodrigues } 276d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), 277d00947d8SCraig Rodrigues udvp, VTOUNIONFS(vp), cnp, td); 278d00947d8SCraig Rodrigues if (lockflag != 0) 279b249ce48SMateusz Guzik VOP_UNLOCK(vp); 280d00947d8SCraig Rodrigues if (error != 0) { 281312d49efSJason A. Harmening UNIONFSDEBUG( 282312d49efSJason A. Harmening "unionfs_lookup: Unable to create shadow dir."); 283d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) 284d00947d8SCraig Rodrigues vput(vp); 285d00947d8SCraig Rodrigues else 286d00947d8SCraig Rodrigues vrele(vp); 287*152c35eeSJason A. Harmening goto unionfs_lookup_cleanup; 288d00947d8SCraig Rodrigues } 289d00947d8SCraig Rodrigues if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED) 290cb05b60aSAttilio Rao vn_lock(vp, LK_SHARED | LK_RETRY); 291d00947d8SCraig Rodrigues } 292d00947d8SCraig Rodrigues /* 293d00947d8SCraig Rodrigues * get unionfs vnode. 294d00947d8SCraig Rodrigues */ 295d00947d8SCraig Rodrigues else { 296d00947d8SCraig Rodrigues if (uvp != NULLVP) 297d00947d8SCraig Rodrigues error = uerror; 298d00947d8SCraig Rodrigues else 299d00947d8SCraig Rodrigues error = lerror; 300d00947d8SCraig Rodrigues if (error != 0) 301*152c35eeSJason A. Harmening goto unionfs_lookup_cleanup; 3021e5da15aSDaichi GOTO /* 3031e5da15aSDaichi GOTO * get socket vnode. 3041e5da15aSDaichi GOTO */ 3051e5da15aSDaichi GOTO if (uvp != NULLVP && uvp->v_type == VSOCK) { 3061e5da15aSDaichi GOTO vp = uvp; 3071e5da15aSDaichi GOTO vref(vp); 3081e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3091e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3101e5da15aSDaichi GOTO } 3111e5da15aSDaichi GOTO else if (lvp != NULLVP && lvp->v_type == VSOCK) { 3121e5da15aSDaichi GOTO vp = lvp; 3131e5da15aSDaichi GOTO vref(vp); 3141e5da15aSDaichi GOTO if (cnp->cn_lkflags & LK_TYPE_MASK) 3151e5da15aSDaichi GOTO vn_lock(vp, cnp->cn_lkflags | LK_RETRY); 3161e5da15aSDaichi GOTO } 3171e5da15aSDaichi GOTO /* 3181e5da15aSDaichi GOTO * get unionfs vnode. 3191e5da15aSDaichi GOTO */ 3201e5da15aSDaichi GOTO else 3211e5da15aSDaichi GOTO error = unionfs_nodeget(dvp->v_mount, uvp, lvp, 3221e5da15aSDaichi GOTO dvp, &vp, cnp, td); 323d00947d8SCraig Rodrigues if (error != 0) { 324312d49efSJason A. Harmening UNIONFSDEBUG( 325312d49efSJason A. Harmening "unionfs_lookup: Unable to create unionfs vnode."); 326*152c35eeSJason A. Harmening goto unionfs_lookup_cleanup; 327d00947d8SCraig Rodrigues } 328d00947d8SCraig Rodrigues if ((nameiop == DELETE || nameiop == RENAME) && 329d00947d8SCraig Rodrigues (cnp->cn_lkflags & LK_TYPE_MASK) == 0) 330cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 331d00947d8SCraig Rodrigues } 332d00947d8SCraig Rodrigues 333d00947d8SCraig Rodrigues *(ap->a_vpp) = vp; 334d00947d8SCraig Rodrigues 3351e5da15aSDaichi GOTO if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK) 336dc2dd185SDaichi GOTO cache_enter(dvp, vp, cnp); 337dc2dd185SDaichi GOTO 338*152c35eeSJason A. Harmening unionfs_lookup_cleanup: 339d00947d8SCraig Rodrigues if (uvp != NULLVP) 340d00947d8SCraig Rodrigues vrele(uvp); 341d00947d8SCraig Rodrigues if (lvp != NULLVP) 342d00947d8SCraig Rodrigues vrele(lvp); 343d00947d8SCraig Rodrigues 3446c21f6edSKonstantin Belousov if (error == ENOENT && (cnflags & MAKEENTRY) != 0) 345dc2dd185SDaichi GOTO cache_enter(dvp, NULLVP, cnp); 346dc2dd185SDaichi GOTO 347*152c35eeSJason A. Harmening unionfs_lookup_return: 348*152c35eeSJason A. Harmening 349*152c35eeSJason A. Harmening /* Ensure subsequent vnops will get a valid pathname buffer. */ 350*152c35eeSJason A. Harmening if (nameiop != LOOKUP && (error == 0 || error == EJUSTRETURN)) 351*152c35eeSJason A. Harmening cnp->cn_flags |= SAVENAME; 352*152c35eeSJason A. Harmening 353d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 354d00947d8SCraig Rodrigues 3552a31267eSMatthew Dillon return (error); 356df8bae1dSRodney W. Grimes } 357df8bae1dSRodney W. Grimes 358c9bf0111SKATO Takenori static int 359d00947d8SCraig Rodrigues unionfs_create(struct vop_create_args *ap) 360996c772fSJohn Dyson { 361d00947d8SCraig Rodrigues struct unionfs_node *dunp; 362d00947d8SCraig Rodrigues struct componentname *cnp; 363d00947d8SCraig Rodrigues struct vnode *udvp; 364d00947d8SCraig Rodrigues struct vnode *vp; 3653bb3827fSDavid Schultz int error; 366996c772fSJohn Dyson 367d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n"); 368d00947d8SCraig Rodrigues 3691e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 3701e5da15aSDaichi GOTO 371d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 372d00947d8SCraig Rodrigues cnp = ap->a_cnp; 373d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 374d00947d8SCraig Rodrigues error = EROFS; 375d00947d8SCraig Rodrigues 376d00947d8SCraig Rodrigues if (udvp != NULLVP) { 3771e5da15aSDaichi GOTO error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap); 3781e5da15aSDaichi GOTO if (error != 0) 3791e5da15aSDaichi GOTO goto unionfs_create_abort; 3801e5da15aSDaichi GOTO 3811e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 3821e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 3831e5da15aSDaichi GOTO else { 384b249ce48SMateusz Guzik VOP_UNLOCK(vp); 385d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 38622db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 387d00947d8SCraig Rodrigues vrele(vp); 388d00947d8SCraig Rodrigues } 389d00947d8SCraig Rodrigues } 390d00947d8SCraig Rodrigues 3911e5da15aSDaichi GOTO unionfs_create_abort: 392d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error); 393d00947d8SCraig Rodrigues 394d00947d8SCraig Rodrigues return (error); 395d00947d8SCraig Rodrigues } 396d00947d8SCraig Rodrigues 397d00947d8SCraig Rodrigues static int 398d00947d8SCraig Rodrigues unionfs_whiteout(struct vop_whiteout_args *ap) 399d00947d8SCraig Rodrigues { 400d00947d8SCraig Rodrigues struct unionfs_node *dunp; 401d00947d8SCraig Rodrigues struct componentname *cnp; 402d00947d8SCraig Rodrigues struct vnode *udvp; 403d00947d8SCraig Rodrigues int error; 404d00947d8SCraig Rodrigues 405d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n"); 406d00947d8SCraig Rodrigues 4071e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 4081e5da15aSDaichi GOTO 409d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 410d00947d8SCraig Rodrigues cnp = ap->a_cnp; 411d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 412d00947d8SCraig Rodrigues error = EOPNOTSUPP; 413d00947d8SCraig Rodrigues 414d00947d8SCraig Rodrigues if (udvp != NULLVP) { 415ac092fb3SDavid Schultz switch (ap->a_flags) { 416ac092fb3SDavid Schultz case CREATE: 417ac092fb3SDavid Schultz case DELETE: 4183bb3827fSDavid Schultz case LOOKUP: 419d00947d8SCraig Rodrigues error = VOP_WHITEOUT(udvp, cnp, ap->a_flags); 420ac092fb3SDavid Schultz break; 421ac092fb3SDavid Schultz default: 422d00947d8SCraig Rodrigues error = EINVAL; 423d00947d8SCraig Rodrigues break; 424ac092fb3SDavid Schultz } 425d00947d8SCraig Rodrigues } 426d00947d8SCraig Rodrigues 427d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error); 428d00947d8SCraig Rodrigues 4292a31267eSMatthew Dillon return (error); 4302a31267eSMatthew Dillon } 4312a31267eSMatthew Dillon 432c9bf0111SKATO Takenori static int 433d00947d8SCraig Rodrigues unionfs_mknod(struct vop_mknod_args *ap) 434df8bae1dSRodney W. Grimes { 435d00947d8SCraig Rodrigues struct unionfs_node *dunp; 436d00947d8SCraig Rodrigues struct componentname *cnp; 437d00947d8SCraig Rodrigues struct vnode *udvp; 438df8bae1dSRodney W. Grimes struct vnode *vp; 439d00947d8SCraig Rodrigues int error; 440df8bae1dSRodney W. Grimes 441d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n"); 442d00947d8SCraig Rodrigues 4431e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 4441e5da15aSDaichi GOTO 445d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 446d00947d8SCraig Rodrigues cnp = ap->a_cnp; 447d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 448d00947d8SCraig Rodrigues error = EROFS; 449d00947d8SCraig Rodrigues 450d00947d8SCraig Rodrigues if (udvp != NULLVP) { 4511e5da15aSDaichi GOTO error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap); 4521e5da15aSDaichi GOTO if (error != 0) 4531e5da15aSDaichi GOTO goto unionfs_mknod_abort; 4541e5da15aSDaichi GOTO 4551e5da15aSDaichi GOTO if (vp->v_type == VSOCK) 4561e5da15aSDaichi GOTO *(ap->a_vpp) = vp; 4571e5da15aSDaichi GOTO else { 458b249ce48SMateusz Guzik VOP_UNLOCK(vp); 459d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 46022db15c0SAttilio Rao ap->a_dvp, ap->a_vpp, cnp, curthread); 461d00947d8SCraig Rodrigues vrele(vp); 462d00947d8SCraig Rodrigues } 463d00947d8SCraig Rodrigues } 464d00947d8SCraig Rodrigues 4651e5da15aSDaichi GOTO unionfs_mknod_abort: 466d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error); 467d00947d8SCraig Rodrigues 468d00947d8SCraig Rodrigues return (error); 469d00947d8SCraig Rodrigues } 470d00947d8SCraig Rodrigues 471d00947d8SCraig Rodrigues static int 472d00947d8SCraig Rodrigues unionfs_open(struct vop_open_args *ap) 473d00947d8SCraig Rodrigues { 474d00947d8SCraig Rodrigues struct unionfs_node *unp; 475d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 476d00947d8SCraig Rodrigues struct vnode *uvp; 477d00947d8SCraig Rodrigues struct vnode *lvp; 478d00947d8SCraig Rodrigues struct vnode *targetvp; 479d00947d8SCraig Rodrigues struct ucred *cred; 480d00947d8SCraig Rodrigues struct thread *td; 481312d49efSJason A. Harmening int error; 482d00947d8SCraig Rodrigues 483d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n"); 484d00947d8SCraig Rodrigues 4851e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 4861e5da15aSDaichi GOTO 487d00947d8SCraig Rodrigues error = 0; 488d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 489d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 490d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 491d00947d8SCraig Rodrigues targetvp = NULLVP; 492d00947d8SCraig Rodrigues cred = ap->a_cred; 493d00947d8SCraig Rodrigues td = ap->a_td; 494d00947d8SCraig Rodrigues 495d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 496d00947d8SCraig Rodrigues 497d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) { 498d00947d8SCraig Rodrigues /* vnode is already opend. */ 499d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt > 0) 500d00947d8SCraig Rodrigues targetvp = uvp; 501d00947d8SCraig Rodrigues else 502d00947d8SCraig Rodrigues targetvp = lvp; 503d00947d8SCraig Rodrigues 504d00947d8SCraig Rodrigues if (targetvp == lvp && 505d00947d8SCraig Rodrigues (ap->a_mode & FWRITE) && lvp->v_type == VREG) 506d00947d8SCraig Rodrigues targetvp = NULLVP; 507d00947d8SCraig Rodrigues } 508d00947d8SCraig Rodrigues if (targetvp == NULLVP) { 509d00947d8SCraig Rodrigues if (uvp == NULLVP) { 510d00947d8SCraig Rodrigues if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) { 511d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 512d00947d8SCraig Rodrigues !(ap->a_mode & O_TRUNC), cred, td); 513d00947d8SCraig Rodrigues if (error != 0) 514d00947d8SCraig Rodrigues goto unionfs_open_abort; 515d00947d8SCraig Rodrigues targetvp = uvp = unp->un_uppervp; 516d00947d8SCraig Rodrigues } else 517d00947d8SCraig Rodrigues targetvp = lvp; 518d00947d8SCraig Rodrigues } else 519d00947d8SCraig Rodrigues targetvp = uvp; 520d00947d8SCraig Rodrigues } 521d00947d8SCraig Rodrigues 5229e223287SKonstantin Belousov error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp); 523d00947d8SCraig Rodrigues if (error == 0) { 524d00947d8SCraig Rodrigues if (targetvp == uvp) { 525d00947d8SCraig Rodrigues if (uvp->v_type == VDIR && lvp != NULLVP && 526d00947d8SCraig Rodrigues unsp->uns_lower_opencnt <= 0) { 527d00947d8SCraig Rodrigues /* open lower for readdir */ 5289e223287SKonstantin Belousov error = VOP_OPEN(lvp, FREAD, cred, td, NULL); 529d00947d8SCraig Rodrigues if (error != 0) { 530d00947d8SCraig Rodrigues VOP_CLOSE(uvp, ap->a_mode, cred, td); 531d00947d8SCraig Rodrigues goto unionfs_open_abort; 532d00947d8SCraig Rodrigues } 533d00947d8SCraig Rodrigues unsp->uns_node_flag |= UNS_OPENL_4_READDIR; 534d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 535d00947d8SCraig Rodrigues } 536d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 537d00947d8SCraig Rodrigues } else { 538d00947d8SCraig Rodrigues unsp->uns_lower_opencnt++; 539d00947d8SCraig Rodrigues unsp->uns_lower_openmode = ap->a_mode; 540d00947d8SCraig Rodrigues } 541d00947d8SCraig Rodrigues ap->a_vp->v_object = targetvp->v_object; 542d00947d8SCraig Rodrigues } 543d00947d8SCraig Rodrigues 544d00947d8SCraig Rodrigues unionfs_open_abort: 545d00947d8SCraig Rodrigues if (error != 0) 546fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 547d00947d8SCraig Rodrigues 548d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error); 549d00947d8SCraig Rodrigues 550d00947d8SCraig Rodrigues return (error); 551d00947d8SCraig Rodrigues } 552d00947d8SCraig Rodrigues 553d00947d8SCraig Rodrigues static int 554d00947d8SCraig Rodrigues unionfs_close(struct vop_close_args *ap) 555d00947d8SCraig Rodrigues { 556d00947d8SCraig Rodrigues struct unionfs_node *unp; 557d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 558d00947d8SCraig Rodrigues struct ucred *cred; 559d00947d8SCraig Rodrigues struct thread *td; 560cb5736b7SDaichi GOTO struct vnode *vp; 561d00947d8SCraig Rodrigues struct vnode *ovp; 562312d49efSJason A. Harmening int error; 563312d49efSJason A. Harmening int locked; 564d00947d8SCraig Rodrigues 565d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 566d00947d8SCraig Rodrigues 5671e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 5681e5da15aSDaichi GOTO 569d00947d8SCraig Rodrigues locked = 0; 570cb5736b7SDaichi GOTO vp = ap->a_vp; 571cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 572d00947d8SCraig Rodrigues cred = ap->a_cred; 573d00947d8SCraig Rodrigues td = ap->a_td; 574d00947d8SCraig Rodrigues 575cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 576cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 577cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 578d00947d8SCraig Rodrigues locked = 1; 579d00947d8SCraig Rodrigues } 580d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 581d00947d8SCraig Rodrigues 582d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 583d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 584d00947d8SCraig Rodrigues printf("unionfs_close: warning: open count is 0\n"); 585df8bae1dSRodney W. Grimes #endif 586d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 587d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 588d00947d8SCraig Rodrigues else 589d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 590d00947d8SCraig Rodrigues } else if (unsp->uns_upper_opencnt > 0) 591d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 592d00947d8SCraig Rodrigues else 593d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 594d00947d8SCraig Rodrigues 595d00947d8SCraig Rodrigues error = VOP_CLOSE(ovp, ap->a_fflag, cred, td); 596d00947d8SCraig Rodrigues 597d00947d8SCraig Rodrigues if (error != 0) 598d00947d8SCraig Rodrigues goto unionfs_close_abort; 599d00947d8SCraig Rodrigues 600cb5736b7SDaichi GOTO vp->v_object = ovp->v_object; 601d00947d8SCraig Rodrigues 602d00947d8SCraig Rodrigues if (ovp == unp->un_uppervp) { 603d00947d8SCraig Rodrigues unsp->uns_upper_opencnt--; 604d00947d8SCraig Rodrigues if (unsp->uns_upper_opencnt == 0) { 605d00947d8SCraig Rodrigues if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 606d00947d8SCraig Rodrigues VOP_CLOSE(unp->un_lowervp, FREAD, cred, td); 607d00947d8SCraig Rodrigues unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 608d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 609df8bae1dSRodney W. Grimes } 610d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) 611cb5736b7SDaichi GOTO vp->v_object = unp->un_lowervp->v_object; 612d00947d8SCraig Rodrigues } 613d00947d8SCraig Rodrigues } else 614d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 615d00947d8SCraig Rodrigues 616d00947d8SCraig Rodrigues unionfs_close_abort: 617fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 618d00947d8SCraig Rodrigues 619d00947d8SCraig Rodrigues if (locked != 0) 620cb5736b7SDaichi GOTO vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 621d00947d8SCraig Rodrigues 622d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 623d00947d8SCraig Rodrigues 624d00947d8SCraig Rodrigues return (error); 625df8bae1dSRodney W. Grimes } 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes /* 628d00947d8SCraig Rodrigues * Check the access mode toward shadow file/dir. 629df8bae1dSRodney W. Grimes */ 630c9bf0111SKATO Takenori static int 631312d49efSJason A. Harmening unionfs_check_corrected_access(accmode_t accmode, struct vattr *va, 632d00947d8SCraig Rodrigues struct ucred *cred) 633df8bae1dSRodney W. Grimes { 634d00947d8SCraig Rodrigues int count; 635d00947d8SCraig Rodrigues uid_t uid; /* upper side vnode's uid */ 636d00947d8SCraig Rodrigues gid_t gid; /* upper side vnode's gid */ 637d00947d8SCraig Rodrigues u_short vmode; /* upper side vnode's mode */ 638d00947d8SCraig Rodrigues u_short mask; 639df8bae1dSRodney W. Grimes 640d00947d8SCraig Rodrigues mask = 0; 641d00947d8SCraig Rodrigues uid = va->va_uid; 642d00947d8SCraig Rodrigues gid = va->va_gid; 643d00947d8SCraig Rodrigues vmode = va->va_mode; 644d00947d8SCraig Rodrigues 645d00947d8SCraig Rodrigues /* check owner */ 646d00947d8SCraig Rodrigues if (cred->cr_uid == uid) { 64715bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 648d00947d8SCraig Rodrigues mask |= S_IXUSR; 64915bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 650d00947d8SCraig Rodrigues mask |= S_IRUSR; 65115bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 652d00947d8SCraig Rodrigues mask |= S_IWUSR; 653d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 654d00947d8SCraig Rodrigues } 655d00947d8SCraig Rodrigues 656d00947d8SCraig Rodrigues /* check group */ 657d00947d8SCraig Rodrigues count = 0; 658838d9858SBrooks Davis if (groupmember(gid, cred)) { 65915bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 660d00947d8SCraig Rodrigues mask |= S_IXGRP; 66115bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 662d00947d8SCraig Rodrigues mask |= S_IRGRP; 66315bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 664d00947d8SCraig Rodrigues mask |= S_IWGRP; 665d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 666d00947d8SCraig Rodrigues } 667d00947d8SCraig Rodrigues 668d00947d8SCraig Rodrigues /* check other */ 66915bc6b2bSEdward Tomasz Napierala if (accmode & VEXEC) 670d00947d8SCraig Rodrigues mask |= S_IXOTH; 67115bc6b2bSEdward Tomasz Napierala if (accmode & VREAD) 672d00947d8SCraig Rodrigues mask |= S_IROTH; 67315bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) 674d00947d8SCraig Rodrigues mask |= S_IWOTH; 675d00947d8SCraig Rodrigues 676d00947d8SCraig Rodrigues return ((vmode & mask) == mask ? 0 : EACCES); 677d00947d8SCraig Rodrigues } 678d00947d8SCraig Rodrigues 679d00947d8SCraig Rodrigues static int 680d00947d8SCraig Rodrigues unionfs_access(struct vop_access_args *ap) 681d00947d8SCraig Rodrigues { 682d00947d8SCraig Rodrigues struct unionfs_mount *ump; 683d00947d8SCraig Rodrigues struct unionfs_node *unp; 684d00947d8SCraig Rodrigues struct vnode *uvp; 685d00947d8SCraig Rodrigues struct vnode *lvp; 686d00947d8SCraig Rodrigues struct thread *td; 687d00947d8SCraig Rodrigues struct vattr va; 68815bc6b2bSEdward Tomasz Napierala accmode_t accmode; 689d00947d8SCraig Rodrigues int error; 690d00947d8SCraig Rodrigues 691d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 692d00947d8SCraig Rodrigues 6931e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 6941e5da15aSDaichi GOTO 695d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 696d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 697d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 698d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 699d00947d8SCraig Rodrigues td = ap->a_td; 70015bc6b2bSEdward Tomasz Napierala accmode = ap->a_accmode; 701d00947d8SCraig Rodrigues error = EACCES; 702d00947d8SCraig Rodrigues 70315bc6b2bSEdward Tomasz Napierala if ((accmode & VWRITE) && 7042a31267eSMatthew Dillon (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 7056ca02614SKATO Takenori switch (ap->a_vp->v_type) { 706831a80b0SMatthew Dillon case VREG: 707831a80b0SMatthew Dillon case VDIR: 708831a80b0SMatthew Dillon case VLNK: 7096ca02614SKATO Takenori return (EROFS); 710831a80b0SMatthew Dillon default: 711831a80b0SMatthew Dillon break; 7126ca02614SKATO Takenori } 7136ca02614SKATO Takenori } 7142a31267eSMatthew Dillon 715d00947d8SCraig Rodrigues if (uvp != NULLVP) { 71615bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(uvp, accmode, ap->a_cred, td); 717d00947d8SCraig Rodrigues 718d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 719d00947d8SCraig Rodrigues 7202a31267eSMatthew Dillon return (error); 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes 723d00947d8SCraig Rodrigues if (lvp != NULLVP) { 72415bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) { 725d00947d8SCraig Rodrigues if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 726d00947d8SCraig Rodrigues switch (ap->a_vp->v_type) { 727d00947d8SCraig Rodrigues case VREG: 728d00947d8SCraig Rodrigues case VDIR: 729d00947d8SCraig Rodrigues case VLNK: 730d00947d8SCraig Rodrigues return (EROFS); 731d00947d8SCraig Rodrigues default: 732d00947d8SCraig Rodrigues break; 733df8bae1dSRodney W. Grimes } 734312d49efSJason A. Harmening } else if (ap->a_vp->v_type == VREG || 735312d49efSJason A. Harmening ap->a_vp->v_type == VDIR) { 736d00947d8SCraig Rodrigues /* check shadow file/dir */ 737d00947d8SCraig Rodrigues if (ump->um_copymode != UNIONFS_TRANSPARENT) { 738d00947d8SCraig Rodrigues error = unionfs_create_uppervattr(ump, 739d00947d8SCraig Rodrigues lvp, &va, ap->a_cred, td); 740d00947d8SCraig Rodrigues if (error != 0) 741d00947d8SCraig Rodrigues return (error); 742d00947d8SCraig Rodrigues 743d00947d8SCraig Rodrigues error = unionfs_check_corrected_access( 74415bc6b2bSEdward Tomasz Napierala accmode, &va, ap->a_cred); 745d00947d8SCraig Rodrigues if (error != 0) 746df8bae1dSRodney W. Grimes return (error); 747df8bae1dSRodney W. Grimes } 748d00947d8SCraig Rodrigues } 7495c0c5a18SEdward Tomasz Napierala accmode &= ~(VWRITE | VAPPEND); 75015bc6b2bSEdward Tomasz Napierala accmode |= VREAD; /* will copy to upper */ 751d00947d8SCraig Rodrigues } 75215bc6b2bSEdward Tomasz Napierala error = VOP_ACCESS(lvp, accmode, ap->a_cred, td); 753d00947d8SCraig Rodrigues } 754df8bae1dSRodney W. Grimes 755d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 756d00947d8SCraig Rodrigues 757d00947d8SCraig Rodrigues return (error); 758d00947d8SCraig Rodrigues } 7592a31267eSMatthew Dillon 760c9bf0111SKATO Takenori static int 761d00947d8SCraig Rodrigues unionfs_getattr(struct vop_getattr_args *ap) 762df8bae1dSRodney W. Grimes { 763d00947d8SCraig Rodrigues struct unionfs_node *unp; 764d00947d8SCraig Rodrigues struct unionfs_mount *ump; 765d00947d8SCraig Rodrigues struct vnode *uvp; 766d00947d8SCraig Rodrigues struct vnode *lvp; 767d00947d8SCraig Rodrigues struct thread *td; 768df8bae1dSRodney W. Grimes struct vattr va; 769312d49efSJason A. Harmening int error; 770df8bae1dSRodney W. Grimes 771d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 772df8bae1dSRodney W. Grimes 7731e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 7741e5da15aSDaichi GOTO 775d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 776d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 777d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 778d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 7790359a12eSAttilio Rao td = curthread; 780df8bae1dSRodney W. Grimes 781d00947d8SCraig Rodrigues if (uvp != NULLVP) { 7820359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 783312d49efSJason A. Harmening ap->a_vap->va_fsid = 784312d49efSJason A. Harmening ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 785d354520eSTakanori Watanabe 786312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG( 787312d49efSJason A. Harmening "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 788d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, 789d00947d8SCraig Rodrigues ap->a_vap->va_gid, error); 790d00947d8SCraig Rodrigues 791d00947d8SCraig Rodrigues return (error); 792d00947d8SCraig Rodrigues } 793d00947d8SCraig Rodrigues 7940359a12eSAttilio Rao error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 795d00947d8SCraig Rodrigues 796d00947d8SCraig Rodrigues if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 797d00947d8SCraig Rodrigues /* correct the attr toward shadow file/dir. */ 798d00947d8SCraig Rodrigues if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 799d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); 800d00947d8SCraig Rodrigues ap->a_vap->va_mode = va.va_mode; 801d00947d8SCraig Rodrigues ap->a_vap->va_uid = va.va_uid; 802d00947d8SCraig Rodrigues ap->a_vap->va_gid = va.va_gid; 803d00947d8SCraig Rodrigues } 804d00947d8SCraig Rodrigues } 805d00947d8SCraig Rodrigues 806d00947d8SCraig Rodrigues if (error == 0) 807d00947d8SCraig Rodrigues ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 808d00947d8SCraig Rodrigues 809312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG( 810312d49efSJason A. Harmening "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 811d00947d8SCraig Rodrigues ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 812d00947d8SCraig Rodrigues 813d00947d8SCraig Rodrigues return (error); 814df8bae1dSRodney W. Grimes } 815df8bae1dSRodney W. Grimes 816c9bf0111SKATO Takenori static int 817d00947d8SCraig Rodrigues unionfs_setattr(struct vop_setattr_args *ap) 818df8bae1dSRodney W. Grimes { 819d00947d8SCraig Rodrigues struct unionfs_node *unp; 820d00947d8SCraig Rodrigues struct vnode *uvp; 821d00947d8SCraig Rodrigues struct vnode *lvp; 822d00947d8SCraig Rodrigues struct thread *td; 823d00947d8SCraig Rodrigues struct vattr *vap; 824312d49efSJason A. Harmening int error; 825df8bae1dSRodney W. Grimes 826d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 827d00947d8SCraig Rodrigues 8281e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8291e5da15aSDaichi GOTO 830d00947d8SCraig Rodrigues error = EROFS; 831d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 832d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 833d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 8340359a12eSAttilio Rao td = curthread; 835d00947d8SCraig Rodrigues vap = ap->a_vap; 836d00947d8SCraig Rodrigues 8376ca02614SKATO Takenori if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 8386ca02614SKATO Takenori (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 8396ca02614SKATO Takenori vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 840d00947d8SCraig Rodrigues vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 8416ca02614SKATO Takenori return (EROFS); 8426ca02614SKATO Takenori 843d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 844d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, (vap->va_size != 0), 845d00947d8SCraig Rodrigues ap->a_cred, td); 846d00947d8SCraig Rodrigues if (error != 0) 847df8bae1dSRodney W. Grimes return (error); 848d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 849df8bae1dSRodney W. Grimes } 850df8bae1dSRodney W. Grimes 851d00947d8SCraig Rodrigues if (uvp != NULLVP) 8520359a12eSAttilio Rao error = VOP_SETATTR(uvp, vap, ap->a_cred); 853d00947d8SCraig Rodrigues 854d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 855d00947d8SCraig Rodrigues 8562a31267eSMatthew Dillon return (error); 857df8bae1dSRodney W. Grimes } 858df8bae1dSRodney W. Grimes 859c9bf0111SKATO Takenori static int 860d00947d8SCraig Rodrigues unionfs_read(struct vop_read_args *ap) 861df8bae1dSRodney W. Grimes { 862d00947d8SCraig Rodrigues struct unionfs_node *unp; 863d00947d8SCraig Rodrigues struct vnode *tvp; 864312d49efSJason A. Harmening int error; 865df8bae1dSRodney W. Grimes 866d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 8672a31267eSMatthew Dillon 8681e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8691e5da15aSDaichi GOTO 870d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 871d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 872996c772fSJohn Dyson 873d00947d8SCraig Rodrigues error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 874996c772fSJohn Dyson 875d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 876d00947d8SCraig Rodrigues 877df8bae1dSRodney W. Grimes return (error); 878df8bae1dSRodney W. Grimes } 879df8bae1dSRodney W. Grimes 880c9bf0111SKATO Takenori static int 881d00947d8SCraig Rodrigues unionfs_write(struct vop_write_args *ap) 882df8bae1dSRodney W. Grimes { 883d00947d8SCraig Rodrigues struct unionfs_node *unp; 884d00947d8SCraig Rodrigues struct vnode *tvp; 885312d49efSJason A. Harmening int error; 886df8bae1dSRodney W. Grimes 887d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 888996c772fSJohn Dyson 8891e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 8901e5da15aSDaichi GOTO 891d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 892d00947d8SCraig Rodrigues tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 893996c772fSJohn Dyson 894d00947d8SCraig Rodrigues error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 895996c772fSJohn Dyson 896d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 897df8bae1dSRodney W. Grimes 898df8bae1dSRodney W. Grimes return (error); 899df8bae1dSRodney W. Grimes } 900df8bae1dSRodney W. Grimes 901c9bf0111SKATO Takenori static int 902d00947d8SCraig Rodrigues unionfs_ioctl(struct vop_ioctl_args *ap) 903df8bae1dSRodney W. Grimes { 904d00947d8SCraig Rodrigues struct unionfs_node *unp; 905d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 906d00947d8SCraig Rodrigues struct vnode *ovp; 907312d49efSJason A. Harmening int error; 908df8bae1dSRodney W. Grimes 909d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 9102a31267eSMatthew Dillon 9111e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9121e5da15aSDaichi GOTO 913cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 914d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 915d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 916d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 917fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 918b249ce48SMateusz Guzik VOP_UNLOCK(ap->a_vp); 919d00947d8SCraig Rodrigues 920d00947d8SCraig Rodrigues if (ovp == NULLVP) 921d00947d8SCraig Rodrigues return (EBADF); 922d00947d8SCraig Rodrigues 923d00947d8SCraig Rodrigues error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 924d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 925d00947d8SCraig Rodrigues 926885868cdSRobert Watson UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error); 927d00947d8SCraig Rodrigues 928d00947d8SCraig Rodrigues return (error); 929df8bae1dSRodney W. Grimes } 930df8bae1dSRodney W. Grimes 931d00947d8SCraig Rodrigues static int 932d00947d8SCraig Rodrigues unionfs_poll(struct vop_poll_args *ap) 933d00947d8SCraig Rodrigues { 934d00947d8SCraig Rodrigues struct unionfs_node *unp; 935d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 936d00947d8SCraig Rodrigues struct vnode *ovp; 9372a31267eSMatthew Dillon 9381e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9391e5da15aSDaichi GOTO 940cb05b60aSAttilio Rao vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 941d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 942d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 943d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 944fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 945b249ce48SMateusz Guzik VOP_UNLOCK(ap->a_vp); 946d00947d8SCraig Rodrigues 947d00947d8SCraig Rodrigues if (ovp == NULLVP) 948d00947d8SCraig Rodrigues return (EBADF); 949d00947d8SCraig Rodrigues 950d00947d8SCraig Rodrigues return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td)); 951d00947d8SCraig Rodrigues } 952d00947d8SCraig Rodrigues 953d00947d8SCraig Rodrigues static int 954d00947d8SCraig Rodrigues unionfs_fsync(struct vop_fsync_args *ap) 955d00947d8SCraig Rodrigues { 956d00947d8SCraig Rodrigues struct unionfs_node *unp; 957d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 958d00947d8SCraig Rodrigues struct vnode *ovp; 959d00947d8SCraig Rodrigues 9601e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 9611e5da15aSDaichi GOTO 962d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 963d00947d8SCraig Rodrigues unionfs_get_node_status(unp, ap->a_td, &unsp); 964d00947d8SCraig Rodrigues ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 965fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 966d00947d8SCraig Rodrigues 967d00947d8SCraig Rodrigues if (ovp == NULLVP) 968d00947d8SCraig Rodrigues return (EBADF); 969d00947d8SCraig Rodrigues 970d00947d8SCraig Rodrigues return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td)); 971d00947d8SCraig Rodrigues } 972d00947d8SCraig Rodrigues 973d00947d8SCraig Rodrigues static int 974d00947d8SCraig Rodrigues unionfs_remove(struct vop_remove_args *ap) 975d00947d8SCraig Rodrigues { 9761e5da15aSDaichi GOTO char *path; 977d00947d8SCraig Rodrigues struct unionfs_node *dunp; 978d00947d8SCraig Rodrigues struct unionfs_node *unp; 97920885defSDaichi GOTO struct unionfs_mount *ump; 980d00947d8SCraig Rodrigues struct vnode *udvp; 981d00947d8SCraig Rodrigues struct vnode *uvp; 982d00947d8SCraig Rodrigues struct vnode *lvp; 9831e5da15aSDaichi GOTO struct vnode *vp; 984d00947d8SCraig Rodrigues struct componentname *cnp; 9851e5da15aSDaichi GOTO struct componentname cn; 986d00947d8SCraig Rodrigues struct thread *td; 987abe95116SJason A. Harmening int error; 988abe95116SJason A. Harmening int pathlen; 989d00947d8SCraig Rodrigues 990d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 991d00947d8SCraig Rodrigues 9921e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 9931e5da15aSDaichi GOTO 994d00947d8SCraig Rodrigues error = 0; 995d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 996d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 997d00947d8SCraig Rodrigues cnp = ap->a_cnp; 998d00947d8SCraig Rodrigues td = curthread; 999d00947d8SCraig Rodrigues 10001e5da15aSDaichi GOTO if (ap->a_vp->v_op != &unionfs_vnodeops) { 10011e5da15aSDaichi GOTO if (ap->a_vp->v_type != VSOCK) 10021e5da15aSDaichi GOTO return (EINVAL); 10031e5da15aSDaichi GOTO ump = NULL; 10041e5da15aSDaichi GOTO vp = uvp = lvp = NULLVP; 10051e5da15aSDaichi GOTO /* search vnode */ 1006b249ce48SMateusz Guzik VOP_UNLOCK(ap->a_vp); 10071e5da15aSDaichi GOTO error = unionfs_relookup(udvp, &vp, cnp, &cn, td, 1008abe95116SJason A. Harmening cnp->cn_nameptr, cnp->cn_namelen, DELETE); 10091e5da15aSDaichi GOTO if (error != 0 && error != ENOENT) { 10101e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 10111e5da15aSDaichi GOTO return (error); 10121e5da15aSDaichi GOTO } 10131e5da15aSDaichi GOTO 10141e5da15aSDaichi GOTO if (error == 0 && vp == ap->a_vp) { 10151e5da15aSDaichi GOTO /* target vnode in upper */ 10161e5da15aSDaichi GOTO uvp = vp; 10171e5da15aSDaichi GOTO vrele(vp); 10181e5da15aSDaichi GOTO } else { 10191e5da15aSDaichi GOTO /* target vnode in lower */ 10201e5da15aSDaichi GOTO if (vp != NULLVP) { 10211e5da15aSDaichi GOTO if (udvp == vp) 10221e5da15aSDaichi GOTO vrele(vp); 10231e5da15aSDaichi GOTO else 10241e5da15aSDaichi GOTO vput(vp); 10251e5da15aSDaichi GOTO } 10261e5da15aSDaichi GOTO vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 10271e5da15aSDaichi GOTO lvp = ap->a_vp; 10281e5da15aSDaichi GOTO } 1029abe95116SJason A. Harmening path = cnp->cn_nameptr; 1030abe95116SJason A. Harmening pathlen = cnp->cn_namelen; 10311e5da15aSDaichi GOTO } else { 10321e5da15aSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 10331e5da15aSDaichi GOTO unp = VTOUNIONFS(ap->a_vp); 10341e5da15aSDaichi GOTO uvp = unp->un_uppervp; 10351e5da15aSDaichi GOTO lvp = unp->un_lowervp; 10361e5da15aSDaichi GOTO path = unp->un_path; 1037abe95116SJason A. Harmening pathlen = unp->un_pathlen; 10381e5da15aSDaichi GOTO } 10391e5da15aSDaichi GOTO 1040d00947d8SCraig Rodrigues if (udvp == NULLVP) 1041d00947d8SCraig Rodrigues return (EROFS); 1042d00947d8SCraig Rodrigues 1043d00947d8SCraig Rodrigues if (uvp != NULLVP) { 10441e5da15aSDaichi GOTO /* 10451e5da15aSDaichi GOTO * XXX: if the vnode type is VSOCK, it will create whiteout 10461e5da15aSDaichi GOTO * after remove. 10471e5da15aSDaichi GOTO */ 10481e5da15aSDaichi GOTO if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS || 10491e5da15aSDaichi GOTO lvp != NULLVP) 1050d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1051d00947d8SCraig Rodrigues error = VOP_REMOVE(udvp, uvp, cnp); 1052d00947d8SCraig Rodrigues } else if (lvp != NULLVP) 1053abe95116SJason A. Harmening error = unionfs_mkwhiteout(udvp, cnp, td, path, pathlen); 1054d00947d8SCraig Rodrigues 1055d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 1056d00947d8SCraig Rodrigues 1057d00947d8SCraig Rodrigues return (error); 1058d00947d8SCraig Rodrigues } 1059d00947d8SCraig Rodrigues 1060d00947d8SCraig Rodrigues static int 1061d00947d8SCraig Rodrigues unionfs_link(struct vop_link_args *ap) 1062d00947d8SCraig Rodrigues { 1063d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1064d00947d8SCraig Rodrigues struct unionfs_node *unp; 1065d00947d8SCraig Rodrigues struct vnode *udvp; 1066d00947d8SCraig Rodrigues struct vnode *uvp; 1067d00947d8SCraig Rodrigues struct componentname *cnp; 1068d00947d8SCraig Rodrigues struct thread *td; 1069312d49efSJason A. Harmening int error; 1070312d49efSJason A. Harmening int needrelookup; 1071d00947d8SCraig Rodrigues 1072d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 1073d00947d8SCraig Rodrigues 10741e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_tdvp); 10751e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 10761e5da15aSDaichi GOTO 1077d00947d8SCraig Rodrigues error = 0; 1078d00947d8SCraig Rodrigues needrelookup = 0; 1079d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_tdvp); 1080d00947d8SCraig Rodrigues unp = NULL; 1081d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1082d00947d8SCraig Rodrigues uvp = NULLVP; 1083d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1084d00947d8SCraig Rodrigues td = curthread; 1085d00947d8SCraig Rodrigues 1086d00947d8SCraig Rodrigues if (udvp == NULLVP) 1087d00947d8SCraig Rodrigues return (EROFS); 1088d00947d8SCraig Rodrigues 1089d00947d8SCraig Rodrigues if (ap->a_vp->v_op != &unionfs_vnodeops) 1090d00947d8SCraig Rodrigues uvp = ap->a_vp; 1091d00947d8SCraig Rodrigues else { 1092d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1093d00947d8SCraig Rodrigues 1094d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1095d00947d8SCraig Rodrigues if (ap->a_vp->v_type != VREG) 1096d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1097d00947d8SCraig Rodrigues 1098d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, cnp->cn_cred, td); 1099d00947d8SCraig Rodrigues if (error != 0) 1100d00947d8SCraig Rodrigues return (error); 1101d00947d8SCraig Rodrigues needrelookup = 1; 1102d00947d8SCraig Rodrigues } 1103d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1104d00947d8SCraig Rodrigues } 1105d00947d8SCraig Rodrigues 1106d00947d8SCraig Rodrigues if (needrelookup != 0) 1107d00947d8SCraig Rodrigues error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td); 1108d00947d8SCraig Rodrigues 1109d00947d8SCraig Rodrigues if (error == 0) 1110d00947d8SCraig Rodrigues error = VOP_LINK(udvp, uvp, cnp); 1111d00947d8SCraig Rodrigues 1112d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 1113d00947d8SCraig Rodrigues 1114d00947d8SCraig Rodrigues return (error); 1115d00947d8SCraig Rodrigues } 1116d00947d8SCraig Rodrigues 1117d00947d8SCraig Rodrigues static int 1118d00947d8SCraig Rodrigues unionfs_rename(struct vop_rename_args *ap) 1119d00947d8SCraig Rodrigues { 1120d00947d8SCraig Rodrigues struct vnode *fdvp; 1121d00947d8SCraig Rodrigues struct vnode *fvp; 1122d00947d8SCraig Rodrigues struct componentname *fcnp; 1123d00947d8SCraig Rodrigues struct vnode *tdvp; 1124d00947d8SCraig Rodrigues struct vnode *tvp; 1125d00947d8SCraig Rodrigues struct componentname *tcnp; 1126d00947d8SCraig Rodrigues struct vnode *ltdvp; 1127d00947d8SCraig Rodrigues struct vnode *ltvp; 1128d00947d8SCraig Rodrigues struct thread *td; 1129d00947d8SCraig Rodrigues 1130d00947d8SCraig Rodrigues /* rename target vnodes */ 1131d00947d8SCraig Rodrigues struct vnode *rfdvp; 1132d00947d8SCraig Rodrigues struct vnode *rfvp; 1133d00947d8SCraig Rodrigues struct vnode *rtdvp; 1134d00947d8SCraig Rodrigues struct vnode *rtvp; 1135d00947d8SCraig Rodrigues 1136d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1137d00947d8SCraig Rodrigues struct unionfs_node *unp; 1138312d49efSJason A. Harmening int error; 1139312d49efSJason A. Harmening int needrelookup; 1140d00947d8SCraig Rodrigues 1141d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 1142d00947d8SCraig Rodrigues 1143d00947d8SCraig Rodrigues error = 0; 1144d00947d8SCraig Rodrigues fdvp = ap->a_fdvp; 1145d00947d8SCraig Rodrigues fvp = ap->a_fvp; 1146d00947d8SCraig Rodrigues fcnp = ap->a_fcnp; 1147d00947d8SCraig Rodrigues tdvp = ap->a_tdvp; 1148d00947d8SCraig Rodrigues tvp = ap->a_tvp; 1149d00947d8SCraig Rodrigues tcnp = ap->a_tcnp; 1150d00947d8SCraig Rodrigues ltdvp = NULLVP; 1151d00947d8SCraig Rodrigues ltvp = NULLVP; 1152d00947d8SCraig Rodrigues td = curthread; 1153d00947d8SCraig Rodrigues rfdvp = fdvp; 1154d00947d8SCraig Rodrigues rfvp = fvp; 1155d00947d8SCraig Rodrigues rtdvp = tdvp; 1156d00947d8SCraig Rodrigues rtvp = tvp; 1157d00947d8SCraig Rodrigues needrelookup = 0; 1158d00947d8SCraig Rodrigues 1159d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 1160d00947d8SCraig Rodrigues if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1161d00947d8SCraig Rodrigues panic("unionfs_rename: no name"); 11622a31267eSMatthew Dillon #endif 11632a31267eSMatthew Dillon 1164d00947d8SCraig Rodrigues /* check for cross device rename */ 1165d00947d8SCraig Rodrigues if (fvp->v_mount != tdvp->v_mount || 1166d00947d8SCraig Rodrigues (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 11671e5da15aSDaichi GOTO if (fvp->v_op != &unionfs_vnodeops) 11681e5da15aSDaichi GOTO error = ENODEV; 11691e5da15aSDaichi GOTO else 1170d00947d8SCraig Rodrigues error = EXDEV; 1171d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1172d00947d8SCraig Rodrigues } 1173d00947d8SCraig Rodrigues 1174d00947d8SCraig Rodrigues /* Renaming a file to itself has no effect. */ 1175d00947d8SCraig Rodrigues if (fvp == tvp) 1176d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1177d00947d8SCraig Rodrigues 1178d00947d8SCraig Rodrigues /* 1179d00947d8SCraig Rodrigues * from/to vnode is unionfs node. 1180d00947d8SCraig Rodrigues */ 1181d00947d8SCraig Rodrigues 11821e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fdvp); 11831e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(fvp); 11841e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tdvp); 11851e5da15aSDaichi GOTO if (tvp != NULLVP) 11861e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(tvp); 11871e5da15aSDaichi GOTO 1188d00947d8SCraig Rodrigues unp = VTOUNIONFS(fdvp); 1189d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1190312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", 1191312d49efSJason A. Harmening fdvp, unp->un_uppervp, unp->un_lowervp); 1192d00947d8SCraig Rodrigues #endif 1193d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1194d00947d8SCraig Rodrigues error = ENODEV; 1195d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1196d00947d8SCraig Rodrigues } 1197d00947d8SCraig Rodrigues rfdvp = unp->un_uppervp; 1198d00947d8SCraig Rodrigues vref(rfdvp); 1199d00947d8SCraig Rodrigues 1200d00947d8SCraig Rodrigues unp = VTOUNIONFS(fvp); 1201d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1202312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", 1203312d49efSJason A. Harmening fvp, unp->un_uppervp, unp->un_lowervp); 1204d00947d8SCraig Rodrigues #endif 1205d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1206d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 12072a31267eSMatthew Dillon switch (fvp->v_type) { 12082a31267eSMatthew Dillon case VREG: 1209cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1210d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1211d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td); 1212b249ce48SMateusz Guzik VOP_UNLOCK(fvp); 1213d00947d8SCraig Rodrigues if (error != 0) 1214d00947d8SCraig Rodrigues goto unionfs_rename_abort; 12152a31267eSMatthew Dillon break; 12162a31267eSMatthew Dillon case VDIR: 1217cb05b60aSAttilio Rao if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1218d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1219d00947d8SCraig Rodrigues error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td); 1220b249ce48SMateusz Guzik VOP_UNLOCK(fvp); 1221d00947d8SCraig Rodrigues if (error != 0) 1222d00947d8SCraig Rodrigues goto unionfs_rename_abort; 12232a31267eSMatthew Dillon break; 12242a31267eSMatthew Dillon default: 1225d00947d8SCraig Rodrigues error = ENODEV; 1226d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1227d00947d8SCraig Rodrigues } 1228d00947d8SCraig Rodrigues 1229d00947d8SCraig Rodrigues needrelookup = 1; 1230d00947d8SCraig Rodrigues } 1231d00947d8SCraig Rodrigues 1232d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1233d00947d8SCraig Rodrigues fcnp->cn_flags |= DOWHITEOUT; 1234d00947d8SCraig Rodrigues rfvp = unp->un_uppervp; 1235d00947d8SCraig Rodrigues vref(rfvp); 1236d00947d8SCraig Rodrigues 1237d00947d8SCraig Rodrigues unp = VTOUNIONFS(tdvp); 1238d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1239312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", 1240312d49efSJason A. Harmening tdvp, unp->un_uppervp, unp->un_lowervp); 1241d00947d8SCraig Rodrigues #endif 1242d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) { 1243d00947d8SCraig Rodrigues error = ENODEV; 1244d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1245d00947d8SCraig Rodrigues } 1246d00947d8SCraig Rodrigues rtdvp = unp->un_uppervp; 1247d00947d8SCraig Rodrigues ltdvp = unp->un_lowervp; 1248d00947d8SCraig Rodrigues vref(rtdvp); 1249d00947d8SCraig Rodrigues 1250d00947d8SCraig Rodrigues if (tdvp == tvp) { 1251d00947d8SCraig Rodrigues rtvp = rtdvp; 1252d00947d8SCraig Rodrigues vref(rtvp); 1253d00947d8SCraig Rodrigues } else if (tvp != NULLVP) { 1254d00947d8SCraig Rodrigues unp = VTOUNIONFS(tvp); 1255d00947d8SCraig Rodrigues #ifdef UNIONFS_IDBG_RENAME 1256312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", 1257312d49efSJason A. Harmening tvp, unp->un_uppervp, unp->un_lowervp); 1258d00947d8SCraig Rodrigues #endif 1259d00947d8SCraig Rodrigues if (unp->un_uppervp == NULLVP) 1260d00947d8SCraig Rodrigues rtvp = NULLVP; 1261d00947d8SCraig Rodrigues else { 1262d00947d8SCraig Rodrigues if (tvp->v_type == VDIR) { 1263d00947d8SCraig Rodrigues error = EINVAL; 1264d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1265d00947d8SCraig Rodrigues } 1266d00947d8SCraig Rodrigues rtvp = unp->un_uppervp; 1267d00947d8SCraig Rodrigues ltvp = unp->un_lowervp; 1268d00947d8SCraig Rodrigues vref(rtvp); 1269df8bae1dSRodney W. Grimes } 12702a31267eSMatthew Dillon } 1271df8bae1dSRodney W. Grimes 12725307411cSDaichi GOTO if (rfvp == rtvp) 12735307411cSDaichi GOTO goto unionfs_rename_abort; 12745307411cSDaichi GOTO 1275d00947d8SCraig Rodrigues if (needrelookup != 0) { 1276cb05b60aSAttilio Rao if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1277d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1278d00947d8SCraig Rodrigues error = unionfs_relookup_for_delete(fdvp, fcnp, td); 1279b249ce48SMateusz Guzik VOP_UNLOCK(fdvp); 1280d00947d8SCraig Rodrigues if (error != 0) 1281d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1282d00947d8SCraig Rodrigues 1283abe95116SJason A. Harmening /* Lock of tvp is canceled in order to avoid recursive lock. */ 1284d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 1285b249ce48SMateusz Guzik VOP_UNLOCK(tvp); 1286d00947d8SCraig Rodrigues error = unionfs_relookup_for_rename(tdvp, tcnp, td); 1287d00947d8SCraig Rodrigues if (tvp != NULLVP && tvp != tdvp) 1288cb05b60aSAttilio Rao vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1289d00947d8SCraig Rodrigues if (error != 0) 1290d00947d8SCraig Rodrigues goto unionfs_rename_abort; 1291df8bae1dSRodney W. Grimes } 1292df8bae1dSRodney W. Grimes 1293d00947d8SCraig Rodrigues error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 12942a31267eSMatthew Dillon 1295dc2dd185SDaichi GOTO if (error == 0) { 1296dc2dd185SDaichi GOTO if (rtvp != NULLVP && rtvp->v_type == VDIR) 1297dc2dd185SDaichi GOTO cache_purge(tdvp); 1298dc2dd185SDaichi GOTO if (fvp->v_type == VDIR && fdvp != tdvp) 1299dc2dd185SDaichi GOTO cache_purge(fdvp); 1300dc2dd185SDaichi GOTO } 1301dc2dd185SDaichi GOTO 13027e0c8995SDaichi GOTO if (ltdvp != NULLVP) 1303b249ce48SMateusz Guzik VOP_UNLOCK(ltdvp); 1304d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1305d00947d8SCraig Rodrigues vrele(tdvp); 13067e0c8995SDaichi GOTO if (ltvp != NULLVP) 1307b249ce48SMateusz Guzik VOP_UNLOCK(ltvp); 1308d00947d8SCraig Rodrigues if (tvp != rtvp && tvp != NULLVP) { 1309d00947d8SCraig Rodrigues if (rtvp == NULLVP) 1310df8bae1dSRodney W. Grimes vput(tvp); 13112a31267eSMatthew Dillon else 13122a31267eSMatthew Dillon vrele(tvp); 13132a31267eSMatthew Dillon } 13145307411cSDaichi GOTO if (fdvp != rfdvp) 13155307411cSDaichi GOTO vrele(fdvp); 13165307411cSDaichi GOTO if (fvp != rfvp) 13175307411cSDaichi GOTO vrele(fvp); 1318d00947d8SCraig Rodrigues 1319d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1320d00947d8SCraig Rodrigues 1321d00947d8SCraig Rodrigues return (error); 1322d00947d8SCraig Rodrigues 1323d00947d8SCraig Rodrigues unionfs_rename_abort: 13245307411cSDaichi GOTO vput(tdvp); 1325d00947d8SCraig Rodrigues if (tdvp != rtdvp) 1326d00947d8SCraig Rodrigues vrele(rtdvp); 1327d00947d8SCraig Rodrigues if (tvp != NULLVP) { 1328d00947d8SCraig Rodrigues if (tdvp != tvp) 1329d00947d8SCraig Rodrigues vput(tvp); 1330d00947d8SCraig Rodrigues else 1331d00947d8SCraig Rodrigues vrele(tvp); 1332d00947d8SCraig Rodrigues } 13335307411cSDaichi GOTO if (tvp != rtvp && rtvp != NULLVP) 13345307411cSDaichi GOTO vrele(rtvp); 13355307411cSDaichi GOTO if (fdvp != rfdvp) 13365307411cSDaichi GOTO vrele(rfdvp); 13375307411cSDaichi GOTO if (fvp != rfvp) 13385307411cSDaichi GOTO vrele(rfvp); 1339d00947d8SCraig Rodrigues vrele(fdvp); 1340d00947d8SCraig Rodrigues vrele(fvp); 1341d00947d8SCraig Rodrigues 1342d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1343d00947d8SCraig Rodrigues 1344df8bae1dSRodney W. Grimes return (error); 1345df8bae1dSRodney W. Grimes } 1346df8bae1dSRodney W. Grimes 1347c9bf0111SKATO Takenori static int 1348d00947d8SCraig Rodrigues unionfs_mkdir(struct vop_mkdir_args *ap) 1349df8bae1dSRodney W. Grimes { 1350d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1351d00947d8SCraig Rodrigues struct componentname *cnp; 1352d00947d8SCraig Rodrigues struct thread *td; 1353d00947d8SCraig Rodrigues struct vnode *udvp; 1354d00947d8SCraig Rodrigues struct vnode *uvp; 1355d00947d8SCraig Rodrigues struct vattr va; 1356312d49efSJason A. Harmening int error; 1357312d49efSJason A. Harmening int lkflags; 1358df8bae1dSRodney W. Grimes 1359d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1360d00947d8SCraig Rodrigues 13611e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 13621e5da15aSDaichi GOTO 1363d00947d8SCraig Rodrigues error = EROFS; 1364d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1365d00947d8SCraig Rodrigues cnp = ap->a_cnp; 136698155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1367d00947d8SCraig Rodrigues td = curthread; 1368d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1369d00947d8SCraig Rodrigues 1370d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1371d00947d8SCraig Rodrigues /* check opaque */ 1372d00947d8SCraig Rodrigues if (!(cnp->cn_flags & ISWHITEOUT)) { 13730359a12eSAttilio Rao error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1374d00947d8SCraig Rodrigues if (error != 0) 1375d00947d8SCraig Rodrigues return (error); 1376*152c35eeSJason A. Harmening if ((va.va_flags & OPAQUE) != 0) 1377d00947d8SCraig Rodrigues cnp->cn_flags |= ISWHITEOUT; 1378d00947d8SCraig Rodrigues } 1379d00947d8SCraig Rodrigues 1380d00947d8SCraig Rodrigues if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1381b249ce48SMateusz Guzik VOP_UNLOCK(uvp); 138298155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1383d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1384d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 138598155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1386d00947d8SCraig Rodrigues vrele(uvp); 1387d00947d8SCraig Rodrigues } 1388d00947d8SCraig Rodrigues } 1389d00947d8SCraig Rodrigues 1390d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1391d00947d8SCraig Rodrigues 1392d00947d8SCraig Rodrigues return (error); 1393d00947d8SCraig Rodrigues } 1394d00947d8SCraig Rodrigues 1395d00947d8SCraig Rodrigues static int 1396d00947d8SCraig Rodrigues unionfs_rmdir(struct vop_rmdir_args *ap) 1397d00947d8SCraig Rodrigues { 1398d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1399d00947d8SCraig Rodrigues struct unionfs_node *unp; 140020885defSDaichi GOTO struct unionfs_mount *ump; 1401d00947d8SCraig Rodrigues struct componentname *cnp; 1402d00947d8SCraig Rodrigues struct thread *td; 1403d00947d8SCraig Rodrigues struct vnode *udvp; 1404d00947d8SCraig Rodrigues struct vnode *uvp; 1405d00947d8SCraig Rodrigues struct vnode *lvp; 1406312d49efSJason A. Harmening int error; 1407d00947d8SCraig Rodrigues 1408d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1409d00947d8SCraig Rodrigues 14101e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 14111e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 14121e5da15aSDaichi GOTO 1413d00947d8SCraig Rodrigues error = 0; 1414d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1415d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1416d00947d8SCraig Rodrigues cnp = ap->a_cnp; 1417d00947d8SCraig Rodrigues td = curthread; 1418d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1419d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1420d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1421d00947d8SCraig Rodrigues 1422d00947d8SCraig Rodrigues if (udvp == NULLVP) 1423d00947d8SCraig Rodrigues return (EROFS); 1424d00947d8SCraig Rodrigues 1425d00947d8SCraig Rodrigues if (udvp == uvp) 1426d00947d8SCraig Rodrigues return (EOPNOTSUPP); 1427d00947d8SCraig Rodrigues 1428d00947d8SCraig Rodrigues if (uvp != NULLVP) { 1429d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1430d00947d8SCraig Rodrigues error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td); 1431d00947d8SCraig Rodrigues if (error != 0) 1432d00947d8SCraig Rodrigues return (error); 1433d00947d8SCraig Rodrigues } 143420885defSDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 143520885defSDaichi GOTO if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1436d00947d8SCraig Rodrigues cnp->cn_flags |= DOWHITEOUT; 1437cb5736b7SDaichi GOTO error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td); 1438*152c35eeSJason A. Harmening if (error == 0) 1439d00947d8SCraig Rodrigues error = VOP_RMDIR(udvp, uvp, cnp); 1440d00947d8SCraig Rodrigues } 1441d00947d8SCraig Rodrigues else if (lvp != NULLVP) 1442abe95116SJason A. Harmening error = unionfs_mkwhiteout(udvp, cnp, td, 1443abe95116SJason A. Harmening unp->un_path, unp->un_pathlen); 1444d00947d8SCraig Rodrigues 1445dc2dd185SDaichi GOTO if (error == 0) { 1446dc2dd185SDaichi GOTO cache_purge(ap->a_dvp); 1447dc2dd185SDaichi GOTO cache_purge(ap->a_vp); 1448dc2dd185SDaichi GOTO } 1449dc2dd185SDaichi GOTO 1450d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1451d00947d8SCraig Rodrigues 1452d00947d8SCraig Rodrigues return (error); 1453d00947d8SCraig Rodrigues } 1454d00947d8SCraig Rodrigues 1455d00947d8SCraig Rodrigues static int 1456d00947d8SCraig Rodrigues unionfs_symlink(struct vop_symlink_args *ap) 1457d00947d8SCraig Rodrigues { 1458d00947d8SCraig Rodrigues struct unionfs_node *dunp; 1459d00947d8SCraig Rodrigues struct componentname *cnp; 1460d00947d8SCraig Rodrigues struct thread *td; 1461d00947d8SCraig Rodrigues struct vnode *udvp; 1462d00947d8SCraig Rodrigues struct vnode *uvp; 1463312d49efSJason A. Harmening int error; 1464312d49efSJason A. Harmening int lkflags; 1465d00947d8SCraig Rodrigues 1466d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1467d00947d8SCraig Rodrigues 14681e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_dvp); 14691e5da15aSDaichi GOTO 1470d00947d8SCraig Rodrigues error = EROFS; 1471d00947d8SCraig Rodrigues dunp = VTOUNIONFS(ap->a_dvp); 1472d00947d8SCraig Rodrigues cnp = ap->a_cnp; 147398155f1fSCraig Rodrigues lkflags = cnp->cn_lkflags; 1474d00947d8SCraig Rodrigues td = curthread; 1475d00947d8SCraig Rodrigues udvp = dunp->un_uppervp; 1476d00947d8SCraig Rodrigues 1477d00947d8SCraig Rodrigues if (udvp != NULLVP) { 1478d00947d8SCraig Rodrigues error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1479d00947d8SCraig Rodrigues if (error == 0) { 1480b249ce48SMateusz Guzik VOP_UNLOCK(uvp); 148198155f1fSCraig Rodrigues cnp->cn_lkflags = LK_EXCLUSIVE; 1482d00947d8SCraig Rodrigues error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1483d00947d8SCraig Rodrigues ap->a_dvp, ap->a_vpp, cnp, td); 148498155f1fSCraig Rodrigues cnp->cn_lkflags = lkflags; 1485d00947d8SCraig Rodrigues vrele(uvp); 1486d00947d8SCraig Rodrigues } 1487d00947d8SCraig Rodrigues } 1488d00947d8SCraig Rodrigues 1489d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1490d00947d8SCraig Rodrigues 1491d00947d8SCraig Rodrigues return (error); 1492d00947d8SCraig Rodrigues } 1493d00947d8SCraig Rodrigues 1494d00947d8SCraig Rodrigues static int 1495d00947d8SCraig Rodrigues unionfs_readdir(struct vop_readdir_args *ap) 1496d00947d8SCraig Rodrigues { 1497d00947d8SCraig Rodrigues struct unionfs_node *unp; 1498d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 1499d00947d8SCraig Rodrigues struct uio *uio; 1500cb5736b7SDaichi GOTO struct vnode *vp; 1501d00947d8SCraig Rodrigues struct vnode *uvp; 1502d00947d8SCraig Rodrigues struct vnode *lvp; 1503d00947d8SCraig Rodrigues struct thread *td; 1504d00947d8SCraig Rodrigues struct vattr va; 1505d00947d8SCraig Rodrigues 1506d00947d8SCraig Rodrigues u_long *cookies_bk; 1507312d49efSJason A. Harmening int error; 1508312d49efSJason A. Harmening int eofflag; 1509312d49efSJason A. Harmening int locked; 1510312d49efSJason A. Harmening int ncookies_bk; 1511312d49efSJason A. Harmening int uio_offset_bk; 1512d00947d8SCraig Rodrigues 1513d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1514d00947d8SCraig Rodrigues 15151e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 15161e5da15aSDaichi GOTO 1517d00947d8SCraig Rodrigues error = 0; 1518d00947d8SCraig Rodrigues eofflag = 0; 151998155f1fSCraig Rodrigues locked = 0; 1520cb5736b7SDaichi GOTO uio_offset_bk = 0; 1521d00947d8SCraig Rodrigues uio = ap->a_uio; 1522cb5736b7SDaichi GOTO uvp = NULLVP; 1523cb5736b7SDaichi GOTO lvp = NULLVP; 1524d00947d8SCraig Rodrigues td = uio->uio_td; 1525d00947d8SCraig Rodrigues ncookies_bk = 0; 1526d00947d8SCraig Rodrigues cookies_bk = NULL; 1527d00947d8SCraig Rodrigues 1528cb5736b7SDaichi GOTO vp = ap->a_vp; 1529cb5736b7SDaichi GOTO if (vp->v_type != VDIR) 1530d00947d8SCraig Rodrigues return (ENOTDIR); 1531d00947d8SCraig Rodrigues 1532cb5736b7SDaichi GOTO /* check the open count. unionfs needs to open before readdir. */ 1533cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 1534cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 1535cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1536cb5736b7SDaichi GOTO locked = 1; 1537cb5736b7SDaichi GOTO } 1538cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 1539cb5736b7SDaichi GOTO if (unp == NULL) 1540cb5736b7SDaichi GOTO error = EBADF; 1541cb5736b7SDaichi GOTO else { 1542cb5736b7SDaichi GOTO uvp = unp->un_uppervp; 1543cb5736b7SDaichi GOTO lvp = unp->un_lowervp; 1544cb5736b7SDaichi GOTO unionfs_get_node_status(unp, td, &unsp); 1545cb5736b7SDaichi GOTO if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 1546cb5736b7SDaichi GOTO (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1547cb5736b7SDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 1548cb5736b7SDaichi GOTO error = EBADF; 1549cb5736b7SDaichi GOTO } 1550cb5736b7SDaichi GOTO } 1551cb5736b7SDaichi GOTO if (locked) 1552cb5736b7SDaichi GOTO vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 1553cb5736b7SDaichi GOTO if (error != 0) 1554cb5736b7SDaichi GOTO goto unionfs_readdir_exit; 1555cb5736b7SDaichi GOTO 1556d00947d8SCraig Rodrigues /* check opaque */ 1557d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp != NULLVP) { 15580359a12eSAttilio Rao if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 15595adc4080SDaichi GOTO goto unionfs_readdir_exit; 1560d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 1561d00947d8SCraig Rodrigues lvp = NULLVP; 1562d00947d8SCraig Rodrigues } 1563d00947d8SCraig Rodrigues 1564d00947d8SCraig Rodrigues /* upper only */ 1565d00947d8SCraig Rodrigues if (uvp != NULLVP && lvp == NULLVP) { 1566d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1567d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1568d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1569d00947d8SCraig Rodrigues 1570d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1571d00947d8SCraig Rodrigues } 1572d00947d8SCraig Rodrigues 1573d00947d8SCraig Rodrigues /* lower only */ 1574d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp != NULLVP) { 1575d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1576d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1577d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1578d00947d8SCraig Rodrigues 1579d00947d8SCraig Rodrigues goto unionfs_readdir_exit; 1580d00947d8SCraig Rodrigues } 1581d00947d8SCraig Rodrigues 1582d00947d8SCraig Rodrigues /* 1583d00947d8SCraig Rodrigues * readdir upper and lower 1584d00947d8SCraig Rodrigues */ 15856c98d0e9SDaichi GOTO KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp")); 15866c98d0e9SDaichi GOTO KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp")); 1587d00947d8SCraig Rodrigues if (uio->uio_offset == 0) 1588d00947d8SCraig Rodrigues unsp->uns_readdir_status = 0; 1589d00947d8SCraig Rodrigues 1590d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 0) { 1591d00947d8SCraig Rodrigues /* read upper */ 1592d00947d8SCraig Rodrigues error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1593d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1594d00947d8SCraig Rodrigues 15955adc4080SDaichi GOTO if (error != 0 || eofflag == 0) 15965adc4080SDaichi GOTO goto unionfs_readdir_exit; 1597d00947d8SCraig Rodrigues unsp->uns_readdir_status = 1; 1598d00947d8SCraig Rodrigues 1599d00947d8SCraig Rodrigues /* 1600cb5736b7SDaichi GOTO * UFS(and other FS) needs size of uio_resid larger than 1601d00947d8SCraig Rodrigues * DIRBLKSIZ. 1602d00947d8SCraig Rodrigues * size of DIRBLKSIZ equals DEV_BSIZE. 1603d00947d8SCraig Rodrigues * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1604d00947d8SCraig Rodrigues */ 16055adc4080SDaichi GOTO if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 16065adc4080SDaichi GOTO goto unionfs_readdir_exit; 1607d00947d8SCraig Rodrigues 1608d00947d8SCraig Rodrigues /* 1609cb5736b7SDaichi GOTO * Backup cookies. 1610d00947d8SCraig Rodrigues * It prepares to readdir in lower. 1611d00947d8SCraig Rodrigues */ 1612d00947d8SCraig Rodrigues if (ap->a_ncookies != NULL) { 1613d00947d8SCraig Rodrigues ncookies_bk = *(ap->a_ncookies); 1614d00947d8SCraig Rodrigues *(ap->a_ncookies) = 0; 1615d00947d8SCraig Rodrigues } 1616d00947d8SCraig Rodrigues if (ap->a_cookies != NULL) { 1617d00947d8SCraig Rodrigues cookies_bk = *(ap->a_cookies); 1618d00947d8SCraig Rodrigues *(ap->a_cookies) = NULL; 1619d00947d8SCraig Rodrigues } 1620d00947d8SCraig Rodrigues } 1621d00947d8SCraig Rodrigues 1622d00947d8SCraig Rodrigues /* initialize for readdir in lower */ 1623d00947d8SCraig Rodrigues if (unsp->uns_readdir_status == 1) { 1624d00947d8SCraig Rodrigues unsp->uns_readdir_status = 2; 1625cb5736b7SDaichi GOTO /* 1626cb5736b7SDaichi GOTO * Backup uio_offset. See the comment after the 1627cb5736b7SDaichi GOTO * VOP_READDIR call on the lower layer. 1628cb5736b7SDaichi GOTO */ 1629cb5736b7SDaichi GOTO uio_offset_bk = uio->uio_offset; 1630d00947d8SCraig Rodrigues uio->uio_offset = 0; 1631d00947d8SCraig Rodrigues } 1632d00947d8SCraig Rodrigues 1633b16f4eecSCraig Rodrigues if (lvp == NULLVP) { 1634b16f4eecSCraig Rodrigues error = EBADF; 1635b16f4eecSCraig Rodrigues goto unionfs_readdir_exit; 1636b16f4eecSCraig Rodrigues } 1637d00947d8SCraig Rodrigues /* read lower */ 1638d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1639d00947d8SCraig Rodrigues ap->a_ncookies, ap->a_cookies); 1640d00947d8SCraig Rodrigues 1641cb5736b7SDaichi GOTO /* 1642cb5736b7SDaichi GOTO * We can't return an uio_offset of 0: this would trigger an 1643cb5736b7SDaichi GOTO * infinite loop, because the next call to unionfs_readdir would 1644cb5736b7SDaichi GOTO * always restart with the upper layer (uio_offset == 0) and 1645cb5736b7SDaichi GOTO * always return some data. 1646cb5736b7SDaichi GOTO * 1647cb5736b7SDaichi GOTO * This happens when the lower layer root directory is removed. 1648cb5736b7SDaichi GOTO * (A root directory deleting of unionfs should not be permitted. 1649cb5736b7SDaichi GOTO * But current VFS can not do it.) 1650cb5736b7SDaichi GOTO */ 1651cb5736b7SDaichi GOTO if (uio->uio_offset == 0) 1652cb5736b7SDaichi GOTO uio->uio_offset = uio_offset_bk; 1653cb5736b7SDaichi GOTO 1654d00947d8SCraig Rodrigues if (cookies_bk != NULL) { 1655d00947d8SCraig Rodrigues /* merge cookies */ 1656d00947d8SCraig Rodrigues int size; 1657d00947d8SCraig Rodrigues u_long *newcookies, *pos; 1658d00947d8SCraig Rodrigues 1659d00947d8SCraig Rodrigues size = *(ap->a_ncookies) + ncookies_bk; 1660d00947d8SCraig Rodrigues newcookies = (u_long *) malloc(size * sizeof(u_long), 1661d00947d8SCraig Rodrigues M_TEMP, M_WAITOK); 1662d00947d8SCraig Rodrigues pos = newcookies; 1663d00947d8SCraig Rodrigues 1664d00947d8SCraig Rodrigues memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long)); 1665508a31f1SDaichi GOTO pos += ncookies_bk; 1666312d49efSJason A. Harmening memcpy(pos, *(ap->a_cookies), 1667312d49efSJason A. Harmening *(ap->a_ncookies) * sizeof(u_long)); 1668d00947d8SCraig Rodrigues free(cookies_bk, M_TEMP); 1669d00947d8SCraig Rodrigues free(*(ap->a_cookies), M_TEMP); 1670d00947d8SCraig Rodrigues *(ap->a_ncookies) = size; 1671d00947d8SCraig Rodrigues *(ap->a_cookies) = newcookies; 1672d00947d8SCraig Rodrigues } 1673d00947d8SCraig Rodrigues 1674d00947d8SCraig Rodrigues unionfs_readdir_exit: 16755adc4080SDaichi GOTO if (error != 0 && ap->a_eofflag != NULL) 16765adc4080SDaichi GOTO *(ap->a_eofflag) = 1; 16775adc4080SDaichi GOTO 1678d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1679d00947d8SCraig Rodrigues 1680d00947d8SCraig Rodrigues return (error); 1681d00947d8SCraig Rodrigues } 1682d00947d8SCraig Rodrigues 1683d00947d8SCraig Rodrigues static int 1684d00947d8SCraig Rodrigues unionfs_readlink(struct vop_readlink_args *ap) 1685d00947d8SCraig Rodrigues { 1686d00947d8SCraig Rodrigues struct unionfs_node *unp; 1687df8bae1dSRodney W. Grimes struct vnode *vp; 1688312d49efSJason A. Harmening int error; 1689df8bae1dSRodney W. Grimes 1690d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 16912a31267eSMatthew Dillon 16921e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 16931e5da15aSDaichi GOTO 1694d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1695d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1696d00947d8SCraig Rodrigues 1697d00947d8SCraig Rodrigues error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1698d00947d8SCraig Rodrigues 1699d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1700d00947d8SCraig Rodrigues 17012a31267eSMatthew Dillon return (error); 1702df8bae1dSRodney W. Grimes } 1703df8bae1dSRodney W. Grimes 1704c9bf0111SKATO Takenori static int 1705d00947d8SCraig Rodrigues unionfs_getwritemount(struct vop_getwritemount_args *ap) 1706df8bae1dSRodney W. Grimes { 1707d00947d8SCraig Rodrigues struct vnode *uvp; 1708d00947d8SCraig Rodrigues struct vnode *vp; 1709312d49efSJason A. Harmening int error; 1710df8bae1dSRodney W. Grimes 1711d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); 1712996c772fSJohn Dyson 1713d00947d8SCraig Rodrigues error = 0; 1714d00947d8SCraig Rodrigues vp = ap->a_vp; 1715d00947d8SCraig Rodrigues 1716d00947d8SCraig Rodrigues if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) 1717d00947d8SCraig Rodrigues return (EACCES); 1718d00947d8SCraig Rodrigues 17191e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(vp); 17201e5da15aSDaichi GOTO 1721d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(vp); 1722d00947d8SCraig Rodrigues if (uvp == NULLVP && VREG == vp->v_type) 1723d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); 1724d00947d8SCraig Rodrigues 1725d00947d8SCraig Rodrigues if (uvp != NULLVP) 1726d00947d8SCraig Rodrigues error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); 1727d00947d8SCraig Rodrigues else { 1728d00947d8SCraig Rodrigues VI_LOCK(vp); 1729cc3593fbSMateusz Guzik if (vp->v_holdcnt == 0) 17306d8e1f82SBrian Feldman error = EOPNOTSUPP; 17316d8e1f82SBrian Feldman else 1732d00947d8SCraig Rodrigues error = EACCES; 1733d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1734df8bae1dSRodney W. Grimes } 1735d00947d8SCraig Rodrigues 1736d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error); 1737d00947d8SCraig Rodrigues 1738df8bae1dSRodney W. Grimes return (error); 1739df8bae1dSRodney W. Grimes } 1740df8bae1dSRodney W. Grimes 1741c9bf0111SKATO Takenori static int 1742d00947d8SCraig Rodrigues unionfs_inactive(struct vop_inactive_args *ap) 1743df8bae1dSRodney W. Grimes { 1744dc2dd185SDaichi GOTO ap->a_vp->v_object = NULL; 1745af6e6b87SEdward Tomasz Napierala vrecycle(ap->a_vp); 1746d00947d8SCraig Rodrigues return (0); 1747df8bae1dSRodney W. Grimes } 1748df8bae1dSRodney W. Grimes 1749c9bf0111SKATO Takenori static int 1750d00947d8SCraig Rodrigues unionfs_reclaim(struct vop_reclaim_args *ap) 1751df8bae1dSRodney W. Grimes { 1752d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1753d00947d8SCraig Rodrigues 17548f226f4cSMateusz Guzik unionfs_noderem(ap->a_vp, curthread); 1755d00947d8SCraig Rodrigues 1756d00947d8SCraig Rodrigues /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1757d00947d8SCraig Rodrigues 1758d00947d8SCraig Rodrigues return (0); 1759d00947d8SCraig Rodrigues } 1760d00947d8SCraig Rodrigues 1761d00947d8SCraig Rodrigues static int 1762d00947d8SCraig Rodrigues unionfs_print(struct vop_print_args *ap) 1763d00947d8SCraig Rodrigues { 1764d00947d8SCraig Rodrigues struct unionfs_node *unp; 1765d00947d8SCraig Rodrigues /* struct unionfs_node_status *unsp; */ 1766d00947d8SCraig Rodrigues 1767d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 1768d00947d8SCraig Rodrigues /* unionfs_get_node_status(unp, curthread, &unsp); */ 1769d00947d8SCraig Rodrigues 1770d00947d8SCraig Rodrigues printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1771d00947d8SCraig Rodrigues ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1772d00947d8SCraig Rodrigues /* 1773d00947d8SCraig Rodrigues printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1774d00947d8SCraig Rodrigues unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1775d00947d8SCraig Rodrigues */ 1776d00947d8SCraig Rodrigues 1777d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 1778411455a8SEdward Tomasz Napierala vn_printf(unp->un_uppervp, "unionfs: upper "); 1779d00947d8SCraig Rodrigues if (unp->un_lowervp != NULLVP) 1780411455a8SEdward Tomasz Napierala vn_printf(unp->un_lowervp, "unionfs: lower "); 1781d00947d8SCraig Rodrigues 1782d00947d8SCraig Rodrigues return (0); 1783d00947d8SCraig Rodrigues } 1784d00947d8SCraig Rodrigues 1785d00947d8SCraig Rodrigues static int 1786cb5736b7SDaichi GOTO unionfs_islocked(struct vop_islocked_args *ap) 1787d00947d8SCraig Rodrigues { 1788cb5736b7SDaichi GOTO struct unionfs_node *unp; 1789d00947d8SCraig Rodrigues 1790cb5736b7SDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 1791cb5736b7SDaichi GOTO 1792cb5736b7SDaichi GOTO unp = VTOUNIONFS(ap->a_vp); 1793cb5736b7SDaichi GOTO if (unp == NULL) 1794cb5736b7SDaichi GOTO return (vop_stdislocked(ap)); 1795cb5736b7SDaichi GOTO 1796cb5736b7SDaichi GOTO if (unp->un_uppervp != NULLVP) 1797cb5736b7SDaichi GOTO return (VOP_ISLOCKED(unp->un_uppervp)); 1798cb5736b7SDaichi GOTO if (unp->un_lowervp != NULLVP) 1799cb5736b7SDaichi GOTO return (VOP_ISLOCKED(unp->un_lowervp)); 1800cb5736b7SDaichi GOTO return (vop_stdislocked(ap)); 1801d00947d8SCraig Rodrigues } 1802d00947d8SCraig Rodrigues 1803cb5736b7SDaichi GOTO static int 1804cb5736b7SDaichi GOTO unionfs_get_llt_revlock(struct vnode *vp, int flags) 1805cb5736b7SDaichi GOTO { 1806cb5736b7SDaichi GOTO int revlock; 1807cb5736b7SDaichi GOTO 1808cb5736b7SDaichi GOTO revlock = 0; 1809cb5736b7SDaichi GOTO 1810cb5736b7SDaichi GOTO switch (flags & LK_TYPE_MASK) { 1811cb5736b7SDaichi GOTO case LK_SHARED: 1812cb5736b7SDaichi GOTO if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) 1813cb5736b7SDaichi GOTO revlock = LK_UPGRADE; 1814cb5736b7SDaichi GOTO else 1815cb5736b7SDaichi GOTO revlock = LK_RELEASE; 1816cb5736b7SDaichi GOTO break; 1817cb5736b7SDaichi GOTO case LK_EXCLUSIVE: 1818cb5736b7SDaichi GOTO case LK_UPGRADE: 1819cb5736b7SDaichi GOTO revlock = LK_RELEASE; 1820cb5736b7SDaichi GOTO break; 1821cb5736b7SDaichi GOTO case LK_DOWNGRADE: 1822cb5736b7SDaichi GOTO revlock = LK_UPGRADE; 1823cb5736b7SDaichi GOTO break; 1824cb5736b7SDaichi GOTO default: 1825cb5736b7SDaichi GOTO break; 1826cb5736b7SDaichi GOTO } 1827cb5736b7SDaichi GOTO 1828cb5736b7SDaichi GOTO return (revlock); 1829cb5736b7SDaichi GOTO } 1830cb5736b7SDaichi GOTO 1831cb5736b7SDaichi GOTO /* 1832cb5736b7SDaichi GOTO * The state of an acquired lock is adjusted similarly to 1833cb5736b7SDaichi GOTO * the time of error generating. 1834cb5736b7SDaichi GOTO * flags: LK_RELEASE or LK_UPGRADE 1835cb5736b7SDaichi GOTO */ 1836cb5736b7SDaichi GOTO static void 1837cb5736b7SDaichi GOTO unionfs_revlock(struct vnode *vp, int flags) 1838cb5736b7SDaichi GOTO { 1839cb5736b7SDaichi GOTO if (flags & LK_RELEASE) 18404a20fe31SMateusz Guzik VOP_UNLOCK_FLAGS(vp, flags); 1841cb5736b7SDaichi GOTO else { 1842cb5736b7SDaichi GOTO /* UPGRADE */ 1843cb5736b7SDaichi GOTO if (vn_lock(vp, flags) != 0) 1844cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1845cb5736b7SDaichi GOTO } 1846d00947d8SCraig Rodrigues } 1847d00947d8SCraig Rodrigues 1848d00947d8SCraig Rodrigues static int 1849d413d210SKonstantin Belousov unionfs_lock(struct vop_lock1_args *ap) 1850d00947d8SCraig Rodrigues { 185157821163SDaichi GOTO struct mount *mp; 1852d00947d8SCraig Rodrigues struct unionfs_mount *ump; 1853d00947d8SCraig Rodrigues struct unionfs_node *unp; 1854d00947d8SCraig Rodrigues struct vnode *vp; 18552a31267eSMatthew Dillon struct vnode *uvp; 1856d00947d8SCraig Rodrigues struct vnode *lvp; 1857312d49efSJason A. Harmening int error; 1858312d49efSJason A. Harmening int flags; 1859312d49efSJason A. Harmening int revlock; 1860312d49efSJason A. Harmening int interlock; 1861312d49efSJason A. Harmening int uhold; 1862df8bae1dSRodney W. Grimes 18631e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 18641e5da15aSDaichi GOTO 1865d00947d8SCraig Rodrigues error = 0; 1866cb5736b7SDaichi GOTO interlock = 1; 1867d00947d8SCraig Rodrigues uhold = 0; 1868d00947d8SCraig Rodrigues flags = ap->a_flags; 1869d00947d8SCraig Rodrigues vp = ap->a_vp; 1870df8bae1dSRodney W. Grimes 1871d00947d8SCraig Rodrigues if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK)) 18724a20fe31SMateusz Guzik return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE)); 18732a31267eSMatthew Dillon 187457821163SDaichi GOTO if ((flags & LK_INTERLOCK) == 0) 1875f3d1ec67SBoris Popov VI_LOCK(vp); 1876d00947d8SCraig Rodrigues 187757821163SDaichi GOTO mp = vp->v_mount; 187857821163SDaichi GOTO if (mp == NULL) 187957821163SDaichi GOTO goto unionfs_lock_null_vnode; 188057821163SDaichi GOTO 188157821163SDaichi GOTO ump = MOUNTTOUNIONFSMOUNT(mp); 1882d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 188357821163SDaichi GOTO if (ump == NULL || unp == NULL) 1884d00947d8SCraig Rodrigues goto unionfs_lock_null_vnode; 1885d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 1886d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 1887f2a2857bSKirk McKusick 1888cb5736b7SDaichi GOTO if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0) 1889cb5736b7SDaichi GOTO panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); 1890cb5736b7SDaichi GOTO 1891bc2258daSAttilio Rao if ((vp->v_iflag & VI_OWEINACT) != 0) 189257821163SDaichi GOTO flags |= LK_NOWAIT; 189357821163SDaichi GOTO 18942a31267eSMatthew Dillon /* 1895d00947d8SCraig Rodrigues * Sometimes, lower or upper is already exclusive locked. 1896d00947d8SCraig Rodrigues * (ex. vfs_domount: mounted vnode is already locked.) 18972a31267eSMatthew Dillon */ 1898d00947d8SCraig Rodrigues if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1899d00947d8SCraig Rodrigues vp == ump->um_rootvp) 1900d00947d8SCraig Rodrigues flags |= LK_CANRECURSE; 19012a31267eSMatthew Dillon 1902d00947d8SCraig Rodrigues if (lvp != NULLVP) { 1903cb5736b7SDaichi GOTO if (uvp != NULLVP && flags & LK_UPGRADE) { 1904312d49efSJason A. Harmening /* 1905312d49efSJason A. Harmening * Share Lock is once released and a deadlock is 1906312d49efSJason A. Harmening * avoided. 1907312d49efSJason A. Harmening */ 190848407115SMateusz Guzik vholdnz(uvp); 1909cb5736b7SDaichi GOTO uhold = 1; 1910b249ce48SMateusz Guzik VOP_UNLOCK(uvp); 1911cb5736b7SDaichi GOTO unp = VTOUNIONFS(vp); 1912cb5736b7SDaichi GOTO if (unp == NULL) { 1913cb5736b7SDaichi GOTO /* vnode is released. */ 1914cb5736b7SDaichi GOTO VI_UNLOCK(vp); 1915b249ce48SMateusz Guzik VOP_UNLOCK(lvp); 1916cb5736b7SDaichi GOTO vdrop(uvp); 1917cb5736b7SDaichi GOTO return (EBUSY); 1918cb5736b7SDaichi GOTO } 1919cb5736b7SDaichi GOTO } 1920d00947d8SCraig Rodrigues VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1921d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1922d00947d8SCraig Rodrigues vholdl(lvp); 1923df8bae1dSRodney W. Grimes 1924d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1925d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1926df8bae1dSRodney W. Grimes 192722db15c0SAttilio Rao error = VOP_LOCK(lvp, flags); 1928df8bae1dSRodney W. Grimes 1929d00947d8SCraig Rodrigues VI_LOCK(vp); 1930d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1931d00947d8SCraig Rodrigues if (unp == NULL) { 1932cb5736b7SDaichi GOTO /* vnode is released. */ 193357821163SDaichi GOTO VI_UNLOCK(vp); 1934d00947d8SCraig Rodrigues if (error == 0) 1935b249ce48SMateusz Guzik VOP_UNLOCK(lvp); 1936d00947d8SCraig Rodrigues vdrop(lvp); 1937cb5736b7SDaichi GOTO if (uhold != 0) 1938cb5736b7SDaichi GOTO vdrop(uvp); 1939d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 19402a31267eSMatthew Dillon } 1941df8bae1dSRodney W. Grimes } 1942df8bae1dSRodney W. Grimes 1943d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 1944cb5736b7SDaichi GOTO if (uhold && flags & LK_UPGRADE) { 1945cb5736b7SDaichi GOTO flags &= ~LK_TYPE_MASK; 1946cb5736b7SDaichi GOTO flags |= LK_EXCLUSIVE; 1947cb5736b7SDaichi GOTO } 1948d00947d8SCraig Rodrigues VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1949d00947d8SCraig Rodrigues flags |= LK_INTERLOCK; 1950cb5736b7SDaichi GOTO if (uhold == 0) { 1951d00947d8SCraig Rodrigues vholdl(uvp); 1952d00947d8SCraig Rodrigues uhold = 1; 1953cb5736b7SDaichi GOTO } 1954df8bae1dSRodney W. Grimes 1955d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1956d00947d8SCraig Rodrigues ap->a_flags &= ~LK_INTERLOCK; 1957d00947d8SCraig Rodrigues 195822db15c0SAttilio Rao error = VOP_LOCK(uvp, flags); 1959d00947d8SCraig Rodrigues 1960d00947d8SCraig Rodrigues VI_LOCK(vp); 1961d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1962d00947d8SCraig Rodrigues if (unp == NULL) { 1963cb5736b7SDaichi GOTO /* vnode is released. */ 196457821163SDaichi GOTO VI_UNLOCK(vp); 1965cb5736b7SDaichi GOTO if (error == 0) 1966b249ce48SMateusz Guzik VOP_UNLOCK(uvp); 1967d00947d8SCraig Rodrigues vdrop(uvp); 1968cb5736b7SDaichi GOTO if (lvp != NULLVP) { 1969b249ce48SMateusz Guzik VOP_UNLOCK(lvp); 1970cb5736b7SDaichi GOTO vdrop(lvp); 1971cb5736b7SDaichi GOTO } 1972d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1973df8bae1dSRodney W. Grimes } 197457821163SDaichi GOTO if (error != 0 && lvp != NULLVP) { 1975cb5736b7SDaichi GOTO /* rollback */ 197657821163SDaichi GOTO VI_UNLOCK(vp); 1977cb5736b7SDaichi GOTO unionfs_revlock(lvp, revlock); 1978cb5736b7SDaichi GOTO interlock = 0; 197957821163SDaichi GOTO } 1980df8bae1dSRodney W. Grimes } 1981df8bae1dSRodney W. Grimes 1982cb5736b7SDaichi GOTO if (interlock) 1983d00947d8SCraig Rodrigues VI_UNLOCK(vp); 1984d00947d8SCraig Rodrigues if (lvp != NULLVP) 1985d00947d8SCraig Rodrigues vdrop(lvp); 1986d00947d8SCraig Rodrigues if (uhold != 0) 1987d00947d8SCraig Rodrigues vdrop(uvp); 1988df8bae1dSRodney W. Grimes 1989df8bae1dSRodney W. Grimes return (error); 1990d00947d8SCraig Rodrigues 1991d00947d8SCraig Rodrigues unionfs_lock_null_vnode: 1992d00947d8SCraig Rodrigues ap->a_flags |= LK_INTERLOCK; 1993d00947d8SCraig Rodrigues return (vop_stdlock(ap)); 1994df8bae1dSRodney W. Grimes } 1995df8bae1dSRodney W. Grimes 1996c9bf0111SKATO Takenori static int 1997d00947d8SCraig Rodrigues unionfs_unlock(struct vop_unlock_args *ap) 1998df8bae1dSRodney W. Grimes { 1999d00947d8SCraig Rodrigues struct vnode *vp; 2000d00947d8SCraig Rodrigues struct vnode *lvp; 2001d00947d8SCraig Rodrigues struct vnode *uvp; 2002d00947d8SCraig Rodrigues struct unionfs_node *unp; 2003312d49efSJason A. Harmening int error; 2004312d49efSJason A. Harmening int uhold; 2005df8bae1dSRodney W. Grimes 20061e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20071e5da15aSDaichi GOTO 2008d00947d8SCraig Rodrigues error = 0; 2009d00947d8SCraig Rodrigues uhold = 0; 2010d00947d8SCraig Rodrigues vp = ap->a_vp; 2011d00947d8SCraig Rodrigues 2012d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 2013d00947d8SCraig Rodrigues if (unp == NULL) 2014d00947d8SCraig Rodrigues goto unionfs_unlock_null_vnode; 2015d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2016d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2017df8bae1dSRodney W. Grimes 2018d00947d8SCraig Rodrigues if (lvp != NULLVP) { 201948407115SMateusz Guzik vholdnz(lvp); 2020b249ce48SMateusz Guzik error = VOP_UNLOCK(lvp); 2021d00947d8SCraig Rodrigues } 2022d00947d8SCraig Rodrigues 2023d00947d8SCraig Rodrigues if (error == 0 && uvp != NULLVP) { 202448407115SMateusz Guzik vholdnz(uvp); 2025d00947d8SCraig Rodrigues uhold = 1; 2026b249ce48SMateusz Guzik error = VOP_UNLOCK(uvp); 2027d00947d8SCraig Rodrigues } 2028d00947d8SCraig Rodrigues 2029d00947d8SCraig Rodrigues if (lvp != NULLVP) 2030d00947d8SCraig Rodrigues vdrop(lvp); 2031d00947d8SCraig Rodrigues if (uhold != 0) 2032d00947d8SCraig Rodrigues vdrop(uvp); 2033d00947d8SCraig Rodrigues 2034d00947d8SCraig Rodrigues return error; 2035d00947d8SCraig Rodrigues 2036d00947d8SCraig Rodrigues unionfs_unlock_null_vnode: 2037d00947d8SCraig Rodrigues return (vop_stdunlock(ap)); 2038d00947d8SCraig Rodrigues } 2039d00947d8SCraig Rodrigues 2040c9bf0111SKATO Takenori static int 2041d00947d8SCraig Rodrigues unionfs_pathconf(struct vop_pathconf_args *ap) 2042df8bae1dSRodney W. Grimes { 2043d00947d8SCraig Rodrigues struct unionfs_node *unp; 2044d00947d8SCraig Rodrigues struct vnode *vp; 2045d00947d8SCraig Rodrigues 20461e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20471e5da15aSDaichi GOTO 2048d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2049d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2050d00947d8SCraig Rodrigues 2051d00947d8SCraig Rodrigues return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 2052d00947d8SCraig Rodrigues } 2053d00947d8SCraig Rodrigues 2054d00947d8SCraig Rodrigues static int 2055d00947d8SCraig Rodrigues unionfs_advlock(struct vop_advlock_args *ap) 2056d00947d8SCraig Rodrigues { 2057d00947d8SCraig Rodrigues struct unionfs_node *unp; 2058d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 2059d00947d8SCraig Rodrigues struct vnode *vp; 2060d00947d8SCraig Rodrigues struct vnode *uvp; 2061d00947d8SCraig Rodrigues struct thread *td; 2062312d49efSJason A. Harmening int error; 2063d00947d8SCraig Rodrigues 2064d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 2065d00947d8SCraig Rodrigues 20661e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 20671e5da15aSDaichi GOTO 2068d00947d8SCraig Rodrigues vp = ap->a_vp; 2069d00947d8SCraig Rodrigues td = curthread; 2070d00947d8SCraig Rodrigues 2071cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2072d00947d8SCraig Rodrigues 2073d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2074d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2075d00947d8SCraig Rodrigues 2076d00947d8SCraig Rodrigues if (uvp == NULLVP) { 2077d00947d8SCraig Rodrigues error = unionfs_copyfile(unp, 1, td->td_ucred, td); 2078d00947d8SCraig Rodrigues if (error != 0) 2079d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2080d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2081d00947d8SCraig Rodrigues 2082d00947d8SCraig Rodrigues unionfs_get_node_status(unp, td, &unsp); 2083d00947d8SCraig Rodrigues if (unsp->uns_lower_opencnt > 0) { 2084d00947d8SCraig Rodrigues /* try reopen the vnode */ 20859e223287SKonstantin Belousov error = VOP_OPEN(uvp, unsp->uns_lower_openmode, 20869e223287SKonstantin Belousov td->td_ucred, td, NULL); 2087d00947d8SCraig Rodrigues if (error) 2088d00947d8SCraig Rodrigues goto unionfs_advlock_abort; 2089d00947d8SCraig Rodrigues unsp->uns_upper_opencnt++; 2090312d49efSJason A. Harmening VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, 2091312d49efSJason A. Harmening td->td_ucred, td); 2092d00947d8SCraig Rodrigues unsp->uns_lower_opencnt--; 2093b2b0db08SDaichi GOTO } else 2094fe5f08cdSDaichi GOTO unionfs_tryrem_node_status(unp, unsp); 2095d00947d8SCraig Rodrigues } 2096d00947d8SCraig Rodrigues 2097b249ce48SMateusz Guzik VOP_UNLOCK(vp); 2098d00947d8SCraig Rodrigues 2099d00947d8SCraig Rodrigues error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 2100d00947d8SCraig Rodrigues 2101d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2102d00947d8SCraig Rodrigues 2103d00947d8SCraig Rodrigues return error; 2104d00947d8SCraig Rodrigues 2105d00947d8SCraig Rodrigues unionfs_advlock_abort: 2106b249ce48SMateusz Guzik VOP_UNLOCK(vp); 2107d00947d8SCraig Rodrigues 2108d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2109d00947d8SCraig Rodrigues 2110d00947d8SCraig Rodrigues return error; 2111d00947d8SCraig Rodrigues } 2112d00947d8SCraig Rodrigues 2113d00947d8SCraig Rodrigues static int 2114d00947d8SCraig Rodrigues unionfs_strategy(struct vop_strategy_args *ap) 2115d00947d8SCraig Rodrigues { 2116d00947d8SCraig Rodrigues struct unionfs_node *unp; 2117d00947d8SCraig Rodrigues struct vnode *vp; 2118d00947d8SCraig Rodrigues 21191e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21201e5da15aSDaichi GOTO 2121d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2122d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2123df8bae1dSRodney W. Grimes 2124df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 2125d00947d8SCraig Rodrigues if (vp == NULLVP) 2126d00947d8SCraig Rodrigues panic("unionfs_strategy: nullvp"); 2127d00947d8SCraig Rodrigues 2128d00947d8SCraig Rodrigues if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 2129d00947d8SCraig Rodrigues panic("unionfs_strategy: writing to lowervp"); 2130df8bae1dSRodney W. Grimes #endif 2131d00947d8SCraig Rodrigues 2132d00947d8SCraig Rodrigues return (VOP_STRATEGY(vp, ap->a_bp)); 2133df8bae1dSRodney W. Grimes } 2134df8bae1dSRodney W. Grimes 213500fff2c7STim J. Robbins static int 2136d00947d8SCraig Rodrigues unionfs_getacl(struct vop_getacl_args *ap) 213700fff2c7STim J. Robbins { 2138d00947d8SCraig Rodrigues struct unionfs_node *unp; 213900fff2c7STim J. Robbins struct vnode *vp; 2140312d49efSJason A. Harmening int error; 214100fff2c7STim J. Robbins 21421e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21431e5da15aSDaichi GOTO 2144d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2145d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2146d00947d8SCraig Rodrigues 2147d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 2148d00947d8SCraig Rodrigues 2149d00947d8SCraig Rodrigues error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2150d00947d8SCraig Rodrigues 2151d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 215200fff2c7STim J. Robbins 215300fff2c7STim J. Robbins return (error); 215400fff2c7STim J. Robbins } 215500fff2c7STim J. Robbins 215600fff2c7STim J. Robbins static int 2157d00947d8SCraig Rodrigues unionfs_setacl(struct vop_setacl_args *ap) 215800fff2c7STim J. Robbins { 2159d00947d8SCraig Rodrigues struct unionfs_node *unp; 2160d00947d8SCraig Rodrigues struct vnode *uvp; 2161d00947d8SCraig Rodrigues struct vnode *lvp; 2162d00947d8SCraig Rodrigues struct thread *td; 2163312d49efSJason A. Harmening int error; 216400fff2c7STim J. Robbins 2165d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 2166d00947d8SCraig Rodrigues 21671e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 21681e5da15aSDaichi GOTO 2169d00947d8SCraig Rodrigues error = EROFS; 2170d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2171d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2172d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2173d00947d8SCraig Rodrigues td = ap->a_td; 2174d00947d8SCraig Rodrigues 2175d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2176d00947d8SCraig Rodrigues return (EROFS); 2177d00947d8SCraig Rodrigues 2178d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2179d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2180d00947d8SCraig Rodrigues return (error); 2181d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2182d00947d8SCraig Rodrigues } 2183d00947d8SCraig Rodrigues 2184d00947d8SCraig Rodrigues if (uvp != NULLVP) 2185d00947d8SCraig Rodrigues error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 2186d00947d8SCraig Rodrigues 2187d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 218800fff2c7STim J. Robbins 218900fff2c7STim J. Robbins return (error); 219000fff2c7STim J. Robbins } 219100fff2c7STim J. Robbins 219200fff2c7STim J. Robbins static int 2193d00947d8SCraig Rodrigues unionfs_aclcheck(struct vop_aclcheck_args *ap) 219400fff2c7STim J. Robbins { 2195d00947d8SCraig Rodrigues struct unionfs_node *unp; 219600fff2c7STim J. Robbins struct vnode *vp; 2197312d49efSJason A. Harmening int error; 219800fff2c7STim J. Robbins 2199d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 2200d00947d8SCraig Rodrigues 22011e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22021e5da15aSDaichi GOTO 2203d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2204d00947d8SCraig Rodrigues vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2205d00947d8SCraig Rodrigues 2206d00947d8SCraig Rodrigues error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2207d00947d8SCraig Rodrigues 2208d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 220900fff2c7STim J. Robbins 221000fff2c7STim J. Robbins return (error); 221100fff2c7STim J. Robbins } 221200fff2c7STim J. Robbins 221300fff2c7STim J. Robbins static int 2214d00947d8SCraig Rodrigues unionfs_openextattr(struct vop_openextattr_args *ap) 221500fff2c7STim J. Robbins { 2216d00947d8SCraig Rodrigues struct unionfs_node *unp; 221700fff2c7STim J. Robbins struct vnode *vp; 221857821163SDaichi GOTO struct vnode *tvp; 2219312d49efSJason A. Harmening int error; 222000fff2c7STim J. Robbins 22211e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22221e5da15aSDaichi GOTO 222357821163SDaichi GOTO vp = ap->a_vp; 222457821163SDaichi GOTO unp = VTOUNIONFS(vp); 222557821163SDaichi GOTO tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2226d00947d8SCraig Rodrigues 222757821163SDaichi GOTO if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 222857821163SDaichi GOTO (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 2229d00947d8SCraig Rodrigues return (EBUSY); 2230d00947d8SCraig Rodrigues 223157821163SDaichi GOTO error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td); 2232d00947d8SCraig Rodrigues 2233d00947d8SCraig Rodrigues if (error == 0) { 2234cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 2235cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 223657821163SDaichi GOTO if (tvp == unp->un_uppervp) 2237d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2238d00947d8SCraig Rodrigues else 2239d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTL; 2240cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2241d00947d8SCraig Rodrigues } 224200fff2c7STim J. Robbins 224300fff2c7STim J. Robbins return (error); 224400fff2c7STim J. Robbins } 224500fff2c7STim J. Robbins 224600fff2c7STim J. Robbins static int 2247d00947d8SCraig Rodrigues unionfs_closeextattr(struct vop_closeextattr_args *ap) 224800fff2c7STim J. Robbins { 2249d00947d8SCraig Rodrigues struct unionfs_node *unp; 225000fff2c7STim J. Robbins struct vnode *vp; 225157821163SDaichi GOTO struct vnode *tvp; 2252312d49efSJason A. Harmening int error; 225300fff2c7STim J. Robbins 22541e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22551e5da15aSDaichi GOTO 225657821163SDaichi GOTO vp = ap->a_vp; 225757821163SDaichi GOTO unp = VTOUNIONFS(vp); 225857821163SDaichi GOTO tvp = NULLVP; 2259d00947d8SCraig Rodrigues 2260d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 226157821163SDaichi GOTO tvp = unp->un_uppervp; 2262d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 226357821163SDaichi GOTO tvp = unp->un_lowervp; 2264d00947d8SCraig Rodrigues 226557821163SDaichi GOTO if (tvp == NULLVP) 2266d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2267d00947d8SCraig Rodrigues 226857821163SDaichi GOTO error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td); 2269d00947d8SCraig Rodrigues 2270d00947d8SCraig Rodrigues if (error == 0) { 2271cb5736b7SDaichi GOTO if (vn_lock(vp, LK_UPGRADE) != 0) 2272cb5736b7SDaichi GOTO vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 227357821163SDaichi GOTO if (tvp == unp->un_uppervp) 2274d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTU; 2275d00947d8SCraig Rodrigues else 2276d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2277cb05b60aSAttilio Rao vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2278d00947d8SCraig Rodrigues } 227900fff2c7STim J. Robbins 228000fff2c7STim J. Robbins return (error); 228100fff2c7STim J. Robbins } 228200fff2c7STim J. Robbins 228300fff2c7STim J. Robbins static int 2284d00947d8SCraig Rodrigues unionfs_getextattr(struct vop_getextattr_args *ap) 228500fff2c7STim J. Robbins { 2286d00947d8SCraig Rodrigues struct unionfs_node *unp; 228700fff2c7STim J. Robbins struct vnode *vp; 228800fff2c7STim J. Robbins 22891e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 22901e5da15aSDaichi GOTO 2291d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2292d00947d8SCraig Rodrigues vp = NULLVP; 2293d00947d8SCraig Rodrigues 2294d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2295d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2296d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2297d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2298d00947d8SCraig Rodrigues 2299d00947d8SCraig Rodrigues if (vp == NULLVP) 2300d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2301d00947d8SCraig Rodrigues 2302d00947d8SCraig Rodrigues return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2303d00947d8SCraig Rodrigues ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2304d00947d8SCraig Rodrigues } 2305d00947d8SCraig Rodrigues 2306d00947d8SCraig Rodrigues static int 2307d00947d8SCraig Rodrigues unionfs_setextattr(struct vop_setextattr_args *ap) 2308d00947d8SCraig Rodrigues { 2309d00947d8SCraig Rodrigues struct unionfs_node *unp; 2310d00947d8SCraig Rodrigues struct vnode *uvp; 2311d00947d8SCraig Rodrigues struct vnode *lvp; 2312d00947d8SCraig Rodrigues struct vnode *ovp; 2313d00947d8SCraig Rodrigues struct ucred *cred; 2314d00947d8SCraig Rodrigues struct thread *td; 2315312d49efSJason A. Harmening int error; 2316d00947d8SCraig Rodrigues 23171e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23181e5da15aSDaichi GOTO 2319d00947d8SCraig Rodrigues error = EROFS; 2320d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2321d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2322d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2323d00947d8SCraig Rodrigues ovp = NULLVP; 2324d00947d8SCraig Rodrigues cred = ap->a_cred; 2325d00947d8SCraig Rodrigues td = ap->a_td; 2326d00947d8SCraig Rodrigues 2327312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", 2328312d49efSJason A. Harmening unp->un_flag); 2329d00947d8SCraig Rodrigues 2330d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2331d00947d8SCraig Rodrigues return (EROFS); 2332d00947d8SCraig Rodrigues 2333d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2334d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2335d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2336d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2337d00947d8SCraig Rodrigues 2338d00947d8SCraig Rodrigues if (ovp == NULLVP) 2339d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2340d00947d8SCraig Rodrigues 2341d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2342d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2343d00947d8SCraig Rodrigues if (uvp == NULLVP && 2344d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2345d00947d8SCraig Rodrigues unionfs_setextattr_reopen: 2346d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2347d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2348d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2349d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2350d00947d8SCraig Rodrigues #endif 2351d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2352d00947d8SCraig Rodrigues } 2353d00947d8SCraig Rodrigues goto unionfs_setextattr_abort; 2354d00947d8SCraig Rodrigues } 2355d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2356d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2357d00947d8SCraig Rodrigues goto unionfs_setextattr_reopen; 2358d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2359d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2360d00947d8SCraig Rodrigues ovp = uvp; 2361d00947d8SCraig Rodrigues } 2362d00947d8SCraig Rodrigues 2363d00947d8SCraig Rodrigues if (ovp == uvp) 2364d00947d8SCraig Rodrigues error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2365d00947d8SCraig Rodrigues ap->a_uio, cred, td); 2366d00947d8SCraig Rodrigues 2367d00947d8SCraig Rodrigues unionfs_setextattr_abort: 2368d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 236900fff2c7STim J. Robbins 237000fff2c7STim J. Robbins return (error); 237100fff2c7STim J. Robbins } 237200fff2c7STim J. Robbins 237300fff2c7STim J. Robbins static int 2374d00947d8SCraig Rodrigues unionfs_listextattr(struct vop_listextattr_args *ap) 237500fff2c7STim J. Robbins { 2376d00947d8SCraig Rodrigues struct unionfs_node *unp; 237700fff2c7STim J. Robbins struct vnode *vp; 237800fff2c7STim J. Robbins 23791e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 23801e5da15aSDaichi GOTO 2381d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2382d00947d8SCraig Rodrigues vp = NULLVP; 2383d00947d8SCraig Rodrigues 2384d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2385d00947d8SCraig Rodrigues vp = unp->un_uppervp; 2386d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2387d00947d8SCraig Rodrigues vp = unp->un_lowervp; 2388d00947d8SCraig Rodrigues 2389d00947d8SCraig Rodrigues if (vp == NULLVP) 2390d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2391d00947d8SCraig Rodrigues 2392d00947d8SCraig Rodrigues return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2393d00947d8SCraig Rodrigues ap->a_size, ap->a_cred, ap->a_td)); 2394d00947d8SCraig Rodrigues } 2395d00947d8SCraig Rodrigues 2396d00947d8SCraig Rodrigues static int 2397d00947d8SCraig Rodrigues unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2398d00947d8SCraig Rodrigues { 2399d00947d8SCraig Rodrigues struct unionfs_node *unp; 2400d00947d8SCraig Rodrigues struct vnode *uvp; 2401d00947d8SCraig Rodrigues struct vnode *lvp; 2402d00947d8SCraig Rodrigues struct vnode *ovp; 2403d00947d8SCraig Rodrigues struct ucred *cred; 2404d00947d8SCraig Rodrigues struct thread *td; 2405312d49efSJason A. Harmening int error; 2406d00947d8SCraig Rodrigues 24071e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 24081e5da15aSDaichi GOTO 2409d00947d8SCraig Rodrigues error = EROFS; 2410d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2411d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2412d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2413d00947d8SCraig Rodrigues ovp = NULLVP; 2414d00947d8SCraig Rodrigues cred = ap->a_cred; 2415d00947d8SCraig Rodrigues td = ap->a_td; 2416d00947d8SCraig Rodrigues 2417312d49efSJason A. Harmening UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", 2418312d49efSJason A. Harmening unp->un_flag); 2419d00947d8SCraig Rodrigues 2420d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2421d00947d8SCraig Rodrigues return (EROFS); 2422d00947d8SCraig Rodrigues 2423d00947d8SCraig Rodrigues if (unp->un_flag & UNIONFS_OPENEXTU) 2424d00947d8SCraig Rodrigues ovp = unp->un_uppervp; 2425d00947d8SCraig Rodrigues else if (unp->un_flag & UNIONFS_OPENEXTL) 2426d00947d8SCraig Rodrigues ovp = unp->un_lowervp; 2427d00947d8SCraig Rodrigues 2428d00947d8SCraig Rodrigues if (ovp == NULLVP) 2429d00947d8SCraig Rodrigues return (EOPNOTSUPP); 2430d00947d8SCraig Rodrigues 2431d00947d8SCraig Rodrigues if (ovp == lvp && lvp->v_type == VREG) { 2432d00947d8SCraig Rodrigues VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2433d00947d8SCraig Rodrigues if (uvp == NULLVP && 2434d00947d8SCraig Rodrigues (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2435d00947d8SCraig Rodrigues unionfs_deleteextattr_reopen: 2436d00947d8SCraig Rodrigues if ((unp->un_flag & UNIONFS_OPENEXTL) && 2437d00947d8SCraig Rodrigues VOP_OPENEXTATTR(lvp, cred, td)) { 2438d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 2439d00947d8SCraig Rodrigues panic("unionfs: VOP_OPENEXTATTR failed"); 2440d00947d8SCraig Rodrigues #endif 2441d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2442d00947d8SCraig Rodrigues } 2443d00947d8SCraig Rodrigues goto unionfs_deleteextattr_abort; 2444d00947d8SCraig Rodrigues } 2445d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2446d00947d8SCraig Rodrigues if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2447d00947d8SCraig Rodrigues goto unionfs_deleteextattr_reopen; 2448d00947d8SCraig Rodrigues unp->un_flag &= ~UNIONFS_OPENEXTL; 2449d00947d8SCraig Rodrigues unp->un_flag |= UNIONFS_OPENEXTU; 2450d00947d8SCraig Rodrigues ovp = uvp; 2451d00947d8SCraig Rodrigues } 2452d00947d8SCraig Rodrigues 2453d00947d8SCraig Rodrigues if (ovp == uvp) 2454d00947d8SCraig Rodrigues error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2455d00947d8SCraig Rodrigues ap->a_cred, ap->a_td); 2456d00947d8SCraig Rodrigues 2457d00947d8SCraig Rodrigues unionfs_deleteextattr_abort: 2458d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 245900fff2c7STim J. Robbins 246000fff2c7STim J. Robbins return (error); 246100fff2c7STim J. Robbins } 246200fff2c7STim J. Robbins 246300fff2c7STim J. Robbins static int 2464d00947d8SCraig Rodrigues unionfs_setlabel(struct vop_setlabel_args *ap) 246500fff2c7STim J. Robbins { 2466d00947d8SCraig Rodrigues struct unionfs_node *unp; 2467d00947d8SCraig Rodrigues struct vnode *uvp; 2468d00947d8SCraig Rodrigues struct vnode *lvp; 2469d00947d8SCraig Rodrigues struct thread *td; 2470312d49efSJason A. Harmening int error; 247100fff2c7STim J. Robbins 2472d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2473d00947d8SCraig Rodrigues 24741e5da15aSDaichi GOTO KASSERT_UNIONFS_VNODE(ap->a_vp); 24751e5da15aSDaichi GOTO 2476d00947d8SCraig Rodrigues error = EROFS; 2477d00947d8SCraig Rodrigues unp = VTOUNIONFS(ap->a_vp); 2478d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2479d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 2480d00947d8SCraig Rodrigues td = ap->a_td; 2481d00947d8SCraig Rodrigues 2482d00947d8SCraig Rodrigues if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2483d00947d8SCraig Rodrigues return (EROFS); 2484d00947d8SCraig Rodrigues 2485d00947d8SCraig Rodrigues if (uvp == NULLVP && lvp->v_type == VREG) { 2486d00947d8SCraig Rodrigues if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2487d00947d8SCraig Rodrigues return (error); 2488d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 2489d00947d8SCraig Rodrigues } 2490d00947d8SCraig Rodrigues 2491d00947d8SCraig Rodrigues if (uvp != NULLVP) 2492d00947d8SCraig Rodrigues error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2493d00947d8SCraig Rodrigues 2494d00947d8SCraig Rodrigues UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 249500fff2c7STim J. Robbins 249600fff2c7STim J. Robbins return (error); 249700fff2c7STim J. Robbins } 249800fff2c7STim J. Robbins 249910bcafe9SPawel Jakub Dawidek static int 250010bcafe9SPawel Jakub Dawidek unionfs_vptofh(struct vop_vptofh_args *ap) 250110bcafe9SPawel Jakub Dawidek { 250210bcafe9SPawel Jakub Dawidek return (EOPNOTSUPP); 250310bcafe9SPawel Jakub Dawidek } 250410bcafe9SPawel Jakub Dawidek 250530d49d53SKonstantin Belousov static int 250630d49d53SKonstantin Belousov unionfs_add_writecount(struct vop_add_writecount_args *ap) 250730d49d53SKonstantin Belousov { 250830d49d53SKonstantin Belousov struct vnode *tvp, *vp; 250930d49d53SKonstantin Belousov struct unionfs_node *unp; 251030d49d53SKonstantin Belousov int error; 251130d49d53SKonstantin Belousov 251230d49d53SKonstantin Belousov vp = ap->a_vp; 251330d49d53SKonstantin Belousov unp = VTOUNIONFS(vp); 251430d49d53SKonstantin Belousov tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp; 251530d49d53SKonstantin Belousov VI_LOCK(vp); 251630d49d53SKonstantin Belousov /* text refs are bypassed to lowervp */ 251730d49d53SKonstantin Belousov VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount")); 251830d49d53SKonstantin Belousov VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp, 251930d49d53SKonstantin Belousov ("wrong writecount inc %d", ap->a_inc)); 252030d49d53SKonstantin Belousov if (tvp != NULL) 252130d49d53SKonstantin Belousov error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc); 252230d49d53SKonstantin Belousov else if (vp->v_writecount < 0) 252330d49d53SKonstantin Belousov error = ETXTBSY; 252430d49d53SKonstantin Belousov else 252530d49d53SKonstantin Belousov error = 0; 252630d49d53SKonstantin Belousov if (error == 0) 252730d49d53SKonstantin Belousov vp->v_writecount += ap->a_inc; 252830d49d53SKonstantin Belousov VI_UNLOCK(vp); 252930d49d53SKonstantin Belousov return (error); 253030d49d53SKonstantin Belousov } 253130d49d53SKonstantin Belousov 2532d00947d8SCraig Rodrigues struct vop_vector unionfs_vnodeops = { 2533aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 253483c64397SPoul-Henning Kamp 2535d00947d8SCraig Rodrigues .vop_access = unionfs_access, 2536d00947d8SCraig Rodrigues .vop_aclcheck = unionfs_aclcheck, 2537d00947d8SCraig Rodrigues .vop_advlock = unionfs_advlock, 2538aec0fb7bSPoul-Henning Kamp .vop_bmap = VOP_EOPNOTSUPP, 2539dc2dd185SDaichi GOTO .vop_cachedlookup = unionfs_lookup, 2540d00947d8SCraig Rodrigues .vop_close = unionfs_close, 2541d00947d8SCraig Rodrigues .vop_closeextattr = unionfs_closeextattr, 2542d00947d8SCraig Rodrigues .vop_create = unionfs_create, 2543d00947d8SCraig Rodrigues .vop_deleteextattr = unionfs_deleteextattr, 2544d00947d8SCraig Rodrigues .vop_fsync = unionfs_fsync, 2545d00947d8SCraig Rodrigues .vop_getacl = unionfs_getacl, 2546d00947d8SCraig Rodrigues .vop_getattr = unionfs_getattr, 2547d00947d8SCraig Rodrigues .vop_getextattr = unionfs_getextattr, 2548d00947d8SCraig Rodrigues .vop_getwritemount = unionfs_getwritemount, 2549d00947d8SCraig Rodrigues .vop_inactive = unionfs_inactive, 25501e2f0cebSMateusz Guzik .vop_need_inactive = vop_stdneed_inactive, 2551cb5736b7SDaichi GOTO .vop_islocked = unionfs_islocked, 2552d00947d8SCraig Rodrigues .vop_ioctl = unionfs_ioctl, 2553d00947d8SCraig Rodrigues .vop_link = unionfs_link, 2554d00947d8SCraig Rodrigues .vop_listextattr = unionfs_listextattr, 2555d413d210SKonstantin Belousov .vop_lock1 = unionfs_lock, 2556dc2dd185SDaichi GOTO .vop_lookup = vfs_cache_lookup, 2557d00947d8SCraig Rodrigues .vop_mkdir = unionfs_mkdir, 2558d00947d8SCraig Rodrigues .vop_mknod = unionfs_mknod, 2559d00947d8SCraig Rodrigues .vop_open = unionfs_open, 2560d00947d8SCraig Rodrigues .vop_openextattr = unionfs_openextattr, 2561d00947d8SCraig Rodrigues .vop_pathconf = unionfs_pathconf, 2562d00947d8SCraig Rodrigues .vop_poll = unionfs_poll, 2563d00947d8SCraig Rodrigues .vop_print = unionfs_print, 2564d00947d8SCraig Rodrigues .vop_read = unionfs_read, 2565d00947d8SCraig Rodrigues .vop_readdir = unionfs_readdir, 2566d00947d8SCraig Rodrigues .vop_readlink = unionfs_readlink, 2567d00947d8SCraig Rodrigues .vop_reclaim = unionfs_reclaim, 2568d00947d8SCraig Rodrigues .vop_remove = unionfs_remove, 2569d00947d8SCraig Rodrigues .vop_rename = unionfs_rename, 2570d00947d8SCraig Rodrigues .vop_rmdir = unionfs_rmdir, 2571d00947d8SCraig Rodrigues .vop_setacl = unionfs_setacl, 2572d00947d8SCraig Rodrigues .vop_setattr = unionfs_setattr, 2573d00947d8SCraig Rodrigues .vop_setextattr = unionfs_setextattr, 2574d00947d8SCraig Rodrigues .vop_setlabel = unionfs_setlabel, 2575d00947d8SCraig Rodrigues .vop_strategy = unionfs_strategy, 2576d00947d8SCraig Rodrigues .vop_symlink = unionfs_symlink, 2577d00947d8SCraig Rodrigues .vop_unlock = unionfs_unlock, 2578d00947d8SCraig Rodrigues .vop_whiteout = unionfs_whiteout, 2579d00947d8SCraig Rodrigues .vop_write = unionfs_write, 258010bcafe9SPawel Jakub Dawidek .vop_vptofh = unionfs_vptofh, 258130d49d53SKonstantin Belousov .vop_add_writecount = unionfs_add_writecount, 2582df8bae1dSRodney W. Grimes }; 25836fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops); 2584