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 ((mp->mnt_kern_flag & MNTK_MPSAFE) != 0 && 1871 (vp->v_iflag & VI_OWEINACT) != 0) 1872 flags |= LK_NOWAIT; 1873 1874 /* 1875 * Sometimes, lower or upper is already exclusive locked. 1876 * (ex. vfs_domount: mounted vnode is already locked.) 1877 */ 1878 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1879 vp == ump->um_rootvp) 1880 flags |= LK_CANRECURSE; 1881 1882 if (lvp != NULLVP) { 1883 if (uvp != NULLVP && flags & LK_UPGRADE) { 1884 /* Share Lock is once released and a deadlock is avoided. */ 1885 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1886 vholdl(uvp); 1887 uhold = 1; 1888 VI_UNLOCK(vp); 1889 VOP_UNLOCK(uvp, LK_RELEASE | LK_INTERLOCK); 1890 VI_LOCK(vp); 1891 unp = VTOUNIONFS(vp); 1892 if (unp == NULL) { 1893 /* vnode is released. */ 1894 VI_UNLOCK(vp); 1895 VOP_UNLOCK(lvp, LK_RELEASE); 1896 vdrop(uvp); 1897 return (EBUSY); 1898 } 1899 } 1900 VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1901 flags |= LK_INTERLOCK; 1902 vholdl(lvp); 1903 1904 VI_UNLOCK(vp); 1905 ap->a_flags &= ~LK_INTERLOCK; 1906 1907 error = VOP_LOCK(lvp, flags); 1908 1909 VI_LOCK(vp); 1910 unp = VTOUNIONFS(vp); 1911 if (unp == NULL) { 1912 /* vnode is released. */ 1913 VI_UNLOCK(vp); 1914 if (error == 0) 1915 VOP_UNLOCK(lvp, LK_RELEASE); 1916 vdrop(lvp); 1917 if (uhold != 0) 1918 vdrop(uvp); 1919 return (vop_stdlock(ap)); 1920 } 1921 } 1922 1923 if (error == 0 && uvp != NULLVP) { 1924 if (uhold && flags & LK_UPGRADE) { 1925 flags &= ~LK_TYPE_MASK; 1926 flags |= LK_EXCLUSIVE; 1927 } 1928 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1929 flags |= LK_INTERLOCK; 1930 if (uhold == 0) { 1931 vholdl(uvp); 1932 uhold = 1; 1933 } 1934 1935 VI_UNLOCK(vp); 1936 ap->a_flags &= ~LK_INTERLOCK; 1937 1938 error = VOP_LOCK(uvp, flags); 1939 1940 VI_LOCK(vp); 1941 unp = VTOUNIONFS(vp); 1942 if (unp == NULL) { 1943 /* vnode is released. */ 1944 VI_UNLOCK(vp); 1945 if (error == 0) 1946 VOP_UNLOCK(uvp, LK_RELEASE); 1947 vdrop(uvp); 1948 if (lvp != NULLVP) { 1949 VOP_UNLOCK(lvp, LK_RELEASE); 1950 vdrop(lvp); 1951 } 1952 return (vop_stdlock(ap)); 1953 } 1954 if (error != 0 && lvp != NULLVP) { 1955 /* rollback */ 1956 VI_UNLOCK(vp); 1957 unionfs_revlock(lvp, revlock); 1958 interlock = 0; 1959 } 1960 } 1961 1962 if (interlock) 1963 VI_UNLOCK(vp); 1964 if (lvp != NULLVP) 1965 vdrop(lvp); 1966 if (uhold != 0) 1967 vdrop(uvp); 1968 1969 return (error); 1970 1971 unionfs_lock_null_vnode: 1972 ap->a_flags |= LK_INTERLOCK; 1973 return (vop_stdlock(ap)); 1974 } 1975 1976 static int 1977 unionfs_unlock(struct vop_unlock_args *ap) 1978 { 1979 int error; 1980 int flags; 1981 int mtxlkflag; 1982 int uhold; 1983 struct vnode *vp; 1984 struct vnode *lvp; 1985 struct vnode *uvp; 1986 struct unionfs_node *unp; 1987 1988 KASSERT_UNIONFS_VNODE(ap->a_vp); 1989 1990 error = 0; 1991 mtxlkflag = 0; 1992 uhold = 0; 1993 flags = ap->a_flags | LK_RELEASE; 1994 vp = ap->a_vp; 1995 1996 if ((flags & LK_INTERLOCK) != 0) 1997 mtxlkflag = 1; 1998 else if (mtx_owned(VI_MTX(vp)) == 0) { 1999 VI_LOCK(vp); 2000 mtxlkflag = 2; 2001 } 2002 2003 unp = VTOUNIONFS(vp); 2004 if (unp == NULL) 2005 goto unionfs_unlock_null_vnode; 2006 lvp = unp->un_lowervp; 2007 uvp = unp->un_uppervp; 2008 2009 if (lvp != NULLVP) { 2010 VI_LOCK_FLAGS(lvp, MTX_DUPOK); 2011 flags |= LK_INTERLOCK; 2012 vholdl(lvp); 2013 2014 VI_UNLOCK(vp); 2015 ap->a_flags &= ~LK_INTERLOCK; 2016 2017 error = VOP_UNLOCK(lvp, flags); 2018 2019 VI_LOCK(vp); 2020 } 2021 2022 if (error == 0 && uvp != NULLVP) { 2023 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 2024 flags |= LK_INTERLOCK; 2025 vholdl(uvp); 2026 uhold = 1; 2027 2028 VI_UNLOCK(vp); 2029 ap->a_flags &= ~LK_INTERLOCK; 2030 2031 error = VOP_UNLOCK(uvp, flags); 2032 2033 VI_LOCK(vp); 2034 } 2035 2036 VI_UNLOCK(vp); 2037 if (lvp != NULLVP) 2038 vdrop(lvp); 2039 if (uhold != 0) 2040 vdrop(uvp); 2041 if (mtxlkflag == 0) 2042 VI_LOCK(vp); 2043 2044 return error; 2045 2046 unionfs_unlock_null_vnode: 2047 if (mtxlkflag == 2) 2048 VI_UNLOCK(vp); 2049 return (vop_stdunlock(ap)); 2050 } 2051 2052 static int 2053 unionfs_pathconf(struct vop_pathconf_args *ap) 2054 { 2055 struct unionfs_node *unp; 2056 struct vnode *vp; 2057 2058 KASSERT_UNIONFS_VNODE(ap->a_vp); 2059 2060 unp = VTOUNIONFS(ap->a_vp); 2061 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2062 2063 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 2064 } 2065 2066 static int 2067 unionfs_advlock(struct vop_advlock_args *ap) 2068 { 2069 int error; 2070 struct unionfs_node *unp; 2071 struct unionfs_node_status *unsp; 2072 struct vnode *vp; 2073 struct vnode *uvp; 2074 struct thread *td; 2075 2076 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 2077 2078 KASSERT_UNIONFS_VNODE(ap->a_vp); 2079 2080 vp = ap->a_vp; 2081 td = curthread; 2082 2083 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2084 2085 unp = VTOUNIONFS(ap->a_vp); 2086 uvp = unp->un_uppervp; 2087 2088 if (uvp == NULLVP) { 2089 error = unionfs_copyfile(unp, 1, td->td_ucred, td); 2090 if (error != 0) 2091 goto unionfs_advlock_abort; 2092 uvp = unp->un_uppervp; 2093 2094 unionfs_get_node_status(unp, td, &unsp); 2095 if (unsp->uns_lower_opencnt > 0) { 2096 /* try reopen the vnode */ 2097 error = VOP_OPEN(uvp, unsp->uns_lower_openmode, 2098 td->td_ucred, td, NULL); 2099 if (error) 2100 goto unionfs_advlock_abort; 2101 unsp->uns_upper_opencnt++; 2102 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td); 2103 unsp->uns_lower_opencnt--; 2104 } else 2105 unionfs_tryrem_node_status(unp, unsp); 2106 } 2107 2108 VOP_UNLOCK(vp, LK_RELEASE); 2109 2110 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 2111 2112 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2113 2114 return error; 2115 2116 unionfs_advlock_abort: 2117 VOP_UNLOCK(vp, LK_RELEASE); 2118 2119 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2120 2121 return error; 2122 } 2123 2124 static int 2125 unionfs_strategy(struct vop_strategy_args *ap) 2126 { 2127 struct unionfs_node *unp; 2128 struct vnode *vp; 2129 2130 KASSERT_UNIONFS_VNODE(ap->a_vp); 2131 2132 unp = VTOUNIONFS(ap->a_vp); 2133 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2134 2135 #ifdef DIAGNOSTIC 2136 if (vp == NULLVP) 2137 panic("unionfs_strategy: nullvp"); 2138 2139 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 2140 panic("unionfs_strategy: writing to lowervp"); 2141 #endif 2142 2143 return (VOP_STRATEGY(vp, ap->a_bp)); 2144 } 2145 2146 static int 2147 unionfs_getacl(struct vop_getacl_args *ap) 2148 { 2149 int error; 2150 struct unionfs_node *unp; 2151 struct vnode *vp; 2152 2153 KASSERT_UNIONFS_VNODE(ap->a_vp); 2154 2155 unp = VTOUNIONFS(ap->a_vp); 2156 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2157 2158 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 2159 2160 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2161 2162 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 2163 2164 return (error); 2165 } 2166 2167 static int 2168 unionfs_setacl(struct vop_setacl_args *ap) 2169 { 2170 int error; 2171 struct unionfs_node *unp; 2172 struct vnode *uvp; 2173 struct vnode *lvp; 2174 struct thread *td; 2175 2176 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 2177 2178 KASSERT_UNIONFS_VNODE(ap->a_vp); 2179 2180 error = EROFS; 2181 unp = VTOUNIONFS(ap->a_vp); 2182 uvp = unp->un_uppervp; 2183 lvp = unp->un_lowervp; 2184 td = ap->a_td; 2185 2186 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2187 return (EROFS); 2188 2189 if (uvp == NULLVP && lvp->v_type == VREG) { 2190 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2191 return (error); 2192 uvp = unp->un_uppervp; 2193 } 2194 2195 if (uvp != NULLVP) 2196 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 2197 2198 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 2199 2200 return (error); 2201 } 2202 2203 static int 2204 unionfs_aclcheck(struct vop_aclcheck_args *ap) 2205 { 2206 int error; 2207 struct unionfs_node *unp; 2208 struct vnode *vp; 2209 2210 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 2211 2212 KASSERT_UNIONFS_VNODE(ap->a_vp); 2213 2214 unp = VTOUNIONFS(ap->a_vp); 2215 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2216 2217 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2218 2219 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 2220 2221 return (error); 2222 } 2223 2224 static int 2225 unionfs_openextattr(struct vop_openextattr_args *ap) 2226 { 2227 int error; 2228 struct unionfs_node *unp; 2229 struct vnode *vp; 2230 struct vnode *tvp; 2231 2232 KASSERT_UNIONFS_VNODE(ap->a_vp); 2233 2234 vp = ap->a_vp; 2235 unp = VTOUNIONFS(vp); 2236 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2237 2238 if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 2239 (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 2240 return (EBUSY); 2241 2242 error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td); 2243 2244 if (error == 0) { 2245 if (vn_lock(vp, LK_UPGRADE) != 0) 2246 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2247 if (tvp == unp->un_uppervp) 2248 unp->un_flag |= UNIONFS_OPENEXTU; 2249 else 2250 unp->un_flag |= UNIONFS_OPENEXTL; 2251 vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2252 } 2253 2254 return (error); 2255 } 2256 2257 static int 2258 unionfs_closeextattr(struct vop_closeextattr_args *ap) 2259 { 2260 int error; 2261 struct unionfs_node *unp; 2262 struct vnode *vp; 2263 struct vnode *tvp; 2264 2265 KASSERT_UNIONFS_VNODE(ap->a_vp); 2266 2267 vp = ap->a_vp; 2268 unp = VTOUNIONFS(vp); 2269 tvp = NULLVP; 2270 2271 if (unp->un_flag & UNIONFS_OPENEXTU) 2272 tvp = unp->un_uppervp; 2273 else if (unp->un_flag & UNIONFS_OPENEXTL) 2274 tvp = unp->un_lowervp; 2275 2276 if (tvp == NULLVP) 2277 return (EOPNOTSUPP); 2278 2279 error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td); 2280 2281 if (error == 0) { 2282 if (vn_lock(vp, LK_UPGRADE) != 0) 2283 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2284 if (tvp == unp->un_uppervp) 2285 unp->un_flag &= ~UNIONFS_OPENEXTU; 2286 else 2287 unp->un_flag &= ~UNIONFS_OPENEXTL; 2288 vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2289 } 2290 2291 return (error); 2292 } 2293 2294 static int 2295 unionfs_getextattr(struct vop_getextattr_args *ap) 2296 { 2297 struct unionfs_node *unp; 2298 struct vnode *vp; 2299 2300 KASSERT_UNIONFS_VNODE(ap->a_vp); 2301 2302 unp = VTOUNIONFS(ap->a_vp); 2303 vp = NULLVP; 2304 2305 if (unp->un_flag & UNIONFS_OPENEXTU) 2306 vp = unp->un_uppervp; 2307 else if (unp->un_flag & UNIONFS_OPENEXTL) 2308 vp = unp->un_lowervp; 2309 2310 if (vp == NULLVP) 2311 return (EOPNOTSUPP); 2312 2313 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2314 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2315 } 2316 2317 static int 2318 unionfs_setextattr(struct vop_setextattr_args *ap) 2319 { 2320 int error; 2321 struct unionfs_node *unp; 2322 struct vnode *uvp; 2323 struct vnode *lvp; 2324 struct vnode *ovp; 2325 struct ucred *cred; 2326 struct thread *td; 2327 2328 KASSERT_UNIONFS_VNODE(ap->a_vp); 2329 2330 error = EROFS; 2331 unp = VTOUNIONFS(ap->a_vp); 2332 uvp = unp->un_uppervp; 2333 lvp = unp->un_lowervp; 2334 ovp = NULLVP; 2335 cred = ap->a_cred; 2336 td = ap->a_td; 2337 2338 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag); 2339 2340 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2341 return (EROFS); 2342 2343 if (unp->un_flag & UNIONFS_OPENEXTU) 2344 ovp = unp->un_uppervp; 2345 else if (unp->un_flag & UNIONFS_OPENEXTL) 2346 ovp = unp->un_lowervp; 2347 2348 if (ovp == NULLVP) 2349 return (EOPNOTSUPP); 2350 2351 if (ovp == lvp && lvp->v_type == VREG) { 2352 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2353 if (uvp == NULLVP && 2354 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2355 unionfs_setextattr_reopen: 2356 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2357 VOP_OPENEXTATTR(lvp, cred, td)) { 2358 #ifdef DIAGNOSTIC 2359 panic("unionfs: VOP_OPENEXTATTR failed"); 2360 #endif 2361 unp->un_flag &= ~UNIONFS_OPENEXTL; 2362 } 2363 goto unionfs_setextattr_abort; 2364 } 2365 uvp = unp->un_uppervp; 2366 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2367 goto unionfs_setextattr_reopen; 2368 unp->un_flag &= ~UNIONFS_OPENEXTL; 2369 unp->un_flag |= UNIONFS_OPENEXTU; 2370 ovp = uvp; 2371 } 2372 2373 if (ovp == uvp) 2374 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2375 ap->a_uio, cred, td); 2376 2377 unionfs_setextattr_abort: 2378 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 2379 2380 return (error); 2381 } 2382 2383 static int 2384 unionfs_listextattr(struct vop_listextattr_args *ap) 2385 { 2386 struct unionfs_node *unp; 2387 struct vnode *vp; 2388 2389 KASSERT_UNIONFS_VNODE(ap->a_vp); 2390 2391 unp = VTOUNIONFS(ap->a_vp); 2392 vp = NULLVP; 2393 2394 if (unp->un_flag & UNIONFS_OPENEXTU) 2395 vp = unp->un_uppervp; 2396 else if (unp->un_flag & UNIONFS_OPENEXTL) 2397 vp = unp->un_lowervp; 2398 2399 if (vp == NULLVP) 2400 return (EOPNOTSUPP); 2401 2402 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2403 ap->a_size, ap->a_cred, ap->a_td)); 2404 } 2405 2406 static int 2407 unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2408 { 2409 int error; 2410 struct unionfs_node *unp; 2411 struct vnode *uvp; 2412 struct vnode *lvp; 2413 struct vnode *ovp; 2414 struct ucred *cred; 2415 struct thread *td; 2416 2417 KASSERT_UNIONFS_VNODE(ap->a_vp); 2418 2419 error = EROFS; 2420 unp = VTOUNIONFS(ap->a_vp); 2421 uvp = unp->un_uppervp; 2422 lvp = unp->un_lowervp; 2423 ovp = NULLVP; 2424 cred = ap->a_cred; 2425 td = ap->a_td; 2426 2427 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag); 2428 2429 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2430 return (EROFS); 2431 2432 if (unp->un_flag & UNIONFS_OPENEXTU) 2433 ovp = unp->un_uppervp; 2434 else if (unp->un_flag & UNIONFS_OPENEXTL) 2435 ovp = unp->un_lowervp; 2436 2437 if (ovp == NULLVP) 2438 return (EOPNOTSUPP); 2439 2440 if (ovp == lvp && lvp->v_type == VREG) { 2441 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2442 if (uvp == NULLVP && 2443 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2444 unionfs_deleteextattr_reopen: 2445 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2446 VOP_OPENEXTATTR(lvp, cred, td)) { 2447 #ifdef DIAGNOSTIC 2448 panic("unionfs: VOP_OPENEXTATTR failed"); 2449 #endif 2450 unp->un_flag &= ~UNIONFS_OPENEXTL; 2451 } 2452 goto unionfs_deleteextattr_abort; 2453 } 2454 uvp = unp->un_uppervp; 2455 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2456 goto unionfs_deleteextattr_reopen; 2457 unp->un_flag &= ~UNIONFS_OPENEXTL; 2458 unp->un_flag |= UNIONFS_OPENEXTU; 2459 ovp = uvp; 2460 } 2461 2462 if (ovp == uvp) 2463 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2464 ap->a_cred, ap->a_td); 2465 2466 unionfs_deleteextattr_abort: 2467 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 2468 2469 return (error); 2470 } 2471 2472 static int 2473 unionfs_setlabel(struct vop_setlabel_args *ap) 2474 { 2475 int error; 2476 struct unionfs_node *unp; 2477 struct vnode *uvp; 2478 struct vnode *lvp; 2479 struct thread *td; 2480 2481 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2482 2483 KASSERT_UNIONFS_VNODE(ap->a_vp); 2484 2485 error = EROFS; 2486 unp = VTOUNIONFS(ap->a_vp); 2487 uvp = unp->un_uppervp; 2488 lvp = unp->un_lowervp; 2489 td = ap->a_td; 2490 2491 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2492 return (EROFS); 2493 2494 if (uvp == NULLVP && lvp->v_type == VREG) { 2495 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2496 return (error); 2497 uvp = unp->un_uppervp; 2498 } 2499 2500 if (uvp != NULLVP) 2501 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2502 2503 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 2504 2505 return (error); 2506 } 2507 2508 static int 2509 unionfs_vptofh(struct vop_vptofh_args *ap) 2510 { 2511 return (EOPNOTSUPP); 2512 } 2513 2514 struct vop_vector unionfs_vnodeops = { 2515 .vop_default = &default_vnodeops, 2516 2517 .vop_access = unionfs_access, 2518 .vop_aclcheck = unionfs_aclcheck, 2519 .vop_advlock = unionfs_advlock, 2520 .vop_bmap = VOP_EOPNOTSUPP, 2521 .vop_cachedlookup = unionfs_lookup, 2522 .vop_close = unionfs_close, 2523 .vop_closeextattr = unionfs_closeextattr, 2524 .vop_create = unionfs_create, 2525 .vop_deleteextattr = unionfs_deleteextattr, 2526 .vop_fsync = unionfs_fsync, 2527 .vop_getacl = unionfs_getacl, 2528 .vop_getattr = unionfs_getattr, 2529 .vop_getextattr = unionfs_getextattr, 2530 .vop_getwritemount = unionfs_getwritemount, 2531 .vop_inactive = unionfs_inactive, 2532 .vop_islocked = unionfs_islocked, 2533 .vop_ioctl = unionfs_ioctl, 2534 .vop_link = unionfs_link, 2535 .vop_listextattr = unionfs_listextattr, 2536 .vop_lock1 = unionfs_lock, 2537 .vop_lookup = vfs_cache_lookup, 2538 .vop_mkdir = unionfs_mkdir, 2539 .vop_mknod = unionfs_mknod, 2540 .vop_open = unionfs_open, 2541 .vop_openextattr = unionfs_openextattr, 2542 .vop_pathconf = unionfs_pathconf, 2543 .vop_poll = unionfs_poll, 2544 .vop_print = unionfs_print, 2545 .vop_read = unionfs_read, 2546 .vop_readdir = unionfs_readdir, 2547 .vop_readlink = unionfs_readlink, 2548 .vop_reclaim = unionfs_reclaim, 2549 .vop_remove = unionfs_remove, 2550 .vop_rename = unionfs_rename, 2551 .vop_rmdir = unionfs_rmdir, 2552 .vop_setacl = unionfs_setacl, 2553 .vop_setattr = unionfs_setattr, 2554 .vop_setextattr = unionfs_setextattr, 2555 .vop_setlabel = unionfs_setlabel, 2556 .vop_strategy = unionfs_strategy, 2557 .vop_symlink = unionfs_symlink, 2558 .vop_unlock = unionfs_unlock, 2559 .vop_whiteout = unionfs_whiteout, 2560 .vop_write = unionfs_write, 2561 .vop_vptofh = unionfs_vptofh, 2562 }; 2563