1 /*- 2 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. 3 * Copyright (c) 1992, 1993, 1994, 1995 4 * The Regents of the University of California. 5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 6 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Jan-Simon Pendry. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 37 * $FreeBSD: src/sys/fs/unionfs/union_vnops.c,v 1.152 2008/01/13 14:44:06 attilio Exp $ 38 * 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/kernel.h> 45 #include <sys/lock.h> 46 #include <sys/malloc.h> 47 #include <sys/mount.h> 48 #include <sys/mutex.h> 49 #include <sys/namei.h> 50 #include <sys/sysctl.h> 51 #include <sys/vnode.h> 52 #include <sys/fcntl.h> 53 #include <sys/stat.h> 54 #include <sys/dirent.h> 55 #include <sys/proc.h> 56 57 #include <fs/unionfs/unionfs.h> 58 59 #if 0 60 #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) 61 #define UNIONFS_IDBG_RENAME 62 #else 63 #define UNIONFS_INTERNAL_DEBUG(msg, args...) 64 #endif 65 66 static int 67 unionfs_lookup(void *v) 68 { 69 struct vop_lookup_args *ap = v; 70 int iswhiteout; 71 int lockflag; 72 int error , uerror, lerror; 73 u_long nameiop; 74 u_long cnflags, cnflagsbk; 75 struct unionfs_node *dunp; 76 struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp; 77 struct vattr va; 78 struct componentname *cnp; 79 80 iswhiteout = 0; 81 lockflag = 0; 82 error = uerror = lerror = ENOENT; 83 cnp = ap->a_cnp; 84 nameiop = cnp->cn_nameiop; 85 cnflags = cnp->cn_flags; 86 dvp = ap->a_dvp; 87 dunp = VTOUNIONFS(dvp); 88 udvp = dunp->un_uppervp; 89 ldvp = dunp->un_lowervp; 90 vp = uvp = lvp = NULLVP; 91 *(ap->a_vpp) = NULLVP; 92 93 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr); 94 95 if (dvp->v_type != VDIR) 96 return (ENOTDIR); 97 98 /* 99 * If read-only and op is not LOOKUP, will return EROFS. 100 */ 101 if ((cnflags & ISLASTCN) && 102 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 103 LOOKUP != nameiop) 104 return (EROFS); 105 106 /* 107 * lookup dotdot 108 */ 109 if (cnflags & ISDOTDOT) { 110 if (LOOKUP != nameiop && udvp == NULLVP) 111 return (EROFS); 112 113 if (udvp != NULLVP) { 114 dtmpvp = udvp; 115 if (ldvp != NULLVP) 116 VOP_UNLOCK(ldvp, 0); 117 } 118 else 119 dtmpvp = ldvp; 120 121 error = VOP_LOOKUP(dtmpvp, &vp, cnp); 122 123 if (dtmpvp == udvp && ldvp != NULLVP) { 124 VOP_UNLOCK(udvp, 0); 125 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 126 } 127 128 if (error == 0) { 129 /* 130 * Exchange lock and reference from vp to 131 * dunp->un_dvp. vp is upper/lower vnode, but it 132 * will need to return the unionfs vnode. 133 */ 134 if (nameiop == DELETE || nameiop == RENAME) 135 VOP_UNLOCK(vp, 0); 136 vrele(vp); 137 138 VOP_UNLOCK(dvp, 0); 139 *(ap->a_vpp) = dunp->un_dvp; 140 vref(dunp->un_dvp); 141 142 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY); 143 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 144 } else if (error == ENOENT && (cnflags & MAKEENTRY) && 145 nameiop != CREATE) 146 cache_enter(dvp, NULLVP, cnp); 147 148 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 149 150 return (error); 151 } 152 153 /* 154 * lookup upper layer 155 */ 156 if (udvp != NULLVP) { 157 uerror = VOP_LOOKUP(udvp, &uvp, cnp); 158 159 if (uerror == 0) { 160 if (udvp == uvp) { /* is dot */ 161 vrele(uvp); 162 *(ap->a_vpp) = dvp; 163 vref(dvp); 164 165 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror); 166 167 return (uerror); 168 } 169 } 170 171 /* check whiteout */ 172 if (uerror == ENOENT || uerror == EJUSTRETURN) 173 if (cnp->cn_flags & ISWHITEOUT) 174 iswhiteout = 1; /* don't lookup lower */ 175 if (iswhiteout == 0 && ldvp != NULLVP) 176 if (VOP_GETATTR(udvp, &va, cnp->cn_cred) == 0 && 177 (va.va_flags & OPAQUE)) 178 iswhiteout = 1; /* don't lookup lower */ 179 #if 0 180 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr); 181 #endif 182 } 183 184 /* 185 * lookup lower layer 186 */ 187 if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) { 188 /* always op is LOOKUP */ 189 cnp->cn_nameiop = LOOKUP; 190 cnflagsbk = cnp->cn_flags; 191 cnp->cn_flags = cnflags; 192 193 lerror = VOP_LOOKUP(ldvp, &lvp, cnp); 194 195 cnp->cn_nameiop = nameiop; 196 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) 197 cnp->cn_flags = cnflagsbk; 198 199 if (lerror == 0) { 200 if (ldvp == lvp) { /* is dot */ 201 if (uvp != NULLVP) 202 vrele(uvp); /* no need? */ 203 vrele(lvp); 204 *(ap->a_vpp) = dvp; 205 vref(dvp); 206 207 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror); 208 if (uvp != NULL) 209 VOP_UNLOCK(uvp, 0); 210 return (lerror); 211 } 212 } 213 } 214 215 /* 216 * check lookup result 217 */ 218 if (uvp == NULLVP && lvp == NULLVP) { 219 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", 220 (udvp != NULLVP ? uerror : lerror)); 221 return (udvp != NULLVP ? uerror : lerror); 222 } 223 224 /* 225 * check vnode type 226 */ 227 if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) { 228 vput(lvp); 229 lvp = NULLVP; 230 } 231 232 /* 233 * check shadow dir 234 */ 235 if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP && 236 lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR && 237 !(dvp->v_mount->mnt_flag & MNT_RDONLY) && 238 (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) { 239 /* get unionfs vnode in order to create a new shadow dir. */ 240 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp, 241 cnp); 242 if (error != 0) 243 goto unionfs_lookup_out; 244 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), 245 udvp, VTOUNIONFS(vp), cnp); 246 if (error != 0) { 247 UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir."); 248 vput(vp); 249 goto unionfs_lookup_out; 250 } 251 } 252 /* 253 * get unionfs vnode. 254 */ 255 else { 256 if (uvp != NULLVP) 257 error = uerror; 258 else 259 error = lerror; 260 if (error != 0) 261 goto unionfs_lookup_out; 262 error = unionfs_nodeget(dvp->v_mount, uvp, lvp, dvp, &vp, cnp); 263 if (error != 0) { 264 UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode."); 265 goto unionfs_lookup_out; 266 } 267 } 268 269 *(ap->a_vpp) = vp; 270 271 if (cnflags & MAKEENTRY) 272 cache_enter(dvp, vp, cnp); 273 274 /* XXXAD lock status on error */ 275 unionfs_lookup_out: 276 if (uvp != NULLVP) 277 vrele(uvp); 278 if (lvp != NULLVP) 279 vrele(lvp); 280 281 if (error == ENOENT && (cnflags & MAKEENTRY) && nameiop != CREATE) 282 cache_enter(dvp, NULLVP, cnp); 283 284 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 285 286 return (error); 287 } 288 289 static int 290 unionfs_create(void *v) 291 { 292 struct vop_create_args *ap = v; 293 struct unionfs_node *dunp; 294 struct componentname *cnp; 295 struct vnode *udvp; 296 struct vnode *vp; 297 int error; 298 299 UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n"); 300 301 dunp = VTOUNIONFS(ap->a_dvp); 302 cnp = ap->a_cnp; 303 udvp = dunp->un_uppervp; 304 error = EROFS; 305 306 if (udvp != NULLVP) { 307 if ((error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap)) == 0) { 308 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 309 ap->a_dvp, ap->a_vpp, cnp); 310 if (error) { 311 vput(vp); 312 } else { 313 vrele(vp); 314 } 315 } 316 } 317 318 UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error); 319 320 return (error); 321 } 322 323 static int 324 unionfs_whiteout(void *v) 325 { 326 struct vop_whiteout_args *ap = v; 327 struct unionfs_node *dunp; 328 struct componentname *cnp; 329 struct vnode *udvp; 330 int error; 331 332 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n"); 333 334 dunp = VTOUNIONFS(ap->a_dvp); 335 cnp = ap->a_cnp; 336 udvp = dunp->un_uppervp; 337 error = EOPNOTSUPP; 338 339 if (udvp != NULLVP) { 340 switch (ap->a_flags) { 341 case CREATE: 342 case DELETE: 343 case LOOKUP: 344 error = VOP_WHITEOUT(udvp, cnp, ap->a_flags); 345 break; 346 default: 347 error = EINVAL; 348 break; 349 } 350 } 351 352 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error); 353 354 return (error); 355 } 356 357 static int 358 unionfs_mknod(void *v) 359 { 360 struct vop_mknod_args *ap = v; 361 struct unionfs_node *dunp; 362 struct componentname *cnp; 363 struct vnode *udvp; 364 struct vnode *vp; 365 int error; 366 367 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n"); 368 369 dunp = VTOUNIONFS(ap->a_dvp); 370 cnp = ap->a_cnp; 371 udvp = dunp->un_uppervp; 372 error = EROFS; 373 374 if (udvp != NULLVP) { 375 if ((error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap)) == 0) { 376 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 377 ap->a_dvp, ap->a_vpp, cnp); 378 if (error) { 379 vput(vp); 380 } else { 381 vrele(vp); 382 } 383 } 384 } 385 386 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error); 387 388 return (error); 389 } 390 391 static int 392 unionfs_open(void *v) 393 { 394 struct vop_open_args *ap = v; 395 int error; 396 struct unionfs_node *unp; 397 struct unionfs_node_status *unsp; 398 struct vnode *uvp; 399 struct vnode *lvp; 400 struct vnode *targetvp; 401 kauth_cred_t cred; 402 403 UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n"); 404 405 error = 0; 406 unp = VTOUNIONFS(ap->a_vp); 407 uvp = unp->un_uppervp; 408 lvp = unp->un_lowervp; 409 targetvp = NULLVP; 410 cred = ap->a_cred; 411 412 unionfs_get_node_status(unp, &unsp); 413 414 if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) { 415 /* vnode is already opend. */ 416 if (unsp->uns_upper_opencnt > 0) 417 targetvp = uvp; 418 else 419 targetvp = lvp; 420 421 if (targetvp == lvp && 422 (ap->a_mode & FWRITE) && lvp->v_type == VREG) 423 targetvp = NULLVP; 424 } 425 if (targetvp == NULLVP) { 426 if (uvp == NULLVP) { 427 if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) { 428 error = unionfs_copyfile(unp, 429 !(ap->a_mode & O_TRUNC), cred); 430 if (error != 0) 431 goto unionfs_open_abort; 432 targetvp = uvp = unp->un_uppervp; 433 } else 434 targetvp = lvp; 435 } else 436 targetvp = uvp; 437 } 438 439 error = VOP_OPEN(targetvp, ap->a_mode, cred); 440 if (error == 0) { 441 if (targetvp == uvp) { 442 if (uvp->v_type == VDIR && lvp != NULLVP && 443 unsp->uns_lower_opencnt <= 0) { 444 /* open lower for readdir */ 445 error = VOP_OPEN(lvp, FREAD, cred); 446 if (error != 0) { 447 VOP_CLOSE(uvp, ap->a_mode, cred); 448 goto unionfs_open_abort; 449 } 450 unsp->uns_node_flag |= UNS_OPENL_4_READDIR; 451 unsp->uns_lower_opencnt++; 452 } 453 unsp->uns_upper_opencnt++; 454 } else { 455 unsp->uns_lower_opencnt++; 456 unsp->uns_lower_openmode = ap->a_mode; 457 } 458 } 459 460 unionfs_open_abort: 461 if (error != 0) 462 unionfs_tryrem_node_status(unp, unsp); 463 464 UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error); 465 466 return (error); 467 } 468 469 static int 470 unionfs_close(void *v) 471 { 472 struct vop_close_args *ap = v; 473 int error; 474 int locked; 475 struct unionfs_node *unp; 476 struct unionfs_node_status *unsp; 477 kauth_cred_t cred; 478 struct vnode *ovp; 479 480 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 481 482 locked = 0; 483 unp = VTOUNIONFS(ap->a_vp); 484 cred = ap->a_cred; 485 486 if (VOP_ISLOCKED(ap->a_vp) != LK_EXCLUSIVE) { 487 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 488 locked = 1; 489 } 490 unionfs_get_node_status(unp, &unsp); 491 492 if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 493 #ifdef DIAGNOSTIC 494 printf("unionfs_close: warning: open count is 0\n"); 495 #endif 496 if (unp->un_uppervp != NULLVP) 497 ovp = unp->un_uppervp; 498 else 499 ovp = unp->un_lowervp; 500 } else if (unsp->uns_upper_opencnt > 0) 501 ovp = unp->un_uppervp; 502 else 503 ovp = unp->un_lowervp; 504 505 error = VOP_CLOSE(ovp, ap->a_fflag, cred); 506 507 if (error != 0) 508 goto unionfs_close_abort; 509 510 if (ovp == unp->un_uppervp) { 511 unsp->uns_upper_opencnt--; 512 if (unsp->uns_upper_opencnt == 0) { 513 if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 514 VOP_CLOSE(unp->un_lowervp, FREAD, cred); 515 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 516 unsp->uns_lower_opencnt--; 517 } 518 } 519 } else 520 unsp->uns_lower_opencnt--; 521 522 unionfs_close_abort: 523 unionfs_tryrem_node_status(unp, unsp); 524 525 if (locked != 0) 526 VOP_UNLOCK(ap->a_vp, 0); 527 528 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 529 530 return (error); 531 } 532 533 /* 534 * Check the access mode toward shadow file/dir. 535 */ 536 static int 537 unionfs_check_corrected_access(u_short mode, struct vattr *va, kauth_cred_t cred) 538 { 539 int result; 540 int error; 541 uid_t uid; /* upper side vnode's uid */ 542 gid_t gid; /* upper side vnode's gid */ 543 u_short vmode; /* upper side vnode's mode */ 544 u_short mask; 545 546 mask = 0; 547 uid = va->va_uid; 548 gid = va->va_gid; 549 vmode = va->va_mode; 550 551 /* check owner */ 552 if (kauth_cred_getuid(cred) == uid) { 553 if (mode & VEXEC) 554 mask |= S_IXUSR; 555 if (mode & VREAD) 556 mask |= S_IRUSR; 557 if (mode & VWRITE) 558 mask |= S_IWUSR; 559 return ((vmode & mask) == mask ? 0 : EACCES); 560 } 561 562 /* check group */ 563 error = kauth_cred_ismember_gid(cred, gid, &result); 564 if (error != 0) 565 return error; 566 if (result) { 567 if (mode & VEXEC) 568 mask |= S_IXGRP; 569 if (mode & VREAD) 570 mask |= S_IRGRP; 571 if (mode & VWRITE) 572 mask |= S_IWGRP; 573 return ((vmode & mask) == mask ? 0 : EACCES); 574 } 575 576 /* check other */ 577 if (mode & VEXEC) 578 mask |= S_IXOTH; 579 if (mode & VREAD) 580 mask |= S_IROTH; 581 if (mode & VWRITE) 582 mask |= S_IWOTH; 583 584 return ((vmode & mask) == mask ? 0 : EACCES); 585 } 586 587 static int 588 unionfs_access(void *v) 589 { 590 struct vop_access_args *ap = v; 591 struct unionfs_mount *ump; 592 struct unionfs_node *unp; 593 struct vnode *uvp; 594 struct vnode *lvp; 595 struct vattr va; 596 int mode; 597 int error; 598 599 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 600 601 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 602 unp = VTOUNIONFS(ap->a_vp); 603 uvp = unp->un_uppervp; 604 lvp = unp->un_lowervp; 605 mode = ap->a_mode; 606 error = EACCES; 607 608 if ((mode & VWRITE) && 609 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 610 switch (ap->a_vp->v_type) { 611 case VREG: 612 case VDIR: 613 case VLNK: 614 return (EROFS); 615 default: 616 break; 617 } 618 } 619 620 if (uvp != NULLVP) { 621 error = VOP_ACCESS(uvp, mode, ap->a_cred); 622 623 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 624 625 return (error); 626 } 627 628 if (lvp != NULLVP) { 629 if (mode & VWRITE) { 630 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 631 switch (ap->a_vp->v_type) { 632 case VREG: 633 case VDIR: 634 case VLNK: 635 return (EROFS); 636 default: 637 break; 638 } 639 } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 640 /* check shadow file/dir */ 641 if (ump->um_copymode != UNIONFS_TRANSPARENT) { 642 error = unionfs_create_uppervattr(ump, 643 lvp, &va, ap->a_cred); 644 if (error != 0) 645 return (error); 646 647 error = unionfs_check_corrected_access( 648 mode, &va, ap->a_cred); 649 if (error != 0) 650 return (error); 651 } 652 } 653 mode &= ~VWRITE; 654 mode |= VREAD; /* will copy to upper */ 655 } 656 error = VOP_ACCESS(lvp, mode, ap->a_cred); 657 } 658 659 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 660 661 return (error); 662 } 663 664 static int 665 unionfs_getattr(void *v) 666 { 667 struct vop_getattr_args *ap = v; 668 int error; 669 struct unionfs_node *unp; 670 struct unionfs_mount *ump; 671 struct vnode *uvp; 672 struct vnode *lvp; 673 struct vattr va; 674 675 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 676 677 unp = VTOUNIONFS(ap->a_vp); 678 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 679 uvp = unp->un_uppervp; 680 lvp = unp->un_lowervp; 681 682 if (uvp != NULLVP) { 683 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 684 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 685 686 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 687 ap->a_vap->va_mode, ap->a_vap->va_uid, 688 ap->a_vap->va_gid, error); 689 690 return (error); 691 } 692 693 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 694 695 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 696 /* correct the attr toward shadow file/dir. */ 697 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 698 unionfs_create_uppervattr_core(ump, ap->a_vap, &va); 699 ap->a_vap->va_mode = va.va_mode; 700 ap->a_vap->va_uid = va.va_uid; 701 ap->a_vap->va_gid = va.va_gid; 702 } 703 } 704 705 if (error == 0) 706 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 707 708 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 709 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 710 711 return (error); 712 } 713 714 static int 715 unionfs_setattr(void *v) 716 { 717 struct vop_setattr_args *ap = v; 718 int error; 719 struct unionfs_node *unp; 720 struct vnode *uvp; 721 struct vnode *lvp; 722 struct vattr *vap; 723 724 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 725 726 error = EROFS; 727 unp = VTOUNIONFS(ap->a_vp); 728 uvp = unp->un_uppervp; 729 lvp = unp->un_lowervp; 730 vap = ap->a_vap; 731 732 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 733 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 734 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 735 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 736 return (EROFS); 737 738 if (uvp == NULLVP && lvp->v_type == VREG) { 739 error = unionfs_copyfile(unp, (vap->va_size != 0), 740 ap->a_cred); 741 if (error != 0) 742 return (error); 743 uvp = unp->un_uppervp; 744 } 745 746 if (uvp != NULLVP) 747 error = VOP_SETATTR(uvp, vap, ap->a_cred); 748 749 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 750 751 return (error); 752 } 753 754 static int 755 unionfs_read(void *v) 756 { 757 struct vop_read_args *ap = v; 758 int error; 759 struct unionfs_node *unp; 760 struct vnode *tvp; 761 762 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 763 764 unp = VTOUNIONFS(ap->a_vp); 765 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 766 767 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 768 769 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 770 771 return (error); 772 } 773 774 static int 775 unionfs_write(void *v) 776 { 777 struct vop_write_args *ap = v; 778 int error; 779 struct unionfs_node *unp; 780 struct vnode *tvp; 781 782 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 783 784 unp = VTOUNIONFS(ap->a_vp); 785 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 786 787 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 788 789 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 790 791 return (error); 792 } 793 794 static int 795 unionfs_ioctl(void *v) 796 { 797 struct vop_ioctl_args *ap = v; 798 int error; 799 struct unionfs_node *unp; 800 struct unionfs_node_status *unsp; 801 struct vnode *ovp; 802 803 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 804 805 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 806 unp = VTOUNIONFS(ap->a_vp); 807 unionfs_get_node_status(unp, &unsp); 808 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 809 unionfs_tryrem_node_status(unp, unsp); 810 VOP_UNLOCK(ap->a_vp, 0); 811 812 if (ovp == NULLVP) 813 return (EBADF); 814 815 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 816 ap->a_cred); 817 818 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error); 819 820 return (error); 821 } 822 823 static int 824 unionfs_poll(void *v) 825 { 826 struct vop_poll_args *ap = v; 827 struct unionfs_node *unp; 828 struct unionfs_node_status *unsp; 829 struct vnode *ovp; 830 831 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 832 unp = VTOUNIONFS(ap->a_vp); 833 unionfs_get_node_status(unp, &unsp); 834 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 835 unionfs_tryrem_node_status(unp, unsp); 836 VOP_UNLOCK(ap->a_vp, 0); 837 838 if (ovp == NULLVP) 839 return (EBADF); 840 841 return (VOP_POLL(ovp, ap->a_events)); 842 } 843 844 static int 845 unionfs_fsync(void *v) 846 { 847 struct vop_fsync_args *ap = v; 848 struct unionfs_node *unp; 849 struct unionfs_node_status *unsp; 850 struct vnode *ovp; 851 852 unp = VTOUNIONFS(ap->a_vp); 853 unionfs_get_node_status(unp, &unsp); 854 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 855 unionfs_tryrem_node_status(unp, unsp); 856 857 if (ovp == NULLVP) 858 return (EBADF); 859 860 return (VOP_FSYNC(ovp, ap->a_cred, ap->a_flags, ap->a_offlo, ap->a_offhi)); 861 } 862 863 static int 864 unionfs_remove(void *v) 865 { 866 struct vop_remove_args *ap = v; 867 int error; 868 struct unionfs_node *dunp; 869 struct unionfs_node *unp; 870 struct unionfs_mount *ump; 871 struct vnode *udvp; 872 struct vnode *uvp; 873 struct vnode *lvp; 874 struct componentname *cnp; 875 876 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 877 878 error = 0; 879 dunp = VTOUNIONFS(ap->a_dvp); 880 unp = VTOUNIONFS(ap->a_vp); 881 udvp = dunp->un_uppervp; 882 uvp = unp->un_uppervp; 883 lvp = unp->un_lowervp; 884 cnp = ap->a_cnp; 885 886 if (udvp == NULLVP) 887 return (EROFS); 888 889 if (uvp != NULLVP) { 890 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 891 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 892 cnp->cn_flags |= DOWHITEOUT; 893 error = VOP_REMOVE(udvp, uvp, cnp); 894 } else if (lvp != NULLVP) 895 error = unionfs_mkwhiteout(udvp, cnp, unp->un_path); 896 897 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 898 899 return (error); 900 } 901 902 static int 903 unionfs_link(void *v) 904 { 905 #if 0 906 struct vop_link_args *ap = v; 907 int error; 908 int needrelookup; 909 struct unionfs_node *dunp; 910 struct unionfs_node *unp; 911 struct vnode *udvp; 912 struct vnode *uvp; 913 struct componentname *cnp; 914 915 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 916 917 error = 0; 918 needrelookup = 0; 919 dunp = VTOUNIONFS(ap->a_tdvp); 920 unp = NULL; 921 udvp = dunp->un_uppervp; 922 uvp = NULLVP; 923 cnp = ap->a_cnp; 924 925 if (udvp == NULLVP) 926 return (EROFS); 927 928 if (ap->a_vp->v_op != unionfs_vnodeop_p) 929 uvp = ap->a_vp; 930 else { 931 unp = VTOUNIONFS(ap->a_vp); 932 933 if (unp->un_uppervp == NULLVP) { 934 if (ap->a_vp->v_type != VREG) 935 return (EOPNOTSUPP); 936 937 error = unionfs_copyfile(unp, 1, cnp->cn_cred); 938 if (error != 0) 939 return (error); 940 needrelookup = 1; 941 } 942 uvp = unp->un_uppervp; 943 } 944 945 if (needrelookup != 0) 946 error = unionfs_relookup_for_create(ap->a_tdvp, cnp); 947 948 if (error == 0) 949 error = VOP_LINK(udvp, uvp, cnp); 950 951 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 952 953 return (error); 954 #else 955 panic("XXXAD"); 956 return 0; 957 #endif 958 } 959 960 static int 961 unionfs_rename(void *v) 962 { 963 struct vop_rename_args *ap = v; 964 int error; 965 struct vnode *fdvp; 966 struct vnode *fvp; 967 struct componentname *fcnp; 968 struct vnode *tdvp; 969 struct vnode *tvp; 970 struct componentname *tcnp; 971 struct vnode *ltdvp; 972 struct vnode *ltvp; 973 974 /* rename target vnodes */ 975 struct vnode *rfdvp; 976 struct vnode *rfvp; 977 struct vnode *rtdvp; 978 struct vnode *rtvp; 979 980 int needrelookup; 981 struct unionfs_mount *ump; 982 struct unionfs_node *unp; 983 984 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 985 986 error = 0; 987 fdvp = ap->a_fdvp; 988 fvp = ap->a_fvp; 989 fcnp = ap->a_fcnp; 990 tdvp = ap->a_tdvp; 991 tvp = ap->a_tvp; 992 tcnp = ap->a_tcnp; 993 ltdvp = NULLVP; 994 ltvp = NULLVP; 995 rfdvp = fdvp; 996 rfvp = fvp; 997 rtdvp = tdvp; 998 rtvp = tvp; 999 needrelookup = 0; 1000 1001 #ifdef DIAGNOSTIC 1002 if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1003 panic("unionfs_rename: no name"); 1004 #endif 1005 1006 /* check for cross device rename */ 1007 if (fvp->v_mount != tdvp->v_mount || 1008 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 1009 error = EXDEV; 1010 goto unionfs_rename_abort; 1011 } 1012 1013 /* Renaming a file to itself has no effect. */ 1014 if (fvp == tvp) 1015 goto unionfs_rename_abort; 1016 1017 /* 1018 * from/to vnode is unionfs node. 1019 */ 1020 1021 unp = VTOUNIONFS(fdvp); 1022 #ifdef UNIONFS_IDBG_RENAME 1023 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp); 1024 #endif 1025 if (unp->un_uppervp == NULLVP) { 1026 error = ENODEV; 1027 goto unionfs_rename_abort; 1028 } 1029 rfdvp = unp->un_uppervp; 1030 vref(rfdvp); 1031 1032 unp = VTOUNIONFS(fvp); 1033 #ifdef UNIONFS_IDBG_RENAME 1034 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp); 1035 #endif 1036 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1037 if (unp->un_uppervp == NULLVP) { 1038 switch (fvp->v_type) { 1039 case VREG: 1040 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1041 goto unionfs_rename_abort; 1042 error = unionfs_copyfile(unp, 1, fcnp->cn_cred); 1043 VOP_UNLOCK(fvp, 0); 1044 if (error != 0) 1045 goto unionfs_rename_abort; 1046 break; 1047 case VDIR: 1048 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1049 goto unionfs_rename_abort; 1050 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp); 1051 VOP_UNLOCK(fvp, 0); 1052 if (error != 0) 1053 goto unionfs_rename_abort; 1054 break; 1055 default: 1056 error = ENODEV; 1057 goto unionfs_rename_abort; 1058 } 1059 1060 needrelookup = 1; 1061 } 1062 1063 if (unp->un_lowervp != NULLVP) 1064 fcnp->cn_flags |= DOWHITEOUT; 1065 rfvp = unp->un_uppervp; 1066 vref(rfvp); 1067 1068 unp = VTOUNIONFS(tdvp); 1069 #ifdef UNIONFS_IDBG_RENAME 1070 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp); 1071 #endif 1072 if (unp->un_uppervp == NULLVP) { 1073 error = ENODEV; 1074 goto unionfs_rename_abort; 1075 } 1076 rtdvp = unp->un_uppervp; 1077 ltdvp = unp->un_lowervp; 1078 vref(rtdvp); 1079 1080 if (tdvp == tvp) { 1081 rtvp = rtdvp; 1082 vref(rtvp); 1083 } else if (tvp != NULLVP) { 1084 unp = VTOUNIONFS(tvp); 1085 #ifdef UNIONFS_IDBG_RENAME 1086 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp); 1087 #endif 1088 if (unp->un_uppervp == NULLVP) 1089 rtvp = NULLVP; 1090 else { 1091 if (tvp->v_type == VDIR) { 1092 error = EINVAL; 1093 goto unionfs_rename_abort; 1094 } 1095 rtvp = unp->un_uppervp; 1096 ltvp = unp->un_lowervp; 1097 vref(rtvp); 1098 } 1099 } 1100 1101 if (needrelookup != 0) { 1102 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1103 goto unionfs_rename_abort; 1104 error = unionfs_relookup_for_delete(fdvp, fcnp); 1105 VOP_UNLOCK(fdvp, 0); 1106 if (error != 0) 1107 goto unionfs_rename_abort; 1108 1109 /* Locke of tvp is canceled in order to avoid recursive lock. */ 1110 if (tvp != NULLVP && tvp != tdvp) 1111 VOP_UNLOCK(tvp, 0); 1112 error = unionfs_relookup_for_rename(tdvp, tcnp); 1113 if (tvp != NULLVP && tvp != tdvp) 1114 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1115 if (error != 0) 1116 goto unionfs_rename_abort; 1117 } 1118 1119 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 1120 1121 if (error == 0) { 1122 if (rtvp != NULLVP && rtvp->v_type == VDIR) 1123 cache_purge(tdvp); 1124 if (fvp->v_type == VDIR && fdvp != tdvp) 1125 cache_purge(fdvp); 1126 } 1127 1128 if (fdvp != rfdvp) 1129 vrele(fdvp); 1130 if (fvp != rfvp) 1131 vrele(fvp); 1132 if (ltdvp != NULLVP) 1133 VOP_UNLOCK(ltdvp, 0); 1134 if (tdvp != rtdvp) 1135 vrele(tdvp); 1136 if (ltvp != NULLVP) 1137 VOP_UNLOCK(ltvp, 0); 1138 if (tvp != rtvp && tvp != NULLVP) { 1139 if (rtvp == NULLVP) 1140 vput(tvp); 1141 else 1142 vrele(tvp); 1143 } 1144 1145 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1146 1147 return (error); 1148 1149 unionfs_rename_abort: 1150 if (fdvp != rfdvp) 1151 vrele(rfdvp); 1152 if (fvp != rfvp) 1153 vrele(rfvp); 1154 if (tdvp != rtdvp) 1155 vrele(rtdvp); 1156 vput(tdvp); 1157 if (tvp != rtvp && rtvp != NULLVP) 1158 vrele(rtvp); 1159 if (tvp != NULLVP) { 1160 if (tdvp != tvp) 1161 vput(tvp); 1162 else 1163 vrele(tvp); 1164 } 1165 vrele(fdvp); 1166 vrele(fvp); 1167 1168 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1169 1170 return (error); 1171 } 1172 1173 static int 1174 unionfs_mkdir(void *v) 1175 { 1176 struct vop_mkdir_args *ap = v; 1177 int error; 1178 struct unionfs_node *dunp; 1179 struct componentname *cnp; 1180 struct vnode *udvp; 1181 struct vnode *uvp; 1182 struct vattr va; 1183 1184 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1185 1186 error = EROFS; 1187 dunp = VTOUNIONFS(ap->a_dvp); 1188 cnp = ap->a_cnp; 1189 udvp = dunp->un_uppervp; 1190 1191 if (udvp != NULLVP) { 1192 /* check opaque */ 1193 if (!(cnp->cn_flags & ISWHITEOUT)) { 1194 error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1195 if (error != 0) 1196 return (error); 1197 if (va.va_flags & OPAQUE) 1198 cnp->cn_flags |= ISWHITEOUT; 1199 } 1200 1201 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1202 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1203 ap->a_dvp, ap->a_vpp, cnp); 1204 if (error) { 1205 vput(uvp); 1206 } else { 1207 vrele(uvp); 1208 } 1209 } 1210 } 1211 1212 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1213 1214 return (error); 1215 } 1216 1217 static int 1218 unionfs_rmdir(void *v) 1219 { 1220 struct vop_rmdir_args *ap = v; 1221 int error; 1222 struct unionfs_node *dunp; 1223 struct unionfs_node *unp; 1224 struct unionfs_mount *ump; 1225 struct componentname *cnp; 1226 struct vnode *udvp; 1227 struct vnode *uvp; 1228 struct vnode *lvp; 1229 1230 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1231 1232 error = 0; 1233 dunp = VTOUNIONFS(ap->a_dvp); 1234 unp = VTOUNIONFS(ap->a_vp); 1235 cnp = ap->a_cnp; 1236 udvp = dunp->un_uppervp; 1237 uvp = unp->un_uppervp; 1238 lvp = unp->un_lowervp; 1239 1240 if (udvp == NULLVP) 1241 return (EROFS); 1242 1243 if (udvp == uvp) 1244 return (EOPNOTSUPP); 1245 1246 if (uvp != NULLVP) { 1247 if (lvp != NULLVP) { 1248 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred); 1249 if (error != 0) 1250 return (error); 1251 } 1252 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 1253 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1254 cnp->cn_flags |= DOWHITEOUT; 1255 error = VOP_RMDIR(udvp, uvp, cnp); 1256 } 1257 else if (lvp != NULLVP) 1258 error = unionfs_mkwhiteout(udvp, cnp, unp->un_path); 1259 1260 if (error == 0) { 1261 cache_purge(ap->a_dvp); 1262 cache_purge(ap->a_vp); 1263 } 1264 1265 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1266 1267 return (error); 1268 } 1269 1270 static int 1271 unionfs_symlink(void *v) 1272 { 1273 struct vop_symlink_args *ap = v; 1274 int error; 1275 struct unionfs_node *dunp; 1276 struct componentname *cnp; 1277 struct vnode *udvp; 1278 struct vnode *uvp; 1279 1280 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1281 1282 error = EROFS; 1283 dunp = VTOUNIONFS(ap->a_dvp); 1284 cnp = ap->a_cnp; 1285 udvp = dunp->un_uppervp; 1286 1287 if (udvp != NULLVP) { 1288 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1289 if (error == 0) { 1290 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1291 ap->a_dvp, ap->a_vpp, cnp); 1292 if (error) { 1293 vput(uvp); 1294 } else { 1295 vrele(uvp); 1296 } 1297 } 1298 } 1299 1300 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1301 1302 return (error); 1303 } 1304 1305 static int 1306 unionfs_readdir(void *v) 1307 { 1308 struct vop_readdir_args *ap = v; 1309 int error; 1310 int eofflag; 1311 int locked; 1312 struct unionfs_node *unp; 1313 struct unionfs_node_status *unsp; 1314 struct uio *uio; 1315 struct vnode *uvp; 1316 struct vnode *lvp; 1317 struct vattr va; 1318 1319 int ncookies_bk; 1320 off_t *cookies_bk; 1321 1322 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1323 1324 error = 0; 1325 eofflag = 0; 1326 locked = 0; 1327 unp = VTOUNIONFS(ap->a_vp); 1328 uio = ap->a_uio; 1329 uvp = unp->un_uppervp; 1330 lvp = unp->un_lowervp; 1331 ncookies_bk = 0; 1332 cookies_bk = NULL; 1333 1334 if (ap->a_vp->v_type != VDIR) 1335 return (ENOTDIR); 1336 1337 /* check opaque */ 1338 if (uvp != NULLVP && lvp != NULLVP) { 1339 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 1340 goto unionfs_readdir_exit; 1341 if (va.va_flags & OPAQUE) 1342 lvp = NULLVP; 1343 } 1344 1345 /* check the open count. unionfs needs to open before readdir. */ 1346 VOP_UNLOCK(ap->a_vp, 0); 1347 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 1348 unionfs_get_node_status(unp, &unsp); 1349 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 1350 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1351 unionfs_tryrem_node_status(unp, unsp); 1352 error = EBADF; 1353 } 1354 if (error != 0) 1355 goto unionfs_readdir_exit; 1356 1357 /* upper only */ 1358 if (uvp != NULLVP && lvp == NULLVP) { 1359 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1360 ap->a_cookies, ap->a_ncookies); 1361 unsp->uns_readdir_status = 0; 1362 1363 goto unionfs_readdir_exit; 1364 } 1365 1366 /* lower only */ 1367 if (uvp == NULLVP && lvp != NULLVP) { 1368 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1369 ap->a_cookies, ap->a_ncookies); 1370 unsp->uns_readdir_status = 2; 1371 1372 goto unionfs_readdir_exit; 1373 } 1374 1375 /* 1376 * readdir upper and lower 1377 */ 1378 KASSERT(uvp != NULLVP); 1379 KASSERT(lvp != NULLVP); 1380 if (uio->uio_offset == 0) 1381 unsp->uns_readdir_status = 0; 1382 1383 if (unsp->uns_readdir_status == 0) { 1384 /* read upper */ 1385 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1386 ap->a_cookies, ap->a_ncookies); 1387 1388 if (error != 0 || eofflag == 0) 1389 goto unionfs_readdir_exit; 1390 unsp->uns_readdir_status = 1; 1391 1392 /* 1393 * ufs(and other fs) needs size of uio_resid larger than 1394 * DIRBLKSIZ. 1395 * size of DIRBLKSIZ equals DEV_BSIZE. 1396 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1397 */ 1398 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 1399 goto unionfs_readdir_exit; 1400 1401 /* 1402 * backup cookies 1403 * It prepares to readdir in lower. 1404 */ 1405 if (ap->a_ncookies != NULL) { 1406 ncookies_bk = *(ap->a_ncookies); 1407 *(ap->a_ncookies) = 0; 1408 } 1409 if (ap->a_cookies != NULL) { 1410 cookies_bk = *(ap->a_cookies); 1411 *(ap->a_cookies) = NULL; 1412 } 1413 } 1414 1415 /* initialize for readdir in lower */ 1416 if (unsp->uns_readdir_status == 1) { 1417 unsp->uns_readdir_status = 2; 1418 uio->uio_offset = 0; 1419 } 1420 1421 if (lvp == NULLVP) { 1422 error = EBADF; 1423 goto unionfs_readdir_exit; 1424 } 1425 /* read lower */ 1426 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1427 ap->a_cookies, ap->a_ncookies); 1428 1429 if (cookies_bk != NULL) { 1430 /* merge cookies */ 1431 int size; 1432 off_t *newcookies, *pos; 1433 1434 size = *(ap->a_ncookies) + ncookies_bk; 1435 newcookies = (off_t *) malloc(size * sizeof(off_t), 1436 M_TEMP, M_WAITOK); 1437 pos = newcookies; 1438 1439 memcpy(pos, cookies_bk, ncookies_bk * sizeof(off_t)); 1440 pos += ncookies_bk * sizeof(off_t); 1441 memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(off_t)); 1442 free(cookies_bk, M_TEMP); 1443 free(*(ap->a_cookies), M_TEMP); 1444 *(ap->a_ncookies) = size; 1445 *(ap->a_cookies) = newcookies; 1446 } 1447 1448 unionfs_readdir_exit: 1449 if (error != 0 && ap->a_eofflag != NULL) 1450 *(ap->a_eofflag) = 1; 1451 1452 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1453 1454 return (error); 1455 } 1456 1457 static int 1458 unionfs_readlink(void *v) 1459 { 1460 struct vop_readlink_args *ap = v; 1461 int error; 1462 struct unionfs_node *unp; 1463 struct vnode *vp; 1464 1465 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 1466 1467 unp = VTOUNIONFS(ap->a_vp); 1468 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1469 1470 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1471 1472 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1473 1474 return (error); 1475 } 1476 1477 static int 1478 unionfs_inactive(void *v) 1479 { 1480 struct vop_inactive_args *ap = v; 1481 *ap->a_recycle = true; 1482 VOP_UNLOCK(ap->a_vp, 0); 1483 return (0); 1484 } 1485 1486 static int 1487 unionfs_reclaim(void *v) 1488 { 1489 struct vop_reclaim_args *ap = v; 1490 1491 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1492 1493 unionfs_noderem(ap->a_vp); 1494 1495 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1496 1497 return (0); 1498 } 1499 1500 static int 1501 unionfs_print(void *v) 1502 { 1503 struct vop_print_args *ap = v; 1504 struct unionfs_node *unp; 1505 /* struct unionfs_node_status *unsp; */ 1506 1507 unp = VTOUNIONFS(ap->a_vp); 1508 /* unionfs_get_node_status(unp, &unsp); */ 1509 1510 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1511 ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1512 /* 1513 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1514 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1515 */ 1516 1517 if (unp->un_uppervp != NULLVP) 1518 vprint("unionfs: upper", unp->un_uppervp); 1519 if (unp->un_lowervp != NULLVP) 1520 vprint("unionfs: lower", unp->un_lowervp); 1521 1522 return (0); 1523 } 1524 1525 static int 1526 unionfs_lock(void *v) 1527 { 1528 struct vop_lock_args *ap = v; 1529 int error; 1530 int flags; 1531 struct vnode *lvp; 1532 struct vnode *uvp; 1533 struct unionfs_node *unp; 1534 1535 unp = VTOUNIONFS(ap->a_vp); 1536 lvp = unp->un_lowervp; 1537 uvp = unp->un_uppervp; 1538 flags = ap->a_flags; 1539 error = 0; 1540 1541 if ((flags & LK_INTERLOCK) != 0) { 1542 mutex_exit(&ap->a_vp->v_interlock); 1543 flags &= ~LK_INTERLOCK; 1544 } 1545 1546 if (lvp != NULLVP) { 1547 error = VOP_LOCK(lvp, flags); 1548 } 1549 if (error == 0 && uvp != NULLVP) { 1550 error = VOP_LOCK(uvp, flags); 1551 if (error != 0) { 1552 VOP_UNLOCK(lvp, 0); 1553 } 1554 } 1555 1556 return error; 1557 } 1558 1559 static int 1560 unionfs_unlock(void *v) 1561 { 1562 struct vop_unlock_args *ap = v; 1563 int error; 1564 struct vnode *lvp; 1565 struct vnode *uvp; 1566 struct unionfs_node *unp; 1567 1568 unp = VTOUNIONFS(ap->a_vp); 1569 lvp = unp->un_lowervp; 1570 uvp = unp->un_uppervp; 1571 error = 0; 1572 1573 if (lvp != NULLVP) { 1574 error = VOP_UNLOCK(lvp, ap->a_flags); 1575 } 1576 if (error == 0 && uvp != NULLVP) { 1577 error = VOP_UNLOCK(uvp, ap->a_flags); 1578 } 1579 1580 return error; 1581 } 1582 1583 static int 1584 unionfs_pathconf(void *v) 1585 { 1586 struct vop_pathconf_args *ap = v; 1587 struct unionfs_node *unp; 1588 struct vnode *vp; 1589 1590 unp = VTOUNIONFS(ap->a_vp); 1591 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1592 1593 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 1594 } 1595 1596 static int 1597 unionfs_advlock(void *v) 1598 { 1599 struct vop_advlock_args *ap = v; 1600 int error; 1601 struct unionfs_node *unp; 1602 struct unionfs_node_status *unsp; 1603 struct vnode *vp; 1604 struct vnode *uvp; 1605 kauth_cred_t cred; 1606 1607 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 1608 1609 vp = ap->a_vp; 1610 cred = kauth_cred_get(); 1611 1612 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1613 1614 unp = VTOUNIONFS(ap->a_vp); 1615 uvp = unp->un_uppervp; 1616 1617 if (uvp == NULLVP) { 1618 error = unionfs_copyfile(unp, 1, cred); 1619 if (error != 0) 1620 goto unionfs_advlock_abort; 1621 uvp = unp->un_uppervp; 1622 1623 unionfs_get_node_status(unp, &unsp); 1624 if (unsp->uns_lower_opencnt > 0) { 1625 /* try reopen the vnode */ 1626 error = VOP_OPEN(uvp, unsp->uns_lower_openmode, cred); 1627 if (error) 1628 goto unionfs_advlock_abort; 1629 unsp->uns_upper_opencnt++; 1630 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, cred); 1631 unsp->uns_lower_opencnt--; 1632 } else 1633 unionfs_tryrem_node_status(unp, unsp); 1634 } 1635 1636 VOP_UNLOCK(vp, 0); 1637 1638 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 1639 1640 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1641 1642 return error; 1643 1644 unionfs_advlock_abort: 1645 VOP_UNLOCK(vp, 0); 1646 1647 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1648 1649 return error; 1650 } 1651 1652 static int 1653 unionfs_strategy(void *v) 1654 { 1655 struct vop_strategy_args *ap = v; 1656 struct unionfs_node *unp; 1657 struct vnode *vp; 1658 1659 unp = VTOUNIONFS(ap->a_vp); 1660 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1661 1662 #ifdef DIAGNOSTIC 1663 if (vp == NULLVP) 1664 panic("unionfs_strategy: nullvp"); 1665 if ((ap->a_bp->b_flags & B_READ) == 0 && vp == unp->un_lowervp) 1666 panic("unionfs_strategy: writing to lowervp"); 1667 #endif 1668 1669 return (VOP_STRATEGY(vp, ap->a_bp)); 1670 } 1671 1672 static int 1673 unionfs_kqfilter(void *v) 1674 { 1675 struct vop_kqfilter_args *ap = v; 1676 struct unionfs_node *unp; 1677 struct vnode *tvp; 1678 1679 unp = VTOUNIONFS(ap->a_vp); 1680 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1681 1682 return VOP_KQFILTER(tvp, ap->a_kn); 1683 } 1684 1685 static int 1686 unionfs_bmap(void *v) 1687 { 1688 struct vop_bmap_args *ap = v; 1689 struct unionfs_node *unp; 1690 struct vnode *tvp; 1691 1692 unp = VTOUNIONFS(ap->a_vp); 1693 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1694 1695 return VOP_BMAP(tvp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 1696 } 1697 1698 static int 1699 unionfs_mmap(void *v) 1700 { 1701 struct vop_mmap_args *ap = v; 1702 struct unionfs_node *unp; 1703 struct vnode *tvp; 1704 1705 unp = VTOUNIONFS(ap->a_vp); 1706 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1707 1708 return VOP_MMAP(tvp, ap->a_prot, ap->a_cred); 1709 } 1710 1711 static int 1712 unionfs_abortop(void *v) 1713 { 1714 struct vop_abortop_args *ap = v; 1715 struct unionfs_node *unp; 1716 struct vnode *tvp; 1717 1718 unp = VTOUNIONFS(ap->a_dvp); 1719 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1720 1721 return VOP_ABORTOP(tvp, ap->a_cnp); 1722 } 1723 1724 static int 1725 unionfs_islocked(void *v) 1726 { 1727 struct vop_islocked_args *ap = v; 1728 struct unionfs_node *unp; 1729 struct vnode *tvp; 1730 1731 unp = VTOUNIONFS(ap->a_vp); 1732 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1733 1734 return VOP_ISLOCKED(tvp); 1735 } 1736 1737 static int 1738 unionfs_seek(void *v) 1739 { 1740 struct vop_seek_args *ap = v; 1741 struct unionfs_node *unp; 1742 struct vnode *tvp; 1743 1744 unp = VTOUNIONFS(ap->a_vp); 1745 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1746 1747 return VOP_SEEK(tvp, ap->a_oldoff, ap->a_newoff, ap->a_cred); 1748 } 1749 1750 static int 1751 unionfs_putpages(void *v) 1752 { 1753 struct vop_putpages_args *ap = v; 1754 struct unionfs_node *unp; 1755 struct vnode *tvp; 1756 1757 unp = VTOUNIONFS(ap->a_vp); 1758 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1759 1760 mutex_exit(&ap->a_vp->v_interlock); 1761 if (ap->a_flags & PGO_RECLAIM) { 1762 return 0; 1763 } 1764 mutex_enter(&tvp->v_interlock); 1765 1766 return VOP_PUTPAGES(tvp, ap->a_offlo, ap->a_offhi, ap->a_flags); 1767 } 1768 1769 static int 1770 unionfs_getpages(void *v) 1771 { 1772 struct vop_getpages_args *ap = v; 1773 struct unionfs_node *unp; 1774 struct vnode *tvp; 1775 1776 unp = VTOUNIONFS(ap->a_vp); 1777 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1778 1779 if (ap->a_flags & PGO_LOCKED) { 1780 return EBUSY; 1781 } 1782 mutex_exit(&ap->a_vp->v_interlock); 1783 mutex_enter(&tvp->v_interlock); 1784 1785 return VOP_GETPAGES(tvp, ap->a_offset, ap->a_m, ap->a_count, 1786 ap->a_centeridx, ap->a_access_type, ap->a_advice, ap->a_flags); 1787 } 1788 1789 static int 1790 unionfs_revoke(void *v) 1791 { 1792 struct vop_revoke_args *ap = v; 1793 struct unionfs_node *unp; 1794 struct vnode *tvp; 1795 int error; 1796 1797 unp = VTOUNIONFS(ap->a_vp); 1798 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1799 1800 error = VOP_REVOKE(tvp, ap->a_flags); 1801 if (error == 0) { 1802 vgone(ap->a_vp); /* ??? */ 1803 } 1804 return error; 1805 } 1806 1807 /* 1808 * Global vfs data structures 1809 */ 1810 int (**unionfs_vnodeop_p)(void *); 1811 const struct vnodeopv_entry_desc unionfs_vnodeop_entries[] = { 1812 { &vop_default_desc, vn_default_error }, 1813 { &vop_lookup_desc, unionfs_lookup }, /* lookup */ 1814 { &vop_create_desc, unionfs_create }, /* create */ 1815 { &vop_whiteout_desc, unionfs_whiteout }, /* whiteout */ 1816 { &vop_mknod_desc, unionfs_mknod }, /* mknod */ 1817 { &vop_open_desc, unionfs_open }, /* open */ 1818 { &vop_close_desc, unionfs_close }, /* close */ 1819 { &vop_access_desc, unionfs_access }, /* access */ 1820 { &vop_getattr_desc, unionfs_getattr }, /* getattr */ 1821 { &vop_setattr_desc, unionfs_setattr }, /* setattr */ 1822 { &vop_read_desc, unionfs_read }, /* read */ 1823 { &vop_write_desc, unionfs_write }, /* write */ 1824 { &vop_ioctl_desc, unionfs_ioctl }, /* ioctl */ 1825 { &vop_poll_desc, unionfs_poll }, /* select */ 1826 { &vop_revoke_desc, unionfs_revoke }, /* revoke */ 1827 { &vop_mmap_desc, unionfs_mmap }, /* mmap */ 1828 { &vop_fsync_desc, unionfs_fsync }, /* fsync */ 1829 { &vop_seek_desc, unionfs_seek }, /* seek */ 1830 { &vop_remove_desc, unionfs_remove }, /* remove */ 1831 { &vop_link_desc, unionfs_link }, /* link */ 1832 { &vop_rename_desc, unionfs_rename }, /* rename */ 1833 { &vop_mkdir_desc, unionfs_mkdir }, /* mkdir */ 1834 { &vop_rmdir_desc, unionfs_rmdir }, /* rmdir */ 1835 { &vop_symlink_desc, unionfs_symlink }, /* symlink */ 1836 { &vop_readdir_desc, unionfs_readdir }, /* readdir */ 1837 { &vop_readlink_desc, unionfs_readlink }, /* readlink */ 1838 { &vop_abortop_desc, unionfs_abortop }, /* abortop */ 1839 { &vop_inactive_desc, unionfs_inactive }, /* inactive */ 1840 { &vop_reclaim_desc, unionfs_reclaim }, /* reclaim */ 1841 { &vop_lock_desc, unionfs_lock }, /* lock */ 1842 { &vop_unlock_desc, unionfs_unlock }, /* unlock */ 1843 { &vop_bmap_desc, unionfs_bmap }, /* bmap */ 1844 { &vop_strategy_desc, unionfs_strategy }, /* strategy */ 1845 { &vop_print_desc, unionfs_print }, /* print */ 1846 { &vop_islocked_desc, unionfs_islocked }, /* islocked */ 1847 { &vop_pathconf_desc, unionfs_pathconf }, /* pathconf */ 1848 { &vop_advlock_desc, unionfs_advlock }, /* advlock */ 1849 { &vop_getpages_desc, unionfs_getpages }, /* getpages */ 1850 { &vop_putpages_desc, unionfs_putpages }, /* putpages */ 1851 { &vop_kqfilter_desc, unionfs_kqfilter }, /* kqfilter */ 1852 #ifdef notdef 1853 { &vop_bwrite_desc, unionfs_bwrite }, /* bwrite */ 1854 #endif 1855 { NULL, NULL } 1856 }; 1857 const struct vnodeopv_desc unionfs_vnodeop_opv_desc = 1858 { &unionfs_vnodeop_p, unionfs_vnodeop_entries }; 1859