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