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