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 int count; 635 uid_t uid; /* upper side vnode's uid */ 636 gid_t gid; /* upper side vnode's gid */ 637 u_short vmode; /* upper side vnode's mode */ 638 u_short mask; 639 640 mask = 0; 641 uid = va->va_uid; 642 gid = va->va_gid; 643 vmode = va->va_mode; 644 645 /* check owner */ 646 if (cred->cr_uid == uid) { 647 if (accmode & VEXEC) 648 mask |= S_IXUSR; 649 if (accmode & VREAD) 650 mask |= S_IRUSR; 651 if (accmode & VWRITE) 652 mask |= S_IWUSR; 653 return ((vmode & mask) == mask ? 0 : EACCES); 654 } 655 656 /* check group */ 657 count = 0; 658 if (groupmember(gid, cred)) { 659 if (accmode & VEXEC) 660 mask |= S_IXGRP; 661 if (accmode & VREAD) 662 mask |= S_IRGRP; 663 if (accmode & VWRITE) 664 mask |= S_IWGRP; 665 return ((vmode & mask) == mask ? 0 : EACCES); 666 } 667 668 /* check other */ 669 if (accmode & VEXEC) 670 mask |= S_IXOTH; 671 if (accmode & VREAD) 672 mask |= S_IROTH; 673 if (accmode & VWRITE) 674 mask |= S_IWOTH; 675 676 return ((vmode & mask) == mask ? 0 : EACCES); 677 } 678 679 static int 680 unionfs_access(struct vop_access_args *ap) 681 { 682 struct unionfs_mount *ump; 683 struct unionfs_node *unp; 684 struct vnode *uvp; 685 struct vnode *lvp; 686 struct thread *td; 687 struct vattr va; 688 accmode_t accmode; 689 int error; 690 691 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 692 693 KASSERT_UNIONFS_VNODE(ap->a_vp); 694 695 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 696 unp = VTOUNIONFS(ap->a_vp); 697 uvp = unp->un_uppervp; 698 lvp = unp->un_lowervp; 699 td = ap->a_td; 700 accmode = ap->a_accmode; 701 error = EACCES; 702 703 if ((accmode & VWRITE) && 704 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 705 switch (ap->a_vp->v_type) { 706 case VREG: 707 case VDIR: 708 case VLNK: 709 return (EROFS); 710 default: 711 break; 712 } 713 } 714 715 if (uvp != NULLVP) { 716 error = VOP_ACCESS(uvp, accmode, ap->a_cred, td); 717 718 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 719 720 return (error); 721 } 722 723 if (lvp != NULLVP) { 724 if (accmode & VWRITE) { 725 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 726 switch (ap->a_vp->v_type) { 727 case VREG: 728 case VDIR: 729 case VLNK: 730 return (EROFS); 731 default: 732 break; 733 } 734 } else if (ap->a_vp->v_type == VREG || 735 ap->a_vp->v_type == VDIR) { 736 /* check shadow file/dir */ 737 if (ump->um_copymode != UNIONFS_TRANSPARENT) { 738 error = unionfs_create_uppervattr(ump, 739 lvp, &va, ap->a_cred, td); 740 if (error != 0) 741 return (error); 742 743 error = unionfs_check_corrected_access( 744 accmode, &va, ap->a_cred); 745 if (error != 0) 746 return (error); 747 } 748 } 749 accmode &= ~(VWRITE | VAPPEND); 750 accmode |= VREAD; /* will copy to upper */ 751 } 752 error = VOP_ACCESS(lvp, accmode, ap->a_cred, td); 753 } 754 755 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 756 757 return (error); 758 } 759 760 static int 761 unionfs_getattr(struct vop_getattr_args *ap) 762 { 763 struct unionfs_node *unp; 764 struct unionfs_mount *ump; 765 struct vnode *uvp; 766 struct vnode *lvp; 767 struct thread *td; 768 struct vattr va; 769 int error; 770 771 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 772 773 KASSERT_UNIONFS_VNODE(ap->a_vp); 774 775 unp = VTOUNIONFS(ap->a_vp); 776 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 777 uvp = unp->un_uppervp; 778 lvp = unp->un_lowervp; 779 td = curthread; 780 781 if (uvp != NULLVP) { 782 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 783 ap->a_vap->va_fsid = 784 ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 785 786 UNIONFS_INTERNAL_DEBUG( 787 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 788 ap->a_vap->va_mode, ap->a_vap->va_uid, 789 ap->a_vap->va_gid, error); 790 791 return (error); 792 } 793 794 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 795 796 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 797 /* correct the attr toward shadow file/dir. */ 798 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 799 unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); 800 ap->a_vap->va_mode = va.va_mode; 801 ap->a_vap->va_uid = va.va_uid; 802 ap->a_vap->va_gid = va.va_gid; 803 } 804 } 805 806 if (error == 0) 807 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 808 809 UNIONFS_INTERNAL_DEBUG( 810 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 811 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 812 813 return (error); 814 } 815 816 static int 817 unionfs_setattr(struct vop_setattr_args *ap) 818 { 819 struct unionfs_node *unp; 820 struct vnode *uvp; 821 struct vnode *lvp; 822 struct thread *td; 823 struct vattr *vap; 824 int error; 825 826 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 827 828 KASSERT_UNIONFS_VNODE(ap->a_vp); 829 830 error = EROFS; 831 unp = VTOUNIONFS(ap->a_vp); 832 uvp = unp->un_uppervp; 833 lvp = unp->un_lowervp; 834 td = curthread; 835 vap = ap->a_vap; 836 837 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 838 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 839 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 840 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 841 return (EROFS); 842 843 if (uvp == NULLVP && lvp->v_type == VREG) { 844 error = unionfs_copyfile(unp, (vap->va_size != 0), 845 ap->a_cred, td); 846 if (error != 0) 847 return (error); 848 uvp = unp->un_uppervp; 849 } 850 851 if (uvp != NULLVP) 852 error = VOP_SETATTR(uvp, vap, ap->a_cred); 853 854 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 855 856 return (error); 857 } 858 859 static int 860 unionfs_read(struct vop_read_args *ap) 861 { 862 struct unionfs_node *unp; 863 struct vnode *tvp; 864 int error; 865 866 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 867 868 KASSERT_UNIONFS_VNODE(ap->a_vp); 869 870 unp = VTOUNIONFS(ap->a_vp); 871 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 872 873 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 874 875 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 876 877 return (error); 878 } 879 880 static int 881 unionfs_write(struct vop_write_args *ap) 882 { 883 struct unionfs_node *unp; 884 struct vnode *tvp; 885 int error; 886 887 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 888 889 KASSERT_UNIONFS_VNODE(ap->a_vp); 890 891 unp = VTOUNIONFS(ap->a_vp); 892 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 893 894 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 895 896 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 897 898 return (error); 899 } 900 901 static int 902 unionfs_ioctl(struct vop_ioctl_args *ap) 903 { 904 struct unionfs_node *unp; 905 struct unionfs_node_status *unsp; 906 struct vnode *ovp; 907 int error; 908 909 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 910 911 KASSERT_UNIONFS_VNODE(ap->a_vp); 912 913 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 914 unp = VTOUNIONFS(ap->a_vp); 915 unionfs_get_node_status(unp, ap->a_td, &unsp); 916 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 917 unionfs_tryrem_node_status(unp, unsp); 918 VOP_UNLOCK(ap->a_vp); 919 920 if (ovp == NULLVP) 921 return (EBADF); 922 923 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 924 ap->a_cred, ap->a_td); 925 926 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error); 927 928 return (error); 929 } 930 931 static int 932 unionfs_poll(struct vop_poll_args *ap) 933 { 934 struct unionfs_node *unp; 935 struct unionfs_node_status *unsp; 936 struct vnode *ovp; 937 938 KASSERT_UNIONFS_VNODE(ap->a_vp); 939 940 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 941 unp = VTOUNIONFS(ap->a_vp); 942 unionfs_get_node_status(unp, ap->a_td, &unsp); 943 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 944 unionfs_tryrem_node_status(unp, unsp); 945 VOP_UNLOCK(ap->a_vp); 946 947 if (ovp == NULLVP) 948 return (EBADF); 949 950 return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td)); 951 } 952 953 static int 954 unionfs_fsync(struct vop_fsync_args *ap) 955 { 956 struct unionfs_node *unp; 957 struct unionfs_node_status *unsp; 958 struct vnode *ovp; 959 960 KASSERT_UNIONFS_VNODE(ap->a_vp); 961 962 unp = VTOUNIONFS(ap->a_vp); 963 unionfs_get_node_status(unp, ap->a_td, &unsp); 964 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 965 unionfs_tryrem_node_status(unp, unsp); 966 967 if (ovp == NULLVP) 968 return (EBADF); 969 970 return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td)); 971 } 972 973 static int 974 unionfs_remove(struct vop_remove_args *ap) 975 { 976 char *path; 977 struct unionfs_node *dunp; 978 struct unionfs_node *unp; 979 struct unionfs_mount *ump; 980 struct vnode *udvp; 981 struct vnode *uvp; 982 struct vnode *lvp; 983 struct vnode *vp; 984 struct componentname *cnp; 985 struct componentname cn; 986 struct thread *td; 987 int error; 988 int pathlen; 989 990 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 991 992 KASSERT_UNIONFS_VNODE(ap->a_dvp); 993 994 error = 0; 995 dunp = VTOUNIONFS(ap->a_dvp); 996 udvp = dunp->un_uppervp; 997 cnp = ap->a_cnp; 998 td = curthread; 999 1000 if (ap->a_vp->v_op != &unionfs_vnodeops) { 1001 if (ap->a_vp->v_type != VSOCK) 1002 return (EINVAL); 1003 ump = NULL; 1004 vp = uvp = lvp = NULLVP; 1005 /* search vnode */ 1006 VOP_UNLOCK(ap->a_vp); 1007 error = unionfs_relookup(udvp, &vp, cnp, &cn, td, 1008 cnp->cn_nameptr, cnp->cn_namelen, DELETE); 1009 if (error != 0 && error != ENOENT) { 1010 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 1011 return (error); 1012 } 1013 1014 if (error == 0 && vp == ap->a_vp) { 1015 /* target vnode in upper */ 1016 uvp = vp; 1017 vrele(vp); 1018 } else { 1019 /* target vnode in lower */ 1020 if (vp != NULLVP) { 1021 if (udvp == vp) 1022 vrele(vp); 1023 else 1024 vput(vp); 1025 } 1026 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 1027 lvp = ap->a_vp; 1028 } 1029 path = cnp->cn_nameptr; 1030 pathlen = cnp->cn_namelen; 1031 } else { 1032 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 1033 unp = VTOUNIONFS(ap->a_vp); 1034 uvp = unp->un_uppervp; 1035 lvp = unp->un_lowervp; 1036 path = unp->un_path; 1037 pathlen = unp->un_pathlen; 1038 } 1039 1040 if (udvp == NULLVP) 1041 return (EROFS); 1042 1043 if (uvp != NULLVP) { 1044 /* 1045 * XXX: if the vnode type is VSOCK, it will create whiteout 1046 * after remove. 1047 */ 1048 if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS || 1049 lvp != NULLVP) 1050 cnp->cn_flags |= DOWHITEOUT; 1051 error = VOP_REMOVE(udvp, uvp, cnp); 1052 } else if (lvp != NULLVP) 1053 error = unionfs_mkwhiteout(udvp, cnp, td, path, pathlen); 1054 1055 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 1056 1057 return (error); 1058 } 1059 1060 static int 1061 unionfs_link(struct vop_link_args *ap) 1062 { 1063 struct unionfs_node *dunp; 1064 struct unionfs_node *unp; 1065 struct vnode *udvp; 1066 struct vnode *uvp; 1067 struct componentname *cnp; 1068 struct thread *td; 1069 int error; 1070 int needrelookup; 1071 1072 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 1073 1074 KASSERT_UNIONFS_VNODE(ap->a_tdvp); 1075 KASSERT_UNIONFS_VNODE(ap->a_vp); 1076 1077 error = 0; 1078 needrelookup = 0; 1079 dunp = VTOUNIONFS(ap->a_tdvp); 1080 unp = NULL; 1081 udvp = dunp->un_uppervp; 1082 uvp = NULLVP; 1083 cnp = ap->a_cnp; 1084 td = curthread; 1085 1086 if (udvp == NULLVP) 1087 return (EROFS); 1088 1089 if (ap->a_vp->v_op != &unionfs_vnodeops) 1090 uvp = ap->a_vp; 1091 else { 1092 unp = VTOUNIONFS(ap->a_vp); 1093 1094 if (unp->un_uppervp == NULLVP) { 1095 if (ap->a_vp->v_type != VREG) 1096 return (EOPNOTSUPP); 1097 1098 error = unionfs_copyfile(unp, 1, cnp->cn_cred, td); 1099 if (error != 0) 1100 return (error); 1101 needrelookup = 1; 1102 } 1103 uvp = unp->un_uppervp; 1104 } 1105 1106 if (needrelookup != 0) 1107 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td); 1108 1109 if (error == 0) 1110 error = VOP_LINK(udvp, uvp, cnp); 1111 1112 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 1113 1114 return (error); 1115 } 1116 1117 static int 1118 unionfs_rename(struct vop_rename_args *ap) 1119 { 1120 struct vnode *fdvp; 1121 struct vnode *fvp; 1122 struct componentname *fcnp; 1123 struct vnode *tdvp; 1124 struct vnode *tvp; 1125 struct componentname *tcnp; 1126 struct vnode *ltdvp; 1127 struct vnode *ltvp; 1128 struct thread *td; 1129 1130 /* rename target vnodes */ 1131 struct vnode *rfdvp; 1132 struct vnode *rfvp; 1133 struct vnode *rtdvp; 1134 struct vnode *rtvp; 1135 1136 struct unionfs_mount *ump; 1137 struct unionfs_node *unp; 1138 int error; 1139 int needrelookup; 1140 1141 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 1142 1143 error = 0; 1144 fdvp = ap->a_fdvp; 1145 fvp = ap->a_fvp; 1146 fcnp = ap->a_fcnp; 1147 tdvp = ap->a_tdvp; 1148 tvp = ap->a_tvp; 1149 tcnp = ap->a_tcnp; 1150 ltdvp = NULLVP; 1151 ltvp = NULLVP; 1152 td = curthread; 1153 rfdvp = fdvp; 1154 rfvp = fvp; 1155 rtdvp = tdvp; 1156 rtvp = tvp; 1157 needrelookup = 0; 1158 1159 #ifdef DIAGNOSTIC 1160 if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1161 panic("unionfs_rename: no name"); 1162 #endif 1163 1164 /* check for cross device rename */ 1165 if (fvp->v_mount != tdvp->v_mount || 1166 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 1167 if (fvp->v_op != &unionfs_vnodeops) 1168 error = ENODEV; 1169 else 1170 error = EXDEV; 1171 goto unionfs_rename_abort; 1172 } 1173 1174 /* Renaming a file to itself has no effect. */ 1175 if (fvp == tvp) 1176 goto unionfs_rename_abort; 1177 1178 /* 1179 * from/to vnode is unionfs node. 1180 */ 1181 1182 KASSERT_UNIONFS_VNODE(fdvp); 1183 KASSERT_UNIONFS_VNODE(fvp); 1184 KASSERT_UNIONFS_VNODE(tdvp); 1185 if (tvp != NULLVP) 1186 KASSERT_UNIONFS_VNODE(tvp); 1187 1188 unp = VTOUNIONFS(fdvp); 1189 #ifdef UNIONFS_IDBG_RENAME 1190 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", 1191 fdvp, unp->un_uppervp, unp->un_lowervp); 1192 #endif 1193 if (unp->un_uppervp == NULLVP) { 1194 error = ENODEV; 1195 goto unionfs_rename_abort; 1196 } 1197 rfdvp = unp->un_uppervp; 1198 vref(rfdvp); 1199 1200 unp = VTOUNIONFS(fvp); 1201 #ifdef UNIONFS_IDBG_RENAME 1202 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", 1203 fvp, unp->un_uppervp, unp->un_lowervp); 1204 #endif 1205 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1206 if (unp->un_uppervp == NULLVP) { 1207 switch (fvp->v_type) { 1208 case VREG: 1209 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1210 goto unionfs_rename_abort; 1211 error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td); 1212 VOP_UNLOCK(fvp); 1213 if (error != 0) 1214 goto unionfs_rename_abort; 1215 break; 1216 case VDIR: 1217 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1218 goto unionfs_rename_abort; 1219 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td); 1220 VOP_UNLOCK(fvp); 1221 if (error != 0) 1222 goto unionfs_rename_abort; 1223 break; 1224 default: 1225 error = ENODEV; 1226 goto unionfs_rename_abort; 1227 } 1228 1229 needrelookup = 1; 1230 } 1231 1232 if (unp->un_lowervp != NULLVP) 1233 fcnp->cn_flags |= DOWHITEOUT; 1234 rfvp = unp->un_uppervp; 1235 vref(rfvp); 1236 1237 unp = VTOUNIONFS(tdvp); 1238 #ifdef UNIONFS_IDBG_RENAME 1239 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", 1240 tdvp, unp->un_uppervp, unp->un_lowervp); 1241 #endif 1242 if (unp->un_uppervp == NULLVP) { 1243 error = ENODEV; 1244 goto unionfs_rename_abort; 1245 } 1246 rtdvp = unp->un_uppervp; 1247 ltdvp = unp->un_lowervp; 1248 vref(rtdvp); 1249 1250 if (tdvp == tvp) { 1251 rtvp = rtdvp; 1252 vref(rtvp); 1253 } else if (tvp != NULLVP) { 1254 unp = VTOUNIONFS(tvp); 1255 #ifdef UNIONFS_IDBG_RENAME 1256 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", 1257 tvp, unp->un_uppervp, unp->un_lowervp); 1258 #endif 1259 if (unp->un_uppervp == NULLVP) 1260 rtvp = NULLVP; 1261 else { 1262 if (tvp->v_type == VDIR) { 1263 error = EINVAL; 1264 goto unionfs_rename_abort; 1265 } 1266 rtvp = unp->un_uppervp; 1267 ltvp = unp->un_lowervp; 1268 vref(rtvp); 1269 } 1270 } 1271 1272 if (rfvp == rtvp) 1273 goto unionfs_rename_abort; 1274 1275 if (needrelookup != 0) { 1276 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1277 goto unionfs_rename_abort; 1278 error = unionfs_relookup_for_delete(fdvp, fcnp, td); 1279 VOP_UNLOCK(fdvp); 1280 if (error != 0) 1281 goto unionfs_rename_abort; 1282 1283 /* Lock of tvp is canceled in order to avoid recursive lock. */ 1284 if (tvp != NULLVP && tvp != tdvp) 1285 VOP_UNLOCK(tvp); 1286 error = unionfs_relookup_for_rename(tdvp, tcnp, td); 1287 if (tvp != NULLVP && tvp != tdvp) 1288 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1289 if (error != 0) 1290 goto unionfs_rename_abort; 1291 } 1292 1293 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 1294 1295 if (error == 0) { 1296 if (rtvp != NULLVP && rtvp->v_type == VDIR) 1297 cache_purge(tdvp); 1298 if (fvp->v_type == VDIR && fdvp != tdvp) 1299 cache_purge(fdvp); 1300 } 1301 1302 if (ltdvp != NULLVP) 1303 VOP_UNLOCK(ltdvp); 1304 if (tdvp != rtdvp) 1305 vrele(tdvp); 1306 if (ltvp != NULLVP) 1307 VOP_UNLOCK(ltvp); 1308 if (tvp != rtvp && tvp != NULLVP) { 1309 if (rtvp == NULLVP) 1310 vput(tvp); 1311 else 1312 vrele(tvp); 1313 } 1314 if (fdvp != rfdvp) 1315 vrele(fdvp); 1316 if (fvp != rfvp) 1317 vrele(fvp); 1318 1319 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1320 1321 return (error); 1322 1323 unionfs_rename_abort: 1324 vput(tdvp); 1325 if (tdvp != rtdvp) 1326 vrele(rtdvp); 1327 if (tvp != NULLVP) { 1328 if (tdvp != tvp) 1329 vput(tvp); 1330 else 1331 vrele(tvp); 1332 } 1333 if (tvp != rtvp && rtvp != NULLVP) 1334 vrele(rtvp); 1335 if (fdvp != rfdvp) 1336 vrele(rfdvp); 1337 if (fvp != rfvp) 1338 vrele(rfvp); 1339 vrele(fdvp); 1340 vrele(fvp); 1341 1342 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1343 1344 return (error); 1345 } 1346 1347 static int 1348 unionfs_mkdir(struct vop_mkdir_args *ap) 1349 { 1350 struct unionfs_node *dunp; 1351 struct componentname *cnp; 1352 struct thread *td; 1353 struct vnode *udvp; 1354 struct vnode *uvp; 1355 struct vattr va; 1356 int error; 1357 int lkflags; 1358 1359 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1360 1361 KASSERT_UNIONFS_VNODE(ap->a_dvp); 1362 1363 error = EROFS; 1364 dunp = VTOUNIONFS(ap->a_dvp); 1365 cnp = ap->a_cnp; 1366 lkflags = cnp->cn_lkflags; 1367 td = curthread; 1368 udvp = dunp->un_uppervp; 1369 1370 if (udvp != NULLVP) { 1371 /* check opaque */ 1372 if (!(cnp->cn_flags & ISWHITEOUT)) { 1373 error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1374 if (error != 0) 1375 return (error); 1376 if ((va.va_flags & OPAQUE) != 0) 1377 cnp->cn_flags |= ISWHITEOUT; 1378 } 1379 1380 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1381 VOP_UNLOCK(uvp); 1382 cnp->cn_lkflags = LK_EXCLUSIVE; 1383 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1384 ap->a_dvp, ap->a_vpp, cnp, td); 1385 cnp->cn_lkflags = lkflags; 1386 vrele(uvp); 1387 } 1388 } 1389 1390 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1391 1392 return (error); 1393 } 1394 1395 static int 1396 unionfs_rmdir(struct vop_rmdir_args *ap) 1397 { 1398 struct unionfs_node *dunp; 1399 struct unionfs_node *unp; 1400 struct unionfs_mount *ump; 1401 struct componentname *cnp; 1402 struct thread *td; 1403 struct vnode *udvp; 1404 struct vnode *uvp; 1405 struct vnode *lvp; 1406 int error; 1407 1408 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1409 1410 KASSERT_UNIONFS_VNODE(ap->a_dvp); 1411 KASSERT_UNIONFS_VNODE(ap->a_vp); 1412 1413 error = 0; 1414 dunp = VTOUNIONFS(ap->a_dvp); 1415 unp = VTOUNIONFS(ap->a_vp); 1416 cnp = ap->a_cnp; 1417 td = curthread; 1418 udvp = dunp->un_uppervp; 1419 uvp = unp->un_uppervp; 1420 lvp = unp->un_lowervp; 1421 1422 if (udvp == NULLVP) 1423 return (EROFS); 1424 1425 if (udvp == uvp) 1426 return (EOPNOTSUPP); 1427 1428 if (uvp != NULLVP) { 1429 if (lvp != NULLVP) { 1430 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td); 1431 if (error != 0) 1432 return (error); 1433 } 1434 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 1435 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1436 cnp->cn_flags |= DOWHITEOUT; 1437 error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td); 1438 if (error == 0) 1439 error = VOP_RMDIR(udvp, uvp, cnp); 1440 } 1441 else if (lvp != NULLVP) 1442 error = unionfs_mkwhiteout(udvp, cnp, td, 1443 unp->un_path, unp->un_pathlen); 1444 1445 if (error == 0) { 1446 cache_purge(ap->a_dvp); 1447 cache_purge(ap->a_vp); 1448 } 1449 1450 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1451 1452 return (error); 1453 } 1454 1455 static int 1456 unionfs_symlink(struct vop_symlink_args *ap) 1457 { 1458 struct unionfs_node *dunp; 1459 struct componentname *cnp; 1460 struct thread *td; 1461 struct vnode *udvp; 1462 struct vnode *uvp; 1463 int error; 1464 int lkflags; 1465 1466 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1467 1468 KASSERT_UNIONFS_VNODE(ap->a_dvp); 1469 1470 error = EROFS; 1471 dunp = VTOUNIONFS(ap->a_dvp); 1472 cnp = ap->a_cnp; 1473 lkflags = cnp->cn_lkflags; 1474 td = curthread; 1475 udvp = dunp->un_uppervp; 1476 1477 if (udvp != NULLVP) { 1478 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1479 if (error == 0) { 1480 VOP_UNLOCK(uvp); 1481 cnp->cn_lkflags = LK_EXCLUSIVE; 1482 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1483 ap->a_dvp, ap->a_vpp, cnp, td); 1484 cnp->cn_lkflags = lkflags; 1485 vrele(uvp); 1486 } 1487 } 1488 1489 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1490 1491 return (error); 1492 } 1493 1494 static int 1495 unionfs_readdir(struct vop_readdir_args *ap) 1496 { 1497 struct unionfs_node *unp; 1498 struct unionfs_node_status *unsp; 1499 struct uio *uio; 1500 struct vnode *vp; 1501 struct vnode *uvp; 1502 struct vnode *lvp; 1503 struct thread *td; 1504 struct vattr va; 1505 1506 u_long *cookies_bk; 1507 int error; 1508 int eofflag; 1509 int locked; 1510 int ncookies_bk; 1511 int uio_offset_bk; 1512 1513 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1514 1515 KASSERT_UNIONFS_VNODE(ap->a_vp); 1516 1517 error = 0; 1518 eofflag = 0; 1519 locked = 0; 1520 uio_offset_bk = 0; 1521 uio = ap->a_uio; 1522 uvp = NULLVP; 1523 lvp = NULLVP; 1524 td = uio->uio_td; 1525 ncookies_bk = 0; 1526 cookies_bk = NULL; 1527 1528 vp = ap->a_vp; 1529 if (vp->v_type != VDIR) 1530 return (ENOTDIR); 1531 1532 /* check the open count. unionfs needs to open before readdir. */ 1533 if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { 1534 if (vn_lock(vp, LK_UPGRADE) != 0) 1535 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1536 locked = 1; 1537 } 1538 unp = VTOUNIONFS(vp); 1539 if (unp == NULL) 1540 error = EBADF; 1541 else { 1542 uvp = unp->un_uppervp; 1543 lvp = unp->un_lowervp; 1544 unionfs_get_node_status(unp, td, &unsp); 1545 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 1546 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1547 unionfs_tryrem_node_status(unp, unsp); 1548 error = EBADF; 1549 } 1550 } 1551 if (locked) 1552 vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 1553 if (error != 0) 1554 goto unionfs_readdir_exit; 1555 1556 /* check opaque */ 1557 if (uvp != NULLVP && lvp != NULLVP) { 1558 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 1559 goto unionfs_readdir_exit; 1560 if (va.va_flags & OPAQUE) 1561 lvp = NULLVP; 1562 } 1563 1564 /* upper only */ 1565 if (uvp != NULLVP && lvp == NULLVP) { 1566 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1567 ap->a_ncookies, ap->a_cookies); 1568 unsp->uns_readdir_status = 0; 1569 1570 goto unionfs_readdir_exit; 1571 } 1572 1573 /* lower only */ 1574 if (uvp == NULLVP && lvp != NULLVP) { 1575 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1576 ap->a_ncookies, ap->a_cookies); 1577 unsp->uns_readdir_status = 2; 1578 1579 goto unionfs_readdir_exit; 1580 } 1581 1582 /* 1583 * readdir upper and lower 1584 */ 1585 KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp")); 1586 KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp")); 1587 if (uio->uio_offset == 0) 1588 unsp->uns_readdir_status = 0; 1589 1590 if (unsp->uns_readdir_status == 0) { 1591 /* read upper */ 1592 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1593 ap->a_ncookies, ap->a_cookies); 1594 1595 if (error != 0 || eofflag == 0) 1596 goto unionfs_readdir_exit; 1597 unsp->uns_readdir_status = 1; 1598 1599 /* 1600 * UFS(and other FS) needs size of uio_resid larger than 1601 * DIRBLKSIZ. 1602 * size of DIRBLKSIZ equals DEV_BSIZE. 1603 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1604 */ 1605 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 1606 goto unionfs_readdir_exit; 1607 1608 /* 1609 * Backup cookies. 1610 * It prepares to readdir in lower. 1611 */ 1612 if (ap->a_ncookies != NULL) { 1613 ncookies_bk = *(ap->a_ncookies); 1614 *(ap->a_ncookies) = 0; 1615 } 1616 if (ap->a_cookies != NULL) { 1617 cookies_bk = *(ap->a_cookies); 1618 *(ap->a_cookies) = NULL; 1619 } 1620 } 1621 1622 /* initialize for readdir in lower */ 1623 if (unsp->uns_readdir_status == 1) { 1624 unsp->uns_readdir_status = 2; 1625 /* 1626 * Backup uio_offset. See the comment after the 1627 * VOP_READDIR call on the lower layer. 1628 */ 1629 uio_offset_bk = uio->uio_offset; 1630 uio->uio_offset = 0; 1631 } 1632 1633 if (lvp == NULLVP) { 1634 error = EBADF; 1635 goto unionfs_readdir_exit; 1636 } 1637 /* read lower */ 1638 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1639 ap->a_ncookies, ap->a_cookies); 1640 1641 /* 1642 * We can't return an uio_offset of 0: this would trigger an 1643 * infinite loop, because the next call to unionfs_readdir would 1644 * always restart with the upper layer (uio_offset == 0) and 1645 * always return some data. 1646 * 1647 * This happens when the lower layer root directory is removed. 1648 * (A root directory deleting of unionfs should not be permitted. 1649 * But current VFS can not do it.) 1650 */ 1651 if (uio->uio_offset == 0) 1652 uio->uio_offset = uio_offset_bk; 1653 1654 if (cookies_bk != NULL) { 1655 /* merge cookies */ 1656 int size; 1657 u_long *newcookies, *pos; 1658 1659 size = *(ap->a_ncookies) + ncookies_bk; 1660 newcookies = (u_long *) malloc(size * sizeof(u_long), 1661 M_TEMP, M_WAITOK); 1662 pos = newcookies; 1663 1664 memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long)); 1665 pos += ncookies_bk; 1666 memcpy(pos, *(ap->a_cookies), 1667 *(ap->a_ncookies) * sizeof(u_long)); 1668 free(cookies_bk, M_TEMP); 1669 free(*(ap->a_cookies), M_TEMP); 1670 *(ap->a_ncookies) = size; 1671 *(ap->a_cookies) = newcookies; 1672 } 1673 1674 unionfs_readdir_exit: 1675 if (error != 0 && ap->a_eofflag != NULL) 1676 *(ap->a_eofflag) = 1; 1677 1678 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1679 1680 return (error); 1681 } 1682 1683 static int 1684 unionfs_readlink(struct vop_readlink_args *ap) 1685 { 1686 struct unionfs_node *unp; 1687 struct vnode *vp; 1688 int error; 1689 1690 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 1691 1692 KASSERT_UNIONFS_VNODE(ap->a_vp); 1693 1694 unp = VTOUNIONFS(ap->a_vp); 1695 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1696 1697 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1698 1699 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1700 1701 return (error); 1702 } 1703 1704 static int 1705 unionfs_getwritemount(struct vop_getwritemount_args *ap) 1706 { 1707 struct vnode *uvp; 1708 struct vnode *vp; 1709 int error; 1710 1711 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); 1712 1713 error = 0; 1714 vp = ap->a_vp; 1715 1716 if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) 1717 return (EACCES); 1718 1719 KASSERT_UNIONFS_VNODE(vp); 1720 1721 uvp = UNIONFSVPTOUPPERVP(vp); 1722 if (uvp == NULLVP && VREG == vp->v_type) 1723 uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); 1724 1725 if (uvp != NULLVP) 1726 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); 1727 else { 1728 VI_LOCK(vp); 1729 if (vp->v_holdcnt == 0) 1730 error = EOPNOTSUPP; 1731 else 1732 error = EACCES; 1733 VI_UNLOCK(vp); 1734 } 1735 1736 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error); 1737 1738 return (error); 1739 } 1740 1741 static int 1742 unionfs_inactive(struct vop_inactive_args *ap) 1743 { 1744 ap->a_vp->v_object = NULL; 1745 vrecycle(ap->a_vp); 1746 return (0); 1747 } 1748 1749 static int 1750 unionfs_reclaim(struct vop_reclaim_args *ap) 1751 { 1752 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1753 1754 unionfs_noderem(ap->a_vp, curthread); 1755 1756 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1757 1758 return (0); 1759 } 1760 1761 static int 1762 unionfs_print(struct vop_print_args *ap) 1763 { 1764 struct unionfs_node *unp; 1765 /* struct unionfs_node_status *unsp; */ 1766 1767 unp = VTOUNIONFS(ap->a_vp); 1768 /* unionfs_get_node_status(unp, curthread, &unsp); */ 1769 1770 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1771 ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1772 /* 1773 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1774 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1775 */ 1776 1777 if (unp->un_uppervp != NULLVP) 1778 vn_printf(unp->un_uppervp, "unionfs: upper "); 1779 if (unp->un_lowervp != NULLVP) 1780 vn_printf(unp->un_lowervp, "unionfs: lower "); 1781 1782 return (0); 1783 } 1784 1785 static int 1786 unionfs_islocked(struct vop_islocked_args *ap) 1787 { 1788 struct unionfs_node *unp; 1789 1790 KASSERT_UNIONFS_VNODE(ap->a_vp); 1791 1792 unp = VTOUNIONFS(ap->a_vp); 1793 if (unp == NULL) 1794 return (vop_stdislocked(ap)); 1795 1796 if (unp->un_uppervp != NULLVP) 1797 return (VOP_ISLOCKED(unp->un_uppervp)); 1798 if (unp->un_lowervp != NULLVP) 1799 return (VOP_ISLOCKED(unp->un_lowervp)); 1800 return (vop_stdislocked(ap)); 1801 } 1802 1803 static int 1804 unionfs_get_llt_revlock(struct vnode *vp, int flags) 1805 { 1806 int revlock; 1807 1808 revlock = 0; 1809 1810 switch (flags & LK_TYPE_MASK) { 1811 case LK_SHARED: 1812 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) 1813 revlock = LK_UPGRADE; 1814 else 1815 revlock = LK_RELEASE; 1816 break; 1817 case LK_EXCLUSIVE: 1818 case LK_UPGRADE: 1819 revlock = LK_RELEASE; 1820 break; 1821 case LK_DOWNGRADE: 1822 revlock = LK_UPGRADE; 1823 break; 1824 default: 1825 break; 1826 } 1827 1828 return (revlock); 1829 } 1830 1831 /* 1832 * The state of an acquired lock is adjusted similarly to 1833 * the time of error generating. 1834 * flags: LK_RELEASE or LK_UPGRADE 1835 */ 1836 static void 1837 unionfs_revlock(struct vnode *vp, int flags) 1838 { 1839 if (flags & LK_RELEASE) 1840 VOP_UNLOCK_FLAGS(vp, flags); 1841 else { 1842 /* UPGRADE */ 1843 if (vn_lock(vp, flags) != 0) 1844 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1845 } 1846 } 1847 1848 static int 1849 unionfs_lock(struct vop_lock1_args *ap) 1850 { 1851 struct mount *mp; 1852 struct unionfs_mount *ump; 1853 struct unionfs_node *unp; 1854 struct vnode *vp; 1855 struct vnode *uvp; 1856 struct vnode *lvp; 1857 int error; 1858 int flags; 1859 int revlock; 1860 int interlock; 1861 int uhold; 1862 1863 KASSERT_UNIONFS_VNODE(ap->a_vp); 1864 1865 error = 0; 1866 interlock = 1; 1867 uhold = 0; 1868 flags = ap->a_flags; 1869 vp = ap->a_vp; 1870 1871 if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK)) 1872 return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE)); 1873 1874 if ((flags & LK_INTERLOCK) == 0) 1875 VI_LOCK(vp); 1876 1877 mp = vp->v_mount; 1878 if (mp == NULL) 1879 goto unionfs_lock_null_vnode; 1880 1881 ump = MOUNTTOUNIONFSMOUNT(mp); 1882 unp = VTOUNIONFS(vp); 1883 if (ump == NULL || unp == NULL) 1884 goto unionfs_lock_null_vnode; 1885 lvp = unp->un_lowervp; 1886 uvp = unp->un_uppervp; 1887 1888 if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0) 1889 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); 1890 1891 if ((vp->v_iflag & VI_OWEINACT) != 0) 1892 flags |= LK_NOWAIT; 1893 1894 /* 1895 * Sometimes, lower or upper is already exclusive locked. 1896 * (ex. vfs_domount: mounted vnode is already locked.) 1897 */ 1898 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1899 vp == ump->um_rootvp) 1900 flags |= LK_CANRECURSE; 1901 1902 if (lvp != NULLVP) { 1903 if (uvp != NULLVP && flags & LK_UPGRADE) { 1904 /* 1905 * Share Lock is once released and a deadlock is 1906 * avoided. 1907 */ 1908 vholdnz(uvp); 1909 uhold = 1; 1910 VOP_UNLOCK(uvp); 1911 unp = VTOUNIONFS(vp); 1912 if (unp == NULL) { 1913 /* vnode is released. */ 1914 VI_UNLOCK(vp); 1915 VOP_UNLOCK(lvp); 1916 vdrop(uvp); 1917 return (EBUSY); 1918 } 1919 } 1920 VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1921 flags |= LK_INTERLOCK; 1922 vholdl(lvp); 1923 1924 VI_UNLOCK(vp); 1925 ap->a_flags &= ~LK_INTERLOCK; 1926 1927 error = VOP_LOCK(lvp, flags); 1928 1929 VI_LOCK(vp); 1930 unp = VTOUNIONFS(vp); 1931 if (unp == NULL) { 1932 /* vnode is released. */ 1933 VI_UNLOCK(vp); 1934 if (error == 0) 1935 VOP_UNLOCK(lvp); 1936 vdrop(lvp); 1937 if (uhold != 0) 1938 vdrop(uvp); 1939 return (vop_stdlock(ap)); 1940 } 1941 } 1942 1943 if (error == 0 && uvp != NULLVP) { 1944 if (uhold && flags & LK_UPGRADE) { 1945 flags &= ~LK_TYPE_MASK; 1946 flags |= LK_EXCLUSIVE; 1947 } 1948 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1949 flags |= LK_INTERLOCK; 1950 if (uhold == 0) { 1951 vholdl(uvp); 1952 uhold = 1; 1953 } 1954 1955 VI_UNLOCK(vp); 1956 ap->a_flags &= ~LK_INTERLOCK; 1957 1958 error = VOP_LOCK(uvp, flags); 1959 1960 VI_LOCK(vp); 1961 unp = VTOUNIONFS(vp); 1962 if (unp == NULL) { 1963 /* vnode is released. */ 1964 VI_UNLOCK(vp); 1965 if (error == 0) 1966 VOP_UNLOCK(uvp); 1967 vdrop(uvp); 1968 if (lvp != NULLVP) { 1969 VOP_UNLOCK(lvp); 1970 vdrop(lvp); 1971 } 1972 return (vop_stdlock(ap)); 1973 } 1974 if (error != 0 && lvp != NULLVP) { 1975 /* rollback */ 1976 VI_UNLOCK(vp); 1977 unionfs_revlock(lvp, revlock); 1978 interlock = 0; 1979 } 1980 } 1981 1982 if (interlock) 1983 VI_UNLOCK(vp); 1984 if (lvp != NULLVP) 1985 vdrop(lvp); 1986 if (uhold != 0) 1987 vdrop(uvp); 1988 1989 return (error); 1990 1991 unionfs_lock_null_vnode: 1992 ap->a_flags |= LK_INTERLOCK; 1993 return (vop_stdlock(ap)); 1994 } 1995 1996 static int 1997 unionfs_unlock(struct vop_unlock_args *ap) 1998 { 1999 struct vnode *vp; 2000 struct vnode *lvp; 2001 struct vnode *uvp; 2002 struct unionfs_node *unp; 2003 int error; 2004 int uhold; 2005 2006 KASSERT_UNIONFS_VNODE(ap->a_vp); 2007 2008 error = 0; 2009 uhold = 0; 2010 vp = ap->a_vp; 2011 2012 unp = VTOUNIONFS(vp); 2013 if (unp == NULL) 2014 goto unionfs_unlock_null_vnode; 2015 lvp = unp->un_lowervp; 2016 uvp = unp->un_uppervp; 2017 2018 if (lvp != NULLVP) { 2019 vholdnz(lvp); 2020 error = VOP_UNLOCK(lvp); 2021 } 2022 2023 if (error == 0 && uvp != NULLVP) { 2024 vholdnz(uvp); 2025 uhold = 1; 2026 error = VOP_UNLOCK(uvp); 2027 } 2028 2029 if (lvp != NULLVP) 2030 vdrop(lvp); 2031 if (uhold != 0) 2032 vdrop(uvp); 2033 2034 return error; 2035 2036 unionfs_unlock_null_vnode: 2037 return (vop_stdunlock(ap)); 2038 } 2039 2040 static int 2041 unionfs_pathconf(struct vop_pathconf_args *ap) 2042 { 2043 struct unionfs_node *unp; 2044 struct vnode *vp; 2045 2046 KASSERT_UNIONFS_VNODE(ap->a_vp); 2047 2048 unp = VTOUNIONFS(ap->a_vp); 2049 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2050 2051 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 2052 } 2053 2054 static int 2055 unionfs_advlock(struct vop_advlock_args *ap) 2056 { 2057 struct unionfs_node *unp; 2058 struct unionfs_node_status *unsp; 2059 struct vnode *vp; 2060 struct vnode *uvp; 2061 struct thread *td; 2062 int error; 2063 2064 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 2065 2066 KASSERT_UNIONFS_VNODE(ap->a_vp); 2067 2068 vp = ap->a_vp; 2069 td = curthread; 2070 2071 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2072 2073 unp = VTOUNIONFS(ap->a_vp); 2074 uvp = unp->un_uppervp; 2075 2076 if (uvp == NULLVP) { 2077 error = unionfs_copyfile(unp, 1, td->td_ucred, td); 2078 if (error != 0) 2079 goto unionfs_advlock_abort; 2080 uvp = unp->un_uppervp; 2081 2082 unionfs_get_node_status(unp, td, &unsp); 2083 if (unsp->uns_lower_opencnt > 0) { 2084 /* try reopen the vnode */ 2085 error = VOP_OPEN(uvp, unsp->uns_lower_openmode, 2086 td->td_ucred, td, NULL); 2087 if (error) 2088 goto unionfs_advlock_abort; 2089 unsp->uns_upper_opencnt++; 2090 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, 2091 td->td_ucred, td); 2092 unsp->uns_lower_opencnt--; 2093 } else 2094 unionfs_tryrem_node_status(unp, unsp); 2095 } 2096 2097 VOP_UNLOCK(vp); 2098 2099 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 2100 2101 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2102 2103 return error; 2104 2105 unionfs_advlock_abort: 2106 VOP_UNLOCK(vp); 2107 2108 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 2109 2110 return error; 2111 } 2112 2113 static int 2114 unionfs_strategy(struct vop_strategy_args *ap) 2115 { 2116 struct unionfs_node *unp; 2117 struct vnode *vp; 2118 2119 KASSERT_UNIONFS_VNODE(ap->a_vp); 2120 2121 unp = VTOUNIONFS(ap->a_vp); 2122 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2123 2124 #ifdef DIAGNOSTIC 2125 if (vp == NULLVP) 2126 panic("unionfs_strategy: nullvp"); 2127 2128 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 2129 panic("unionfs_strategy: writing to lowervp"); 2130 #endif 2131 2132 return (VOP_STRATEGY(vp, ap->a_bp)); 2133 } 2134 2135 static int 2136 unionfs_getacl(struct vop_getacl_args *ap) 2137 { 2138 struct unionfs_node *unp; 2139 struct vnode *vp; 2140 int error; 2141 2142 KASSERT_UNIONFS_VNODE(ap->a_vp); 2143 2144 unp = VTOUNIONFS(ap->a_vp); 2145 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2146 2147 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 2148 2149 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2150 2151 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 2152 2153 return (error); 2154 } 2155 2156 static int 2157 unionfs_setacl(struct vop_setacl_args *ap) 2158 { 2159 struct unionfs_node *unp; 2160 struct vnode *uvp; 2161 struct vnode *lvp; 2162 struct thread *td; 2163 int error; 2164 2165 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 2166 2167 KASSERT_UNIONFS_VNODE(ap->a_vp); 2168 2169 error = EROFS; 2170 unp = VTOUNIONFS(ap->a_vp); 2171 uvp = unp->un_uppervp; 2172 lvp = unp->un_lowervp; 2173 td = ap->a_td; 2174 2175 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2176 return (EROFS); 2177 2178 if (uvp == NULLVP && lvp->v_type == VREG) { 2179 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2180 return (error); 2181 uvp = unp->un_uppervp; 2182 } 2183 2184 if (uvp != NULLVP) 2185 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 2186 2187 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 2188 2189 return (error); 2190 } 2191 2192 static int 2193 unionfs_aclcheck(struct vop_aclcheck_args *ap) 2194 { 2195 struct unionfs_node *unp; 2196 struct vnode *vp; 2197 int error; 2198 2199 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 2200 2201 KASSERT_UNIONFS_VNODE(ap->a_vp); 2202 2203 unp = VTOUNIONFS(ap->a_vp); 2204 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2205 2206 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 2207 2208 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 2209 2210 return (error); 2211 } 2212 2213 static int 2214 unionfs_openextattr(struct vop_openextattr_args *ap) 2215 { 2216 struct unionfs_node *unp; 2217 struct vnode *vp; 2218 struct vnode *tvp; 2219 int error; 2220 2221 KASSERT_UNIONFS_VNODE(ap->a_vp); 2222 2223 vp = ap->a_vp; 2224 unp = VTOUNIONFS(vp); 2225 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 2226 2227 if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 2228 (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 2229 return (EBUSY); 2230 2231 error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td); 2232 2233 if (error == 0) { 2234 if (vn_lock(vp, LK_UPGRADE) != 0) 2235 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2236 if (tvp == unp->un_uppervp) 2237 unp->un_flag |= UNIONFS_OPENEXTU; 2238 else 2239 unp->un_flag |= UNIONFS_OPENEXTL; 2240 vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2241 } 2242 2243 return (error); 2244 } 2245 2246 static int 2247 unionfs_closeextattr(struct vop_closeextattr_args *ap) 2248 { 2249 struct unionfs_node *unp; 2250 struct vnode *vp; 2251 struct vnode *tvp; 2252 int error; 2253 2254 KASSERT_UNIONFS_VNODE(ap->a_vp); 2255 2256 vp = ap->a_vp; 2257 unp = VTOUNIONFS(vp); 2258 tvp = NULLVP; 2259 2260 if (unp->un_flag & UNIONFS_OPENEXTU) 2261 tvp = unp->un_uppervp; 2262 else if (unp->un_flag & UNIONFS_OPENEXTL) 2263 tvp = unp->un_lowervp; 2264 2265 if (tvp == NULLVP) 2266 return (EOPNOTSUPP); 2267 2268 error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td); 2269 2270 if (error == 0) { 2271 if (vn_lock(vp, LK_UPGRADE) != 0) 2272 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2273 if (tvp == unp->un_uppervp) 2274 unp->un_flag &= ~UNIONFS_OPENEXTU; 2275 else 2276 unp->un_flag &= ~UNIONFS_OPENEXTL; 2277 vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 2278 } 2279 2280 return (error); 2281 } 2282 2283 static int 2284 unionfs_getextattr(struct vop_getextattr_args *ap) 2285 { 2286 struct unionfs_node *unp; 2287 struct vnode *vp; 2288 2289 KASSERT_UNIONFS_VNODE(ap->a_vp); 2290 2291 unp = VTOUNIONFS(ap->a_vp); 2292 vp = NULLVP; 2293 2294 if (unp->un_flag & UNIONFS_OPENEXTU) 2295 vp = unp->un_uppervp; 2296 else if (unp->un_flag & UNIONFS_OPENEXTL) 2297 vp = unp->un_lowervp; 2298 2299 if (vp == NULLVP) 2300 return (EOPNOTSUPP); 2301 2302 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2303 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2304 } 2305 2306 static int 2307 unionfs_setextattr(struct vop_setextattr_args *ap) 2308 { 2309 struct unionfs_node *unp; 2310 struct vnode *uvp; 2311 struct vnode *lvp; 2312 struct vnode *ovp; 2313 struct ucred *cred; 2314 struct thread *td; 2315 int error; 2316 2317 KASSERT_UNIONFS_VNODE(ap->a_vp); 2318 2319 error = EROFS; 2320 unp = VTOUNIONFS(ap->a_vp); 2321 uvp = unp->un_uppervp; 2322 lvp = unp->un_lowervp; 2323 ovp = NULLVP; 2324 cred = ap->a_cred; 2325 td = ap->a_td; 2326 2327 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", 2328 unp->un_flag); 2329 2330 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2331 return (EROFS); 2332 2333 if (unp->un_flag & UNIONFS_OPENEXTU) 2334 ovp = unp->un_uppervp; 2335 else if (unp->un_flag & UNIONFS_OPENEXTL) 2336 ovp = unp->un_lowervp; 2337 2338 if (ovp == NULLVP) 2339 return (EOPNOTSUPP); 2340 2341 if (ovp == lvp && lvp->v_type == VREG) { 2342 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2343 if (uvp == NULLVP && 2344 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2345 unionfs_setextattr_reopen: 2346 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2347 VOP_OPENEXTATTR(lvp, cred, td)) { 2348 #ifdef DIAGNOSTIC 2349 panic("unionfs: VOP_OPENEXTATTR failed"); 2350 #endif 2351 unp->un_flag &= ~UNIONFS_OPENEXTL; 2352 } 2353 goto unionfs_setextattr_abort; 2354 } 2355 uvp = unp->un_uppervp; 2356 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2357 goto unionfs_setextattr_reopen; 2358 unp->un_flag &= ~UNIONFS_OPENEXTL; 2359 unp->un_flag |= UNIONFS_OPENEXTU; 2360 ovp = uvp; 2361 } 2362 2363 if (ovp == uvp) 2364 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2365 ap->a_uio, cred, td); 2366 2367 unionfs_setextattr_abort: 2368 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 2369 2370 return (error); 2371 } 2372 2373 static int 2374 unionfs_listextattr(struct vop_listextattr_args *ap) 2375 { 2376 struct unionfs_node *unp; 2377 struct vnode *vp; 2378 2379 KASSERT_UNIONFS_VNODE(ap->a_vp); 2380 2381 unp = VTOUNIONFS(ap->a_vp); 2382 vp = NULLVP; 2383 2384 if (unp->un_flag & UNIONFS_OPENEXTU) 2385 vp = unp->un_uppervp; 2386 else if (unp->un_flag & UNIONFS_OPENEXTL) 2387 vp = unp->un_lowervp; 2388 2389 if (vp == NULLVP) 2390 return (EOPNOTSUPP); 2391 2392 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2393 ap->a_size, ap->a_cred, ap->a_td)); 2394 } 2395 2396 static int 2397 unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2398 { 2399 struct unionfs_node *unp; 2400 struct vnode *uvp; 2401 struct vnode *lvp; 2402 struct vnode *ovp; 2403 struct ucred *cred; 2404 struct thread *td; 2405 int error; 2406 2407 KASSERT_UNIONFS_VNODE(ap->a_vp); 2408 2409 error = EROFS; 2410 unp = VTOUNIONFS(ap->a_vp); 2411 uvp = unp->un_uppervp; 2412 lvp = unp->un_lowervp; 2413 ovp = NULLVP; 2414 cred = ap->a_cred; 2415 td = ap->a_td; 2416 2417 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", 2418 unp->un_flag); 2419 2420 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2421 return (EROFS); 2422 2423 if (unp->un_flag & UNIONFS_OPENEXTU) 2424 ovp = unp->un_uppervp; 2425 else if (unp->un_flag & UNIONFS_OPENEXTL) 2426 ovp = unp->un_lowervp; 2427 2428 if (ovp == NULLVP) 2429 return (EOPNOTSUPP); 2430 2431 if (ovp == lvp && lvp->v_type == VREG) { 2432 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2433 if (uvp == NULLVP && 2434 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2435 unionfs_deleteextattr_reopen: 2436 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2437 VOP_OPENEXTATTR(lvp, cred, td)) { 2438 #ifdef DIAGNOSTIC 2439 panic("unionfs: VOP_OPENEXTATTR failed"); 2440 #endif 2441 unp->un_flag &= ~UNIONFS_OPENEXTL; 2442 } 2443 goto unionfs_deleteextattr_abort; 2444 } 2445 uvp = unp->un_uppervp; 2446 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2447 goto unionfs_deleteextattr_reopen; 2448 unp->un_flag &= ~UNIONFS_OPENEXTL; 2449 unp->un_flag |= UNIONFS_OPENEXTU; 2450 ovp = uvp; 2451 } 2452 2453 if (ovp == uvp) 2454 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2455 ap->a_cred, ap->a_td); 2456 2457 unionfs_deleteextattr_abort: 2458 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 2459 2460 return (error); 2461 } 2462 2463 static int 2464 unionfs_setlabel(struct vop_setlabel_args *ap) 2465 { 2466 struct unionfs_node *unp; 2467 struct vnode *uvp; 2468 struct vnode *lvp; 2469 struct thread *td; 2470 int error; 2471 2472 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2473 2474 KASSERT_UNIONFS_VNODE(ap->a_vp); 2475 2476 error = EROFS; 2477 unp = VTOUNIONFS(ap->a_vp); 2478 uvp = unp->un_uppervp; 2479 lvp = unp->un_lowervp; 2480 td = ap->a_td; 2481 2482 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2483 return (EROFS); 2484 2485 if (uvp == NULLVP && lvp->v_type == VREG) { 2486 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2487 return (error); 2488 uvp = unp->un_uppervp; 2489 } 2490 2491 if (uvp != NULLVP) 2492 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2493 2494 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 2495 2496 return (error); 2497 } 2498 2499 static int 2500 unionfs_vptofh(struct vop_vptofh_args *ap) 2501 { 2502 return (EOPNOTSUPP); 2503 } 2504 2505 static int 2506 unionfs_add_writecount(struct vop_add_writecount_args *ap) 2507 { 2508 struct vnode *tvp, *vp; 2509 struct unionfs_node *unp; 2510 int error; 2511 2512 vp = ap->a_vp; 2513 unp = VTOUNIONFS(vp); 2514 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp; 2515 VI_LOCK(vp); 2516 /* text refs are bypassed to lowervp */ 2517 VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount")); 2518 VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp, 2519 ("wrong writecount inc %d", ap->a_inc)); 2520 if (tvp != NULL) 2521 error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc); 2522 else if (vp->v_writecount < 0) 2523 error = ETXTBSY; 2524 else 2525 error = 0; 2526 if (error == 0) 2527 vp->v_writecount += ap->a_inc; 2528 VI_UNLOCK(vp); 2529 return (error); 2530 } 2531 2532 struct vop_vector unionfs_vnodeops = { 2533 .vop_default = &default_vnodeops, 2534 2535 .vop_access = unionfs_access, 2536 .vop_aclcheck = unionfs_aclcheck, 2537 .vop_advlock = unionfs_advlock, 2538 .vop_bmap = VOP_EOPNOTSUPP, 2539 .vop_cachedlookup = unionfs_lookup, 2540 .vop_close = unionfs_close, 2541 .vop_closeextattr = unionfs_closeextattr, 2542 .vop_create = unionfs_create, 2543 .vop_deleteextattr = unionfs_deleteextattr, 2544 .vop_fsync = unionfs_fsync, 2545 .vop_getacl = unionfs_getacl, 2546 .vop_getattr = unionfs_getattr, 2547 .vop_getextattr = unionfs_getextattr, 2548 .vop_getwritemount = unionfs_getwritemount, 2549 .vop_inactive = unionfs_inactive, 2550 .vop_need_inactive = vop_stdneed_inactive, 2551 .vop_islocked = unionfs_islocked, 2552 .vop_ioctl = unionfs_ioctl, 2553 .vop_link = unionfs_link, 2554 .vop_listextattr = unionfs_listextattr, 2555 .vop_lock1 = unionfs_lock, 2556 .vop_lookup = vfs_cache_lookup, 2557 .vop_mkdir = unionfs_mkdir, 2558 .vop_mknod = unionfs_mknod, 2559 .vop_open = unionfs_open, 2560 .vop_openextattr = unionfs_openextattr, 2561 .vop_pathconf = unionfs_pathconf, 2562 .vop_poll = unionfs_poll, 2563 .vop_print = unionfs_print, 2564 .vop_read = unionfs_read, 2565 .vop_readdir = unionfs_readdir, 2566 .vop_readlink = unionfs_readlink, 2567 .vop_reclaim = unionfs_reclaim, 2568 .vop_remove = unionfs_remove, 2569 .vop_rename = unionfs_rename, 2570 .vop_rmdir = unionfs_rmdir, 2571 .vop_setacl = unionfs_setacl, 2572 .vop_setattr = unionfs_setattr, 2573 .vop_setextattr = unionfs_setextattr, 2574 .vop_setlabel = unionfs_setlabel, 2575 .vop_strategy = unionfs_strategy, 2576 .vop_symlink = unionfs_symlink, 2577 .vop_unlock = unionfs_unlock, 2578 .vop_whiteout = unionfs_whiteout, 2579 .vop_write = unionfs_write, 2580 .vop_vptofh = unionfs_vptofh, 2581 .vop_add_writecount = unionfs_add_writecount, 2582 }; 2583 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops); 2584