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