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