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