1 /*- 2 * Copyright (c) 1994 Jan-Simon Pendry 3 * Copyright (c) 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 6 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 36 * $FreeBSD: src/sys/fs/unionfs/union_subr.c,v 1.99 2008/01/24 12:34:27 attilio Exp $ 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <sys/malloc.h> 45 #include <sys/mount.h> 46 #include <sys/namei.h> 47 #include <sys/proc.h> 48 #include <sys/vnode.h> 49 #include <sys/dirent.h> 50 #include <sys/fcntl.h> 51 #include <sys/filedesc.h> 52 #include <sys/stat.h> 53 #include <sys/kauth.h> 54 #include <sys/resourcevar.h> 55 56 #include <fs/unionfs/unionfs.h> 57 58 MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part"); 59 60 /* 61 * Make a new or get existing unionfs node. 62 * 63 * uppervp and lowervp should be unlocked. Because if new unionfs vnode is 64 * locked, uppervp or lowervp is locked too. In order to prevent dead lock, 65 * you should not lock plurality simultaneously. 66 */ 67 int 68 unionfs_nodeget(struct mount *mp, struct vnode *uppervp, 69 struct vnode *lowervp, struct vnode *dvp, 70 struct vnode **vpp, struct componentname *cnp) 71 { 72 struct unionfs_mount *ump; 73 struct unionfs_node *unp; 74 struct vnode *vp; 75 int error; 76 const char *path; 77 78 ump = MOUNTTOUNIONFSMOUNT(mp); 79 path = (cnp ? cnp->cn_nameptr : NULL); 80 81 if (uppervp == NULLVP && lowervp == NULLVP) 82 panic("unionfs_nodeget: upper and lower is null"); 83 84 /* If it has no ISLASTCN flag, path check is skipped. */ 85 if (cnp && !(cnp->cn_flags & ISLASTCN)) 86 path = NULL; 87 88 if ((uppervp == NULLVP || ump->um_uppervp != uppervp) || 89 (lowervp == NULLVP || ump->um_lowervp != lowervp)) { 90 if (dvp == NULLVP) 91 return (EINVAL); 92 } 93 94 unp = kmem_zalloc(sizeof(*unp), KM_SLEEP); 95 if (unp == NULL) 96 return (ENOMEM); 97 error = getnewvnode(VT_UNION, mp, unionfs_vnodeop_p, &vp); 98 if (error != 0) { 99 kmem_free(unp, sizeof(*unp)); 100 return (error); 101 } 102 if (dvp != NULLVP) 103 vref(dvp); 104 if (uppervp != NULLVP) 105 vref(uppervp); 106 if (lowervp != NULLVP) 107 vref(lowervp); 108 109 unp->un_vnode = vp; 110 unp->un_uppervp = uppervp; 111 unp->un_lowervp = lowervp; 112 unp->un_dvp = dvp; 113 if (uppervp != NULLVP) 114 vp->v_vnlock = uppervp->v_vnlock; 115 else 116 vp->v_vnlock = lowervp->v_vnlock; 117 118 if (path != NULL) { 119 unp->un_path = (char *) 120 malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO); 121 bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen); 122 unp->un_path[cnp->cn_namelen] = '\0'; 123 } 124 vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type); 125 vp->v_data = unp; 126 uvm_vnp_setsize(vp, 0); 127 128 if ((uppervp != NULLVP && ump->um_uppervp == uppervp) && 129 (lowervp != NULLVP && ump->um_lowervp == lowervp)) 130 vp->v_vflag |= VV_ROOT; 131 132 *vpp = vp; 133 134 return (0); 135 } 136 137 /* 138 * Clean up the unionfs node. 139 */ 140 void 141 unionfs_noderem(struct vnode *vp) 142 { 143 struct unionfs_mount *ump; 144 struct unionfs_node *unp; 145 struct unionfs_node_status *unsp; 146 struct vnode *lvp; 147 struct vnode *uvp; 148 149 ump = MOUNTTOUNIONFSMOUNT(vp->v_mount); 150 151 /* 152 * Use the interlock to protect the clearing of v_data to 153 * prevent faults in unionfs_lock(). 154 */ 155 unp = VTOUNIONFS(vp); 156 lvp = unp->un_lowervp; 157 uvp = unp->un_uppervp; 158 unp->un_lowervp = unp->un_uppervp = NULLVP; 159 vp->v_vnlock = &(vp->v_lock); 160 vp->v_data = NULL; 161 162 if (lvp != NULLVP) 163 vrele(lvp); 164 if (uvp != NULLVP) 165 vrele(uvp); 166 if (unp->un_dvp != NULLVP) { 167 vrele(unp->un_dvp); 168 unp->un_dvp = NULLVP; 169 } 170 if (unp->un_path) { 171 free(unp->un_path, M_UNIONFSPATH); 172 unp->un_path = NULL; 173 } 174 175 while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) { 176 LIST_REMOVE(unsp, uns_list); 177 free(unsp, M_TEMP); 178 } 179 kmem_free(unp, sizeof(*unp)); 180 } 181 182 /* 183 * Get the unionfs node status. 184 * You need exclusive lock this vnode. 185 */ 186 void 187 unionfs_get_node_status(struct unionfs_node *unp, 188 struct unionfs_node_status **unspp) 189 { 190 struct unionfs_node_status *unsp; 191 pid_t pid; 192 lwpid_t lid; 193 194 KASSERT(NULL != unspp); 195 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 196 197 pid = curproc->p_pid; 198 lid = curlwp->l_lid; 199 200 LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) { 201 if (unsp->uns_pid == pid && unsp->uns_lid == lid) { 202 *unspp = unsp; 203 return; 204 } 205 } 206 207 /* create a new unionfs node status */ 208 unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP); 209 unsp->uns_pid = pid; 210 unsp->uns_lid = lid; 211 LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list); 212 213 *unspp = unsp; 214 } 215 216 /* 217 * Remove the unionfs node status, if you can. 218 * You need exclusive lock this vnode. 219 */ 220 void 221 unionfs_tryrem_node_status(struct unionfs_node *unp, 222 struct unionfs_node_status *unsp) 223 { 224 KASSERT(NULL != unsp); 225 KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE); 226 227 if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt) 228 return; 229 230 LIST_REMOVE(unsp, uns_list); 231 kmem_free(unsp, sizeof(*unsp)); 232 } 233 234 /* 235 * Create upper node attr. 236 */ 237 void 238 unionfs_create_uppervattr_core(struct unionfs_mount *ump, 239 struct vattr *lva, 240 struct vattr *uva) 241 { 242 VATTR_NULL(uva); 243 uva->va_type = lva->va_type; 244 uva->va_atime = lva->va_atime; 245 uva->va_mtime = lva->va_mtime; 246 uva->va_ctime = lva->va_ctime; 247 248 switch (ump->um_copymode) { 249 case UNIONFS_TRANSPARENT: 250 uva->va_mode = lva->va_mode; 251 uva->va_uid = lva->va_uid; 252 uva->va_gid = lva->va_gid; 253 break; 254 case UNIONFS_MASQUERADE: 255 if (ump->um_uid == lva->va_uid) { 256 uva->va_mode = lva->va_mode & 077077; 257 uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700; 258 uva->va_uid = lva->va_uid; 259 uva->va_gid = lva->va_gid; 260 } else { 261 uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile); 262 uva->va_uid = ump->um_uid; 263 uva->va_gid = ump->um_gid; 264 } 265 break; 266 default: /* UNIONFS_TRADITIONAL */ 267 uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask; 268 uva->va_uid = ump->um_uid; 269 uva->va_gid = ump->um_gid; 270 break; 271 } 272 } 273 274 /* 275 * Create upper node attr. 276 */ 277 int 278 unionfs_create_uppervattr(struct unionfs_mount *ump, 279 struct vnode *lvp, 280 struct vattr *uva, 281 kauth_cred_t cred) 282 { 283 int error; 284 struct vattr lva; 285 286 if ((error = VOP_GETATTR(lvp, &lva, cred))) 287 return (error); 288 289 unionfs_create_uppervattr_core(ump, &lva, uva); 290 291 return (error); 292 } 293 294 /* 295 * relookup 296 * 297 * dvp should be locked on entry and will be locked on return. 298 * 299 * If an error is returned, *vpp will be invalid, otherwise it will hold a 300 * locked, referenced vnode. If *vpp == dvp then remember that only one 301 * LK_EXCLUSIVE lock is held. 302 */ 303 static int 304 unionfs_relookup(struct vnode *dvp, struct vnode **vpp, 305 struct componentname *cnp, struct componentname *cn, 306 const char *path, int pathlen, u_long nameiop) 307 { 308 int error; 309 310 cn->cn_namelen = pathlen; 311 cn->cn_pnbuf = PNBUF_GET(); 312 bcopy(path, cn->cn_pnbuf, pathlen); 313 cn->cn_pnbuf[pathlen] = '\0'; 314 315 cn->cn_nameiop = nameiop; 316 cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN); 317 cn->cn_cred = cnp->cn_cred; 318 319 cn->cn_nameptr = cn->cn_pnbuf; 320 cn->cn_consume = cnp->cn_consume; 321 322 if (nameiop == DELETE) 323 cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART)); 324 else if (RENAME == nameiop) 325 cn->cn_flags |= (cnp->cn_flags & SAVESTART); 326 327 vref(dvp); 328 VOP_UNLOCK(dvp, 0); 329 330 if ((error = relookup(dvp, vpp, cn))) { 331 PNBUF_PUT(cn->cn_pnbuf); 332 cn->cn_flags &= ~HASBUF; 333 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 334 } else 335 vrele(dvp); 336 337 return (error); 338 } 339 340 /* 341 * relookup for CREATE namei operation. 342 * 343 * dvp is unionfs vnode. dvp should be locked. 344 * 345 * If it called 'unionfs_copyfile' function by unionfs_link etc, 346 * VOP_LOOKUP information is broken. 347 * So it need relookup in order to create link etc. 348 */ 349 int 350 unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp) 351 { 352 int error; 353 struct vnode *udvp; 354 struct vnode *vp; 355 struct componentname cn; 356 357 udvp = UNIONFSVPTOUPPERVP(dvp); 358 vp = NULLVP; 359 360 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr, 361 strlen(cnp->cn_nameptr), CREATE); 362 if (error) 363 return (error); 364 365 if (vp != NULLVP) { 366 if (udvp == vp) 367 vrele(vp); 368 else 369 vput(vp); 370 371 error = EEXIST; 372 } 373 374 if (cn.cn_flags & HASBUF) { 375 PNBUF_PUT(cn.cn_pnbuf); 376 cn.cn_flags &= ~HASBUF; 377 } 378 379 if (!error) { 380 cn.cn_flags |= (cnp->cn_flags & HASBUF); 381 cnp->cn_flags = cn.cn_flags; 382 } 383 384 return (error); 385 } 386 387 /* 388 * relookup for DELETE namei operation. 389 * 390 * dvp is unionfs vnode. dvp should be locked. 391 */ 392 int 393 unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp) 394 { 395 int error; 396 struct vnode *udvp; 397 struct vnode *vp; 398 struct componentname cn; 399 400 udvp = UNIONFSVPTOUPPERVP(dvp); 401 vp = NULLVP; 402 403 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr, 404 strlen(cnp->cn_nameptr), DELETE); 405 if (error) 406 return (error); 407 408 if (vp == NULLVP) 409 error = ENOENT; 410 else { 411 if (udvp == vp) 412 vrele(vp); 413 else 414 vput(vp); 415 } 416 417 if (cn.cn_flags & HASBUF) { 418 PNBUF_PUT(cn.cn_pnbuf); 419 cn.cn_flags &= ~HASBUF; 420 } 421 422 if (!error) { 423 cn.cn_flags |= (cnp->cn_flags & HASBUF); 424 cnp->cn_flags = cn.cn_flags; 425 } 426 427 return (error); 428 } 429 430 /* 431 * relookup for RENAME namei operation. 432 * 433 * dvp is unionfs vnode. dvp should be locked. 434 */ 435 int 436 unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp) 437 { 438 int error; 439 struct vnode *udvp; 440 struct vnode *vp; 441 struct componentname cn; 442 443 udvp = UNIONFSVPTOUPPERVP(dvp); 444 vp = NULLVP; 445 446 error = unionfs_relookup(udvp, &vp, cnp, &cn, cnp->cn_nameptr, 447 strlen(cnp->cn_nameptr), RENAME); 448 if (error) 449 return (error); 450 451 if (vp != NULLVP) { 452 if (udvp == vp) 453 vrele(vp); 454 else 455 vput(vp); 456 } 457 458 if (cn.cn_flags & HASBUF) { 459 PNBUF_PUT(cn.cn_pnbuf); 460 cn.cn_flags &= ~HASBUF; 461 } 462 463 if (!error) { 464 cn.cn_flags |= (cnp->cn_flags & HASBUF); 465 cnp->cn_flags = cn.cn_flags; 466 } 467 468 return (error); 469 470 } 471 472 /* 473 * Update the unionfs_node. 474 * 475 * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the 476 * uvp's lock and lower's lock will be unlocked. 477 */ 478 static void 479 unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp) 480 { 481 int count, lockcnt; 482 struct vnode *vp; 483 struct vnode *lvp; 484 485 vp = UNIONFSTOV(unp); 486 lvp = unp->un_lowervp; 487 488 /* 489 * lock update 490 */ 491 mutex_enter(&vp->v_interlock); 492 unp->un_uppervp = uvp; 493 vp->v_vnlock = uvp->v_vnlock; 494 lockcnt = lvp->v_vnlock->vl_recursecnt + 495 rw_write_held(&lvp->v_vnlock->vl_lock); 496 if (lockcnt <= 0) 497 panic("unionfs: no exclusive lock"); 498 mutex_exit(&vp->v_interlock); 499 for (count = 1; count < lockcnt; count++) 500 vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY); 501 } 502 503 /* 504 * Create a new shadow dir. 505 * 506 * udvp should be locked on entry and will be locked on return. 507 * 508 * If no error returned, unp will be updated. 509 */ 510 int 511 unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, 512 struct unionfs_node *unp, struct componentname *cnp) 513 { 514 int error; 515 struct vnode *lvp; 516 struct vnode *uvp; 517 struct vattr va; 518 struct vattr lva; 519 struct componentname cn; 520 521 if (unp->un_uppervp != NULLVP) 522 return (EEXIST); 523 524 lvp = unp->un_lowervp; 525 uvp = NULLVP; 526 527 memset(&cn, 0, sizeof(cn)); 528 529 if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred))) 530 goto unionfs_mkshadowdir_abort; 531 532 if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, cnp->cn_nameptr, cnp->cn_namelen, CREATE))) 533 goto unionfs_mkshadowdir_abort; 534 if (uvp != NULLVP) { 535 if (udvp == uvp) 536 vrele(uvp); 537 else 538 vput(uvp); 539 540 error = EEXIST; 541 goto unionfs_mkshadowdir_free_out; 542 } 543 544 unionfs_create_uppervattr_core(ump, &lva, &va); 545 546 error = VOP_MKDIR(udvp, &uvp, &cn, &va); 547 548 if (!error) { 549 unionfs_node_update(unp, uvp); 550 551 /* 552 * XXX The bug which cannot set uid/gid was corrected. 553 * Ignore errors. XXXNETBSD Why is this done as root? 554 */ 555 va.va_type = VNON; 556 VOP_SETATTR(uvp, &va, lwp0.l_cred); 557 } 558 559 unionfs_mkshadowdir_free_out: 560 if (cn.cn_flags & HASBUF) { 561 PNBUF_PUT(cn.cn_pnbuf); 562 cn.cn_flags &= ~HASBUF; 563 } 564 565 unionfs_mkshadowdir_abort: 566 567 return (error); 568 } 569 570 /* 571 * Create a new whiteout. 572 * 573 * dvp should be locked on entry and will be locked on return. 574 */ 575 int 576 unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path) 577 { 578 int error; 579 struct vnode *wvp; 580 struct componentname cn; 581 582 if (path == NULL) 583 path = cnp->cn_nameptr; 584 585 wvp = NULLVP; 586 if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, path, strlen(path), CREATE))) 587 return (error); 588 if (wvp != NULLVP) { 589 if (cn.cn_flags & HASBUF) { 590 PNBUF_PUT(cn.cn_pnbuf); 591 cn.cn_flags &= ~HASBUF; 592 } 593 if (dvp == wvp) 594 vrele(wvp); 595 else 596 vput(wvp); 597 598 return (EEXIST); 599 } 600 601 if (cn.cn_flags & HASBUF) { 602 PNBUF_PUT(cn.cn_pnbuf); 603 cn.cn_flags &= ~HASBUF; 604 } 605 606 return (error); 607 } 608 609 /* 610 * Create a new vnode for create a new shadow file. 611 * 612 * If an error is returned, *vpp will be invalid, otherwise it will hold a 613 * locked, referenced and opened vnode. 614 * 615 * unp is never updated. 616 */ 617 static int 618 unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp, 619 struct unionfs_node *unp, struct vattr *uvap) 620 { 621 struct unionfs_mount *ump; 622 struct vnode *vp; 623 struct vnode *lvp; 624 kauth_cred_t cred; 625 struct vattr lva; 626 int fmode; 627 int error; 628 struct componentname cn; 629 630 ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); 631 vp = NULLVP; 632 lvp = unp->un_lowervp; 633 cred = kauth_cred_get(); 634 fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL); 635 error = 0; 636 637 if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0) 638 return (error); 639 unionfs_create_uppervattr_core(ump, &lva, uvap); 640 641 if (unp->un_path == NULL) 642 panic("unionfs: un_path is null"); 643 644 cn.cn_namelen = strlen(unp->un_path); 645 cn.cn_pnbuf = PNBUF_GET(); 646 bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1); 647 cn.cn_nameiop = CREATE; 648 cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN); 649 cn.cn_cred = cred; 650 cn.cn_nameptr = cn.cn_pnbuf; 651 cn.cn_consume = 0; 652 653 vref(udvp); 654 if ((error = relookup(udvp, &vp, &cn)) != 0) 655 goto unionfs_vn_create_on_upper_free_out2; 656 vrele(udvp); 657 658 if (vp != NULLVP) { 659 if (vp == udvp) 660 vrele(vp); 661 else 662 vput(vp); 663 error = EEXIST; 664 goto unionfs_vn_create_on_upper_free_out1; 665 } 666 667 if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) 668 goto unionfs_vn_create_on_upper_free_out1; 669 670 if ((error = VOP_OPEN(vp, fmode, cred)) != 0) { 671 vput(vp); 672 goto unionfs_vn_create_on_upper_free_out1; 673 } 674 vp->v_writecount++; 675 *vpp = vp; 676 677 unionfs_vn_create_on_upper_free_out1: 678 VOP_UNLOCK(udvp, 0); 679 680 unionfs_vn_create_on_upper_free_out2: 681 if (cn.cn_flags & HASBUF) { 682 PNBUF_PUT(cn.cn_pnbuf); 683 cn.cn_flags &= ~HASBUF; 684 } 685 686 return (error); 687 } 688 689 /* 690 * Copy from lvp to uvp. 691 * 692 * lvp and uvp should be locked and opened on entry and will be locked and 693 * opened on return. 694 */ 695 static int 696 unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp, 697 kauth_cred_t cred) 698 { 699 int error; 700 off_t offset; 701 int count; 702 int bufoffset; 703 char *buf; 704 struct uio uio; 705 struct iovec iov; 706 707 error = 0; 708 memset(&uio, 0, sizeof(uio)); 709 UIO_SETUP_SYSSPACE(&uio); 710 uio.uio_offset = 0; 711 712 buf = kmem_alloc(MAXBSIZE, KM_SLEEP); 713 if (buf == NULL) 714 return ENOMEM; 715 716 while (error == 0) { 717 offset = uio.uio_offset; 718 719 uio.uio_iov = &iov; 720 uio.uio_iovcnt = 1; 721 iov.iov_base = buf; 722 iov.iov_len = MAXBSIZE; 723 uio.uio_resid = iov.iov_len; 724 uio.uio_rw = UIO_READ; 725 726 if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0) 727 break; 728 if ((count = MAXBSIZE - uio.uio_resid) == 0) 729 break; 730 731 bufoffset = 0; 732 while (bufoffset < count) { 733 uio.uio_iov = &iov; 734 uio.uio_iovcnt = 1; 735 iov.iov_base = buf + bufoffset; 736 iov.iov_len = count - bufoffset; 737 uio.uio_offset = offset + bufoffset; 738 uio.uio_resid = iov.iov_len; 739 uio.uio_rw = UIO_WRITE; 740 741 if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0) 742 break; 743 744 bufoffset += (count - bufoffset) - uio.uio_resid; 745 } 746 747 uio.uio_offset = offset + bufoffset; 748 } 749 750 kmem_free(buf, MAXBSIZE); 751 752 return (error); 753 } 754 755 /* 756 * Copy file from lower to upper. 757 * 758 * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to 759 * docopy. 760 * 761 * If no error returned, unp will be updated. 762 */ 763 int 764 unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred) 765 { 766 int error; 767 struct vnode *udvp; 768 struct vnode *lvp; 769 struct vnode *uvp; 770 struct vattr uva; 771 772 lvp = unp->un_lowervp; 773 uvp = NULLVP; 774 775 if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY)) 776 return (EROFS); 777 if (unp->un_dvp == NULLVP) 778 return (EINVAL); 779 if (unp->un_uppervp != NULLVP) 780 return (EEXIST); 781 udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp; 782 if (udvp == NULLVP) 783 return (EROFS); 784 if ((udvp->v_mount->mnt_flag & MNT_RDONLY)) 785 return (EROFS); 786 787 error = VOP_ACCESS(lvp, VREAD, cred); 788 if (error != 0) 789 return (error); 790 791 error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva); 792 if (error != 0) 793 return (error); 794 795 if (docopy != 0) { 796 error = VOP_OPEN(lvp, FREAD, cred); 797 if (error == 0) { 798 error = unionfs_copyfile_core(lvp, uvp, cred); 799 VOP_CLOSE(lvp, FREAD, cred); 800 } 801 } 802 VOP_CLOSE(uvp, FWRITE, cred); 803 uvp->v_writecount--; 804 805 if (error == 0) { 806 /* Reset the attributes. Ignore errors. */ 807 uva.va_type = VNON; 808 VOP_SETATTR(uvp, &uva, cred); 809 } 810 811 unionfs_node_update(unp, uvp); 812 813 return (error); 814 } 815 816 /* 817 * It checks whether vp can rmdir. (check empty) 818 * 819 * vp is unionfs vnode. 820 * vp should be locked. 821 */ 822 int 823 unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred) 824 { 825 int error; 826 int eofflag; 827 int lookuperr; 828 struct vnode *uvp; 829 struct vnode *lvp; 830 struct vnode *tvp; 831 struct vattr va; 832 struct componentname cn; 833 /* 834 * The size of buf needs to be larger than DIRBLKSIZ. 835 */ 836 char buf[256 * 6]; 837 struct dirent *dp; 838 struct dirent *edp; 839 struct uio uio; 840 struct iovec iov; 841 842 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 843 844 eofflag = 0; 845 uvp = UNIONFSVPTOUPPERVP(vp); 846 lvp = UNIONFSVPTOLOWERVP(vp); 847 848 /* check opaque */ 849 if ((error = VOP_GETATTR(uvp, &va, cred)) != 0) 850 return (error); 851 if (va.va_flags & OPAQUE) 852 return (0); 853 854 /* open vnode */ 855 if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0) 856 return (error); 857 if ((error = VOP_OPEN(vp, FREAD, cred)) != 0) 858 return (error); 859 860 UIO_SETUP_SYSSPACE(&uio); 861 uio.uio_rw = UIO_READ; 862 uio.uio_offset = 0; 863 864 while (!error && !eofflag) { 865 iov.iov_base = buf; 866 iov.iov_len = sizeof(buf); 867 uio.uio_iov = &iov; 868 uio.uio_iovcnt = 1; 869 uio.uio_resid = iov.iov_len; 870 871 error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL); 872 if (error) 873 break; 874 875 edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid]; 876 for (dp = (struct dirent*)buf; !error && dp < edp; 877 dp = (struct dirent*)((char *)dp + dp->d_reclen)) { 878 if (dp->d_type == DT_WHT || 879 (dp->d_namlen == 1 && dp->d_name[0] == '.') || 880 (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2))) 881 continue; 882 883 cn.cn_namelen = dp->d_namlen; 884 cn.cn_pnbuf = NULL; 885 cn.cn_nameptr = dp->d_name; 886 cn.cn_nameiop = LOOKUP; 887 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN); 888 cn.cn_cred = cred; 889 cn.cn_consume = 0; 890 891 /* 892 * check entry in lower. 893 * Sometimes, readdir function returns 894 * wrong entry. 895 */ 896 lookuperr = VOP_LOOKUP(lvp, &tvp, &cn); 897 898 if (!lookuperr) 899 vput(tvp); 900 else 901 continue; /* skip entry */ 902 903 /* 904 * check entry 905 * If it has no exist/whiteout entry in upper, 906 * directory is not empty. 907 */ 908 cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN); 909 lookuperr = VOP_LOOKUP(uvp, &tvp, &cn); 910 911 if (!lookuperr) 912 vput(tvp); 913 914 /* ignore exist or whiteout entry */ 915 if (!lookuperr || 916 (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT))) 917 continue; 918 919 error = ENOTEMPTY; 920 } 921 } 922 923 /* close vnode */ 924 VOP_CLOSE(vp, FREAD, cred); 925 926 return (error); 927 } 928 929 #ifdef DIAGNOSTIC 930 931 struct vnode * 932 unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno) 933 { 934 struct unionfs_node *unp; 935 936 unp = VTOUNIONFS(vp); 937 938 #ifdef notyet 939 if (vp->v_op != unionfs_vnodeop_p) { 940 printf("unionfs_checkuppervp: on non-unionfs-node.\n"); 941 #ifdef KDB 942 kdb_enter(KDB_WHY_UNIONFS, 943 "unionfs_checkuppervp: on non-unionfs-node.\n"); 944 #endif 945 panic("unionfs_checkuppervp"); 946 }; 947 #endif 948 return (unp->un_uppervp); 949 } 950 951 struct vnode * 952 unionfs_checklowervp(struct vnode *vp, const char *fil, int lno) 953 { 954 struct unionfs_node *unp; 955 956 unp = VTOUNIONFS(vp); 957 958 #ifdef notyet 959 if (vp->v_op != unionfs_vnodeop_p) { 960 printf("unionfs_checklowervp: on non-unionfs-node.\n"); 961 #ifdef KDB 962 kdb_enter(KDB_WHY_UNIONFS, 963 "unionfs_checklowervp: on non-unionfs-node.\n"); 964 #endif 965 panic("unionfs_checklowervp"); 966 }; 967 #endif 968 return (unp->un_lowervp); 969 } 970 #endif 971