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); 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); 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); 136 vrele(vp); 137 138 VOP_UNLOCK(dvp); 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); 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 struct unionfs_node *unp; 475 struct unionfs_node_status *unsp; 476 kauth_cred_t cred; 477 struct vnode *ovp; 478 479 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 480 481 KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE); 482 unp = VTOUNIONFS(ap->a_vp); 483 cred = ap->a_cred; 484 485 unionfs_get_node_status(unp, &unsp); 486 487 if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 488 #ifdef DIAGNOSTIC 489 printf("unionfs_close: warning: open count is 0\n"); 490 #endif 491 if (unp->un_uppervp != NULLVP) 492 ovp = unp->un_uppervp; 493 else 494 ovp = unp->un_lowervp; 495 } else if (unsp->uns_upper_opencnt > 0) 496 ovp = unp->un_uppervp; 497 else 498 ovp = unp->un_lowervp; 499 500 error = VOP_CLOSE(ovp, ap->a_fflag, cred); 501 502 if (error != 0) 503 goto unionfs_close_abort; 504 505 if (ovp == unp->un_uppervp) { 506 unsp->uns_upper_opencnt--; 507 if (unsp->uns_upper_opencnt == 0) { 508 if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 509 VOP_CLOSE(unp->un_lowervp, FREAD, cred); 510 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 511 unsp->uns_lower_opencnt--; 512 } 513 } 514 } else 515 unsp->uns_lower_opencnt--; 516 517 unionfs_close_abort: 518 unionfs_tryrem_node_status(unp, unsp); 519 520 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 521 522 return (error); 523 } 524 525 /* 526 * Check the access mode toward shadow file/dir. 527 */ 528 static int 529 unionfs_check_corrected_access(u_short mode, struct vattr *va, kauth_cred_t cred) 530 { 531 int result; 532 int error; 533 uid_t uid; /* upper side vnode's uid */ 534 gid_t gid; /* upper side vnode's gid */ 535 u_short vmode; /* upper side vnode's mode */ 536 u_short mask; 537 538 mask = 0; 539 uid = va->va_uid; 540 gid = va->va_gid; 541 vmode = va->va_mode; 542 543 /* check owner */ 544 if (kauth_cred_getuid(cred) == uid) { 545 if (mode & VEXEC) 546 mask |= S_IXUSR; 547 if (mode & VREAD) 548 mask |= S_IRUSR; 549 if (mode & VWRITE) 550 mask |= S_IWUSR; 551 return ((vmode & mask) == mask ? 0 : EACCES); 552 } 553 554 /* check group */ 555 error = kauth_cred_ismember_gid(cred, gid, &result); 556 if (error != 0) 557 return error; 558 if (result) { 559 if (mode & VEXEC) 560 mask |= S_IXGRP; 561 if (mode & VREAD) 562 mask |= S_IRGRP; 563 if (mode & VWRITE) 564 mask |= S_IWGRP; 565 return ((vmode & mask) == mask ? 0 : EACCES); 566 } 567 568 /* check other */ 569 if (mode & VEXEC) 570 mask |= S_IXOTH; 571 if (mode & VREAD) 572 mask |= S_IROTH; 573 if (mode & VWRITE) 574 mask |= S_IWOTH; 575 576 return ((vmode & mask) == mask ? 0 : EACCES); 577 } 578 579 static int 580 unionfs_access(void *v) 581 { 582 struct vop_access_args *ap = v; 583 struct unionfs_mount *ump; 584 struct unionfs_node *unp; 585 struct vnode *uvp; 586 struct vnode *lvp; 587 struct vattr va; 588 int mode; 589 int error; 590 591 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 592 593 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 594 unp = VTOUNIONFS(ap->a_vp); 595 uvp = unp->un_uppervp; 596 lvp = unp->un_lowervp; 597 mode = ap->a_mode; 598 error = EACCES; 599 600 if ((mode & VWRITE) && 601 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 602 switch (ap->a_vp->v_type) { 603 case VREG: 604 case VDIR: 605 case VLNK: 606 return (EROFS); 607 default: 608 break; 609 } 610 } 611 612 if (uvp != NULLVP) { 613 error = VOP_ACCESS(uvp, mode, ap->a_cred); 614 615 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 616 617 return (error); 618 } 619 620 if (lvp != NULLVP) { 621 if (mode & VWRITE) { 622 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 623 switch (ap->a_vp->v_type) { 624 case VREG: 625 case VDIR: 626 case VLNK: 627 return (EROFS); 628 default: 629 break; 630 } 631 } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 632 /* check shadow file/dir */ 633 if (ump->um_copymode != UNIONFS_TRANSPARENT) { 634 error = unionfs_create_uppervattr(ump, 635 lvp, &va, ap->a_cred); 636 if (error != 0) 637 return (error); 638 639 error = unionfs_check_corrected_access( 640 mode, &va, ap->a_cred); 641 if (error != 0) 642 return (error); 643 } 644 } 645 mode &= ~VWRITE; 646 mode |= VREAD; /* will copy to upper */ 647 } 648 error = VOP_ACCESS(lvp, mode, ap->a_cred); 649 } 650 651 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 652 653 return (error); 654 } 655 656 static int 657 unionfs_getattr(void *v) 658 { 659 struct vop_getattr_args *ap = v; 660 int error; 661 struct unionfs_node *unp; 662 struct unionfs_mount *ump; 663 struct vnode *uvp; 664 struct vnode *lvp; 665 struct vattr va; 666 667 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 668 669 unp = VTOUNIONFS(ap->a_vp); 670 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 671 uvp = unp->un_uppervp; 672 lvp = unp->un_lowervp; 673 674 if (uvp != NULLVP) { 675 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) 676 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 677 678 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 679 ap->a_vap->va_mode, ap->a_vap->va_uid, 680 ap->a_vap->va_gid, error); 681 682 return (error); 683 } 684 685 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); 686 687 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 688 /* correct the attr toward shadow file/dir. */ 689 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 690 unionfs_create_uppervattr_core(ump, ap->a_vap, &va); 691 ap->a_vap->va_mode = va.va_mode; 692 ap->a_vap->va_uid = va.va_uid; 693 ap->a_vap->va_gid = va.va_gid; 694 } 695 } 696 697 if (error == 0) 698 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid; 699 700 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 701 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 702 703 return (error); 704 } 705 706 static int 707 unionfs_setattr(void *v) 708 { 709 struct vop_setattr_args *ap = v; 710 int error; 711 struct unionfs_node *unp; 712 struct vnode *uvp; 713 struct vnode *lvp; 714 struct vattr *vap; 715 716 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 717 718 error = EROFS; 719 unp = VTOUNIONFS(ap->a_vp); 720 uvp = unp->un_uppervp; 721 lvp = unp->un_lowervp; 722 vap = ap->a_vap; 723 724 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 725 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 726 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 727 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 728 return (EROFS); 729 730 if (uvp == NULLVP && lvp->v_type == VREG) { 731 error = unionfs_copyfile(unp, (vap->va_size != 0), 732 ap->a_cred); 733 if (error != 0) 734 return (error); 735 uvp = unp->un_uppervp; 736 } 737 738 if (uvp != NULLVP) 739 error = VOP_SETATTR(uvp, vap, ap->a_cred); 740 741 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 742 743 return (error); 744 } 745 746 static int 747 unionfs_read(void *v) 748 { 749 struct vop_read_args *ap = v; 750 int error; 751 struct unionfs_node *unp; 752 struct vnode *tvp; 753 754 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 755 756 unp = VTOUNIONFS(ap->a_vp); 757 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 758 759 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 760 761 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 762 763 return (error); 764 } 765 766 static int 767 unionfs_write(void *v) 768 { 769 struct vop_write_args *ap = v; 770 int error; 771 struct unionfs_node *unp; 772 struct vnode *tvp; 773 774 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 775 776 unp = VTOUNIONFS(ap->a_vp); 777 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 778 779 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 780 781 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 782 783 return (error); 784 } 785 786 static int 787 unionfs_ioctl(void *v) 788 { 789 struct vop_ioctl_args *ap = v; 790 int error; 791 struct unionfs_node *unp; 792 struct unionfs_node_status *unsp; 793 struct vnode *ovp; 794 795 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 796 797 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 798 unp = VTOUNIONFS(ap->a_vp); 799 unionfs_get_node_status(unp, &unsp); 800 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 801 unionfs_tryrem_node_status(unp, unsp); 802 VOP_UNLOCK(ap->a_vp); 803 804 if (ovp == NULLVP) 805 return (EBADF); 806 807 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 808 ap->a_cred); 809 810 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error); 811 812 return (error); 813 } 814 815 static int 816 unionfs_poll(void *v) 817 { 818 struct vop_poll_args *ap = v; 819 struct unionfs_node *unp; 820 struct unionfs_node_status *unsp; 821 struct vnode *ovp; 822 823 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 824 unp = VTOUNIONFS(ap->a_vp); 825 unionfs_get_node_status(unp, &unsp); 826 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 827 unionfs_tryrem_node_status(unp, unsp); 828 VOP_UNLOCK(ap->a_vp); 829 830 if (ovp == NULLVP) 831 return (EBADF); 832 833 return (VOP_POLL(ovp, ap->a_events)); 834 } 835 836 static int 837 unionfs_fsync(void *v) 838 { 839 struct vop_fsync_args *ap = v; 840 struct unionfs_node *unp; 841 struct unionfs_node_status *unsp; 842 struct vnode *ovp; 843 844 unp = VTOUNIONFS(ap->a_vp); 845 unionfs_get_node_status(unp, &unsp); 846 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 847 unionfs_tryrem_node_status(unp, unsp); 848 849 if (ovp == NULLVP) 850 return (EBADF); 851 852 return (VOP_FSYNC(ovp, ap->a_cred, ap->a_flags, ap->a_offlo, ap->a_offhi)); 853 } 854 855 static int 856 unionfs_remove(void *v) 857 { 858 struct vop_remove_args *ap = v; 859 int error; 860 struct unionfs_node *dunp; 861 struct unionfs_node *unp; 862 struct unionfs_mount *ump; 863 struct vnode *udvp; 864 struct vnode *uvp; 865 struct vnode *lvp; 866 struct componentname *cnp; 867 868 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 869 870 error = 0; 871 dunp = VTOUNIONFS(ap->a_dvp); 872 unp = VTOUNIONFS(ap->a_vp); 873 udvp = dunp->un_uppervp; 874 uvp = unp->un_uppervp; 875 lvp = unp->un_lowervp; 876 cnp = ap->a_cnp; 877 878 if (udvp == NULLVP) 879 return (EROFS); 880 881 if (uvp != NULLVP) { 882 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 883 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 884 cnp->cn_flags |= DOWHITEOUT; 885 error = VOP_REMOVE(udvp, uvp, cnp); 886 } else if (lvp != NULLVP) 887 error = unionfs_mkwhiteout(udvp, cnp, unp->un_path); 888 889 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 890 891 return (error); 892 } 893 894 static int 895 unionfs_link(void *v) 896 { 897 #if 0 898 struct vop_link_args *ap = v; 899 int error; 900 int needrelookup; 901 struct unionfs_node *dunp; 902 struct unionfs_node *unp; 903 struct vnode *udvp; 904 struct vnode *uvp; 905 struct componentname *cnp; 906 907 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 908 909 error = 0; 910 needrelookup = 0; 911 dunp = VTOUNIONFS(ap->a_tdvp); 912 unp = NULL; 913 udvp = dunp->un_uppervp; 914 uvp = NULLVP; 915 cnp = ap->a_cnp; 916 917 if (udvp == NULLVP) 918 return (EROFS); 919 920 if (ap->a_vp->v_op != unionfs_vnodeop_p) 921 uvp = ap->a_vp; 922 else { 923 unp = VTOUNIONFS(ap->a_vp); 924 925 if (unp->un_uppervp == NULLVP) { 926 if (ap->a_vp->v_type != VREG) 927 return (EOPNOTSUPP); 928 929 error = unionfs_copyfile(unp, 1, cnp->cn_cred); 930 if (error != 0) 931 return (error); 932 needrelookup = 1; 933 } 934 uvp = unp->un_uppervp; 935 } 936 937 if (needrelookup != 0) 938 error = unionfs_relookup_for_create(ap->a_tdvp, cnp); 939 940 if (error == 0) 941 error = VOP_LINK(udvp, uvp, cnp); 942 943 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 944 945 return (error); 946 #else 947 panic("XXXAD"); 948 return 0; 949 #endif 950 } 951 952 static int 953 unionfs_rename(void *v) 954 { 955 struct vop_rename_args *ap = v; 956 int error; 957 struct vnode *fdvp; 958 struct vnode *fvp; 959 struct componentname *fcnp; 960 struct vnode *tdvp; 961 struct vnode *tvp; 962 struct componentname *tcnp; 963 struct vnode *ltdvp; 964 struct vnode *ltvp; 965 966 /* rename target vnodes */ 967 struct vnode *rfdvp; 968 struct vnode *rfvp; 969 struct vnode *rtdvp; 970 struct vnode *rtvp; 971 972 int needrelookup; 973 struct unionfs_mount *ump; 974 struct unionfs_node *unp; 975 976 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 977 978 error = 0; 979 fdvp = ap->a_fdvp; 980 fvp = ap->a_fvp; 981 fcnp = ap->a_fcnp; 982 tdvp = ap->a_tdvp; 983 tvp = ap->a_tvp; 984 tcnp = ap->a_tcnp; 985 ltdvp = NULLVP; 986 ltvp = NULLVP; 987 rfdvp = fdvp; 988 rfvp = fvp; 989 rtdvp = tdvp; 990 rtvp = tvp; 991 needrelookup = 0; 992 993 #ifdef DIAGNOSTIC 994 if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 995 panic("unionfs_rename: no name"); 996 #endif 997 998 /* check for cross device rename */ 999 if (fvp->v_mount != tdvp->v_mount || 1000 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 1001 error = EXDEV; 1002 goto unionfs_rename_abort; 1003 } 1004 1005 /* Renaming a file to itself has no effect. */ 1006 if (fvp == tvp) 1007 goto unionfs_rename_abort; 1008 1009 /* 1010 * from/to vnode is unionfs node. 1011 */ 1012 1013 unp = VTOUNIONFS(fdvp); 1014 #ifdef UNIONFS_IDBG_RENAME 1015 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp); 1016 #endif 1017 if (unp->un_uppervp == NULLVP) { 1018 error = ENODEV; 1019 goto unionfs_rename_abort; 1020 } 1021 rfdvp = unp->un_uppervp; 1022 vref(rfdvp); 1023 1024 unp = VTOUNIONFS(fvp); 1025 #ifdef UNIONFS_IDBG_RENAME 1026 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp); 1027 #endif 1028 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1029 if (unp->un_uppervp == NULLVP) { 1030 switch (fvp->v_type) { 1031 case VREG: 1032 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1033 goto unionfs_rename_abort; 1034 error = unionfs_copyfile(unp, 1, fcnp->cn_cred); 1035 VOP_UNLOCK(fvp); 1036 if (error != 0) 1037 goto unionfs_rename_abort; 1038 break; 1039 case VDIR: 1040 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1041 goto unionfs_rename_abort; 1042 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp); 1043 VOP_UNLOCK(fvp); 1044 if (error != 0) 1045 goto unionfs_rename_abort; 1046 break; 1047 default: 1048 error = ENODEV; 1049 goto unionfs_rename_abort; 1050 } 1051 1052 needrelookup = 1; 1053 } 1054 1055 if (unp->un_lowervp != NULLVP) 1056 fcnp->cn_flags |= DOWHITEOUT; 1057 rfvp = unp->un_uppervp; 1058 vref(rfvp); 1059 1060 unp = VTOUNIONFS(tdvp); 1061 #ifdef UNIONFS_IDBG_RENAME 1062 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp); 1063 #endif 1064 if (unp->un_uppervp == NULLVP) { 1065 error = ENODEV; 1066 goto unionfs_rename_abort; 1067 } 1068 rtdvp = unp->un_uppervp; 1069 ltdvp = unp->un_lowervp; 1070 vref(rtdvp); 1071 1072 if (tdvp == tvp) { 1073 rtvp = rtdvp; 1074 vref(rtvp); 1075 } else if (tvp != NULLVP) { 1076 unp = VTOUNIONFS(tvp); 1077 #ifdef UNIONFS_IDBG_RENAME 1078 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp); 1079 #endif 1080 if (unp->un_uppervp == NULLVP) 1081 rtvp = NULLVP; 1082 else { 1083 if (tvp->v_type == VDIR) { 1084 error = EINVAL; 1085 goto unionfs_rename_abort; 1086 } 1087 rtvp = unp->un_uppervp; 1088 ltvp = unp->un_lowervp; 1089 vref(rtvp); 1090 } 1091 } 1092 1093 if (needrelookup != 0) { 1094 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0) 1095 goto unionfs_rename_abort; 1096 error = unionfs_relookup_for_delete(fdvp, fcnp); 1097 VOP_UNLOCK(fdvp); 1098 if (error != 0) 1099 goto unionfs_rename_abort; 1100 1101 /* Locke of tvp is canceled in order to avoid recursive lock. */ 1102 if (tvp != NULLVP && tvp != tdvp) 1103 VOP_UNLOCK(tvp); 1104 error = unionfs_relookup_for_rename(tdvp, tcnp); 1105 if (tvp != NULLVP && tvp != tdvp) 1106 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); 1107 if (error != 0) 1108 goto unionfs_rename_abort; 1109 } 1110 1111 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 1112 1113 if (error == 0) { 1114 if (rtvp != NULLVP && rtvp->v_type == VDIR) 1115 cache_purge(tdvp); 1116 if (fvp->v_type == VDIR && fdvp != tdvp) 1117 cache_purge(fdvp); 1118 } 1119 1120 if (fdvp != rfdvp) 1121 vrele(fdvp); 1122 if (fvp != rfvp) 1123 vrele(fvp); 1124 if (ltdvp != NULLVP) 1125 VOP_UNLOCK(ltdvp); 1126 if (tdvp != rtdvp) 1127 vrele(tdvp); 1128 if (ltvp != NULLVP) 1129 VOP_UNLOCK(ltvp); 1130 if (tvp != rtvp && tvp != NULLVP) { 1131 if (rtvp == NULLVP) 1132 vput(tvp); 1133 else 1134 vrele(tvp); 1135 } 1136 1137 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1138 1139 return (error); 1140 1141 unionfs_rename_abort: 1142 if (fdvp != rfdvp) 1143 vrele(rfdvp); 1144 if (fvp != rfvp) 1145 vrele(rfvp); 1146 if (tdvp != rtdvp) 1147 vrele(rtdvp); 1148 vput(tdvp); 1149 if (tvp != rtvp && rtvp != NULLVP) 1150 vrele(rtvp); 1151 if (tvp != NULLVP) { 1152 if (tdvp != tvp) 1153 vput(tvp); 1154 else 1155 vrele(tvp); 1156 } 1157 vrele(fdvp); 1158 vrele(fvp); 1159 1160 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1161 1162 return (error); 1163 } 1164 1165 static int 1166 unionfs_mkdir(void *v) 1167 { 1168 struct vop_mkdir_args *ap = v; 1169 int error; 1170 struct unionfs_node *dunp; 1171 struct componentname *cnp; 1172 struct vnode *udvp; 1173 struct vnode *uvp; 1174 struct vattr va; 1175 1176 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1177 1178 error = EROFS; 1179 dunp = VTOUNIONFS(ap->a_dvp); 1180 cnp = ap->a_cnp; 1181 udvp = dunp->un_uppervp; 1182 1183 if (udvp != NULLVP) { 1184 /* check opaque */ 1185 if (!(cnp->cn_flags & ISWHITEOUT)) { 1186 error = VOP_GETATTR(udvp, &va, cnp->cn_cred); 1187 if (error != 0) 1188 return (error); 1189 if (va.va_flags & OPAQUE) 1190 cnp->cn_flags |= ISWHITEOUT; 1191 } 1192 1193 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1194 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1195 ap->a_dvp, ap->a_vpp, cnp); 1196 if (error) { 1197 vput(uvp); 1198 } else { 1199 vrele(uvp); 1200 } 1201 } 1202 } 1203 1204 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1205 1206 return (error); 1207 } 1208 1209 static int 1210 unionfs_rmdir(void *v) 1211 { 1212 struct vop_rmdir_args *ap = v; 1213 int error; 1214 struct unionfs_node *dunp; 1215 struct unionfs_node *unp; 1216 struct unionfs_mount *ump; 1217 struct componentname *cnp; 1218 struct vnode *udvp; 1219 struct vnode *uvp; 1220 struct vnode *lvp; 1221 1222 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1223 1224 error = 0; 1225 dunp = VTOUNIONFS(ap->a_dvp); 1226 unp = VTOUNIONFS(ap->a_vp); 1227 cnp = ap->a_cnp; 1228 udvp = dunp->un_uppervp; 1229 uvp = unp->un_uppervp; 1230 lvp = unp->un_lowervp; 1231 1232 if (udvp == NULLVP) 1233 return (EROFS); 1234 1235 if (udvp == uvp) 1236 return (EOPNOTSUPP); 1237 1238 if (uvp != NULLVP) { 1239 if (lvp != NULLVP) { 1240 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred); 1241 if (error != 0) 1242 return (error); 1243 } 1244 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 1245 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) 1246 cnp->cn_flags |= DOWHITEOUT; 1247 error = VOP_RMDIR(udvp, uvp, cnp); 1248 } 1249 else if (lvp != NULLVP) 1250 error = unionfs_mkwhiteout(udvp, cnp, unp->un_path); 1251 1252 if (error == 0) { 1253 cache_purge(ap->a_dvp); 1254 cache_purge(ap->a_vp); 1255 } 1256 1257 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1258 1259 return (error); 1260 } 1261 1262 static int 1263 unionfs_symlink(void *v) 1264 { 1265 struct vop_symlink_args *ap = v; 1266 int error; 1267 struct unionfs_node *dunp; 1268 struct componentname *cnp; 1269 struct vnode *udvp; 1270 struct vnode *uvp; 1271 1272 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1273 1274 error = EROFS; 1275 dunp = VTOUNIONFS(ap->a_dvp); 1276 cnp = ap->a_cnp; 1277 udvp = dunp->un_uppervp; 1278 1279 if (udvp != NULLVP) { 1280 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1281 if (error == 0) { 1282 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1283 ap->a_dvp, ap->a_vpp, cnp); 1284 if (error) { 1285 vput(uvp); 1286 } else { 1287 vrele(uvp); 1288 } 1289 } 1290 } 1291 1292 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1293 1294 return (error); 1295 } 1296 1297 static int 1298 unionfs_readdir(void *v) 1299 { 1300 struct vop_readdir_args *ap = v; 1301 int error; 1302 int eofflag; 1303 int locked; 1304 struct unionfs_node *unp; 1305 struct unionfs_node_status *unsp; 1306 struct uio *uio; 1307 struct vnode *uvp; 1308 struct vnode *lvp; 1309 struct vattr va; 1310 1311 int ncookies_bk; 1312 off_t *cookies_bk; 1313 1314 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1315 1316 error = 0; 1317 eofflag = 0; 1318 locked = 0; 1319 unp = VTOUNIONFS(ap->a_vp); 1320 uio = ap->a_uio; 1321 uvp = unp->un_uppervp; 1322 lvp = unp->un_lowervp; 1323 ncookies_bk = 0; 1324 cookies_bk = NULL; 1325 1326 if (ap->a_vp->v_type != VDIR) 1327 return (ENOTDIR); 1328 1329 /* check opaque */ 1330 if (uvp != NULLVP && lvp != NULLVP) { 1331 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0) 1332 goto unionfs_readdir_exit; 1333 if (va.va_flags & OPAQUE) 1334 lvp = NULLVP; 1335 } 1336 1337 /* check the open count. unionfs needs to open before readdir. */ 1338 VOP_UNLOCK(ap->a_vp); 1339 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); 1340 unionfs_get_node_status(unp, &unsp); 1341 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) || 1342 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) { 1343 unionfs_tryrem_node_status(unp, unsp); 1344 error = EBADF; 1345 } 1346 if (error != 0) 1347 goto unionfs_readdir_exit; 1348 1349 /* upper only */ 1350 if (uvp != NULLVP && lvp == NULLVP) { 1351 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1352 ap->a_cookies, ap->a_ncookies); 1353 unsp->uns_readdir_status = 0; 1354 1355 goto unionfs_readdir_exit; 1356 } 1357 1358 /* lower only */ 1359 if (uvp == NULLVP && lvp != NULLVP) { 1360 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1361 ap->a_cookies, ap->a_ncookies); 1362 unsp->uns_readdir_status = 2; 1363 1364 goto unionfs_readdir_exit; 1365 } 1366 1367 /* 1368 * readdir upper and lower 1369 */ 1370 KASSERT(uvp != NULLVP); 1371 KASSERT(lvp != NULLVP); 1372 if (uio->uio_offset == 0) 1373 unsp->uns_readdir_status = 0; 1374 1375 if (unsp->uns_readdir_status == 0) { 1376 /* read upper */ 1377 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1378 ap->a_cookies, ap->a_ncookies); 1379 1380 if (error != 0 || eofflag == 0) 1381 goto unionfs_readdir_exit; 1382 unsp->uns_readdir_status = 1; 1383 1384 /* 1385 * ufs(and other fs) needs size of uio_resid larger than 1386 * DIRBLKSIZ. 1387 * size of DIRBLKSIZ equals DEV_BSIZE. 1388 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1389 */ 1390 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) 1391 goto unionfs_readdir_exit; 1392 1393 /* 1394 * backup cookies 1395 * It prepares to readdir in lower. 1396 */ 1397 if (ap->a_ncookies != NULL) { 1398 ncookies_bk = *(ap->a_ncookies); 1399 *(ap->a_ncookies) = 0; 1400 } 1401 if (ap->a_cookies != NULL) { 1402 cookies_bk = *(ap->a_cookies); 1403 *(ap->a_cookies) = NULL; 1404 } 1405 } 1406 1407 /* initialize for readdir in lower */ 1408 if (unsp->uns_readdir_status == 1) { 1409 unsp->uns_readdir_status = 2; 1410 uio->uio_offset = 0; 1411 } 1412 1413 if (lvp == NULLVP) { 1414 error = EBADF; 1415 goto unionfs_readdir_exit; 1416 } 1417 /* read lower */ 1418 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1419 ap->a_cookies, ap->a_ncookies); 1420 1421 if (cookies_bk != NULL) { 1422 /* merge cookies */ 1423 int size; 1424 off_t *newcookies, *pos; 1425 1426 size = *(ap->a_ncookies) + ncookies_bk; 1427 newcookies = (off_t *) malloc(size * sizeof(off_t), 1428 M_TEMP, M_WAITOK); 1429 pos = newcookies; 1430 1431 memcpy(pos, cookies_bk, ncookies_bk * sizeof(off_t)); 1432 pos += ncookies_bk * sizeof(off_t); 1433 memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(off_t)); 1434 free(cookies_bk, M_TEMP); 1435 free(*(ap->a_cookies), M_TEMP); 1436 *(ap->a_ncookies) = size; 1437 *(ap->a_cookies) = newcookies; 1438 } 1439 1440 unionfs_readdir_exit: 1441 if (error != 0 && ap->a_eofflag != NULL) 1442 *(ap->a_eofflag) = 1; 1443 1444 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1445 1446 return (error); 1447 } 1448 1449 static int 1450 unionfs_readlink(void *v) 1451 { 1452 struct vop_readlink_args *ap = v; 1453 int error; 1454 struct unionfs_node *unp; 1455 struct vnode *vp; 1456 1457 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 1458 1459 unp = VTOUNIONFS(ap->a_vp); 1460 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1461 1462 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1463 1464 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1465 1466 return (error); 1467 } 1468 1469 static int 1470 unionfs_inactive(void *v) 1471 { 1472 struct vop_inactive_args *ap = v; 1473 *ap->a_recycle = true; 1474 VOP_UNLOCK(ap->a_vp); 1475 return (0); 1476 } 1477 1478 static int 1479 unionfs_reclaim(void *v) 1480 { 1481 struct vop_reclaim_args *ap = v; 1482 1483 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1484 1485 unionfs_noderem(ap->a_vp); 1486 1487 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1488 1489 return (0); 1490 } 1491 1492 static int 1493 unionfs_print(void *v) 1494 { 1495 struct vop_print_args *ap = v; 1496 struct unionfs_node *unp; 1497 /* struct unionfs_node_status *unsp; */ 1498 1499 unp = VTOUNIONFS(ap->a_vp); 1500 /* unionfs_get_node_status(unp, &unsp); */ 1501 1502 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1503 ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1504 /* 1505 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1506 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1507 */ 1508 1509 if (unp->un_uppervp != NULLVP) 1510 vprint("unionfs: upper", unp->un_uppervp); 1511 if (unp->un_lowervp != NULLVP) 1512 vprint("unionfs: lower", unp->un_lowervp); 1513 1514 return (0); 1515 } 1516 1517 static int 1518 unionfs_lock(void *v) 1519 { 1520 struct vop_lock_args *ap = v; 1521 int error; 1522 int flags; 1523 struct vnode *lvp; 1524 struct vnode *uvp; 1525 struct unionfs_node *unp; 1526 1527 unp = VTOUNIONFS(ap->a_vp); 1528 lvp = unp->un_lowervp; 1529 uvp = unp->un_uppervp; 1530 flags = ap->a_flags; 1531 error = 0; 1532 1533 if (lvp != NULLVP) { 1534 error = VOP_LOCK(lvp, flags); 1535 } 1536 if (error == 0 && uvp != NULLVP) { 1537 error = VOP_LOCK(uvp, flags); 1538 if (error != 0) { 1539 VOP_UNLOCK(lvp); 1540 } 1541 } 1542 1543 return error; 1544 } 1545 1546 static int 1547 unionfs_unlock(void *v) 1548 { 1549 struct vop_unlock_args *ap = v; 1550 int error; 1551 struct vnode *lvp; 1552 struct vnode *uvp; 1553 struct unionfs_node *unp; 1554 1555 unp = VTOUNIONFS(ap->a_vp); 1556 lvp = unp->un_lowervp; 1557 uvp = unp->un_uppervp; 1558 error = 0; 1559 1560 if (lvp != NULLVP) { 1561 error = VOP_UNLOCK(lvp); 1562 } 1563 if (error == 0 && uvp != NULLVP) { 1564 error = VOP_UNLOCK(uvp); 1565 } 1566 1567 return error; 1568 } 1569 1570 static int 1571 unionfs_pathconf(void *v) 1572 { 1573 struct vop_pathconf_args *ap = v; 1574 struct unionfs_node *unp; 1575 struct vnode *vp; 1576 1577 unp = VTOUNIONFS(ap->a_vp); 1578 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1579 1580 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 1581 } 1582 1583 static int 1584 unionfs_advlock(void *v) 1585 { 1586 struct vop_advlock_args *ap = v; 1587 int error; 1588 struct unionfs_node *unp; 1589 struct unionfs_node_status *unsp; 1590 struct vnode *vp; 1591 struct vnode *uvp; 1592 kauth_cred_t cred; 1593 1594 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 1595 1596 vp = ap->a_vp; 1597 cred = kauth_cred_get(); 1598 1599 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1600 1601 unp = VTOUNIONFS(ap->a_vp); 1602 uvp = unp->un_uppervp; 1603 1604 if (uvp == NULLVP) { 1605 error = unionfs_copyfile(unp, 1, cred); 1606 if (error != 0) 1607 goto unionfs_advlock_abort; 1608 uvp = unp->un_uppervp; 1609 1610 unionfs_get_node_status(unp, &unsp); 1611 if (unsp->uns_lower_opencnt > 0) { 1612 /* try reopen the vnode */ 1613 error = VOP_OPEN(uvp, unsp->uns_lower_openmode, cred); 1614 if (error) 1615 goto unionfs_advlock_abort; 1616 unsp->uns_upper_opencnt++; 1617 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, cred); 1618 unsp->uns_lower_opencnt--; 1619 } else 1620 unionfs_tryrem_node_status(unp, unsp); 1621 } 1622 1623 VOP_UNLOCK(vp); 1624 1625 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 1626 1627 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1628 1629 return error; 1630 1631 unionfs_advlock_abort: 1632 VOP_UNLOCK(vp); 1633 1634 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1635 1636 return error; 1637 } 1638 1639 static int 1640 unionfs_strategy(void *v) 1641 { 1642 struct vop_strategy_args *ap = v; 1643 struct unionfs_node *unp; 1644 struct vnode *vp; 1645 1646 unp = VTOUNIONFS(ap->a_vp); 1647 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1648 1649 #ifdef DIAGNOSTIC 1650 if (vp == NULLVP) 1651 panic("unionfs_strategy: nullvp"); 1652 if ((ap->a_bp->b_flags & B_READ) == 0 && vp == unp->un_lowervp) 1653 panic("unionfs_strategy: writing to lowervp"); 1654 #endif 1655 1656 return (VOP_STRATEGY(vp, ap->a_bp)); 1657 } 1658 1659 static int 1660 unionfs_kqfilter(void *v) 1661 { 1662 struct vop_kqfilter_args *ap = v; 1663 struct unionfs_node *unp; 1664 struct vnode *tvp; 1665 1666 unp = VTOUNIONFS(ap->a_vp); 1667 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1668 1669 return VOP_KQFILTER(tvp, ap->a_kn); 1670 } 1671 1672 static int 1673 unionfs_bmap(void *v) 1674 { 1675 struct vop_bmap_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_BMAP(tvp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 1683 } 1684 1685 static int 1686 unionfs_mmap(void *v) 1687 { 1688 struct vop_mmap_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_MMAP(tvp, ap->a_prot, ap->a_cred); 1696 } 1697 1698 static int 1699 unionfs_abortop(void *v) 1700 { 1701 struct vop_abortop_args *ap = v; 1702 struct unionfs_node *unp; 1703 struct vnode *tvp; 1704 1705 unp = VTOUNIONFS(ap->a_dvp); 1706 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1707 1708 return VOP_ABORTOP(tvp, ap->a_cnp); 1709 } 1710 1711 static int 1712 unionfs_islocked(void *v) 1713 { 1714 struct vop_islocked_args *ap = v; 1715 struct unionfs_node *unp; 1716 struct vnode *tvp; 1717 1718 unp = VTOUNIONFS(ap->a_vp); 1719 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1720 1721 return VOP_ISLOCKED(tvp); 1722 } 1723 1724 static int 1725 unionfs_seek(void *v) 1726 { 1727 struct vop_seek_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_SEEK(tvp, ap->a_oldoff, ap->a_newoff, ap->a_cred); 1735 } 1736 1737 static int 1738 unionfs_putpages(void *v) 1739 { 1740 struct vop_putpages_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 mutex_exit(&ap->a_vp->v_interlock); 1748 if (ap->a_flags & PGO_RECLAIM) { 1749 return 0; 1750 } 1751 mutex_enter(&tvp->v_interlock); 1752 1753 return VOP_PUTPAGES(tvp, ap->a_offlo, ap->a_offhi, ap->a_flags); 1754 } 1755 1756 static int 1757 unionfs_getpages(void *v) 1758 { 1759 struct vop_getpages_args *ap = v; 1760 struct unionfs_node *unp; 1761 struct vnode *tvp; 1762 1763 unp = VTOUNIONFS(ap->a_vp); 1764 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1765 1766 if (ap->a_flags & PGO_LOCKED) { 1767 return EBUSY; 1768 } 1769 mutex_exit(&ap->a_vp->v_interlock); 1770 mutex_enter(&tvp->v_interlock); 1771 1772 return VOP_GETPAGES(tvp, ap->a_offset, ap->a_m, ap->a_count, 1773 ap->a_centeridx, ap->a_access_type, ap->a_advice, ap->a_flags); 1774 } 1775 1776 static int 1777 unionfs_revoke(void *v) 1778 { 1779 struct vop_revoke_args *ap = v; 1780 struct unionfs_node *unp; 1781 struct vnode *tvp; 1782 int error; 1783 1784 unp = VTOUNIONFS(ap->a_vp); 1785 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1786 1787 error = VOP_REVOKE(tvp, ap->a_flags); 1788 if (error == 0) { 1789 vgone(ap->a_vp); /* ??? */ 1790 } 1791 return error; 1792 } 1793 1794 /* 1795 * Global vfs data structures 1796 */ 1797 int (**unionfs_vnodeop_p)(void *); 1798 const struct vnodeopv_entry_desc unionfs_vnodeop_entries[] = { 1799 { &vop_default_desc, vn_default_error }, 1800 { &vop_lookup_desc, unionfs_lookup }, /* lookup */ 1801 { &vop_create_desc, unionfs_create }, /* create */ 1802 { &vop_whiteout_desc, unionfs_whiteout }, /* whiteout */ 1803 { &vop_mknod_desc, unionfs_mknod }, /* mknod */ 1804 { &vop_open_desc, unionfs_open }, /* open */ 1805 { &vop_close_desc, unionfs_close }, /* close */ 1806 { &vop_access_desc, unionfs_access }, /* access */ 1807 { &vop_getattr_desc, unionfs_getattr }, /* getattr */ 1808 { &vop_setattr_desc, unionfs_setattr }, /* setattr */ 1809 { &vop_read_desc, unionfs_read }, /* read */ 1810 { &vop_write_desc, unionfs_write }, /* write */ 1811 { &vop_ioctl_desc, unionfs_ioctl }, /* ioctl */ 1812 { &vop_poll_desc, unionfs_poll }, /* select */ 1813 { &vop_revoke_desc, unionfs_revoke }, /* revoke */ 1814 { &vop_mmap_desc, unionfs_mmap }, /* mmap */ 1815 { &vop_fsync_desc, unionfs_fsync }, /* fsync */ 1816 { &vop_seek_desc, unionfs_seek }, /* seek */ 1817 { &vop_remove_desc, unionfs_remove }, /* remove */ 1818 { &vop_link_desc, unionfs_link }, /* link */ 1819 { &vop_rename_desc, unionfs_rename }, /* rename */ 1820 { &vop_mkdir_desc, unionfs_mkdir }, /* mkdir */ 1821 { &vop_rmdir_desc, unionfs_rmdir }, /* rmdir */ 1822 { &vop_symlink_desc, unionfs_symlink }, /* symlink */ 1823 { &vop_readdir_desc, unionfs_readdir }, /* readdir */ 1824 { &vop_readlink_desc, unionfs_readlink }, /* readlink */ 1825 { &vop_abortop_desc, unionfs_abortop }, /* abortop */ 1826 { &vop_inactive_desc, unionfs_inactive }, /* inactive */ 1827 { &vop_reclaim_desc, unionfs_reclaim }, /* reclaim */ 1828 { &vop_lock_desc, unionfs_lock }, /* lock */ 1829 { &vop_unlock_desc, unionfs_unlock }, /* unlock */ 1830 { &vop_bmap_desc, unionfs_bmap }, /* bmap */ 1831 { &vop_strategy_desc, unionfs_strategy }, /* strategy */ 1832 { &vop_print_desc, unionfs_print }, /* print */ 1833 { &vop_islocked_desc, unionfs_islocked }, /* islocked */ 1834 { &vop_pathconf_desc, unionfs_pathconf }, /* pathconf */ 1835 { &vop_advlock_desc, unionfs_advlock }, /* advlock */ 1836 { &vop_getpages_desc, unionfs_getpages }, /* getpages */ 1837 { &vop_putpages_desc, unionfs_putpages }, /* putpages */ 1838 { &vop_kqfilter_desc, unionfs_kqfilter }, /* kqfilter */ 1839 #ifdef notdef 1840 { &vop_bwrite_desc, unionfs_bwrite }, /* bwrite */ 1841 #endif 1842 { NULL, NULL } 1843 }; 1844 const struct vnodeopv_desc unionfs_vnodeop_opv_desc = 1845 { &unionfs_vnodeop_p, unionfs_vnodeop_entries }; 1846