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