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