1 /* 2 * Copyright (c) 1992, 1993, 1994 The Regents of the University of California. 3 * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Jan-Simon Pendry. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)union_vnops.c 8.18 (Berkeley) 06/24/94 12 */ 13 14 #include <sys/param.h> 15 #include <sys/systm.h> 16 #include <sys/proc.h> 17 #include <sys/file.h> 18 #include <sys/time.h> 19 #include <sys/types.h> 20 #include <sys/vnode.h> 21 #include <sys/mount.h> 22 #include <sys/namei.h> 23 #include <sys/malloc.h> 24 #include <sys/buf.h> 25 #include <sys/queue.h> 26 #include <miscfs/union/union.h> 27 28 #define FIXUP(un) { \ 29 if (((un)->un_flags & UN_ULOCK) == 0) { \ 30 union_fixup(un); \ 31 } \ 32 } 33 34 static void 35 union_fixup(un) 36 struct union_node *un; 37 { 38 39 VOP_LOCK(un->un_uppervp); 40 un->un_flags |= UN_ULOCK; 41 } 42 43 static int 44 union_lookup1(udvp, dvpp, vpp, cnp) 45 struct vnode *udvp; 46 struct vnode **dvpp; 47 struct vnode **vpp; 48 struct componentname *cnp; 49 { 50 int error; 51 struct vnode *tdvp; 52 struct vnode *dvp; 53 struct mount *mp; 54 55 dvp = *dvpp; 56 57 /* 58 * If stepping up the directory tree, check for going 59 * back across the mount point, in which case do what 60 * lookup would do by stepping back down the mount 61 * hierarchy. 62 */ 63 if (cnp->cn_flags & ISDOTDOT) { 64 while ((dvp != udvp) && (dvp->v_flag & VROOT)) { 65 /* 66 * Don't do the NOCROSSMOUNT check 67 * at this level. By definition, 68 * union fs deals with namespaces, not 69 * filesystems. 70 */ 71 tdvp = dvp; 72 *dvpp = dvp = dvp->v_mount->mnt_vnodecovered; 73 vput(tdvp); 74 VREF(dvp); 75 VOP_LOCK(dvp); 76 } 77 } 78 79 error = VOP_LOOKUP(dvp, &tdvp, cnp); 80 if (error) 81 return (error); 82 83 /* 84 * The parent directory will have been unlocked, unless lookup 85 * found the last component. In which case, re-lock the node 86 * here to allow it to be unlocked again (phew) in union_lookup. 87 */ 88 if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) 89 VOP_LOCK(dvp); 90 91 dvp = tdvp; 92 93 /* 94 * Lastly check if the current node is a mount point in 95 * which case walk up the mount hierarchy making sure not to 96 * bump into the root of the mount tree (ie. dvp != udvp). 97 */ 98 while (dvp != udvp && (dvp->v_type == VDIR) && 99 (mp = dvp->v_mountedhere)) { 100 101 if (mp->mnt_flag & MNT_MLOCK) { 102 mp->mnt_flag |= MNT_MWAIT; 103 sleep((caddr_t) mp, PVFS); 104 continue; 105 } 106 107 if (error = VFS_ROOT(mp, &tdvp)) { 108 vput(dvp); 109 return (error); 110 } 111 112 vput(dvp); 113 dvp = tdvp; 114 } 115 116 *vpp = dvp; 117 return (0); 118 } 119 120 int 121 union_lookup(ap) 122 struct vop_lookup_args /* { 123 struct vnodeop_desc *a_desc; 124 struct vnode *a_dvp; 125 struct vnode **a_vpp; 126 struct componentname *a_cnp; 127 } */ *ap; 128 { 129 int error; 130 int uerror, lerror; 131 struct vnode *uppervp, *lowervp; 132 struct vnode *upperdvp, *lowerdvp; 133 struct vnode *dvp = ap->a_dvp; 134 struct union_node *dun = VTOUNION(dvp); 135 struct componentname *cnp = ap->a_cnp; 136 int lockparent = cnp->cn_flags & LOCKPARENT; 137 int rdonly = cnp->cn_flags & RDONLY; 138 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); 139 struct ucred *saved_cred; 140 141 #ifdef notyet 142 if (cnp->cn_namelen == 3 && 143 cnp->cn_nameptr[2] == '.' && 144 cnp->cn_nameptr[1] == '.' && 145 cnp->cn_nameptr[0] == '.') { 146 dvp = *ap->a_vpp = LOWERVP(ap->a_dvp); 147 if (dvp == NULLVP) 148 return (ENOENT); 149 VREF(dvp); 150 VOP_LOCK(dvp); 151 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 152 VOP_UNLOCK(ap->a_dvp); 153 return (0); 154 } 155 #endif 156 157 cnp->cn_flags |= LOCKPARENT; 158 159 upperdvp = dun->un_uppervp; 160 lowerdvp = dun->un_lowervp; 161 uppervp = NULLVP; 162 lowervp = NULLVP; 163 164 /* 165 * do the lookup in the upper level. 166 * if that level comsumes additional pathnames, 167 * then assume that something special is going 168 * on and just return that vnode. 169 */ 170 if (upperdvp != NULLVP) { 171 FIXUP(dun); 172 uerror = union_lookup1(um->um_uppervp, &upperdvp, 173 &uppervp, cnp); 174 /*if (uppervp == upperdvp) 175 dun->un_flags |= UN_KLOCK;*/ 176 177 if (cnp->cn_consume != 0) { 178 *ap->a_vpp = uppervp; 179 if (!lockparent) 180 cnp->cn_flags &= ~LOCKPARENT; 181 return (uerror); 182 } 183 } else { 184 uerror = ENOENT; 185 } 186 187 /* 188 * in a similar way to the upper layer, do the lookup 189 * in the lower layer. this time, if there is some 190 * component magic going on, then vput whatever we got 191 * back from the upper layer and return the lower vnode 192 * instead. 193 */ 194 if (lowerdvp != NULLVP) { 195 int nameiop; 196 197 VOP_LOCK(lowerdvp); 198 199 /* 200 * Only do a LOOKUP on the bottom node, since 201 * we won't be making changes to it anyway. 202 */ 203 nameiop = cnp->cn_nameiop; 204 cnp->cn_nameiop = LOOKUP; 205 if (um->um_op == UNMNT_BELOW) { 206 saved_cred = cnp->cn_cred; 207 cnp->cn_cred = um->um_cred; 208 } 209 lerror = union_lookup1(um->um_lowervp, &lowerdvp, 210 &lowervp, cnp); 211 if (um->um_op == UNMNT_BELOW) 212 cnp->cn_cred = saved_cred; 213 cnp->cn_nameiop = nameiop; 214 215 if (lowervp != lowerdvp) 216 VOP_UNLOCK(lowerdvp); 217 218 if (cnp->cn_consume != 0) { 219 if (uppervp != NULLVP) { 220 if (uppervp == upperdvp) 221 vrele(uppervp); 222 else 223 vput(uppervp); 224 uppervp = NULLVP; 225 } 226 *ap->a_vpp = lowervp; 227 if (!lockparent) 228 cnp->cn_flags &= ~LOCKPARENT; 229 return (lerror); 230 } 231 } else { 232 lerror = ENOENT; 233 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { 234 lowervp = LOWERVP(dun->un_pvp); 235 if (lowervp != NULLVP) { 236 VREF(lowervp); 237 VOP_LOCK(lowervp); 238 lerror = 0; 239 } 240 } 241 } 242 243 if (!lockparent) 244 cnp->cn_flags &= ~LOCKPARENT; 245 246 /* 247 * at this point, we have uerror and lerror indicating 248 * possible errors with the lookups in the upper and lower 249 * layers. additionally, uppervp and lowervp are (locked) 250 * references to existing vnodes in the upper and lower layers. 251 * 252 * there are now three cases to consider. 253 * 1. if both layers returned an error, then return whatever 254 * error the upper layer generated. 255 * 256 * 2. if the top layer failed and the bottom layer succeeded 257 * then two subcases occur. 258 * a. the bottom vnode is not a directory, in which 259 * case just return a new union vnode referencing 260 * an empty top layer and the existing bottom layer. 261 * b. the bottom vnode is a directory, in which case 262 * create a new directory in the top-level and 263 * continue as in case 3. 264 * 265 * 3. if the top layer succeeded then return a new union 266 * vnode referencing whatever the new top layer and 267 * whatever the bottom layer returned. 268 */ 269 270 *ap->a_vpp = NULLVP; 271 272 /* case 1. */ 273 if ((uerror != 0) && (lerror != 0)) { 274 return (uerror); 275 } 276 277 /* case 2. */ 278 if (uerror != 0 /* && (lerror == 0) */ ) { 279 if (lowervp->v_type == VDIR) { /* case 2b. */ 280 dun->un_flags &= ~UN_ULOCK; 281 VOP_UNLOCK(upperdvp); 282 uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); 283 VOP_LOCK(upperdvp); 284 dun->un_flags |= UN_ULOCK; 285 286 if (uerror) { 287 if (lowervp != NULLVP) { 288 vput(lowervp); 289 lowervp = NULLVP; 290 } 291 return (uerror); 292 } 293 } 294 } 295 296 if (lowervp != NULLVP) 297 VOP_UNLOCK(lowervp); 298 299 error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, 300 uppervp, lowervp); 301 302 if (error) { 303 if (uppervp != NULLVP) 304 vput(uppervp); 305 if (lowervp != NULLVP) 306 vrele(lowervp); 307 } else { 308 if (*ap->a_vpp != dvp) 309 if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 310 VOP_UNLOCK(dvp); 311 } 312 313 return (error); 314 } 315 316 int 317 union_create(ap) 318 struct vop_create_args /* { 319 struct vnode *a_dvp; 320 struct vnode **a_vpp; 321 struct componentname *a_cnp; 322 struct vattr *a_vap; 323 } */ *ap; 324 { 325 struct union_node *un = VTOUNION(ap->a_dvp); 326 struct vnode *dvp = un->un_uppervp; 327 328 if (dvp != NULLVP) { 329 int error; 330 struct vnode *vp; 331 332 FIXUP(un); 333 334 VREF(dvp); 335 un->un_flags |= UN_KLOCK; 336 vput(ap->a_dvp); 337 error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); 338 if (error) 339 return (error); 340 341 error = union_allocvp( 342 ap->a_vpp, 343 ap->a_dvp->v_mount, 344 ap->a_dvp, 345 NULLVP, 346 ap->a_cnp, 347 vp, 348 NULLVP); 349 if (error) 350 vput(vp); 351 return (error); 352 } 353 354 vput(ap->a_dvp); 355 return (EROFS); 356 } 357 358 int 359 union_mknod(ap) 360 struct vop_mknod_args /* { 361 struct vnode *a_dvp; 362 struct vnode **a_vpp; 363 struct componentname *a_cnp; 364 struct vattr *a_vap; 365 } */ *ap; 366 { 367 struct union_node *un = VTOUNION(ap->a_dvp); 368 struct vnode *dvp = un->un_uppervp; 369 370 if (dvp != NULLVP) { 371 int error; 372 struct vnode *vp; 373 374 FIXUP(un); 375 376 VREF(dvp); 377 un->un_flags |= UN_KLOCK; 378 vput(ap->a_dvp); 379 error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); 380 if (error) 381 return (error); 382 383 if (vp != NULLVP) { 384 error = union_allocvp( 385 ap->a_vpp, 386 ap->a_dvp->v_mount, 387 ap->a_dvp, 388 NULLVP, 389 ap->a_cnp, 390 vp, 391 NULLVP); 392 if (error) 393 vput(vp); 394 } 395 return (error); 396 } 397 398 vput(ap->a_dvp); 399 return (EROFS); 400 } 401 402 int 403 union_open(ap) 404 struct vop_open_args /* { 405 struct vnodeop_desc *a_desc; 406 struct vnode *a_vp; 407 int a_mode; 408 struct ucred *a_cred; 409 struct proc *a_p; 410 } */ *ap; 411 { 412 struct union_node *un = VTOUNION(ap->a_vp); 413 struct vnode *tvp; 414 int mode = ap->a_mode; 415 struct ucred *cred = ap->a_cred; 416 struct proc *p = ap->a_p; 417 int error; 418 419 /* 420 * If there is an existing upper vp then simply open that. 421 */ 422 tvp = un->un_uppervp; 423 if (tvp == NULLVP) { 424 /* 425 * If the lower vnode is being opened for writing, then 426 * copy the file contents to the upper vnode and open that, 427 * otherwise can simply open the lower vnode. 428 */ 429 tvp = un->un_lowervp; 430 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { 431 error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); 432 if (error == 0) 433 error = VOP_OPEN(un->un_uppervp, mode, cred, p); 434 return (error); 435 } 436 437 /* 438 * Just open the lower vnode 439 */ 440 un->un_openl++; 441 VOP_LOCK(tvp); 442 error = VOP_OPEN(tvp, mode, cred, p); 443 VOP_UNLOCK(tvp); 444 445 return (error); 446 } 447 448 FIXUP(un); 449 450 error = VOP_OPEN(tvp, mode, cred, p); 451 452 return (error); 453 } 454 455 int 456 union_close(ap) 457 struct vop_close_args /* { 458 struct vnode *a_vp; 459 int a_fflag; 460 struct ucred *a_cred; 461 struct proc *a_p; 462 } */ *ap; 463 { 464 struct union_node *un = VTOUNION(ap->a_vp); 465 struct vnode *vp; 466 467 if (un->un_uppervp != NULLVP) { 468 vp = un->un_uppervp; 469 } else { 470 #ifdef UNION_DIAGNOSTIC 471 if (un->un_openl <= 0) 472 panic("union: un_openl cnt"); 473 #endif 474 --un->un_openl; 475 vp = un->un_lowervp; 476 } 477 478 return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p)); 479 } 480 481 /* 482 * Check access permission on the union vnode. 483 * The access check being enforced is to check 484 * against both the underlying vnode, and any 485 * copied vnode. This ensures that no additional 486 * file permissions are given away simply because 487 * the user caused an implicit file copy. 488 */ 489 int 490 union_access(ap) 491 struct vop_access_args /* { 492 struct vnodeop_desc *a_desc; 493 struct vnode *a_vp; 494 int a_mode; 495 struct ucred *a_cred; 496 struct proc *a_p; 497 } */ *ap; 498 { 499 struct union_node *un = VTOUNION(ap->a_vp); 500 int error = EACCES; 501 struct vnode *vp; 502 503 if ((vp = un->un_uppervp) != NULLVP) { 504 FIXUP(un); 505 return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p)); 506 } 507 508 if ((vp = un->un_lowervp) != NULLVP) { 509 VOP_LOCK(vp); 510 error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); 511 if (error == 0) { 512 struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount); 513 514 if (um->um_op == UNMNT_BELOW) 515 error = VOP_ACCESS(vp, ap->a_mode, 516 um->um_cred, ap->a_p); 517 } 518 VOP_UNLOCK(vp); 519 if (error) 520 return (error); 521 } 522 523 return (error); 524 } 525 526 /* 527 * We handle getattr only to change the fsid and 528 * track object sizes 529 */ 530 int 531 union_getattr(ap) 532 struct vop_getattr_args /* { 533 struct vnode *a_vp; 534 struct vattr *a_vap; 535 struct ucred *a_cred; 536 struct proc *a_p; 537 } */ *ap; 538 { 539 int error; 540 struct union_node *un = VTOUNION(ap->a_vp); 541 struct vnode *vp = un->un_uppervp; 542 struct vattr *vap; 543 struct vattr va; 544 545 546 /* 547 * Some programs walk the filesystem hierarchy by counting 548 * links to directories to avoid stat'ing all the time. 549 * This means the link count on directories needs to be "correct". 550 * The only way to do that is to call getattr on both layers 551 * and fix up the link count. The link count will not necessarily 552 * be accurate but will be large enough to defeat the tree walkers. 553 */ 554 555 vap = ap->a_vap; 556 557 vp = un->un_uppervp; 558 if (vp != NULLVP) { 559 /* 560 * It's not clear whether VOP_GETATTR is to be 561 * called with the vnode locked or not. stat() calls 562 * it with (vp) locked, and fstat calls it with 563 * (vp) unlocked. 564 * In the mean time, compensate here by checking 565 * the union_node's lock flag. 566 */ 567 if (un->un_flags & UN_LOCKED) 568 FIXUP(un); 569 570 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 571 if (error) 572 return (error); 573 union_newsize(ap->a_vp, vap->va_size, VNOVAL); 574 } 575 576 if (vp == NULLVP) { 577 vp = un->un_lowervp; 578 } else if (vp->v_type == VDIR) { 579 vp = un->un_lowervp; 580 vap = &va; 581 } else { 582 vp = NULLVP; 583 } 584 585 if (vp != NULLVP) { 586 VOP_LOCK(vp); 587 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 588 VOP_UNLOCK(vp); 589 if (error) 590 return (error); 591 union_newsize(ap->a_vp, VNOVAL, vap->va_size); 592 } 593 594 if ((vap != ap->a_vap) && (vap->va_type == VDIR)) 595 ap->a_vap->va_nlink += vap->va_nlink; 596 597 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 598 return (0); 599 } 600 601 int 602 union_setattr(ap) 603 struct vop_setattr_args /* { 604 struct vnode *a_vp; 605 struct vattr *a_vap; 606 struct ucred *a_cred; 607 struct proc *a_p; 608 } */ *ap; 609 { 610 struct union_node *un = VTOUNION(ap->a_vp); 611 int error; 612 613 /* 614 * Handle case of truncating lower object to zero size, 615 * by creating a zero length upper object. This is to 616 * handle the case of open with O_TRUNC and O_CREAT. 617 */ 618 if ((un->un_uppervp == NULLVP) && 619 /* assert(un->un_lowervp != NULLVP) */ 620 (un->un_lowervp->v_type == VREG) && 621 (ap->a_vap->va_size == 0)) { 622 struct vnode *vp; 623 624 error = union_vn_create(&vp, un, ap->a_p); 625 if (error) 626 return (error); 627 628 /* at this point, uppervp is locked */ 629 union_newupper(un, vp); 630 631 VOP_UNLOCK(vp); 632 union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p); 633 VOP_LOCK(vp); 634 un->un_flags |= UN_ULOCK; 635 } 636 637 /* 638 * Try to set attributes in upper layer, 639 * otherwise return read-only filesystem error. 640 */ 641 if (un->un_uppervp != NULLVP) { 642 FIXUP(un); 643 error = VOP_SETATTR(un->un_uppervp, ap->a_vap, 644 ap->a_cred, ap->a_p); 645 if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) 646 union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); 647 } else { 648 error = EROFS; 649 } 650 651 return (error); 652 } 653 654 int 655 union_read(ap) 656 struct vop_read_args /* { 657 struct vnode *a_vp; 658 struct uio *a_uio; 659 int a_ioflag; 660 struct ucred *a_cred; 661 } */ *ap; 662 { 663 int error; 664 struct vnode *vp = OTHERVP(ap->a_vp); 665 int dolock = (vp == LOWERVP(ap->a_vp)); 666 667 if (dolock) 668 VOP_LOCK(vp); 669 else 670 FIXUP(VTOUNION(ap->a_vp)); 671 error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 672 if (dolock) 673 VOP_UNLOCK(vp); 674 675 /* 676 * XXX 677 * perhaps the size of the underlying object has changed under 678 * our feet. take advantage of the offset information present 679 * in the uio structure. 680 */ 681 if (error == 0) { 682 struct union_node *un = VTOUNION(ap->a_vp); 683 off_t cur = ap->a_uio->uio_offset; 684 685 if (vp == un->un_uppervp) { 686 if (cur > un->un_uppersz) 687 union_newsize(ap->a_vp, cur, VNOVAL); 688 } else { 689 if (cur > un->un_lowersz) 690 union_newsize(ap->a_vp, VNOVAL, cur); 691 } 692 } 693 694 return (error); 695 } 696 697 int 698 union_write(ap) 699 struct vop_read_args /* { 700 struct vnode *a_vp; 701 struct uio *a_uio; 702 int a_ioflag; 703 struct ucred *a_cred; 704 } */ *ap; 705 { 706 int error; 707 struct vnode *vp = OTHERVP(ap->a_vp); 708 int dolock = (vp == LOWERVP(ap->a_vp)); 709 710 if (dolock) 711 VOP_LOCK(vp); 712 else 713 FIXUP(VTOUNION(ap->a_vp)); 714 error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 715 if (dolock) 716 VOP_UNLOCK(vp); 717 718 /* 719 * the size of the underlying object may be changed by the 720 * write. 721 */ 722 if (error == 0) { 723 struct union_node *un = VTOUNION(ap->a_vp); 724 off_t cur = ap->a_uio->uio_offset; 725 726 if (vp == un->un_uppervp) { 727 if (cur > un->un_uppersz) 728 union_newsize(ap->a_vp, cur, VNOVAL); 729 } else { 730 if (cur > un->un_lowersz) 731 union_newsize(ap->a_vp, VNOVAL, cur); 732 } 733 } 734 735 return (error); 736 } 737 738 int 739 union_ioctl(ap) 740 struct vop_ioctl_args /* { 741 struct vnode *a_vp; 742 int a_command; 743 caddr_t a_data; 744 int a_fflag; 745 struct ucred *a_cred; 746 struct proc *a_p; 747 } */ *ap; 748 { 749 750 return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, 751 ap->a_fflag, ap->a_cred, ap->a_p)); 752 } 753 754 int 755 union_select(ap) 756 struct vop_select_args /* { 757 struct vnode *a_vp; 758 int a_which; 759 int a_fflags; 760 struct ucred *a_cred; 761 struct proc *a_p; 762 } */ *ap; 763 { 764 765 return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, 766 ap->a_cred, ap->a_p)); 767 } 768 769 int 770 union_mmap(ap) 771 struct vop_mmap_args /* { 772 struct vnode *a_vp; 773 int a_fflags; 774 struct ucred *a_cred; 775 struct proc *a_p; 776 } */ *ap; 777 { 778 779 return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, 780 ap->a_cred, ap->a_p)); 781 } 782 783 int 784 union_fsync(ap) 785 struct vop_fsync_args /* { 786 struct vnode *a_vp; 787 struct ucred *a_cred; 788 int a_waitfor; 789 struct proc *a_p; 790 } */ *ap; 791 { 792 int error = 0; 793 struct vnode *targetvp = OTHERVP(ap->a_vp); 794 795 if (targetvp != NULLVP) { 796 int dolock = (targetvp == LOWERVP(ap->a_vp)); 797 798 if (dolock) 799 VOP_LOCK(targetvp); 800 else 801 FIXUP(VTOUNION(ap->a_vp)); 802 error = VOP_FSYNC(targetvp, ap->a_cred, 803 ap->a_waitfor, ap->a_p); 804 if (dolock) 805 VOP_UNLOCK(targetvp); 806 } 807 808 return (error); 809 } 810 811 int 812 union_seek(ap) 813 struct vop_seek_args /* { 814 struct vnode *a_vp; 815 off_t a_oldoff; 816 off_t a_newoff; 817 struct ucred *a_cred; 818 } */ *ap; 819 { 820 821 return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); 822 } 823 824 int 825 union_remove(ap) 826 struct vop_remove_args /* { 827 struct vnode *a_dvp; 828 struct vnode *a_vp; 829 struct componentname *a_cnp; 830 } */ *ap; 831 { 832 int error; 833 struct union_node *dun = VTOUNION(ap->a_dvp); 834 struct union_node *un = VTOUNION(ap->a_vp); 835 836 if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) { 837 struct vnode *dvp = dun->un_uppervp; 838 struct vnode *vp = un->un_uppervp; 839 840 FIXUP(dun); 841 VREF(dvp); 842 dun->un_flags |= UN_KLOCK; 843 vput(ap->a_dvp); 844 FIXUP(un); 845 VREF(vp); 846 un->un_flags |= UN_KLOCK; 847 vput(ap->a_vp); 848 849 error = VOP_REMOVE(dvp, vp, ap->a_cnp); 850 if (!error) 851 union_removed_upper(un); 852 853 /* 854 * XXX: should create a whiteout here 855 */ 856 } else { 857 /* 858 * XXX: should create a whiteout here 859 */ 860 vput(ap->a_dvp); 861 vput(ap->a_vp); 862 error = EROFS; 863 } 864 865 return (error); 866 } 867 868 int 869 union_link(ap) 870 struct vop_link_args /* { 871 struct vnode *a_vp; 872 struct vnode *a_tdvp; 873 struct componentname *a_cnp; 874 } */ *ap; 875 { 876 int error = 0; 877 struct union_node *un; 878 struct vnode *vp; 879 struct vnode *tdvp; 880 881 un = VTOUNION(ap->a_vp); 882 883 if (ap->a_vp->v_op != ap->a_tdvp->v_op) { 884 tdvp = ap->a_tdvp; 885 } else { 886 struct union_node *tdun = VTOUNION(ap->a_tdvp); 887 if (tdun->un_uppervp == NULLVP) { 888 VOP_LOCK(ap->a_tdvp); 889 if (un->un_uppervp == tdun->un_dirvp) { 890 un->un_flags &= ~UN_ULOCK; 891 VOP_UNLOCK(un->un_uppervp); 892 } 893 error = union_copyup(tdun, 1, ap->a_cnp->cn_cred, 894 ap->a_cnp->cn_proc); 895 if (un->un_uppervp == tdun->un_dirvp) { 896 VOP_LOCK(un->un_uppervp); 897 un->un_flags |= UN_ULOCK; 898 } 899 VOP_UNLOCK(ap->a_tdvp); 900 } 901 tdvp = tdun->un_uppervp; 902 } 903 904 vp = un->un_uppervp; 905 if (vp == NULLVP) 906 error = EROFS; 907 908 if (error) { 909 vput(ap->a_vp); 910 return (error); 911 } 912 913 FIXUP(un); 914 VREF(vp); 915 un->un_flags |= UN_KLOCK; 916 vput(ap->a_vp); 917 918 return (VOP_LINK(vp, tdvp, ap->a_cnp)); 919 } 920 921 int 922 union_rename(ap) 923 struct vop_rename_args /* { 924 struct vnode *a_fdvp; 925 struct vnode *a_fvp; 926 struct componentname *a_fcnp; 927 struct vnode *a_tdvp; 928 struct vnode *a_tvp; 929 struct componentname *a_tcnp; 930 } */ *ap; 931 { 932 int error; 933 934 struct vnode *fdvp = ap->a_fdvp; 935 struct vnode *fvp = ap->a_fvp; 936 struct vnode *tdvp = ap->a_tdvp; 937 struct vnode *tvp = ap->a_tvp; 938 939 if (fdvp->v_op == union_vnodeop_p) { /* always true */ 940 struct union_node *un = VTOUNION(fdvp); 941 if (un->un_uppervp == NULLVP) { 942 error = EROFS; 943 goto bad; 944 } 945 946 fdvp = un->un_uppervp; 947 VREF(fdvp); 948 vrele(ap->a_fdvp); 949 } 950 951 if (fvp->v_op == union_vnodeop_p) { /* always true */ 952 struct union_node *un = VTOUNION(fvp); 953 if (un->un_uppervp == NULLVP) { 954 error = EROFS; 955 goto bad; 956 } 957 958 fvp = un->un_uppervp; 959 VREF(fvp); 960 vrele(ap->a_fvp); 961 } 962 963 if (tdvp->v_op == union_vnodeop_p) { 964 struct union_node *un = VTOUNION(tdvp); 965 if (un->un_uppervp == NULLVP) { 966 /* 967 * this should never happen in normal 968 * operation but might if there was 969 * a problem creating the top-level shadow 970 * directory. 971 */ 972 error = EROFS; 973 goto bad; 974 } 975 976 tdvp = un->un_uppervp; 977 VREF(tdvp); 978 un->un_flags |= UN_KLOCK; 979 vput(ap->a_tdvp); 980 } 981 982 if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { 983 struct union_node *un = VTOUNION(tvp); 984 985 tvp = un->un_uppervp; 986 if (tvp != NULLVP) { 987 VREF(tvp); 988 un->un_flags |= UN_KLOCK; 989 } 990 vput(ap->a_tvp); 991 } 992 993 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 994 995 bad: 996 vrele(fdvp); 997 vrele(fvp); 998 vput(tdvp); 999 if (tvp != NULLVP) 1000 vput(tvp); 1001 1002 return (error); 1003 } 1004 1005 int 1006 union_mkdir(ap) 1007 struct vop_mkdir_args /* { 1008 struct vnode *a_dvp; 1009 struct vnode **a_vpp; 1010 struct componentname *a_cnp; 1011 struct vattr *a_vap; 1012 } */ *ap; 1013 { 1014 struct union_node *un = VTOUNION(ap->a_dvp); 1015 struct vnode *dvp = un->un_uppervp; 1016 1017 if (dvp != NULLVP) { 1018 int error; 1019 struct vnode *vp; 1020 1021 FIXUP(un); 1022 VREF(dvp); 1023 un->un_flags |= UN_KLOCK; 1024 vput(ap->a_dvp); 1025 error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); 1026 if (error) 1027 return (error); 1028 1029 error = union_allocvp( 1030 ap->a_vpp, 1031 ap->a_dvp->v_mount, 1032 ap->a_dvp, 1033 NULLVP, 1034 ap->a_cnp, 1035 vp, 1036 NULLVP); 1037 if (error) 1038 vput(vp); 1039 return (error); 1040 } 1041 1042 vput(ap->a_dvp); 1043 return (EROFS); 1044 } 1045 1046 int 1047 union_rmdir(ap) 1048 struct vop_rmdir_args /* { 1049 struct vnode *a_dvp; 1050 struct vnode *a_vp; 1051 struct componentname *a_cnp; 1052 } */ *ap; 1053 { 1054 int error; 1055 struct union_node *dun = VTOUNION(ap->a_dvp); 1056 struct union_node *un = VTOUNION(ap->a_vp); 1057 1058 if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) { 1059 struct vnode *dvp = dun->un_uppervp; 1060 struct vnode *vp = un->un_uppervp; 1061 1062 FIXUP(dun); 1063 VREF(dvp); 1064 dun->un_flags |= UN_KLOCK; 1065 vput(ap->a_dvp); 1066 FIXUP(un); 1067 VREF(vp); 1068 un->un_flags |= UN_KLOCK; 1069 vput(ap->a_vp); 1070 1071 error = VOP_RMDIR(dvp, vp, ap->a_cnp); 1072 if (!error) 1073 union_removed_upper(un); 1074 1075 /* 1076 * XXX: should create a whiteout here 1077 */ 1078 } else { 1079 /* 1080 * XXX: should create a whiteout here 1081 */ 1082 vput(ap->a_dvp); 1083 vput(ap->a_vp); 1084 error = EROFS; 1085 } 1086 1087 return (error); 1088 } 1089 1090 int 1091 union_symlink(ap) 1092 struct vop_symlink_args /* { 1093 struct vnode *a_dvp; 1094 struct vnode **a_vpp; 1095 struct componentname *a_cnp; 1096 struct vattr *a_vap; 1097 char *a_target; 1098 } */ *ap; 1099 { 1100 struct union_node *un = VTOUNION(ap->a_dvp); 1101 struct vnode *dvp = un->un_uppervp; 1102 1103 if (dvp != NULLVP) { 1104 int error; 1105 struct vnode *vp; 1106 struct mount *mp = ap->a_dvp->v_mount; 1107 1108 FIXUP(un); 1109 VREF(dvp); 1110 un->un_flags |= UN_KLOCK; 1111 vput(ap->a_dvp); 1112 error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, 1113 ap->a_vap, ap->a_target); 1114 *ap->a_vpp = NULLVP; 1115 return (error); 1116 } 1117 1118 vput(ap->a_dvp); 1119 return (EROFS); 1120 } 1121 1122 /* 1123 * union_readdir works in concert with getdirentries and 1124 * readdir(3) to provide a list of entries in the unioned 1125 * directories. getdirentries is responsible for walking 1126 * down the union stack. readdir(3) is responsible for 1127 * eliminating duplicate names from the returned data stream. 1128 */ 1129 int 1130 union_readdir(ap) 1131 struct vop_readdir_args /* { 1132 struct vnodeop_desc *a_desc; 1133 struct vnode *a_vp; 1134 struct uio *a_uio; 1135 struct ucred *a_cred; 1136 int *a_eofflag; 1137 u_long *a_cookies; 1138 int a_ncookies; 1139 } */ *ap; 1140 { 1141 register struct union_node *un = VTOUNION(ap->a_vp); 1142 register struct vnode *uvp = un->un_uppervp; 1143 1144 if (uvp == NULLVP) 1145 return (0); 1146 1147 FIXUP(un); 1148 ap->a_vp = uvp; 1149 return (VOCALL(uvp->v_op, VOFFSET(vop_readdir), ap)); 1150 } 1151 1152 int 1153 union_readlink(ap) 1154 struct vop_readlink_args /* { 1155 struct vnode *a_vp; 1156 struct uio *a_uio; 1157 struct ucred *a_cred; 1158 } */ *ap; 1159 { 1160 int error; 1161 struct vnode *vp = OTHERVP(ap->a_vp); 1162 int dolock = (vp == LOWERVP(ap->a_vp)); 1163 1164 if (dolock) 1165 VOP_LOCK(vp); 1166 else 1167 FIXUP(VTOUNION(ap->a_vp)); 1168 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1169 if (dolock) 1170 VOP_UNLOCK(vp); 1171 1172 return (error); 1173 } 1174 1175 int 1176 union_abortop(ap) 1177 struct vop_abortop_args /* { 1178 struct vnode *a_dvp; 1179 struct componentname *a_cnp; 1180 } */ *ap; 1181 { 1182 int error; 1183 struct vnode *vp = OTHERVP(ap->a_dvp); 1184 struct union_node *un = VTOUNION(ap->a_dvp); 1185 int islocked = un->un_flags & UN_LOCKED; 1186 int dolock = (vp == LOWERVP(ap->a_dvp)); 1187 1188 if (islocked) { 1189 if (dolock) 1190 VOP_LOCK(vp); 1191 else 1192 FIXUP(VTOUNION(ap->a_dvp)); 1193 } 1194 error = VOP_ABORTOP(vp, ap->a_cnp); 1195 if (islocked && dolock) 1196 VOP_UNLOCK(vp); 1197 1198 return (error); 1199 } 1200 1201 int 1202 union_inactive(ap) 1203 struct vop_inactive_args /* { 1204 struct vnode *a_vp; 1205 } */ *ap; 1206 { 1207 struct union_node *un = VTOUNION(ap->a_vp); 1208 1209 /* 1210 * Do nothing (and _don't_ bypass). 1211 * Wait to vrele lowervp until reclaim, 1212 * so that until then our union_node is in the 1213 * cache and reusable. 1214 * 1215 * NEEDSWORK: Someday, consider inactive'ing 1216 * the lowervp and then trying to reactivate it 1217 * with capabilities (v_id) 1218 * like they do in the name lookup cache code. 1219 * That's too much work for now. 1220 */ 1221 1222 #ifdef UNION_DIAGNOSTIC 1223 if (un->un_flags & UN_LOCKED) 1224 panic("union: inactivating locked node"); 1225 if (un->un_flags & UN_ULOCK) 1226 panic("union: inactivating w/locked upper node"); 1227 #endif 1228 1229 if ((un->un_flags & UN_CACHED) == 0) 1230 vgone(ap->a_vp); 1231 1232 return (0); 1233 } 1234 1235 int 1236 union_reclaim(ap) 1237 struct vop_reclaim_args /* { 1238 struct vnode *a_vp; 1239 } */ *ap; 1240 { 1241 1242 union_freevp(ap->a_vp); 1243 1244 return (0); 1245 } 1246 1247 int 1248 union_lock(ap) 1249 struct vop_lock_args *ap; 1250 { 1251 struct vnode *vp = ap->a_vp; 1252 struct union_node *un; 1253 1254 start: 1255 while (vp->v_flag & VXLOCK) { 1256 vp->v_flag |= VXWANT; 1257 sleep((caddr_t)vp, PINOD); 1258 } 1259 1260 un = VTOUNION(vp); 1261 1262 if (un->un_uppervp != NULLVP) { 1263 if (((un->un_flags & UN_ULOCK) == 0) && 1264 (vp->v_usecount != 0)) { 1265 un->un_flags |= UN_ULOCK; 1266 VOP_LOCK(un->un_uppervp); 1267 } 1268 #ifdef DIAGNOSTIC 1269 if (un->un_flags & UN_KLOCK) 1270 panic("union: dangling upper lock"); 1271 #endif 1272 } 1273 1274 if (un->un_flags & UN_LOCKED) { 1275 #ifdef DIAGNOSTIC 1276 if (curproc && un->un_pid == curproc->p_pid && 1277 un->un_pid > -1 && curproc->p_pid > -1) 1278 panic("union: locking against myself"); 1279 #endif 1280 un->un_flags |= UN_WANT; 1281 sleep((caddr_t) &un->un_flags, PINOD); 1282 goto start; 1283 } 1284 1285 #ifdef DIAGNOSTIC 1286 if (curproc) 1287 un->un_pid = curproc->p_pid; 1288 else 1289 un->un_pid = -1; 1290 #endif 1291 1292 un->un_flags |= UN_LOCKED; 1293 return (0); 1294 } 1295 1296 int 1297 union_unlock(ap) 1298 struct vop_lock_args *ap; 1299 { 1300 struct union_node *un = VTOUNION(ap->a_vp); 1301 1302 #ifdef DIAGNOSTIC 1303 if ((un->un_flags & UN_LOCKED) == 0) 1304 panic("union: unlock unlocked node"); 1305 if (curproc && un->un_pid != curproc->p_pid && 1306 curproc->p_pid > -1 && un->un_pid > -1) 1307 panic("union: unlocking other process's union node"); 1308 #endif 1309 1310 un->un_flags &= ~UN_LOCKED; 1311 1312 if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) 1313 VOP_UNLOCK(un->un_uppervp); 1314 1315 un->un_flags &= ~(UN_ULOCK|UN_KLOCK); 1316 1317 if (un->un_flags & UN_WANT) { 1318 un->un_flags &= ~UN_WANT; 1319 wakeup((caddr_t) &un->un_flags); 1320 } 1321 1322 #ifdef DIAGNOSTIC 1323 un->un_pid = 0; 1324 #endif 1325 1326 return (0); 1327 } 1328 1329 int 1330 union_bmap(ap) 1331 struct vop_bmap_args /* { 1332 struct vnode *a_vp; 1333 daddr_t a_bn; 1334 struct vnode **a_vpp; 1335 daddr_t *a_bnp; 1336 int *a_runp; 1337 } */ *ap; 1338 { 1339 int error; 1340 struct vnode *vp = OTHERVP(ap->a_vp); 1341 int dolock = (vp == LOWERVP(ap->a_vp)); 1342 1343 if (dolock) 1344 VOP_LOCK(vp); 1345 else 1346 FIXUP(VTOUNION(ap->a_vp)); 1347 error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 1348 if (dolock) 1349 VOP_UNLOCK(vp); 1350 1351 return (error); 1352 } 1353 1354 int 1355 union_print(ap) 1356 struct vop_print_args /* { 1357 struct vnode *a_vp; 1358 } */ *ap; 1359 { 1360 struct vnode *vp = ap->a_vp; 1361 1362 printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n", 1363 vp, UPPERVP(vp), LOWERVP(vp)); 1364 return (0); 1365 } 1366 1367 int 1368 union_islocked(ap) 1369 struct vop_islocked_args /* { 1370 struct vnode *a_vp; 1371 } */ *ap; 1372 { 1373 1374 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 1375 } 1376 1377 int 1378 union_pathconf(ap) 1379 struct vop_pathconf_args /* { 1380 struct vnode *a_vp; 1381 int a_name; 1382 int *a_retval; 1383 } */ *ap; 1384 { 1385 int error; 1386 struct vnode *vp = OTHERVP(ap->a_vp); 1387 int dolock = (vp == LOWERVP(ap->a_vp)); 1388 1389 if (dolock) 1390 VOP_LOCK(vp); 1391 else 1392 FIXUP(VTOUNION(ap->a_vp)); 1393 error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); 1394 if (dolock) 1395 VOP_UNLOCK(vp); 1396 1397 return (error); 1398 } 1399 1400 int 1401 union_advlock(ap) 1402 struct vop_advlock_args /* { 1403 struct vnode *a_vp; 1404 caddr_t a_id; 1405 int a_op; 1406 struct flock *a_fl; 1407 int a_flags; 1408 } */ *ap; 1409 { 1410 1411 return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, 1412 ap->a_fl, ap->a_flags)); 1413 } 1414 1415 1416 /* 1417 * XXX - vop_strategy must be hand coded because it has no 1418 * vnode in its arguments. 1419 * This goes away with a merged VM/buffer cache. 1420 */ 1421 int 1422 union_strategy(ap) 1423 struct vop_strategy_args /* { 1424 struct buf *a_bp; 1425 } */ *ap; 1426 { 1427 struct buf *bp = ap->a_bp; 1428 int error; 1429 struct vnode *savedvp; 1430 1431 savedvp = bp->b_vp; 1432 bp->b_vp = OTHERVP(bp->b_vp); 1433 1434 #ifdef DIAGNOSTIC 1435 if (bp->b_vp == NULLVP) 1436 panic("union_strategy: nil vp"); 1437 if (((bp->b_flags & B_READ) == 0) && 1438 (bp->b_vp == LOWERVP(savedvp))) 1439 panic("union_strategy: writing to lowervp"); 1440 #endif 1441 1442 error = VOP_STRATEGY(bp); 1443 bp->b_vp = savedvp; 1444 1445 return (error); 1446 } 1447 1448 /* 1449 * Global vfs data structures 1450 */ 1451 int (**union_vnodeop_p)(); 1452 struct vnodeopv_entry_desc union_vnodeop_entries[] = { 1453 { &vop_default_desc, vn_default_error }, 1454 { &vop_lookup_desc, union_lookup }, /* lookup */ 1455 { &vop_create_desc, union_create }, /* create */ 1456 { &vop_mknod_desc, union_mknod }, /* mknod */ 1457 { &vop_open_desc, union_open }, /* open */ 1458 { &vop_close_desc, union_close }, /* close */ 1459 { &vop_access_desc, union_access }, /* access */ 1460 { &vop_getattr_desc, union_getattr }, /* getattr */ 1461 { &vop_setattr_desc, union_setattr }, /* setattr */ 1462 { &vop_read_desc, union_read }, /* read */ 1463 { &vop_write_desc, union_write }, /* write */ 1464 { &vop_ioctl_desc, union_ioctl }, /* ioctl */ 1465 { &vop_select_desc, union_select }, /* select */ 1466 { &vop_mmap_desc, union_mmap }, /* mmap */ 1467 { &vop_fsync_desc, union_fsync }, /* fsync */ 1468 { &vop_seek_desc, union_seek }, /* seek */ 1469 { &vop_remove_desc, union_remove }, /* remove */ 1470 { &vop_link_desc, union_link }, /* link */ 1471 { &vop_rename_desc, union_rename }, /* rename */ 1472 { &vop_mkdir_desc, union_mkdir }, /* mkdir */ 1473 { &vop_rmdir_desc, union_rmdir }, /* rmdir */ 1474 { &vop_symlink_desc, union_symlink }, /* symlink */ 1475 { &vop_readdir_desc, union_readdir }, /* readdir */ 1476 { &vop_readlink_desc, union_readlink }, /* readlink */ 1477 { &vop_abortop_desc, union_abortop }, /* abortop */ 1478 { &vop_inactive_desc, union_inactive }, /* inactive */ 1479 { &vop_reclaim_desc, union_reclaim }, /* reclaim */ 1480 { &vop_lock_desc, union_lock }, /* lock */ 1481 { &vop_unlock_desc, union_unlock }, /* unlock */ 1482 { &vop_bmap_desc, union_bmap }, /* bmap */ 1483 { &vop_strategy_desc, union_strategy }, /* strategy */ 1484 { &vop_print_desc, union_print }, /* print */ 1485 { &vop_islocked_desc, union_islocked }, /* islocked */ 1486 { &vop_pathconf_desc, union_pathconf }, /* pathconf */ 1487 { &vop_advlock_desc, union_advlock }, /* advlock */ 1488 #ifdef notdef 1489 { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ 1490 { &vop_valloc_desc, union_valloc }, /* valloc */ 1491 { &vop_vfree_desc, union_vfree }, /* vfree */ 1492 { &vop_truncate_desc, union_truncate }, /* truncate */ 1493 { &vop_update_desc, union_update }, /* update */ 1494 { &vop_bwrite_desc, union_bwrite }, /* bwrite */ 1495 #endif 1496 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1497 }; 1498 struct vnodeopv_desc union_vnodeop_opv_desc = 1499 { &union_vnodeop_p, union_vnodeop_entries }; 1500