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