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