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