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$ 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/kdb.h> 53 #include <sys/fcntl.h> 54 #include <sys/stat.h> 55 #include <sys/dirent.h> 56 #include <sys/proc.h> 57 #include <sys/bio.h> 58 #include <sys/buf.h> 59 60 #include <fs/unionfs/union.h> 61 62 #include <vm/vm.h> 63 #include <vm/vm_extern.h> 64 #include <vm/vm_object.h> 65 #include <vm/vnode_pager.h> 66 67 #if 0 68 #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) 69 #define UNIONFS_IDBG_RENAME 70 #else 71 #define UNIONFS_INTERNAL_DEBUG(msg, args...) 72 #endif 73 74 /* lockmgr lock <-> reverse table */ 75 struct lk_lr_table { 76 int lock; 77 int revlock; 78 }; 79 80 static struct lk_lr_table un_llt[] = { 81 {LK_SHARED, LK_RELEASE}, 82 {LK_EXCLUSIVE, LK_RELEASE}, 83 {LK_UPGRADE, LK_DOWNGRADE}, 84 {LK_EXCLUPGRADE, LK_DOWNGRADE}, 85 {LK_DOWNGRADE, LK_UPGRADE}, 86 {0, 0} 87 }; 88 89 90 static int 91 unionfs_lookup(struct vop_lookup_args *ap) 92 { 93 int iswhiteout; 94 int lockflag; 95 int error , uerror, lerror; 96 u_long nameiop; 97 u_long cnflags, cnflagsbk; 98 struct unionfs_node *dunp; 99 struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp; 100 struct vattr va; 101 struct componentname *cnp; 102 struct thread *td; 103 104 iswhiteout = 0; 105 lockflag = 0; 106 error = uerror = lerror = ENOENT; 107 cnp = ap->a_cnp; 108 nameiop = cnp->cn_nameiop; 109 cnflags = cnp->cn_flags; 110 dvp = ap->a_dvp; 111 dunp = VTOUNIONFS(dvp); 112 udvp = dunp->un_uppervp; 113 ldvp = dunp->un_lowervp; 114 vp = uvp = lvp = NULLVP; 115 td = curthread; 116 *(ap->a_vpp) = NULLVP; 117 118 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr); 119 120 if (dvp->v_type != VDIR) 121 return (ENOTDIR); 122 123 /* 124 * If read-only and op is not LOOKUP, will return EROFS. 125 */ 126 if ((cnflags & ISLASTCN) && 127 (dvp->v_mount->mnt_flag & MNT_RDONLY) && 128 LOOKUP != nameiop) 129 return (EROFS); 130 131 /* 132 * lookup dotdot 133 */ 134 if (cnflags & ISDOTDOT) { 135 if (LOOKUP != nameiop && udvp == NULLVP) 136 return (EROFS); 137 138 if (udvp != NULLVP) { 139 dtmpvp = udvp; 140 if (ldvp != NULLVP) 141 VOP_UNLOCK(ldvp, 0, td); 142 } 143 else 144 dtmpvp = ldvp; 145 146 error = VOP_LOOKUP(dtmpvp, &vp, cnp); 147 148 if (dtmpvp == udvp && ldvp != NULLVP) { 149 VOP_UNLOCK(udvp, 0, td); 150 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 151 } 152 153 if (error == 0) { 154 /* 155 * Exchange lock and reference from vp to 156 * dunp->un_dvp. vp is upper/lower vnode, but it 157 * will need to return the unionfs vnode. 158 */ 159 if (nameiop == DELETE || nameiop == RENAME || 160 (cnp->cn_lkflags & LK_TYPE_MASK)) 161 VOP_UNLOCK(vp, 0, td); 162 vrele(vp); 163 164 VOP_UNLOCK(dvp, 0, td); 165 *(ap->a_vpp) = dunp->un_dvp; 166 vref(dunp->un_dvp); 167 168 if (nameiop == DELETE || nameiop == RENAME) 169 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY, td); 170 else if (cnp->cn_lkflags & LK_TYPE_MASK) 171 vn_lock(dunp->un_dvp, cnp->cn_lkflags | LK_RETRY, td); 172 173 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 174 } 175 176 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 177 178 return (error); 179 } 180 181 /* 182 * lookup upper layer 183 */ 184 if (udvp != NULLVP) { 185 uerror = VOP_LOOKUP(udvp, &uvp, cnp); 186 187 if (uerror == 0) { 188 if (udvp == uvp) { /* is dot */ 189 vrele(uvp); 190 *(ap->a_vpp) = dvp; 191 vref(dvp); 192 193 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror); 194 195 return (uerror); 196 } 197 if (nameiop == DELETE || nameiop == RENAME || 198 (cnp->cn_lkflags & LK_TYPE_MASK)) 199 VOP_UNLOCK(uvp, 0, td); 200 } 201 202 /* check whiteout */ 203 if (uerror == ENOENT || uerror == EJUSTRETURN) 204 if (cnp->cn_flags & ISWHITEOUT) 205 iswhiteout = 1; /* don't lookup lower */ 206 if (iswhiteout == 0 && ldvp != NULLVP) 207 if (VOP_GETATTR(udvp, &va, cnp->cn_cred, td) == 0 && 208 (va.va_flags & OPAQUE)) 209 iswhiteout = 1; /* don't lookup lower */ 210 #if 0 211 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr); 212 #endif 213 } 214 215 /* 216 * lookup lower layer 217 */ 218 if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) { 219 /* always op is LOOKUP */ 220 cnp->cn_nameiop = LOOKUP; 221 cnflagsbk = cnp->cn_flags; 222 cnp->cn_flags = cnflags; 223 224 lerror = VOP_LOOKUP(ldvp, &lvp, cnp); 225 226 cnp->cn_nameiop = nameiop; 227 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN)) 228 cnp->cn_flags = cnflagsbk; 229 230 if (lerror == 0) { 231 if (ldvp == lvp) { /* is dot */ 232 if (uvp != NULLVP) 233 vrele(uvp); /* no need? */ 234 vrele(lvp); 235 *(ap->a_vpp) = dvp; 236 vref(dvp); 237 238 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror); 239 240 return (lerror); 241 } 242 if (cnp->cn_lkflags & LK_TYPE_MASK) 243 VOP_UNLOCK(lvp, 0, td); 244 } 245 } 246 247 /* 248 * check lookup result 249 */ 250 if (uvp == NULLVP && lvp == NULLVP) { 251 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", 252 (udvp != NULLVP ? uerror : lerror)); 253 return (udvp != NULLVP ? uerror : lerror); 254 } 255 256 /* 257 * check vnode type 258 */ 259 if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) { 260 vrele(lvp); 261 lvp = NULLVP; 262 } 263 264 /* 265 * check shadow dir 266 */ 267 if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP && 268 lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR && 269 !(dvp->v_mount->mnt_flag & MNT_RDONLY) && 270 (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) { 271 /* get unionfs vnode in order to create a new shadow dir. */ 272 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp, 273 cnp, td); 274 if (error != 0) 275 goto unionfs_lookup_out; 276 277 if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK)) 278 VOP_UNLOCK(vp, 0, td); 279 if (LK_EXCLUSIVE != VOP_ISLOCKED(vp, td)) { 280 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 281 lockflag = 1; 282 } 283 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount), 284 udvp, VTOUNIONFS(vp), cnp, td); 285 if (lockflag != 0) 286 VOP_UNLOCK(vp, 0, td); 287 if (error != 0) { 288 UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir."); 289 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE) 290 vput(vp); 291 else 292 vrele(vp); 293 goto unionfs_lookup_out; 294 } 295 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED) 296 vn_lock(vp, LK_SHARED | LK_RETRY, td); 297 } 298 /* 299 * get unionfs vnode. 300 */ 301 else { 302 if (uvp != NULLVP) 303 error = uerror; 304 else 305 error = lerror; 306 if (error != 0) 307 goto unionfs_lookup_out; 308 error = unionfs_nodeget(dvp->v_mount, uvp, lvp, dvp, &vp, 309 cnp, td); 310 if (error != 0) { 311 UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode."); 312 goto unionfs_lookup_out; 313 } 314 if ((nameiop == DELETE || nameiop == RENAME) && 315 (cnp->cn_lkflags & LK_TYPE_MASK) == 0) 316 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 317 } 318 319 *(ap->a_vpp) = vp; 320 321 unionfs_lookup_out: 322 if (uvp != NULLVP) 323 vrele(uvp); 324 if (lvp != NULLVP) 325 vrele(lvp); 326 327 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error); 328 329 return (error); 330 } 331 332 static int 333 unionfs_create(struct vop_create_args *ap) 334 { 335 struct unionfs_node *dunp; 336 struct componentname *cnp; 337 struct thread *td; 338 struct vnode *udvp; 339 struct vnode *vp; 340 int error; 341 342 UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n"); 343 344 dunp = VTOUNIONFS(ap->a_dvp); 345 cnp = ap->a_cnp; 346 td = curthread; 347 udvp = dunp->un_uppervp; 348 error = EROFS; 349 350 if (udvp != NULLVP) { 351 if ((error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap)) == 0) { 352 VOP_UNLOCK(vp, 0, td); 353 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 354 ap->a_dvp, ap->a_vpp, cnp, td); 355 vrele(vp); 356 } 357 } 358 359 UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error); 360 361 return (error); 362 } 363 364 static int 365 unionfs_whiteout(struct vop_whiteout_args *ap) 366 { 367 struct unionfs_node *dunp; 368 struct componentname *cnp; 369 struct vnode *udvp; 370 int error; 371 372 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n"); 373 374 dunp = VTOUNIONFS(ap->a_dvp); 375 cnp = ap->a_cnp; 376 udvp = dunp->un_uppervp; 377 error = EOPNOTSUPP; 378 379 if (udvp != NULLVP) { 380 switch (ap->a_flags) { 381 case CREATE: 382 case DELETE: 383 case LOOKUP: 384 error = VOP_WHITEOUT(udvp, cnp, ap->a_flags); 385 break; 386 default: 387 error = EINVAL; 388 break; 389 } 390 } 391 392 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error); 393 394 return (error); 395 } 396 397 static int 398 unionfs_mknod(struct vop_mknod_args *ap) 399 { 400 struct unionfs_node *dunp; 401 struct componentname *cnp; 402 struct thread *td; 403 struct vnode *udvp; 404 struct vnode *vp; 405 int error; 406 407 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n"); 408 409 dunp = VTOUNIONFS(ap->a_dvp); 410 cnp = ap->a_cnp; 411 td = curthread; 412 udvp = dunp->un_uppervp; 413 error = EROFS; 414 415 if (udvp != NULLVP) { 416 if ((error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap)) == 0) { 417 VOP_UNLOCK(vp, 0, td); 418 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP, 419 ap->a_dvp, ap->a_vpp, cnp, td); 420 vrele(vp); 421 } 422 } 423 424 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error); 425 426 return (error); 427 } 428 429 static int 430 unionfs_open(struct vop_open_args *ap) 431 { 432 int error; 433 struct unionfs_node *unp; 434 struct unionfs_node_status *unsp; 435 struct vnode *uvp; 436 struct vnode *lvp; 437 struct vnode *targetvp; 438 struct ucred *cred; 439 struct thread *td; 440 441 UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n"); 442 443 error = 0; 444 unp = VTOUNIONFS(ap->a_vp); 445 uvp = unp->un_uppervp; 446 lvp = unp->un_lowervp; 447 targetvp = NULLVP; 448 cred = ap->a_cred; 449 td = ap->a_td; 450 451 unionfs_get_node_status(unp, td, &unsp); 452 453 if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) { 454 /* vnode is already opend. */ 455 if (unsp->uns_upper_opencnt > 0) 456 targetvp = uvp; 457 else 458 targetvp = lvp; 459 460 if (targetvp == lvp && 461 (ap->a_mode & FWRITE) && lvp->v_type == VREG) 462 targetvp = NULLVP; 463 } 464 if (targetvp == NULLVP) { 465 if (uvp == NULLVP) { 466 if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) { 467 error = unionfs_copyfile(unp, 468 !(ap->a_mode & O_TRUNC), cred, td); 469 if (error != 0) 470 goto unionfs_open_abort; 471 targetvp = uvp = unp->un_uppervp; 472 } else 473 targetvp = lvp; 474 } else 475 targetvp = uvp; 476 } 477 478 error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fdidx); 479 if (error == 0) { 480 if (targetvp == uvp) { 481 if (uvp->v_type == VDIR && lvp != NULLVP && 482 unsp->uns_lower_opencnt <= 0) { 483 /* open lower for readdir */ 484 error = VOP_OPEN(lvp, FREAD, cred, td, -1); 485 if (error != 0) { 486 VOP_CLOSE(uvp, ap->a_mode, cred, td); 487 goto unionfs_open_abort; 488 } 489 unsp->uns_node_flag |= UNS_OPENL_4_READDIR; 490 unsp->uns_lower_opencnt++; 491 } 492 unsp->uns_upper_opencnt++; 493 } else { 494 unsp->uns_lower_opencnt++; 495 unsp->uns_lower_openmode = ap->a_mode; 496 unsp->uns_lower_fdidx = ap->a_fdidx; 497 } 498 ap->a_vp->v_object = targetvp->v_object; 499 } 500 501 unionfs_open_abort: 502 if (error != 0) 503 unionfs_tryrem_node_status(unp, td, unsp); 504 505 UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error); 506 507 return (error); 508 } 509 510 static int 511 unionfs_close(struct vop_close_args *ap) 512 { 513 int error; 514 int locked; 515 struct unionfs_node *unp; 516 struct unionfs_node_status *unsp; 517 struct ucred *cred; 518 struct thread *td; 519 struct vnode *ovp; 520 521 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n"); 522 523 locked = 0; 524 unp = VTOUNIONFS(ap->a_vp); 525 cred = ap->a_cred; 526 td = ap->a_td; 527 528 if (VOP_ISLOCKED(ap->a_vp, td) != LK_EXCLUSIVE) { 529 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td); 530 locked = 1; 531 } 532 unionfs_get_node_status(unp, td, &unsp); 533 534 if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) { 535 #ifdef DIAGNOSTIC 536 printf("unionfs_close: warning: open count is 0\n"); 537 #endif 538 if (unp->un_uppervp != NULLVP) 539 ovp = unp->un_uppervp; 540 else 541 ovp = unp->un_lowervp; 542 } else if (unsp->uns_upper_opencnt > 0) 543 ovp = unp->un_uppervp; 544 else 545 ovp = unp->un_lowervp; 546 547 error = VOP_CLOSE(ovp, ap->a_fflag, cred, td); 548 549 if (error != 0) 550 goto unionfs_close_abort; 551 552 ap->a_vp->v_object = ovp->v_object; 553 554 if (ovp == unp->un_uppervp) { 555 unsp->uns_upper_opencnt--; 556 if (unsp->uns_upper_opencnt == 0) { 557 if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) { 558 VOP_CLOSE(unp->un_lowervp, FREAD, cred, td); 559 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR; 560 unsp->uns_lower_opencnt--; 561 } 562 if (unsp->uns_lower_opencnt > 0) 563 ap->a_vp->v_object = unp->un_lowervp->v_object; 564 } 565 } else 566 unsp->uns_lower_opencnt--; 567 568 unionfs_close_abort: 569 unionfs_tryrem_node_status(unp, td, unsp); 570 571 if (locked != 0) 572 VOP_UNLOCK(ap->a_vp, 0, td); 573 574 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error); 575 576 return (error); 577 } 578 579 /* 580 * Check the access mode toward shadow file/dir. 581 */ 582 static int 583 unionfs_check_corrected_access(u_short mode, 584 struct vattr *va, 585 struct ucred *cred) 586 { 587 int count; 588 uid_t uid; /* upper side vnode's uid */ 589 gid_t gid; /* upper side vnode's gid */ 590 u_short vmode; /* upper side vnode's mode */ 591 gid_t *gp; 592 u_short mask; 593 594 mask = 0; 595 uid = va->va_uid; 596 gid = va->va_gid; 597 vmode = va->va_mode; 598 599 /* check owner */ 600 if (cred->cr_uid == uid) { 601 if (mode & VEXEC) 602 mask |= S_IXUSR; 603 if (mode & VREAD) 604 mask |= S_IRUSR; 605 if (mode & VWRITE) 606 mask |= S_IWUSR; 607 return ((vmode & mask) == mask ? 0 : EACCES); 608 } 609 610 /* check group */ 611 count = 0; 612 gp = cred->cr_groups; 613 for (; count < cred->cr_ngroups; count++, gp++) { 614 if (gid == *gp) { 615 if (mode & VEXEC) 616 mask |= S_IXGRP; 617 if (mode & VREAD) 618 mask |= S_IRGRP; 619 if (mode & VWRITE) 620 mask |= S_IWGRP; 621 return ((vmode & mask) == mask ? 0 : EACCES); 622 } 623 } 624 625 /* check other */ 626 if (mode & VEXEC) 627 mask |= S_IXOTH; 628 if (mode & VREAD) 629 mask |= S_IROTH; 630 if (mode & VWRITE) 631 mask |= S_IWOTH; 632 633 return ((vmode & mask) == mask ? 0 : EACCES); 634 } 635 636 static int 637 unionfs_access(struct vop_access_args *ap) 638 { 639 struct unionfs_mount *ump; 640 struct unionfs_node *unp; 641 struct vnode *uvp; 642 struct vnode *lvp; 643 struct thread *td; 644 struct vattr va; 645 int mode; 646 int error; 647 648 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n"); 649 650 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 651 unp = VTOUNIONFS(ap->a_vp); 652 uvp = unp->un_uppervp; 653 lvp = unp->un_lowervp; 654 td = ap->a_td; 655 mode = ap->a_mode; 656 error = EACCES; 657 658 if ((mode & VWRITE) && 659 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) { 660 switch (ap->a_vp->v_type) { 661 case VREG: 662 case VDIR: 663 case VLNK: 664 return (EROFS); 665 default: 666 break; 667 } 668 } 669 670 if (uvp != NULLVP) { 671 error = VOP_ACCESS(uvp, mode, ap->a_cred, td); 672 673 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 674 675 return (error); 676 } 677 678 if (lvp != NULLVP) { 679 if (mode & VWRITE) { 680 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { 681 switch (ap->a_vp->v_type) { 682 case VREG: 683 case VDIR: 684 case VLNK: 685 return (EROFS); 686 default: 687 break; 688 } 689 } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 690 /* check shadow file/dir */ 691 if (ump->um_copymode != UNIONFS_TRANSPARENT) { 692 error = unionfs_create_uppervattr(ump, 693 lvp, &va, ap->a_cred, td); 694 if (error != 0) 695 return (error); 696 697 error = unionfs_check_corrected_access( 698 mode, &va, ap->a_cred); 699 if (error != 0) 700 return (error); 701 } 702 } 703 mode &= ~VWRITE; 704 mode |= VREAD; /* will copy to upper */ 705 } 706 error = VOP_ACCESS(lvp, mode, ap->a_cred, td); 707 } 708 709 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); 710 711 return (error); 712 } 713 714 static int 715 unionfs_getattr(struct vop_getattr_args *ap) 716 { 717 int error; 718 struct unionfs_node *unp; 719 struct unionfs_mount *ump; 720 struct vnode *uvp; 721 struct vnode *lvp; 722 struct thread *td; 723 struct vattr va; 724 725 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); 726 727 unp = VTOUNIONFS(ap->a_vp); 728 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); 729 uvp = unp->un_uppervp; 730 lvp = unp->un_lowervp; 731 td = ap->a_td; 732 733 if (uvp != NULLVP) { 734 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred, td)) == 0) 735 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 736 737 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 738 ap->a_vap->va_mode, ap->a_vap->va_uid, 739 ap->a_vap->va_gid, error); 740 741 return (error); 742 } 743 744 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred, td); 745 746 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { 747 /* correct the attr toward shadow file/dir. */ 748 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { 749 unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); 750 ap->a_vap->va_mode = va.va_mode; 751 ap->a_vap->va_uid = va.va_uid; 752 ap->a_vap->va_gid = va.va_gid; 753 } 754 } 755 756 if (error == 0) 757 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 758 759 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", 760 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error); 761 762 return (error); 763 } 764 765 static int 766 unionfs_setattr(struct vop_setattr_args *ap) 767 { 768 int error; 769 struct unionfs_node *unp; 770 struct vnode *uvp; 771 struct vnode *lvp; 772 struct thread *td; 773 struct vattr *vap; 774 775 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n"); 776 777 error = EROFS; 778 unp = VTOUNIONFS(ap->a_vp); 779 uvp = unp->un_uppervp; 780 lvp = unp->un_lowervp; 781 td = ap->a_td; 782 vap = ap->a_vap; 783 784 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) && 785 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 786 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 787 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)) 788 return (EROFS); 789 790 if (uvp == NULLVP && lvp->v_type == VREG) { 791 error = unionfs_copyfile(unp, (vap->va_size != 0), 792 ap->a_cred, td); 793 if (error != 0) 794 return (error); 795 uvp = unp->un_uppervp; 796 } 797 798 if (uvp != NULLVP) 799 error = VOP_SETATTR(uvp, vap, ap->a_cred, td); 800 801 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error); 802 803 return (error); 804 } 805 806 static int 807 unionfs_read(struct vop_read_args *ap) 808 { 809 int error; 810 struct unionfs_node *unp; 811 struct vnode *tvp; 812 813 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */ 814 815 unp = VTOUNIONFS(ap->a_vp); 816 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 817 818 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 819 820 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */ 821 822 return (error); 823 } 824 825 static int 826 unionfs_write(struct vop_write_args *ap) 827 { 828 int error; 829 struct unionfs_node *unp; 830 struct vnode *tvp; 831 832 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */ 833 834 unp = VTOUNIONFS(ap->a_vp); 835 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 836 837 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred); 838 839 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */ 840 841 return (error); 842 } 843 844 static int 845 unionfs_lease(struct vop_lease_args *ap) 846 { 847 int error; 848 struct unionfs_node *unp; 849 struct vnode *vp; 850 851 UNIONFS_INTERNAL_DEBUG("unionfs_lease: enter\n"); 852 853 unp = VTOUNIONFS(ap->a_vp); 854 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 855 856 error = VOP_LEASE(vp, ap->a_td, ap->a_cred, ap->a_flag); 857 858 UNIONFS_INTERNAL_DEBUG("unionfs_lease: lease (%d)\n", error); 859 860 return (error); 861 } 862 863 static int 864 unionfs_ioctl(struct vop_ioctl_args *ap) 865 { 866 int error; 867 struct unionfs_node *unp; 868 struct unionfs_node_status *unsp; 869 struct vnode *ovp; 870 871 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n"); 872 873 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td); 874 unp = VTOUNIONFS(ap->a_vp); 875 unionfs_get_node_status(unp, ap->a_td, &unsp); 876 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 877 VOP_UNLOCK(ap->a_vp, 0, ap->a_td); 878 879 if (ovp == NULLVP) 880 return (EBADF); 881 882 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag, 883 ap->a_cred, ap->a_td); 884 885 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error); 886 887 return (error); 888 } 889 890 static int 891 unionfs_poll(struct vop_poll_args *ap) 892 { 893 struct unionfs_node *unp; 894 struct unionfs_node_status *unsp; 895 struct vnode *ovp; 896 897 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td); 898 unp = VTOUNIONFS(ap->a_vp); 899 unionfs_get_node_status(unp, ap->a_td, &unsp); 900 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 901 VOP_UNLOCK(ap->a_vp, 0, ap->a_td); 902 903 if (ovp == NULLVP) 904 return (EBADF); 905 906 return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td)); 907 } 908 909 static int 910 unionfs_fsync(struct vop_fsync_args *ap) 911 { 912 struct unionfs_node *unp; 913 struct unionfs_node_status *unsp; 914 struct vnode *ovp; 915 916 unp = VTOUNIONFS(ap->a_vp); 917 unionfs_get_node_status(unp, ap->a_td, &unsp); 918 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp); 919 920 if (ovp == NULLVP) 921 return (EBADF); 922 923 return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td)); 924 } 925 926 static int 927 unionfs_remove(struct vop_remove_args *ap) 928 { 929 int error; 930 struct unionfs_node *dunp; 931 struct unionfs_node *unp; 932 struct vnode *udvp; 933 struct vnode *uvp; 934 struct vnode *lvp; 935 struct componentname *cnp; 936 struct thread *td; 937 938 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n"); 939 940 error = 0; 941 dunp = VTOUNIONFS(ap->a_dvp); 942 unp = VTOUNIONFS(ap->a_vp); 943 udvp = dunp->un_uppervp; 944 uvp = unp->un_uppervp; 945 lvp = unp->un_lowervp; 946 cnp = ap->a_cnp; 947 td = curthread; 948 949 if (udvp == NULLVP) 950 return (EROFS); 951 952 if (uvp != NULLVP) { 953 cnp->cn_flags |= DOWHITEOUT; 954 error = VOP_REMOVE(udvp, uvp, cnp); 955 } else if (lvp != NULLVP) 956 error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path); 957 958 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error); 959 960 return (error); 961 } 962 963 static int 964 unionfs_link(struct vop_link_args *ap) 965 { 966 int error; 967 int needrelookup; 968 struct unionfs_node *dunp; 969 struct unionfs_node *unp; 970 struct vnode *udvp; 971 struct vnode *uvp; 972 struct componentname *cnp; 973 struct thread *td; 974 975 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n"); 976 977 error = 0; 978 needrelookup = 0; 979 dunp = VTOUNIONFS(ap->a_tdvp); 980 unp = NULL; 981 udvp = dunp->un_uppervp; 982 uvp = NULLVP; 983 cnp = ap->a_cnp; 984 td = curthread; 985 986 if (udvp == NULLVP) 987 return (EROFS); 988 989 if (ap->a_vp->v_op != &unionfs_vnodeops) 990 uvp = ap->a_vp; 991 else { 992 unp = VTOUNIONFS(ap->a_vp); 993 994 if (unp->un_uppervp == NULLVP) { 995 if (ap->a_vp->v_type != VREG) 996 return (EOPNOTSUPP); 997 998 error = unionfs_copyfile(unp, 1, cnp->cn_cred, td); 999 if (error != 0) 1000 return (error); 1001 needrelookup = 1; 1002 } 1003 uvp = unp->un_uppervp; 1004 } 1005 1006 if (needrelookup != 0) 1007 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td); 1008 1009 if (error == 0) 1010 error = VOP_LINK(udvp, uvp, cnp); 1011 1012 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error); 1013 1014 return (error); 1015 } 1016 1017 static int 1018 unionfs_rename(struct vop_rename_args *ap) 1019 { 1020 int error; 1021 struct vnode *fdvp; 1022 struct vnode *fvp; 1023 struct componentname *fcnp; 1024 struct vnode *tdvp; 1025 struct vnode *tvp; 1026 struct componentname *tcnp; 1027 struct vnode *ltdvp; 1028 struct vnode *ltvp; 1029 struct thread *td; 1030 1031 /* rename target vnodes */ 1032 struct vnode *rfdvp; 1033 struct vnode *rfvp; 1034 struct vnode *rtdvp; 1035 struct vnode *rtvp; 1036 1037 int needrelookup; 1038 struct unionfs_mount *ump; 1039 struct unionfs_node *unp; 1040 1041 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n"); 1042 1043 error = 0; 1044 fdvp = ap->a_fdvp; 1045 fvp = ap->a_fvp; 1046 fcnp = ap->a_fcnp; 1047 tdvp = ap->a_tdvp; 1048 tvp = ap->a_tvp; 1049 tcnp = ap->a_tcnp; 1050 ltdvp = NULLVP; 1051 ltvp = NULLVP; 1052 td = curthread; 1053 rfdvp = fdvp; 1054 rfvp = fvp; 1055 rtdvp = tdvp; 1056 rtvp = tvp; 1057 needrelookup = 0; 1058 1059 #ifdef DIAGNOSTIC 1060 if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF)) 1061 panic("unionfs_rename: no name"); 1062 #endif 1063 1064 /* check for cross device rename */ 1065 if (fvp->v_mount != tdvp->v_mount || 1066 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) { 1067 error = EXDEV; 1068 goto unionfs_rename_abort; 1069 } 1070 1071 /* Renaming a file to itself has no effect. */ 1072 if (fvp == tvp) 1073 goto unionfs_rename_abort; 1074 1075 /* 1076 * from/to vnode is unionfs node. 1077 */ 1078 1079 unp = VTOUNIONFS(fdvp); 1080 #ifdef UNIONFS_IDBG_RENAME 1081 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp); 1082 #endif 1083 if (unp->un_uppervp == NULLVP) { 1084 error = ENODEV; 1085 goto unionfs_rename_abort; 1086 } 1087 rfdvp = unp->un_uppervp; 1088 vref(rfdvp); 1089 1090 unp = VTOUNIONFS(fvp); 1091 #ifdef UNIONFS_IDBG_RENAME 1092 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp); 1093 #endif 1094 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount); 1095 if (unp->un_uppervp == NULLVP) { 1096 switch (fvp->v_type) { 1097 case VREG: 1098 if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0) 1099 goto unionfs_rename_abort; 1100 error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td); 1101 VOP_UNLOCK(fvp, 0, td); 1102 if (error != 0) 1103 goto unionfs_rename_abort; 1104 break; 1105 case VDIR: 1106 if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0) 1107 goto unionfs_rename_abort; 1108 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td); 1109 VOP_UNLOCK(fvp, 0, td); 1110 if (error != 0) 1111 goto unionfs_rename_abort; 1112 break; 1113 default: 1114 error = ENODEV; 1115 goto unionfs_rename_abort; 1116 } 1117 1118 needrelookup = 1; 1119 } 1120 1121 if (unp->un_lowervp != NULLVP) 1122 fcnp->cn_flags |= DOWHITEOUT; 1123 rfvp = unp->un_uppervp; 1124 vref(rfvp); 1125 1126 unp = VTOUNIONFS(tdvp); 1127 #ifdef UNIONFS_IDBG_RENAME 1128 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp); 1129 #endif 1130 if (unp->un_uppervp == NULLVP) { 1131 error = ENODEV; 1132 goto unionfs_rename_abort; 1133 } 1134 rtdvp = unp->un_uppervp; 1135 ltdvp = unp->un_lowervp; 1136 vref(rtdvp); 1137 1138 if (tdvp == tvp) { 1139 rtvp = rtdvp; 1140 vref(rtvp); 1141 } else if (tvp != NULLVP) { 1142 unp = VTOUNIONFS(tvp); 1143 #ifdef UNIONFS_IDBG_RENAME 1144 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp); 1145 #endif 1146 if (unp->un_uppervp == NULLVP) 1147 rtvp = NULLVP; 1148 else { 1149 if (tvp->v_type == VDIR) { 1150 error = EINVAL; 1151 goto unionfs_rename_abort; 1152 } 1153 rtvp = unp->un_uppervp; 1154 ltvp = unp->un_lowervp; 1155 vref(rtvp); 1156 } 1157 } 1158 1159 if (needrelookup != 0) { 1160 if ((error = vn_lock(fdvp, LK_EXCLUSIVE, td)) != 0) 1161 goto unionfs_rename_abort; 1162 error = unionfs_relookup_for_delete(fdvp, fcnp, td); 1163 VOP_UNLOCK(fdvp, 0, td); 1164 if (error != 0) 1165 goto unionfs_rename_abort; 1166 1167 /* Locke of tvp is canceled in order to avoid recursive lock. */ 1168 if (tvp != NULLVP && tvp != tdvp) 1169 VOP_UNLOCK(tvp, 0, td); 1170 error = unionfs_relookup_for_rename(tdvp, tcnp, td); 1171 if (tvp != NULLVP && tvp != tdvp) 1172 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, td); 1173 if (error != 0) 1174 goto unionfs_rename_abort; 1175 } 1176 1177 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp); 1178 1179 if (fdvp != rfdvp) 1180 vrele(fdvp); 1181 if (fvp != rfvp) 1182 vrele(fvp); 1183 if (tdvp != rtdvp) 1184 vrele(tdvp); 1185 if (tvp != rtvp && tvp != NULLVP) { 1186 if (rtvp == NULLVP) 1187 vput(tvp); 1188 else 1189 vrele(tvp); 1190 } 1191 if (ltdvp != NULLVP) 1192 VOP_UNLOCK(ltdvp, 0, td); 1193 if (ltvp != NULLVP) 1194 VOP_UNLOCK(ltvp, 0, td); 1195 1196 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1197 1198 return (error); 1199 1200 unionfs_rename_abort: 1201 if (fdvp != rfdvp) 1202 vrele(rfdvp); 1203 if (fvp != rfvp) 1204 vrele(rfvp); 1205 if (tdvp != rtdvp) 1206 vrele(rtdvp); 1207 vput(tdvp); 1208 if (tvp != rtvp && rtvp != NULLVP) 1209 vrele(rtvp); 1210 if (tvp != NULLVP) { 1211 if (tdvp != tvp) 1212 vput(tvp); 1213 else 1214 vrele(tvp); 1215 } 1216 vrele(fdvp); 1217 vrele(fvp); 1218 1219 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error); 1220 1221 return (error); 1222 } 1223 1224 static int 1225 unionfs_mkdir(struct vop_mkdir_args *ap) 1226 { 1227 int error; 1228 int lkflags; 1229 struct unionfs_node *dunp; 1230 struct componentname *cnp; 1231 struct thread *td; 1232 struct vnode *udvp; 1233 struct vnode *uvp; 1234 struct vattr va; 1235 1236 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n"); 1237 1238 error = EROFS; 1239 dunp = VTOUNIONFS(ap->a_dvp); 1240 cnp = ap->a_cnp; 1241 lkflags = cnp->cn_lkflags; 1242 td = curthread; 1243 udvp = dunp->un_uppervp; 1244 1245 if (udvp != NULLVP) { 1246 /* check opaque */ 1247 if (!(cnp->cn_flags & ISWHITEOUT)) { 1248 error = VOP_GETATTR(udvp, &va, cnp->cn_cred, td); 1249 if (error != 0) 1250 return (error); 1251 if (va.va_flags & OPAQUE) 1252 cnp->cn_flags |= ISWHITEOUT; 1253 } 1254 1255 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) { 1256 VOP_UNLOCK(uvp, 0, td); 1257 cnp->cn_lkflags = LK_EXCLUSIVE; 1258 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1259 ap->a_dvp, ap->a_vpp, cnp, td); 1260 cnp->cn_lkflags = lkflags; 1261 vrele(uvp); 1262 } 1263 } 1264 1265 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error); 1266 1267 return (error); 1268 } 1269 1270 static int 1271 unionfs_rmdir(struct vop_rmdir_args *ap) 1272 { 1273 int error; 1274 struct unionfs_node *dunp; 1275 struct unionfs_node *unp; 1276 struct componentname *cnp; 1277 struct thread *td; 1278 struct vnode *udvp; 1279 struct vnode *uvp; 1280 struct vnode *lvp; 1281 1282 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n"); 1283 1284 error = 0; 1285 dunp = VTOUNIONFS(ap->a_dvp); 1286 unp = VTOUNIONFS(ap->a_vp); 1287 cnp = ap->a_cnp; 1288 td = curthread; 1289 udvp = dunp->un_uppervp; 1290 uvp = unp->un_uppervp; 1291 lvp = unp->un_lowervp; 1292 1293 if (udvp == NULLVP) 1294 return (EROFS); 1295 1296 if (udvp == uvp) 1297 return (EOPNOTSUPP); 1298 1299 if (uvp != NULLVP) { 1300 if (lvp != NULLVP) { 1301 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td); 1302 if (error != 0) 1303 return (error); 1304 } 1305 cnp->cn_flags |= DOWHITEOUT; 1306 error = VOP_RMDIR(udvp, uvp, cnp); 1307 } 1308 else if (lvp != NULLVP) 1309 error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path); 1310 1311 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error); 1312 1313 return (error); 1314 } 1315 1316 static int 1317 unionfs_symlink(struct vop_symlink_args *ap) 1318 { 1319 int error; 1320 int lkflags; 1321 struct unionfs_node *dunp; 1322 struct componentname *cnp; 1323 struct thread *td; 1324 struct vnode *udvp; 1325 struct vnode *uvp; 1326 1327 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n"); 1328 1329 error = EROFS; 1330 dunp = VTOUNIONFS(ap->a_dvp); 1331 cnp = ap->a_cnp; 1332 lkflags = cnp->cn_lkflags; 1333 td = curthread; 1334 udvp = dunp->un_uppervp; 1335 1336 if (udvp != NULLVP) { 1337 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target); 1338 if (error == 0) { 1339 VOP_UNLOCK(uvp, 0, td); 1340 cnp->cn_lkflags = LK_EXCLUSIVE; 1341 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP, 1342 ap->a_dvp, ap->a_vpp, cnp, td); 1343 cnp->cn_lkflags = lkflags; 1344 vrele(uvp); 1345 } 1346 } 1347 1348 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error); 1349 1350 return (error); 1351 } 1352 1353 static int 1354 unionfs_readdir(struct vop_readdir_args *ap) 1355 { 1356 int error; 1357 int eofflag; 1358 int locked; 1359 struct unionfs_node *unp; 1360 struct unionfs_node_status *unsp; 1361 struct uio *uio; 1362 struct vnode *uvp; 1363 struct vnode *lvp; 1364 struct thread *td; 1365 struct vattr va; 1366 1367 int ncookies_bk; 1368 u_long *cookies_bk; 1369 1370 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n"); 1371 1372 error = 0; 1373 eofflag = 0; 1374 locked = 0; 1375 unp = VTOUNIONFS(ap->a_vp); 1376 uio = ap->a_uio; 1377 uvp = unp->un_uppervp; 1378 lvp = unp->un_lowervp; 1379 td = uio->uio_td; 1380 ncookies_bk = 0; 1381 cookies_bk = NULL; 1382 1383 if (ap->a_vp->v_type != VDIR) 1384 return (ENOTDIR); 1385 1386 /* check opaque */ 1387 if (uvp != NULLVP && lvp != NULLVP) { 1388 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred, td)) != 0) 1389 return (error); 1390 if (va.va_flags & OPAQUE) 1391 lvp = NULLVP; 1392 } 1393 1394 if (VOP_ISLOCKED(ap->a_vp, td) != LK_EXCLUSIVE) { 1395 vn_lock(ap->a_vp, LK_UPGRADE | LK_RETRY, td); 1396 locked = 1; 1397 } 1398 unionfs_get_node_status(unp, curthread, &unsp); 1399 if (locked == 1) 1400 vn_lock(ap->a_vp, LK_DOWNGRADE | LK_RETRY, td); 1401 1402 /* upper only */ 1403 if (uvp != NULLVP && lvp == NULLVP) { 1404 if (unsp->uns_upper_opencnt <= 0) 1405 error = EBADF; 1406 else { 1407 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag, 1408 ap->a_ncookies, ap->a_cookies); 1409 unsp->uns_readdir_status = 0; 1410 } 1411 1412 goto unionfs_readdir_exit; 1413 } 1414 1415 /* lower only */ 1416 if (uvp == NULLVP && lvp != NULLVP) { 1417 if (unsp->uns_lower_opencnt <= 0) 1418 error = EBADF; 1419 else { 1420 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1421 ap->a_ncookies, ap->a_cookies); 1422 unsp->uns_readdir_status = 2; 1423 } 1424 1425 goto unionfs_readdir_exit; 1426 } 1427 1428 /* 1429 * readdir upper and lower 1430 */ 1431 if (unsp->uns_lower_opencnt <= 0 || unsp->uns_upper_opencnt <= 0) { 1432 error = EBADF; 1433 goto unionfs_readdir_exit; 1434 } 1435 1436 if (uio->uio_offset == 0) 1437 unsp->uns_readdir_status = 0; 1438 1439 if (unsp->uns_readdir_status == 0) { 1440 /* read upper */ 1441 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag, 1442 ap->a_ncookies, ap->a_cookies); 1443 1444 if (error != 0 || eofflag == 0) { 1445 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1446 return (error); 1447 } 1448 unsp->uns_readdir_status = 1; 1449 1450 /* 1451 * ufs(and other fs) needs size of uio_resid larger than 1452 * DIRBLKSIZ. 1453 * size of DIRBLKSIZ equals DEV_BSIZE. 1454 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h) 1455 */ 1456 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1))) { 1457 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1458 return (0); 1459 } 1460 1461 /* 1462 * backup cookies 1463 * It prepares to readdir in lower. 1464 */ 1465 if (ap->a_ncookies != NULL) { 1466 ncookies_bk = *(ap->a_ncookies); 1467 *(ap->a_ncookies) = 0; 1468 } 1469 if (ap->a_cookies != NULL) { 1470 cookies_bk = *(ap->a_cookies); 1471 *(ap->a_cookies) = NULL; 1472 } 1473 } 1474 1475 /* initialize for readdir in lower */ 1476 if (unsp->uns_readdir_status == 1) { 1477 unsp->uns_readdir_status = 2; 1478 uio->uio_offset = 0; 1479 } 1480 1481 if (lvp == NULLVP) { 1482 error = EBADF; 1483 goto unionfs_readdir_exit; 1484 } 1485 /* read lower */ 1486 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag, 1487 ap->a_ncookies, ap->a_cookies); 1488 1489 if (cookies_bk != NULL) { 1490 /* merge cookies */ 1491 int size; 1492 u_long *newcookies, *pos; 1493 1494 size = *(ap->a_ncookies) + ncookies_bk; 1495 newcookies = (u_long *) malloc(size * sizeof(u_long), 1496 M_TEMP, M_WAITOK); 1497 pos = newcookies; 1498 1499 memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long)); 1500 pos += ncookies_bk * sizeof(u_long); 1501 memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long)); 1502 free(cookies_bk, M_TEMP); 1503 free(*(ap->a_cookies), M_TEMP); 1504 *(ap->a_ncookies) = size; 1505 *(ap->a_cookies) = newcookies; 1506 } 1507 1508 unionfs_readdir_exit: 1509 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error); 1510 1511 return (error); 1512 } 1513 1514 static int 1515 unionfs_readlink(struct vop_readlink_args *ap) 1516 { 1517 int error; 1518 struct unionfs_node *unp; 1519 struct vnode *vp; 1520 1521 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n"); 1522 1523 unp = VTOUNIONFS(ap->a_vp); 1524 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1525 1526 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 1527 1528 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error); 1529 1530 return (error); 1531 } 1532 1533 static int 1534 unionfs_getwritemount(struct vop_getwritemount_args *ap) 1535 { 1536 int error; 1537 struct vnode *uvp; 1538 struct vnode *vp; 1539 1540 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n"); 1541 1542 error = 0; 1543 vp = ap->a_vp; 1544 1545 if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY)) 1546 return (EACCES); 1547 1548 uvp = UNIONFSVPTOUPPERVP(vp); 1549 if (uvp == NULLVP && VREG == vp->v_type) 1550 uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp); 1551 1552 if (uvp != NULLVP) 1553 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); 1554 else { 1555 VI_LOCK(vp); 1556 if (vp->v_iflag & VI_FREE) 1557 error = EOPNOTSUPP; 1558 else 1559 error = EACCES; 1560 VI_UNLOCK(vp); 1561 } 1562 1563 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error); 1564 1565 return (error); 1566 } 1567 1568 static int 1569 unionfs_inactive(struct vop_inactive_args *ap) 1570 { 1571 struct unionfs_node *unp; 1572 1573 unp = VTOUNIONFS(ap->a_vp); 1574 1575 if (unp == NULL || !(unp->un_flag & UNIONFS_CACHED)) 1576 vgone(ap->a_vp); 1577 1578 return (0); 1579 } 1580 1581 static int 1582 unionfs_reclaim(struct vop_reclaim_args *ap) 1583 { 1584 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */ 1585 1586 unionfs_hashrem(ap->a_vp, ap->a_td); 1587 1588 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */ 1589 1590 return (0); 1591 } 1592 1593 static int 1594 unionfs_print(struct vop_print_args *ap) 1595 { 1596 struct unionfs_node *unp; 1597 /* struct unionfs_node_status *unsp; */ 1598 1599 unp = VTOUNIONFS(ap->a_vp); 1600 /* unionfs_get_node_status(unp, curthread, &unsp); */ 1601 1602 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n", 1603 ap->a_vp, unp->un_uppervp, unp->un_lowervp); 1604 /* 1605 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n", 1606 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt); 1607 */ 1608 1609 if (unp->un_uppervp != NULLVP) 1610 vprint("unionfs: upper", unp->un_uppervp); 1611 if (unp->un_lowervp != NULLVP) 1612 vprint("unionfs: lower", unp->un_lowervp); 1613 1614 return (0); 1615 } 1616 1617 static int 1618 unionfs_get_llt_revlock(int flags) 1619 { 1620 int count; 1621 1622 flags &= LK_TYPE_MASK; 1623 for (count = 0; un_llt[count].lock != 0; count++) { 1624 if (flags == un_llt[count].lock) { 1625 return un_llt[count].revlock; 1626 } 1627 } 1628 1629 return 0; 1630 } 1631 1632 static int 1633 unionfs_lock(struct _vop_lock_args *ap) 1634 { 1635 int error; 1636 int flags; 1637 int revlock; 1638 int uhold; 1639 struct unionfs_mount *ump; 1640 struct unionfs_node *unp; 1641 struct vnode *vp; 1642 struct vnode *uvp; 1643 struct vnode *lvp; 1644 struct thread *td; 1645 1646 error = 0; 1647 uhold = 0; 1648 flags = ap->a_flags; 1649 vp = ap->a_vp; 1650 td = ap->a_td; 1651 1652 if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK)) 1653 return (VOP_UNLOCK(vp, flags, td)); 1654 1655 if ((revlock = unionfs_get_llt_revlock(flags)) == 0) 1656 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); 1657 1658 if (!(flags & LK_INTERLOCK)) 1659 VI_LOCK(vp); 1660 1661 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount); 1662 unp = VTOUNIONFS(vp); 1663 if (NULL == unp) 1664 goto unionfs_lock_null_vnode; 1665 lvp = unp->un_lowervp; 1666 uvp = unp->un_uppervp; 1667 1668 /* 1669 * Sometimes, lower or upper is already exclusive locked. 1670 * (ex. vfs_domount: mounted vnode is already locked.) 1671 */ 1672 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE && 1673 vp == ump->um_rootvp) 1674 flags |= LK_CANRECURSE; 1675 1676 if (lvp != NULLVP) { 1677 VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1678 flags |= LK_INTERLOCK; 1679 vholdl(lvp); 1680 1681 VI_UNLOCK(vp); 1682 ap->a_flags &= ~LK_INTERLOCK; 1683 1684 error = VOP_LOCK(lvp, flags, td); 1685 1686 VI_LOCK(vp); 1687 unp = VTOUNIONFS(vp); 1688 if (unp == NULL) { 1689 if (error == 0) 1690 VOP_UNLOCK(lvp, 0, td); 1691 VI_UNLOCK(vp); 1692 vdrop(lvp); 1693 return (vop_stdlock(ap)); 1694 } 1695 } 1696 1697 if (error == 0 && uvp != NULLVP) { 1698 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1699 flags |= LK_INTERLOCK; 1700 vholdl(uvp); 1701 uhold = 1; 1702 1703 VI_UNLOCK(vp); 1704 ap->a_flags &= ~LK_INTERLOCK; 1705 1706 error = VOP_LOCK(uvp, flags, td); 1707 1708 VI_LOCK(vp); 1709 unp = VTOUNIONFS(vp); 1710 if (unp == NULL) { 1711 if (error == 0) { 1712 VOP_UNLOCK(uvp, 0, td); 1713 if (lvp != NULLVP) 1714 VOP_UNLOCK(lvp, 0, td); 1715 } 1716 VI_UNLOCK(vp); 1717 if (lvp != NULLVP) 1718 vdrop(lvp); 1719 vdrop(uvp); 1720 return (vop_stdlock(ap)); 1721 } 1722 1723 if (error != 0 && lvp != NULLVP) 1724 vn_lock(lvp, revlock | LK_RETRY, td); 1725 } 1726 1727 VI_UNLOCK(vp); 1728 if (lvp != NULLVP) 1729 vdrop(lvp); 1730 if (uhold != 0) 1731 vdrop(uvp); 1732 1733 return (error); 1734 1735 unionfs_lock_null_vnode: 1736 ap->a_flags |= LK_INTERLOCK; 1737 return (vop_stdlock(ap)); 1738 } 1739 1740 static int 1741 unionfs_unlock(struct vop_unlock_args *ap) 1742 { 1743 int error; 1744 int flags; 1745 int mtxlkflag; 1746 int uhold; 1747 struct vnode *vp; 1748 struct vnode *lvp; 1749 struct vnode *uvp; 1750 struct unionfs_node *unp; 1751 1752 error = 0; 1753 mtxlkflag = 0; 1754 uhold = 0; 1755 flags = ap->a_flags | LK_RELEASE; 1756 vp = ap->a_vp; 1757 1758 if (flags & LK_INTERLOCK) 1759 mtxlkflag = 1; 1760 else if (mtx_owned(VI_MTX(vp)) == 0) { 1761 VI_LOCK(vp); 1762 mtxlkflag = 2; 1763 } 1764 1765 unp = VTOUNIONFS(vp); 1766 if (unp == NULL) 1767 goto unionfs_unlock_null_vnode; 1768 lvp = unp->un_lowervp; 1769 uvp = unp->un_uppervp; 1770 1771 if (lvp != NULLVP) { 1772 VI_LOCK_FLAGS(lvp, MTX_DUPOK); 1773 flags |= LK_INTERLOCK; 1774 vholdl(lvp); 1775 1776 VI_UNLOCK(vp); 1777 ap->a_flags &= ~LK_INTERLOCK; 1778 1779 error = VOP_UNLOCK(lvp, flags, ap->a_td); 1780 1781 VI_LOCK(vp); 1782 } 1783 1784 if (error == 0 && uvp != NULLVP) { 1785 VI_LOCK_FLAGS(uvp, MTX_DUPOK); 1786 flags |= LK_INTERLOCK; 1787 vholdl(uvp); 1788 uhold = 1; 1789 1790 VI_UNLOCK(vp); 1791 ap->a_flags &= ~LK_INTERLOCK; 1792 1793 error = VOP_UNLOCK(uvp, flags, ap->a_td); 1794 1795 VI_LOCK(vp); 1796 } 1797 1798 VI_UNLOCK(vp); 1799 if (lvp != NULLVP) 1800 vdrop(lvp); 1801 if (uhold != 0) 1802 vdrop(uvp); 1803 if (mtxlkflag == 0) 1804 VI_LOCK(vp); 1805 1806 return error; 1807 1808 unionfs_unlock_null_vnode: 1809 if (mtxlkflag == 2) 1810 VI_UNLOCK(vp); 1811 return (vop_stdunlock(ap)); 1812 } 1813 1814 static int 1815 unionfs_pathconf(struct vop_pathconf_args *ap) 1816 { 1817 struct unionfs_node *unp; 1818 struct vnode *vp; 1819 1820 unp = VTOUNIONFS(ap->a_vp); 1821 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1822 1823 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval)); 1824 } 1825 1826 static int 1827 unionfs_advlock(struct vop_advlock_args *ap) 1828 { 1829 int error; 1830 struct unionfs_node *unp; 1831 struct unionfs_node_status *unsp; 1832 struct vnode *vp; 1833 struct vnode *uvp; 1834 struct thread *td; 1835 1836 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); 1837 1838 vp = ap->a_vp; 1839 td = curthread; 1840 1841 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1842 1843 unp = VTOUNIONFS(ap->a_vp); 1844 uvp = unp->un_uppervp; 1845 1846 if (uvp == NULLVP) { 1847 error = unionfs_copyfile(unp, 1, td->td_ucred, td); 1848 if (error != 0) 1849 goto unionfs_advlock_abort; 1850 uvp = unp->un_uppervp; 1851 1852 unionfs_get_node_status(unp, td, &unsp); 1853 if (unsp->uns_lower_opencnt > 0) { 1854 /* try reopen the vnode */ 1855 error = VOP_OPEN(uvp, unsp->uns_lower_openmode, td->td_ucred, td, unsp->uns_lower_fdidx); 1856 if (error) 1857 goto unionfs_advlock_abort; 1858 unsp->uns_upper_opencnt++; 1859 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td); 1860 unsp->uns_lower_opencnt--; 1861 } 1862 } 1863 1864 VOP_UNLOCK(vp, 0, td); 1865 1866 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); 1867 1868 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1869 1870 return error; 1871 1872 unionfs_advlock_abort: 1873 VOP_UNLOCK(vp, 0, td); 1874 1875 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); 1876 1877 return error; 1878 } 1879 1880 static int 1881 unionfs_strategy(struct vop_strategy_args *ap) 1882 { 1883 struct unionfs_node *unp; 1884 struct vnode *vp; 1885 1886 unp = VTOUNIONFS(ap->a_vp); 1887 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1888 1889 #ifdef DIAGNOSTIC 1890 if (vp == NULLVP) 1891 panic("unionfs_strategy: nullvp"); 1892 1893 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp) 1894 panic("unionfs_strategy: writing to lowervp"); 1895 #endif 1896 1897 return (VOP_STRATEGY(vp, ap->a_bp)); 1898 } 1899 1900 static int 1901 unionfs_getacl(struct vop_getacl_args *ap) 1902 { 1903 int error; 1904 struct unionfs_node *unp; 1905 struct vnode *vp; 1906 1907 unp = VTOUNIONFS(ap->a_vp); 1908 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1909 1910 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n"); 1911 1912 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 1913 1914 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error); 1915 1916 return (error); 1917 } 1918 1919 static int 1920 unionfs_setacl(struct vop_setacl_args *ap) 1921 { 1922 int error; 1923 struct unionfs_node *unp; 1924 struct vnode *uvp; 1925 struct vnode *lvp; 1926 struct thread *td; 1927 1928 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n"); 1929 1930 error = EROFS; 1931 unp = VTOUNIONFS(ap->a_vp); 1932 uvp = unp->un_uppervp; 1933 lvp = unp->un_lowervp; 1934 td = ap->a_td; 1935 1936 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 1937 return (EROFS); 1938 1939 if (uvp == NULLVP && lvp->v_type == VREG) { 1940 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 1941 return (error); 1942 uvp = unp->un_uppervp; 1943 } 1944 1945 if (uvp != NULLVP) 1946 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td); 1947 1948 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error); 1949 1950 return (error); 1951 } 1952 1953 static int 1954 unionfs_aclcheck(struct vop_aclcheck_args *ap) 1955 { 1956 int error; 1957 struct unionfs_node *unp; 1958 struct vnode *vp; 1959 1960 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n"); 1961 1962 unp = VTOUNIONFS(ap->a_vp); 1963 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1964 1965 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td); 1966 1967 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error); 1968 1969 return (error); 1970 } 1971 1972 static int 1973 unionfs_openextattr(struct vop_openextattr_args *ap) 1974 { 1975 int error; 1976 struct unionfs_node *unp; 1977 struct vnode *vp; 1978 1979 unp = VTOUNIONFS(ap->a_vp); 1980 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp); 1981 1982 if ((vp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) || 1983 (vp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL))) 1984 return (EBUSY); 1985 1986 error = VOP_OPENEXTATTR(vp, ap->a_cred, ap->a_td); 1987 1988 if (error == 0) { 1989 if (vp == unp->un_uppervp) 1990 unp->un_flag |= UNIONFS_OPENEXTU; 1991 else 1992 unp->un_flag |= UNIONFS_OPENEXTL; 1993 } 1994 1995 return (error); 1996 } 1997 1998 static int 1999 unionfs_closeextattr(struct vop_closeextattr_args *ap) 2000 { 2001 int error; 2002 struct unionfs_node *unp; 2003 struct vnode *vp; 2004 2005 unp = VTOUNIONFS(ap->a_vp); 2006 vp = NULLVP; 2007 2008 if (unp->un_flag & UNIONFS_OPENEXTU) 2009 vp = unp->un_uppervp; 2010 else if (unp->un_flag & UNIONFS_OPENEXTL) 2011 vp = unp->un_lowervp; 2012 2013 if (vp == NULLVP) 2014 return (EOPNOTSUPP); 2015 2016 error = VOP_CLOSEEXTATTR(vp, ap->a_commit, ap->a_cred, ap->a_td); 2017 2018 if (error == 0) { 2019 if (vp == unp->un_uppervp) 2020 unp->un_flag &= ~UNIONFS_OPENEXTU; 2021 else 2022 unp->un_flag &= ~UNIONFS_OPENEXTL; 2023 } 2024 2025 return (error); 2026 } 2027 2028 static int 2029 unionfs_getextattr(struct vop_getextattr_args *ap) 2030 { 2031 struct unionfs_node *unp; 2032 struct vnode *vp; 2033 2034 unp = VTOUNIONFS(ap->a_vp); 2035 vp = NULLVP; 2036 2037 if (unp->un_flag & UNIONFS_OPENEXTU) 2038 vp = unp->un_uppervp; 2039 else if (unp->un_flag & UNIONFS_OPENEXTL) 2040 vp = unp->un_lowervp; 2041 2042 if (vp == NULLVP) 2043 return (EOPNOTSUPP); 2044 2045 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name, 2046 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); 2047 } 2048 2049 static int 2050 unionfs_setextattr(struct vop_setextattr_args *ap) 2051 { 2052 int error; 2053 struct unionfs_node *unp; 2054 struct vnode *uvp; 2055 struct vnode *lvp; 2056 struct vnode *ovp; 2057 struct ucred *cred; 2058 struct thread *td; 2059 2060 error = EROFS; 2061 unp = VTOUNIONFS(ap->a_vp); 2062 uvp = unp->un_uppervp; 2063 lvp = unp->un_lowervp; 2064 ovp = NULLVP; 2065 cred = ap->a_cred; 2066 td = ap->a_td; 2067 2068 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag); 2069 2070 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2071 return (EROFS); 2072 2073 if (unp->un_flag & UNIONFS_OPENEXTU) 2074 ovp = unp->un_uppervp; 2075 else if (unp->un_flag & UNIONFS_OPENEXTL) 2076 ovp = unp->un_lowervp; 2077 2078 if (ovp == NULLVP) 2079 return (EOPNOTSUPP); 2080 2081 if (ovp == lvp && lvp->v_type == VREG) { 2082 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2083 if (uvp == NULLVP && 2084 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2085 unionfs_setextattr_reopen: 2086 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2087 VOP_OPENEXTATTR(lvp, cred, td)) { 2088 #ifdef DIAGNOSTIC 2089 panic("unionfs: VOP_OPENEXTATTR failed"); 2090 #endif 2091 unp->un_flag &= ~UNIONFS_OPENEXTL; 2092 } 2093 goto unionfs_setextattr_abort; 2094 } 2095 uvp = unp->un_uppervp; 2096 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2097 goto unionfs_setextattr_reopen; 2098 unp->un_flag &= ~UNIONFS_OPENEXTL; 2099 unp->un_flag |= UNIONFS_OPENEXTU; 2100 ovp = uvp; 2101 } 2102 2103 if (ovp == uvp) 2104 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2105 ap->a_uio, cred, td); 2106 2107 unionfs_setextattr_abort: 2108 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error); 2109 2110 return (error); 2111 } 2112 2113 static int 2114 unionfs_listextattr(struct vop_listextattr_args *ap) 2115 { 2116 struct unionfs_node *unp; 2117 struct vnode *vp; 2118 2119 unp = VTOUNIONFS(ap->a_vp); 2120 vp = NULLVP; 2121 2122 if (unp->un_flag & UNIONFS_OPENEXTU) 2123 vp = unp->un_uppervp; 2124 else if (unp->un_flag & UNIONFS_OPENEXTL) 2125 vp = unp->un_lowervp; 2126 2127 if (vp == NULLVP) 2128 return (EOPNOTSUPP); 2129 2130 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio, 2131 ap->a_size, ap->a_cred, ap->a_td)); 2132 } 2133 2134 static int 2135 unionfs_deleteextattr(struct vop_deleteextattr_args *ap) 2136 { 2137 int error; 2138 struct unionfs_node *unp; 2139 struct vnode *uvp; 2140 struct vnode *lvp; 2141 struct vnode *ovp; 2142 struct ucred *cred; 2143 struct thread *td; 2144 2145 error = EROFS; 2146 unp = VTOUNIONFS(ap->a_vp); 2147 uvp = unp->un_uppervp; 2148 lvp = unp->un_lowervp; 2149 ovp = NULLVP; 2150 cred = ap->a_cred; 2151 td = ap->a_td; 2152 2153 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag); 2154 2155 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2156 return (EROFS); 2157 2158 if (unp->un_flag & UNIONFS_OPENEXTU) 2159 ovp = unp->un_uppervp; 2160 else if (unp->un_flag & UNIONFS_OPENEXTL) 2161 ovp = unp->un_lowervp; 2162 2163 if (ovp == NULLVP) 2164 return (EOPNOTSUPP); 2165 2166 if (ovp == lvp && lvp->v_type == VREG) { 2167 VOP_CLOSEEXTATTR(lvp, 0, cred, td); 2168 if (uvp == NULLVP && 2169 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) { 2170 unionfs_deleteextattr_reopen: 2171 if ((unp->un_flag & UNIONFS_OPENEXTL) && 2172 VOP_OPENEXTATTR(lvp, cred, td)) { 2173 #ifdef DIAGNOSTIC 2174 panic("unionfs: VOP_OPENEXTATTR failed"); 2175 #endif 2176 unp->un_flag &= ~UNIONFS_OPENEXTL; 2177 } 2178 goto unionfs_deleteextattr_abort; 2179 } 2180 uvp = unp->un_uppervp; 2181 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0) 2182 goto unionfs_deleteextattr_reopen; 2183 unp->un_flag &= ~UNIONFS_OPENEXTL; 2184 unp->un_flag |= UNIONFS_OPENEXTU; 2185 ovp = uvp; 2186 } 2187 2188 if (ovp == uvp) 2189 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name, 2190 ap->a_cred, ap->a_td); 2191 2192 unionfs_deleteextattr_abort: 2193 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error); 2194 2195 return (error); 2196 } 2197 2198 static int 2199 unionfs_setlabel(struct vop_setlabel_args *ap) 2200 { 2201 int error; 2202 struct unionfs_node *unp; 2203 struct vnode *uvp; 2204 struct vnode *lvp; 2205 struct thread *td; 2206 2207 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n"); 2208 2209 error = EROFS; 2210 unp = VTOUNIONFS(ap->a_vp); 2211 uvp = unp->un_uppervp; 2212 lvp = unp->un_lowervp; 2213 td = ap->a_td; 2214 2215 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 2216 return (EROFS); 2217 2218 if (uvp == NULLVP && lvp->v_type == VREG) { 2219 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0) 2220 return (error); 2221 uvp = unp->un_uppervp; 2222 } 2223 2224 if (uvp != NULLVP) 2225 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td); 2226 2227 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error); 2228 2229 return (error); 2230 } 2231 2232 static int 2233 unionfs_vptofh(struct vop_vptofh_args *ap) 2234 { 2235 return (EOPNOTSUPP); 2236 } 2237 2238 struct vop_vector unionfs_vnodeops = { 2239 .vop_default = &default_vnodeops, 2240 2241 .vop_access = unionfs_access, 2242 .vop_aclcheck = unionfs_aclcheck, 2243 .vop_advlock = unionfs_advlock, 2244 .vop_bmap = VOP_EOPNOTSUPP, 2245 .vop_close = unionfs_close, 2246 .vop_closeextattr = unionfs_closeextattr, 2247 .vop_create = unionfs_create, 2248 .vop_deleteextattr = unionfs_deleteextattr, 2249 .vop_fsync = unionfs_fsync, 2250 .vop_getacl = unionfs_getacl, 2251 .vop_getattr = unionfs_getattr, 2252 .vop_getextattr = unionfs_getextattr, 2253 .vop_getwritemount = unionfs_getwritemount, 2254 .vop_inactive = unionfs_inactive, 2255 .vop_ioctl = unionfs_ioctl, 2256 .vop_lease = unionfs_lease, 2257 .vop_link = unionfs_link, 2258 .vop_listextattr = unionfs_listextattr, 2259 ._vop_lock = unionfs_lock, 2260 .vop_lookup = unionfs_lookup, 2261 .vop_mkdir = unionfs_mkdir, 2262 .vop_mknod = unionfs_mknod, 2263 .vop_open = unionfs_open, 2264 .vop_openextattr = unionfs_openextattr, 2265 .vop_pathconf = unionfs_pathconf, 2266 .vop_poll = unionfs_poll, 2267 .vop_print = unionfs_print, 2268 .vop_read = unionfs_read, 2269 .vop_readdir = unionfs_readdir, 2270 .vop_readlink = unionfs_readlink, 2271 .vop_reclaim = unionfs_reclaim, 2272 .vop_remove = unionfs_remove, 2273 .vop_rename = unionfs_rename, 2274 .vop_rmdir = unionfs_rmdir, 2275 .vop_setacl = unionfs_setacl, 2276 .vop_setattr = unionfs_setattr, 2277 .vop_setextattr = unionfs_setextattr, 2278 .vop_setlabel = unionfs_setlabel, 2279 .vop_strategy = unionfs_strategy, 2280 .vop_symlink = unionfs_symlink, 2281 .vop_unlock = unionfs_unlock, 2282 .vop_whiteout = unionfs_whiteout, 2283 .vop_write = unionfs_write, 2284 .vop_vptofh = unionfs_vptofh, 2285 }; 2286