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