1 /* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 9 * 2005 program. 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * tmpfs vnode interface. 42 */ 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 #include <sys/param.h> 47 #include <sys/fcntl.h> 48 #include <sys/lockf.h> 49 #include <sys/namei.h> 50 #include <sys/priv.h> 51 #include <sys/proc.h> 52 #include <sys/resourcevar.h> 53 #include <sys/stat.h> 54 #include <sys/systm.h> 55 #include <sys/unistd.h> 56 #include <sys/vnode.h> 57 58 #include <vm/vm.h> 59 #include <vm/vm_object.h> 60 #include <vm/vm_page.h> 61 #include <vm/vm_pager.h> 62 #include <sys/sched.h> 63 #include <sys/sf_buf.h> 64 #include <machine/_inttypes.h> 65 66 #include <fs/fifofs/fifo.h> 67 #include <fs/tmpfs/tmpfs_vnops.h> 68 #include <fs/tmpfs/tmpfs.h> 69 70 /* --------------------------------------------------------------------- */ 71 72 static int 73 tmpfs_lookup(struct vop_cachedlookup_args *v) 74 { 75 struct vnode *dvp = v->a_dvp; 76 struct vnode **vpp = v->a_vpp; 77 struct componentname *cnp = v->a_cnp; 78 struct thread *td = cnp->cn_thread; 79 80 int error; 81 struct tmpfs_dirent *de; 82 struct tmpfs_node *dnode; 83 84 dnode = VP_TO_TMPFS_DIR(dvp); 85 *vpp = NULLVP; 86 87 /* Check accessibility of requested node as a first step. */ 88 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 89 if (error != 0) 90 goto out; 91 92 /* We cannot be requesting the parent directory of the root node. */ 93 MPASS(IMPLIES(dnode->tn_type == VDIR && 94 dnode->tn_dir.tn_parent == dnode, 95 !(cnp->cn_flags & ISDOTDOT))); 96 97 if (cnp->cn_flags & ISDOTDOT) { 98 int ltype = 0; 99 100 ltype = VOP_ISLOCKED(dvp, td); 101 vhold(dvp); 102 VOP_UNLOCK(dvp, 0); 103 /* Allocate a new vnode on the matching entry. */ 104 error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent, 105 cnp->cn_lkflags, vpp, td); 106 107 vn_lock(dvp, ltype | LK_RETRY); 108 vdrop(dvp); 109 } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 110 VREF(dvp); 111 *vpp = dvp; 112 error = 0; 113 } else { 114 de = tmpfs_dir_lookup(dnode, cnp); 115 if (de == NULL) { 116 /* The entry was not found in the directory. 117 * This is OK if we are creating or renaming an 118 * entry and are working on the last component of 119 * the path name. */ 120 if ((cnp->cn_flags & ISLASTCN) && 121 (cnp->cn_nameiop == CREATE || \ 122 cnp->cn_nameiop == RENAME)) { 123 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 124 cnp->cn_thread); 125 if (error != 0) 126 goto out; 127 128 /* Keep the component name in the buffer for 129 * future uses. */ 130 cnp->cn_flags |= SAVENAME; 131 132 error = EJUSTRETURN; 133 } else 134 error = ENOENT; 135 } else { 136 struct tmpfs_node *tnode; 137 138 /* The entry was found, so get its associated 139 * tmpfs_node. */ 140 tnode = de->td_node; 141 142 /* If we are not at the last path component and 143 * found a non-directory or non-link entry (which 144 * may itself be pointing to a directory), raise 145 * an error. */ 146 if ((tnode->tn_type != VDIR && 147 tnode->tn_type != VLNK) && 148 !(cnp->cn_flags & ISLASTCN)) { 149 error = ENOTDIR; 150 goto out; 151 } 152 153 /* If we are deleting or renaming the entry, keep 154 * track of its tmpfs_dirent so that it can be 155 * easily deleted later. */ 156 if ((cnp->cn_flags & ISLASTCN) && 157 (cnp->cn_nameiop == DELETE || 158 cnp->cn_nameiop == RENAME)) { 159 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 160 cnp->cn_thread); 161 if (error != 0) 162 goto out; 163 164 /* Allocate a new vnode on the matching entry. */ 165 error = tmpfs_alloc_vp(dvp->v_mount, tnode, 166 cnp->cn_lkflags, vpp, td); 167 if (error != 0) 168 goto out; 169 170 if ((dnode->tn_mode & S_ISTXT) && 171 VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) && 172 VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) { 173 error = EPERM; 174 vput(*vpp); 175 *vpp = NULL; 176 goto out; 177 } 178 cnp->cn_flags |= SAVENAME; 179 } else { 180 error = tmpfs_alloc_vp(dvp->v_mount, tnode, 181 cnp->cn_lkflags, vpp, td); 182 } 183 } 184 } 185 186 /* Store the result of this lookup in the cache. Avoid this if the 187 * request was for creation, as it does not improve timings on 188 * emprical tests. */ 189 if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 190 cache_enter(dvp, *vpp, cnp); 191 192 out: 193 /* If there were no errors, *vpp cannot be null and it must be 194 * locked. */ 195 MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp, td))); 196 197 return error; 198 } 199 200 /* --------------------------------------------------------------------- */ 201 202 static int 203 tmpfs_create(struct vop_create_args *v) 204 { 205 struct vnode *dvp = v->a_dvp; 206 struct vnode **vpp = v->a_vpp; 207 struct componentname *cnp = v->a_cnp; 208 struct vattr *vap = v->a_vap; 209 210 MPASS(vap->va_type == VREG || vap->va_type == VSOCK); 211 212 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 213 } 214 /* --------------------------------------------------------------------- */ 215 216 static int 217 tmpfs_mknod(struct vop_mknod_args *v) 218 { 219 struct vnode *dvp = v->a_dvp; 220 struct vnode **vpp = v->a_vpp; 221 struct componentname *cnp = v->a_cnp; 222 struct vattr *vap = v->a_vap; 223 224 if (vap->va_type != VBLK && vap->va_type != VCHR && 225 vap->va_type != VFIFO) 226 return EINVAL; 227 228 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 229 } 230 231 /* --------------------------------------------------------------------- */ 232 233 static int 234 tmpfs_open(struct vop_open_args *v) 235 { 236 struct vnode *vp = v->a_vp; 237 int mode = v->a_mode; 238 239 int error; 240 struct tmpfs_node *node; 241 242 MPASS(VOP_ISLOCKED(vp, v->a_td)); 243 244 node = VP_TO_TMPFS_NODE(vp); 245 246 /* The file is still active but all its names have been removed 247 * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as 248 * it is about to die. */ 249 if (node->tn_links < 1) 250 return (ENOENT); 251 252 /* If the file is marked append-only, deny write requests. */ 253 if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) 254 error = EPERM; 255 else { 256 error = 0; 257 vnode_create_vobject(vp, node->tn_size, v->a_td); 258 } 259 260 MPASS(VOP_ISLOCKED(vp, v->a_td)); 261 return error; 262 } 263 264 /* --------------------------------------------------------------------- */ 265 266 static int 267 tmpfs_close(struct vop_close_args *v) 268 { 269 struct vnode *vp = v->a_vp; 270 271 struct tmpfs_node *node; 272 273 MPASS(VOP_ISLOCKED(vp, v->a_td)); 274 275 node = VP_TO_TMPFS_NODE(vp); 276 277 if (node->tn_links > 0) { 278 /* Update node times. No need to do it if the node has 279 * been deleted, because it will vanish after we return. */ 280 tmpfs_update(vp); 281 } 282 283 return 0; 284 } 285 286 /* --------------------------------------------------------------------- */ 287 288 int 289 tmpfs_access(struct vop_access_args *v) 290 { 291 struct vnode *vp = v->a_vp; 292 int mode = v->a_mode; 293 struct ucred *cred = v->a_cred; 294 295 int error; 296 struct tmpfs_node *node; 297 298 MPASS(VOP_ISLOCKED(vp, v->a_td)); 299 300 node = VP_TO_TMPFS_NODE(vp); 301 302 switch (vp->v_type) { 303 case VDIR: 304 /* FALLTHROUGH */ 305 case VLNK: 306 /* FALLTHROUGH */ 307 case VREG: 308 if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { 309 error = EROFS; 310 goto out; 311 } 312 break; 313 314 case VBLK: 315 /* FALLTHROUGH */ 316 case VCHR: 317 /* FALLTHROUGH */ 318 case VSOCK: 319 /* FALLTHROUGH */ 320 case VFIFO: 321 break; 322 323 default: 324 error = EINVAL; 325 goto out; 326 } 327 328 if (mode & VWRITE && node->tn_flags & IMMUTABLE) { 329 error = EPERM; 330 goto out; 331 } 332 333 error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, 334 node->tn_gid, mode, cred, NULL); 335 336 out: 337 MPASS(VOP_ISLOCKED(vp, v->a_td)); 338 339 return error; 340 } 341 342 /* --------------------------------------------------------------------- */ 343 344 int 345 tmpfs_getattr(struct vop_getattr_args *v) 346 { 347 struct vnode *vp = v->a_vp; 348 struct vattr *vap = v->a_vap; 349 350 struct tmpfs_node *node; 351 352 node = VP_TO_TMPFS_NODE(vp); 353 354 VATTR_NULL(vap); 355 356 tmpfs_update(vp); 357 358 vap->va_type = vp->v_type; 359 vap->va_mode = node->tn_mode; 360 vap->va_nlink = node->tn_links; 361 vap->va_uid = node->tn_uid; 362 vap->va_gid = node->tn_gid; 363 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 364 vap->va_fileid = node->tn_id; 365 vap->va_size = node->tn_size; 366 vap->va_blocksize = PAGE_SIZE; 367 vap->va_atime = node->tn_atime; 368 vap->va_mtime = node->tn_mtime; 369 vap->va_ctime = node->tn_ctime; 370 vap->va_birthtime = node->tn_birthtime; 371 vap->va_gen = node->tn_gen; 372 vap->va_flags = node->tn_flags; 373 vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? 374 node->tn_rdev : VNOVAL; 375 vap->va_bytes = round_page(node->tn_size); 376 vap->va_filerev = VNOVAL; 377 vap->va_vaflags = 0; 378 vap->va_spare = VNOVAL; /* XXX */ 379 380 return 0; 381 } 382 383 /* --------------------------------------------------------------------- */ 384 385 /* XXX Should this operation be atomic? I think it should, but code in 386 * XXX other places (e.g., ufs) doesn't seem to be... */ 387 int 388 tmpfs_setattr(struct vop_setattr_args *v) 389 { 390 struct vnode *vp = v->a_vp; 391 struct vattr *vap = v->a_vap; 392 struct ucred *cred = v->a_cred; 393 struct thread *l = v->a_td; 394 395 int error; 396 397 MPASS(VOP_ISLOCKED(vp, l)); 398 399 error = 0; 400 401 /* Abort if any unsettable attribute is given. */ 402 if (vap->va_type != VNON || 403 vap->va_nlink != VNOVAL || 404 vap->va_fsid != VNOVAL || 405 vap->va_fileid != VNOVAL || 406 vap->va_blocksize != VNOVAL || 407 vap->va_gen != VNOVAL || 408 vap->va_rdev != VNOVAL || 409 vap->va_bytes != VNOVAL) 410 error = EINVAL; 411 412 if (error == 0 && (vap->va_flags != VNOVAL)) 413 error = tmpfs_chflags(vp, vap->va_flags, cred, l); 414 415 if (error == 0 && (vap->va_size != VNOVAL)) 416 error = tmpfs_chsize(vp, vap->va_size, cred, l); 417 418 if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) 419 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, 420 l); 421 422 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) 423 error = tmpfs_chmod(vp, vap->va_mode, cred, l); 424 425 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 426 vap->va_atime.tv_nsec != VNOVAL) || 427 (vap->va_mtime.tv_sec != VNOVAL && 428 vap->va_mtime.tv_nsec != VNOVAL) || 429 (vap->va_birthtime.tv_sec != VNOVAL && 430 vap->va_birthtime.tv_nsec != VNOVAL))) 431 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime, 432 &vap->va_birthtime, vap->va_vaflags, cred, l); 433 434 /* Update the node times. We give preference to the error codes 435 * generated by this function rather than the ones that may arise 436 * from tmpfs_update. */ 437 tmpfs_update(vp); 438 439 MPASS(VOP_ISLOCKED(vp, l)); 440 441 return error; 442 } 443 444 /* --------------------------------------------------------------------- */ 445 446 static int 447 tmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio) 448 { 449 vm_pindex_t idx; 450 vm_page_t m; 451 struct sf_buf *sf; 452 off_t offset, addr; 453 size_t tlen; 454 caddr_t va; 455 int error; 456 457 addr = uio->uio_offset; 458 idx = OFF_TO_IDX(addr); 459 offset = addr & PAGE_MASK; 460 tlen = MIN(PAGE_SIZE - offset, len); 461 462 if ((vobj == NULL) || (vobj->resident_page_count == 0)) 463 goto nocache; 464 465 VM_OBJECT_LOCK(vobj); 466 lookupvpg: 467 if (((m = vm_page_lookup(vobj, idx)) != NULL) && 468 vm_page_is_valid(m, offset, tlen)) { 469 if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr")) 470 goto lookupvpg; 471 vm_page_busy(m); 472 VM_OBJECT_UNLOCK(vobj); 473 sched_pin(); 474 sf = sf_buf_alloc(m, SFB_CPUPRIVATE); 475 va = (caddr_t)sf_buf_kva(sf); 476 error = uiomove(va + offset, tlen, uio); 477 sf_buf_free(sf); 478 sched_unpin(); 479 VM_OBJECT_LOCK(vobj); 480 vm_page_wakeup(m); 481 VM_OBJECT_UNLOCK(vobj); 482 return (error); 483 } 484 VM_OBJECT_UNLOCK(vobj); 485 nocache: 486 VM_OBJECT_LOCK(tobj); 487 vm_object_pip_add(tobj, 1); 488 m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED | 489 VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 490 if (m->valid != VM_PAGE_BITS_ALL) { 491 int behind, ahead; 492 if (vm_pager_has_page(tobj, idx, &behind, &ahead)) { 493 error = vm_pager_get_pages(tobj, &m, 1, 0); 494 if (error != 0) { 495 printf("tmpfs get pages from pager error [read]\n"); 496 goto out; 497 } 498 } else 499 vm_page_zero_invalid(m, TRUE); 500 } 501 VM_OBJECT_UNLOCK(tobj); 502 sched_pin(); 503 sf = sf_buf_alloc(m, SFB_CPUPRIVATE); 504 va = (caddr_t)sf_buf_kva(sf); 505 error = uiomove(va + offset, tlen, uio); 506 sf_buf_free(sf); 507 sched_unpin(); 508 VM_OBJECT_LOCK(tobj); 509 out: 510 vm_page_lock_queues(); 511 vm_page_unwire(m, 0); 512 vm_page_activate(m); 513 vm_page_unlock_queues(); 514 vm_page_wakeup(m); 515 vm_object_pip_subtract(tobj, 1); 516 VM_OBJECT_UNLOCK(tobj); 517 518 return (error); 519 } 520 521 static int 522 tmpfs_read(struct vop_read_args *v) 523 { 524 struct vnode *vp = v->a_vp; 525 struct uio *uio = v->a_uio; 526 527 struct tmpfs_node *node; 528 vm_object_t uobj; 529 size_t len; 530 int resid; 531 532 int error = 0; 533 534 node = VP_TO_TMPFS_NODE(vp); 535 536 if (vp->v_type != VREG) { 537 error = EISDIR; 538 goto out; 539 } 540 541 if (uio->uio_offset < 0) { 542 error = EINVAL; 543 goto out; 544 } 545 546 node->tn_status |= TMPFS_NODE_ACCESSED; 547 548 uobj = node->tn_reg.tn_aobj; 549 while ((resid = uio->uio_resid) > 0) { 550 error = 0; 551 if (node->tn_size <= uio->uio_offset) 552 break; 553 len = MIN(node->tn_size - uio->uio_offset, resid); 554 if (len == 0) 555 break; 556 error = tmpfs_mappedread(vp->v_object, uobj, len, uio); 557 if ((error != 0) || (resid == uio->uio_resid)) 558 break; 559 } 560 561 out: 562 563 return error; 564 } 565 566 /* --------------------------------------------------------------------- */ 567 568 static int 569 tmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio) 570 { 571 vm_pindex_t idx; 572 vm_page_t vpg, tpg; 573 struct sf_buf *sf; 574 off_t offset, addr; 575 size_t tlen; 576 caddr_t va; 577 int error; 578 579 error = 0; 580 581 addr = uio->uio_offset; 582 idx = OFF_TO_IDX(addr); 583 offset = addr & PAGE_MASK; 584 tlen = MIN(PAGE_SIZE - offset, len); 585 586 if ((vobj == NULL) || (vobj->resident_page_count == 0)) { 587 vpg = NULL; 588 goto nocache; 589 } 590 591 VM_OBJECT_LOCK(vobj); 592 lookupvpg: 593 if (((vpg = vm_page_lookup(vobj, idx)) != NULL) && 594 vm_page_is_valid(vpg, offset, tlen)) { 595 if (vm_page_sleep_if_busy(vpg, FALSE, "tmfsmw")) 596 goto lookupvpg; 597 vm_page_busy(vpg); 598 vm_page_lock_queues(); 599 vm_page_undirty(vpg); 600 vm_page_unlock_queues(); 601 VM_OBJECT_UNLOCK(vobj); 602 sched_pin(); 603 sf = sf_buf_alloc(vpg, SFB_CPUPRIVATE); 604 va = (caddr_t)sf_buf_kva(sf); 605 error = uiomove(va + offset, tlen, uio); 606 sf_buf_free(sf); 607 sched_unpin(); 608 } else { 609 VM_OBJECT_UNLOCK(vobj); 610 vpg = NULL; 611 } 612 nocache: 613 VM_OBJECT_LOCK(tobj); 614 vm_object_pip_add(tobj, 1); 615 tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED | 616 VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 617 if (tpg->valid != VM_PAGE_BITS_ALL) { 618 int behind, ahead; 619 if (vm_pager_has_page(tobj, idx, &behind, &ahead)) { 620 error = vm_pager_get_pages(tobj, &tpg, 1, 0); 621 if (error != 0) { 622 printf("tmpfs get pages from pager error [write]\n"); 623 goto out; 624 } 625 } else 626 vm_page_zero_invalid(tpg, TRUE); 627 } 628 VM_OBJECT_UNLOCK(tobj); 629 if (vpg == NULL) { 630 sched_pin(); 631 sf = sf_buf_alloc(tpg, SFB_CPUPRIVATE); 632 va = (caddr_t)sf_buf_kva(sf); 633 error = uiomove(va + offset, tlen, uio); 634 sf_buf_free(sf); 635 sched_unpin(); 636 } else { 637 KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid")); 638 pmap_copy_page(vpg, tpg); 639 } 640 VM_OBJECT_LOCK(tobj); 641 out: 642 if (vobj != NULL) 643 VM_OBJECT_LOCK(vobj); 644 vm_page_lock_queues(); 645 if (error == 0) { 646 vm_page_set_validclean(tpg, offset, tlen); 647 vm_page_zero_invalid(tpg, TRUE); 648 vm_page_dirty(tpg); 649 } 650 vm_page_unwire(tpg, 0); 651 vm_page_activate(tpg); 652 vm_page_unlock_queues(); 653 vm_page_wakeup(tpg); 654 if (vpg != NULL) 655 vm_page_wakeup(vpg); 656 if (vobj != NULL) 657 VM_OBJECT_UNLOCK(vobj); 658 vm_object_pip_subtract(tobj, 1); 659 VM_OBJECT_UNLOCK(tobj); 660 661 return (error); 662 } 663 664 static int 665 tmpfs_write(struct vop_write_args *v) 666 { 667 struct vnode *vp = v->a_vp; 668 struct uio *uio = v->a_uio; 669 int ioflag = v->a_ioflag; 670 struct thread *td = uio->uio_td; 671 672 boolean_t extended; 673 int error = 0; 674 off_t oldsize; 675 struct tmpfs_node *node; 676 vm_object_t uobj; 677 size_t len; 678 int resid; 679 680 node = VP_TO_TMPFS_NODE(vp); 681 oldsize = node->tn_size; 682 683 if (uio->uio_offset < 0 || vp->v_type != VREG) { 684 error = EINVAL; 685 goto out; 686 } 687 688 if (uio->uio_resid == 0) { 689 error = 0; 690 goto out; 691 } 692 693 if (ioflag & IO_APPEND) 694 uio->uio_offset = node->tn_size; 695 696 if (uio->uio_offset + uio->uio_resid > 697 VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) 698 return (EFBIG); 699 700 if (vp->v_type == VREG && td != NULL) { 701 PROC_LOCK(td->td_proc); 702 if (uio->uio_offset + uio->uio_resid > 703 lim_cur(td->td_proc, RLIMIT_FSIZE)) { 704 psignal(td->td_proc, SIGXFSZ); 705 PROC_UNLOCK(td->td_proc); 706 return (EFBIG); 707 } 708 PROC_UNLOCK(td->td_proc); 709 } 710 711 extended = uio->uio_offset + uio->uio_resid > node->tn_size; 712 if (extended) { 713 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid); 714 if (error != 0) 715 goto out; 716 } 717 718 uobj = node->tn_reg.tn_aobj; 719 while ((resid = uio->uio_resid) > 0) { 720 if (node->tn_size <= uio->uio_offset) 721 break; 722 len = MIN(node->tn_size - uio->uio_offset, resid); 723 if (len == 0) 724 break; 725 error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio); 726 if ((error != 0) || (resid == uio->uio_resid)) 727 break; 728 } 729 730 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 731 (extended ? TMPFS_NODE_CHANGED : 0); 732 733 if (node->tn_mode & (S_ISUID | S_ISGID)) { 734 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0)) 735 node->tn_mode &= ~(S_ISUID | S_ISGID); 736 } 737 738 if (error != 0) 739 (void)tmpfs_reg_resize(vp, oldsize); 740 741 out: 742 MPASS(IMPLIES(error == 0, uio->uio_resid == 0)); 743 MPASS(IMPLIES(error != 0, oldsize == node->tn_size)); 744 745 return error; 746 } 747 748 /* --------------------------------------------------------------------- */ 749 750 static int 751 tmpfs_fsync(struct vop_fsync_args *v) 752 { 753 struct vnode *vp = v->a_vp; 754 755 MPASS(VOP_ISLOCKED(vp, v->a_td)); 756 757 tmpfs_update(vp); 758 759 return 0; 760 } 761 762 /* --------------------------------------------------------------------- */ 763 764 static int 765 tmpfs_remove(struct vop_remove_args *v) 766 { 767 struct vnode *dvp = v->a_dvp; 768 struct vnode *vp = v->a_vp; 769 770 int error; 771 struct tmpfs_dirent *de; 772 struct tmpfs_mount *tmp; 773 struct tmpfs_node *dnode; 774 struct tmpfs_node *node; 775 776 MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread)); 777 MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread)); 778 779 if (vp->v_type == VDIR) { 780 error = EISDIR; 781 goto out; 782 } 783 784 dnode = VP_TO_TMPFS_DIR(dvp); 785 node = VP_TO_TMPFS_NODE(vp); 786 tmp = VFS_TO_TMPFS(vp->v_mount); 787 de = tmpfs_dir_search(dnode, node); 788 MPASS(de != NULL); 789 790 /* Files marked as immutable or append-only cannot be deleted. */ 791 if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) || 792 (dnode->tn_flags & APPEND)) { 793 error = EPERM; 794 goto out; 795 } 796 797 /* Remove the entry from the directory; as it is a file, we do not 798 * have to change the number of hard links of the directory. */ 799 tmpfs_dir_detach(dvp, de); 800 801 /* Free the directory entry we just deleted. Note that the node 802 * referred by it will not be removed until the vnode is really 803 * reclaimed. */ 804 tmpfs_free_dirent(tmp, de, TRUE); 805 806 if (node->tn_links > 0) 807 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 808 TMPFS_NODE_MODIFIED; 809 error = 0; 810 811 out: 812 813 return error; 814 } 815 816 /* --------------------------------------------------------------------- */ 817 818 static int 819 tmpfs_link(struct vop_link_args *v) 820 { 821 struct vnode *dvp = v->a_tdvp; 822 struct vnode *vp = v->a_vp; 823 struct componentname *cnp = v->a_cnp; 824 825 int error; 826 struct tmpfs_dirent *de; 827 struct tmpfs_node *node; 828 829 MPASS(VOP_ISLOCKED(dvp, cnp->cn_thread)); 830 MPASS(cnp->cn_flags & HASBUF); 831 MPASS(dvp != vp); /* XXX When can this be false? */ 832 833 node = VP_TO_TMPFS_NODE(vp); 834 835 /* XXX: Why aren't the following two tests done by the caller? */ 836 837 /* Hard links of directories are forbidden. */ 838 if (vp->v_type == VDIR) { 839 error = EPERM; 840 goto out; 841 } 842 843 /* Cannot create cross-device links. */ 844 if (dvp->v_mount != vp->v_mount) { 845 error = EXDEV; 846 goto out; 847 } 848 849 /* Ensure that we do not overflow the maximum number of links imposed 850 * by the system. */ 851 MPASS(node->tn_links <= LINK_MAX); 852 if (node->tn_links == LINK_MAX) { 853 error = EMLINK; 854 goto out; 855 } 856 857 /* We cannot create links of files marked immutable or append-only. */ 858 if (node->tn_flags & (IMMUTABLE | APPEND)) { 859 error = EPERM; 860 goto out; 861 } 862 863 /* Allocate a new directory entry to represent the node. */ 864 error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, 865 cnp->cn_nameptr, cnp->cn_namelen, &de); 866 if (error != 0) 867 goto out; 868 869 /* Insert the new directory entry into the appropriate directory. */ 870 tmpfs_dir_attach(dvp, de); 871 872 /* vp link count has changed, so update node times. */ 873 node->tn_status |= TMPFS_NODE_CHANGED; 874 tmpfs_update(vp); 875 876 error = 0; 877 878 out: 879 return error; 880 } 881 882 /* --------------------------------------------------------------------- */ 883 884 static int 885 tmpfs_rename(struct vop_rename_args *v) 886 { 887 struct vnode *fdvp = v->a_fdvp; 888 struct vnode *fvp = v->a_fvp; 889 struct componentname *fcnp = v->a_fcnp; 890 struct vnode *tdvp = v->a_tdvp; 891 struct vnode *tvp = v->a_tvp; 892 struct componentname *tcnp = v->a_tcnp; 893 894 char *newname; 895 int error; 896 struct tmpfs_dirent *de; 897 struct tmpfs_node *fdnode; 898 struct tmpfs_node *fnode; 899 struct tmpfs_node *tnode; 900 struct tmpfs_node *tdnode; 901 902 MPASS(VOP_ISLOCKED(tdvp, tcnp->cn_thread)); 903 MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp, tcnp->cn_thread))); 904 MPASS(fcnp->cn_flags & HASBUF); 905 MPASS(tcnp->cn_flags & HASBUF); 906 907 tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); 908 909 /* Disallow cross-device renames. 910 * XXX Why isn't this done by the caller? */ 911 if (fvp->v_mount != tdvp->v_mount || 912 (tvp != NULL && fvp->v_mount != tvp->v_mount)) { 913 error = EXDEV; 914 goto out; 915 } 916 917 tdnode = VP_TO_TMPFS_DIR(tdvp); 918 919 /* If source and target are the same file, there is nothing to do. */ 920 if (fvp == tvp) { 921 error = 0; 922 goto out; 923 } 924 925 /* If we need to move the directory between entries, lock the 926 * source so that we can safely operate on it. */ 927 if (tdvp != fdvp) { 928 error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); 929 if (error != 0) 930 goto out; 931 } 932 fdnode = VP_TO_TMPFS_DIR(fdvp); 933 fnode = VP_TO_TMPFS_NODE(fvp); 934 de = tmpfs_dir_search(fdnode, fnode); 935 936 /* Avoid manipulating '.' and '..' entries. */ 937 if (de == NULL) { 938 MPASS(fvp->v_type == VDIR); 939 error = EINVAL; 940 goto out_locked; 941 } 942 MPASS(de->td_node == fnode); 943 944 /* If re-naming a directory to another preexisting directory 945 * ensure that the target directory is empty so that its 946 * removal causes no side effects. 947 * Kern_rename gurantees the destination to be a directory 948 * if the source is one. */ 949 if (tvp != NULL) { 950 MPASS(tnode != NULL); 951 952 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 953 (tdnode->tn_flags & (APPEND | IMMUTABLE))) { 954 error = EPERM; 955 goto out_locked; 956 } 957 958 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) { 959 if (tnode->tn_size > 0) { 960 error = ENOTEMPTY; 961 goto out_locked; 962 } 963 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { 964 error = ENOTDIR; 965 goto out_locked; 966 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { 967 error = EISDIR; 968 goto out_locked; 969 } else { 970 MPASS(fnode->tn_type != VDIR && 971 tnode->tn_type != VDIR); 972 } 973 } 974 975 if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) 976 || (fdnode->tn_flags & (APPEND | IMMUTABLE))) { 977 error = EPERM; 978 goto out_locked; 979 } 980 981 /* Ensure that we have enough memory to hold the new name, if it 982 * has to be changed. */ 983 if (fcnp->cn_namelen != tcnp->cn_namelen || 984 memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 985 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK); 986 } else 987 newname = NULL; 988 989 /* If the node is being moved to another directory, we have to do 990 * the move. */ 991 if (fdnode != tdnode) { 992 /* In case we are moving a directory, we have to adjust its 993 * parent to point to the new parent. */ 994 if (de->td_node->tn_type == VDIR) { 995 struct tmpfs_node *n; 996 997 /* Ensure the target directory is not a child of the 998 * directory being moved. Otherwise, we'd end up 999 * with stale nodes. */ 1000 n = tdnode; 1001 while (n != n->tn_dir.tn_parent) { 1002 if (n == fnode) { 1003 error = EINVAL; 1004 if (newname != NULL) 1005 free(newname, M_TMPFSNAME); 1006 goto out_locked; 1007 } 1008 n = n->tn_dir.tn_parent; 1009 } 1010 1011 /* Adjust the parent pointer. */ 1012 TMPFS_VALIDATE_DIR(fnode); 1013 de->td_node->tn_dir.tn_parent = tdnode; 1014 1015 /* As a result of changing the target of the '..' 1016 * entry, the link count of the source and target 1017 * directories has to be adjusted. */ 1018 fdnode->tn_links--; 1019 tdnode->tn_links++; 1020 } 1021 1022 /* Do the move: just remove the entry from the source directory 1023 * and insert it into the target one. */ 1024 tmpfs_dir_detach(fdvp, de); 1025 tmpfs_dir_attach(tdvp, de); 1026 } 1027 1028 /* If the name has changed, we need to make it effective by changing 1029 * it in the directory entry. */ 1030 if (newname != NULL) { 1031 MPASS(tcnp->cn_namelen <= MAXNAMLEN); 1032 1033 free(de->td_name, M_TMPFSNAME); 1034 de->td_namelen = (uint16_t)tcnp->cn_namelen; 1035 memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 1036 de->td_name = newname; 1037 1038 fnode->tn_status |= TMPFS_NODE_CHANGED; 1039 tdnode->tn_status |= TMPFS_NODE_MODIFIED; 1040 } 1041 1042 /* If we are overwriting an entry, we have to remove the old one 1043 * from the target directory. */ 1044 if (tvp != NULL) { 1045 /* Remove the old entry from the target directory. */ 1046 de = tmpfs_dir_search(tdnode, tnode); 1047 tmpfs_dir_detach(tdvp, de); 1048 1049 /* Free the directory entry we just deleted. Note that the 1050 * node referred by it will not be removed until the vnode is 1051 * really reclaimed. */ 1052 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE); 1053 } 1054 1055 error = 0; 1056 1057 out_locked: 1058 if (fdnode != tdnode) 1059 VOP_UNLOCK(fdvp, 0); 1060 1061 out: 1062 /* Release target nodes. */ 1063 /* XXX: I don't understand when tdvp can be the same as tvp, but 1064 * other code takes care of this... */ 1065 if (tdvp == tvp) 1066 vrele(tdvp); 1067 else 1068 vput(tdvp); 1069 if (tvp != NULL) 1070 vput(tvp); 1071 1072 /* Release source nodes. */ 1073 vrele(fdvp); 1074 vrele(fvp); 1075 1076 return error; 1077 } 1078 1079 /* --------------------------------------------------------------------- */ 1080 1081 static int 1082 tmpfs_mkdir(struct vop_mkdir_args *v) 1083 { 1084 struct vnode *dvp = v->a_dvp; 1085 struct vnode **vpp = v->a_vpp; 1086 struct componentname *cnp = v->a_cnp; 1087 struct vattr *vap = v->a_vap; 1088 1089 MPASS(vap->va_type == VDIR); 1090 1091 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 1092 } 1093 1094 /* --------------------------------------------------------------------- */ 1095 1096 static int 1097 tmpfs_rmdir(struct vop_rmdir_args *v) 1098 { 1099 struct vnode *dvp = v->a_dvp; 1100 struct vnode *vp = v->a_vp; 1101 1102 int error; 1103 struct tmpfs_dirent *de; 1104 struct tmpfs_mount *tmp; 1105 struct tmpfs_node *dnode; 1106 struct tmpfs_node *node; 1107 1108 MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread)); 1109 MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread)); 1110 1111 tmp = VFS_TO_TMPFS(dvp->v_mount); 1112 dnode = VP_TO_TMPFS_DIR(dvp); 1113 node = VP_TO_TMPFS_DIR(vp); 1114 1115 /* Directories with more than two entries ('.' and '..') cannot be 1116 * removed. */ 1117 if (node->tn_size > 0) { 1118 error = ENOTEMPTY; 1119 goto out; 1120 } 1121 1122 if ((dnode->tn_flags & APPEND) 1123 || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) { 1124 error = EPERM; 1125 goto out; 1126 } 1127 1128 /* This invariant holds only if we are not trying to remove "..". 1129 * We checked for that above so this is safe now. */ 1130 MPASS(node->tn_dir.tn_parent == dnode); 1131 1132 /* Get the directory entry associated with node (vp). This was 1133 * filled by tmpfs_lookup while looking up the entry. */ 1134 de = tmpfs_dir_search(dnode, node); 1135 MPASS(TMPFS_DIRENT_MATCHES(de, 1136 v->a_cnp->cn_nameptr, 1137 v->a_cnp->cn_namelen)); 1138 1139 /* Check flags to see if we are allowed to remove the directory. */ 1140 if (dnode->tn_flags & APPEND 1141 || node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) { 1142 error = EPERM; 1143 goto out; 1144 } 1145 1146 /* Detach the directory entry from the directory (dnode). */ 1147 tmpfs_dir_detach(dvp, de); 1148 1149 node->tn_links--; 1150 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 1151 TMPFS_NODE_MODIFIED; 1152 node->tn_dir.tn_parent->tn_links--; 1153 node->tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \ 1154 TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1155 1156 cache_purge(dvp); 1157 cache_purge(vp); 1158 1159 /* Free the directory entry we just deleted. Note that the node 1160 * referred by it will not be removed until the vnode is really 1161 * reclaimed. */ 1162 tmpfs_free_dirent(tmp, de, TRUE); 1163 1164 /* Release the deleted vnode (will destroy the node, notify 1165 * interested parties and clean it from the cache). */ 1166 1167 dnode->tn_status |= TMPFS_NODE_CHANGED; 1168 tmpfs_update(dvp); 1169 1170 error = 0; 1171 1172 out: 1173 return error; 1174 } 1175 1176 /* --------------------------------------------------------------------- */ 1177 1178 static int 1179 tmpfs_symlink(struct vop_symlink_args *v) 1180 { 1181 struct vnode *dvp = v->a_dvp; 1182 struct vnode **vpp = v->a_vpp; 1183 struct componentname *cnp = v->a_cnp; 1184 struct vattr *vap = v->a_vap; 1185 char *target = v->a_target; 1186 1187 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */ 1188 MPASS(vap->va_type == VLNK); 1189 #else 1190 vap->va_type = VLNK; 1191 #endif 1192 1193 return tmpfs_alloc_file(dvp, vpp, vap, cnp, target); 1194 } 1195 1196 /* --------------------------------------------------------------------- */ 1197 1198 static int 1199 tmpfs_readdir(struct vop_readdir_args *v) 1200 { 1201 struct vnode *vp = v->a_vp; 1202 struct uio *uio = v->a_uio; 1203 int *eofflag = v->a_eofflag; 1204 u_long **cookies = v->a_cookies; 1205 int *ncookies = v->a_ncookies; 1206 1207 int error; 1208 off_t startoff; 1209 off_t cnt = 0; 1210 struct tmpfs_node *node; 1211 1212 /* This operation only makes sense on directory nodes. */ 1213 if (vp->v_type != VDIR) 1214 return ENOTDIR; 1215 1216 node = VP_TO_TMPFS_DIR(vp); 1217 1218 startoff = uio->uio_offset; 1219 1220 if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { 1221 error = tmpfs_dir_getdotdent(node, uio); 1222 if (error != 0) 1223 goto outok; 1224 cnt++; 1225 } 1226 1227 if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) { 1228 error = tmpfs_dir_getdotdotdent(node, uio); 1229 if (error != 0) 1230 goto outok; 1231 cnt++; 1232 } 1233 1234 error = tmpfs_dir_getdents(node, uio, &cnt); 1235 1236 outok: 1237 MPASS(error >= -1); 1238 1239 if (error == -1) 1240 error = 0; 1241 1242 if (eofflag != NULL) 1243 *eofflag = 1244 (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); 1245 1246 /* Update NFS-related variables. */ 1247 if (error == 0 && cookies != NULL && ncookies != NULL) { 1248 off_t i; 1249 off_t off = startoff; 1250 struct tmpfs_dirent *de = NULL; 1251 1252 *ncookies = cnt; 1253 *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK); 1254 1255 for (i = 0; i < cnt; i++) { 1256 MPASS(off != TMPFS_DIRCOOKIE_EOF); 1257 if (off == TMPFS_DIRCOOKIE_DOT) { 1258 off = TMPFS_DIRCOOKIE_DOTDOT; 1259 } else { 1260 if (off == TMPFS_DIRCOOKIE_DOTDOT) { 1261 de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); 1262 } else if (de != NULL) { 1263 de = TAILQ_NEXT(de, td_entries); 1264 } else { 1265 de = tmpfs_dir_lookupbycookie(node, 1266 off); 1267 MPASS(de != NULL); 1268 de = TAILQ_NEXT(de, td_entries); 1269 } 1270 if (de == NULL) 1271 off = TMPFS_DIRCOOKIE_EOF; 1272 else 1273 off = tmpfs_dircookie(de); 1274 } 1275 1276 (*cookies)[i] = off; 1277 } 1278 MPASS(uio->uio_offset == off); 1279 } 1280 1281 return error; 1282 } 1283 1284 /* --------------------------------------------------------------------- */ 1285 1286 static int 1287 tmpfs_readlink(struct vop_readlink_args *v) 1288 { 1289 struct vnode *vp = v->a_vp; 1290 struct uio *uio = v->a_uio; 1291 1292 int error; 1293 struct tmpfs_node *node; 1294 1295 MPASS(uio->uio_offset == 0); 1296 MPASS(vp->v_type == VLNK); 1297 1298 node = VP_TO_TMPFS_NODE(vp); 1299 1300 error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid), 1301 uio); 1302 node->tn_status |= TMPFS_NODE_ACCESSED; 1303 1304 return error; 1305 } 1306 1307 /* --------------------------------------------------------------------- */ 1308 1309 static int 1310 tmpfs_inactive(struct vop_inactive_args *v) 1311 { 1312 struct vnode *vp = v->a_vp; 1313 struct thread *l = v->a_td; 1314 1315 struct tmpfs_node *node; 1316 1317 MPASS(VOP_ISLOCKED(vp, l)); 1318 1319 node = VP_TO_TMPFS_NODE(vp); 1320 1321 if (node->tn_links == 0) 1322 vrecycle(vp, l); 1323 1324 return 0; 1325 } 1326 1327 /* --------------------------------------------------------------------- */ 1328 1329 int 1330 tmpfs_reclaim(struct vop_reclaim_args *v) 1331 { 1332 struct vnode *vp = v->a_vp; 1333 1334 struct tmpfs_mount *tmp; 1335 struct tmpfs_node *node; 1336 1337 node = VP_TO_TMPFS_NODE(vp); 1338 tmp = VFS_TO_TMPFS(vp->v_mount); 1339 1340 vnode_destroy_vobject(vp); 1341 cache_purge(vp); 1342 tmpfs_free_vp(vp); 1343 1344 /* If the node referenced by this vnode was deleted by the user, 1345 * we must free its associated data structures (now that the vnode 1346 * is being reclaimed). */ 1347 if (node->tn_links == 0) 1348 tmpfs_free_node(tmp, node); 1349 1350 MPASS(vp->v_data == NULL); 1351 return 0; 1352 } 1353 1354 /* --------------------------------------------------------------------- */ 1355 1356 static int 1357 tmpfs_print(struct vop_print_args *v) 1358 { 1359 struct vnode *vp = v->a_vp; 1360 1361 struct tmpfs_node *node; 1362 1363 node = VP_TO_TMPFS_NODE(vp); 1364 1365 printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n", 1366 node, node->tn_flags, node->tn_links); 1367 printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX 1368 ", status 0x%x\n", 1369 node->tn_mode, node->tn_uid, node->tn_gid, 1370 (uintmax_t)node->tn_size, node->tn_status); 1371 1372 if (vp->v_type == VFIFO) 1373 fifo_printinfo(vp); 1374 1375 printf("\n"); 1376 1377 return 0; 1378 } 1379 1380 /* --------------------------------------------------------------------- */ 1381 1382 static int 1383 tmpfs_pathconf(struct vop_pathconf_args *v) 1384 { 1385 int name = v->a_name; 1386 register_t *retval = v->a_retval; 1387 1388 int error; 1389 1390 error = 0; 1391 1392 switch (name) { 1393 case _PC_LINK_MAX: 1394 *retval = LINK_MAX; 1395 break; 1396 1397 case _PC_NAME_MAX: 1398 *retval = NAME_MAX; 1399 break; 1400 1401 case _PC_PATH_MAX: 1402 *retval = PATH_MAX; 1403 break; 1404 1405 case _PC_PIPE_BUF: 1406 *retval = PIPE_BUF; 1407 break; 1408 1409 case _PC_CHOWN_RESTRICTED: 1410 *retval = 1; 1411 break; 1412 1413 case _PC_NO_TRUNC: 1414 *retval = 1; 1415 break; 1416 1417 case _PC_SYNC_IO: 1418 *retval = 1; 1419 break; 1420 1421 case _PC_FILESIZEBITS: 1422 *retval = 0; /* XXX Don't know which value should I return. */ 1423 break; 1424 1425 default: 1426 error = EINVAL; 1427 } 1428 1429 return error; 1430 } 1431 1432 /* --------------------------------------------------------------------- */ 1433 1434 static int 1435 tmpfs_advlock(struct vop_advlock_args *v) 1436 { 1437 struct vnode *vp = v->a_vp; 1438 1439 struct tmpfs_node *node; 1440 1441 node = VP_TO_TMPFS_NODE(vp); 1442 1443 return lf_advlock(v, &node->tn_lockf, node->tn_size); 1444 } 1445 1446 /* --------------------------------------------------------------------- */ 1447 1448 static int 1449 tmpfs_vptofh(struct vop_vptofh_args *ap) 1450 { 1451 struct tmpfs_fid *tfhp; 1452 struct tmpfs_node *node; 1453 1454 tfhp = (struct tmpfs_fid *)ap->a_fhp; 1455 node = VP_TO_TMPFS_NODE(ap->a_vp); 1456 1457 tfhp->tf_len = sizeof(struct tmpfs_fid); 1458 tfhp->tf_id = node->tn_id; 1459 tfhp->tf_gen = node->tn_gen; 1460 1461 return (0); 1462 } 1463 1464 /* --------------------------------------------------------------------- */ 1465 1466 /* 1467 * vnode operations vector used for files stored in a tmpfs file system. 1468 */ 1469 struct vop_vector tmpfs_vnodeop_entries = { 1470 .vop_default = &default_vnodeops, 1471 .vop_lookup = vfs_cache_lookup, 1472 .vop_cachedlookup = tmpfs_lookup, 1473 .vop_create = tmpfs_create, 1474 .vop_mknod = tmpfs_mknod, 1475 .vop_open = tmpfs_open, 1476 .vop_close = tmpfs_close, 1477 .vop_access = tmpfs_access, 1478 .vop_getattr = tmpfs_getattr, 1479 .vop_setattr = tmpfs_setattr, 1480 .vop_read = tmpfs_read, 1481 .vop_write = tmpfs_write, 1482 .vop_fsync = tmpfs_fsync, 1483 .vop_remove = tmpfs_remove, 1484 .vop_link = tmpfs_link, 1485 .vop_rename = tmpfs_rename, 1486 .vop_mkdir = tmpfs_mkdir, 1487 .vop_rmdir = tmpfs_rmdir, 1488 .vop_symlink = tmpfs_symlink, 1489 .vop_readdir = tmpfs_readdir, 1490 .vop_readlink = tmpfs_readlink, 1491 .vop_inactive = tmpfs_inactive, 1492 .vop_reclaim = tmpfs_reclaim, 1493 .vop_print = tmpfs_print, 1494 .vop_pathconf = tmpfs_pathconf, 1495 .vop_advlock = tmpfs_advlock, 1496 .vop_vptofh = tmpfs_vptofh, 1497 .vop_bmap = VOP_EOPNOTSUPP, 1498 }; 1499 1500