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