1 /* $NetBSD: tmpfs_subr.c,v 1.35 2007/07/09 21:10:50 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2005 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Efficient memory file system supporting functions. 35 */ 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #include <sys/namei.h> 41 #include <sys/priv.h> 42 #include <sys/proc.h> 43 #include <sys/stat.h> 44 #include <sys/systm.h> 45 #include <sys/sysctl.h> 46 #include <sys/vnode.h> 47 #include <sys/vmmeter.h> 48 49 #include <vm/vm.h> 50 #include <vm/vm_object.h> 51 #include <vm/vm_page.h> 52 #include <vm/vm_pageout.h> 53 #include <vm/vm_pager.h> 54 #include <vm/vm_extern.h> 55 56 #include <fs/tmpfs/tmpfs.h> 57 #include <fs/tmpfs/tmpfs_fifoops.h> 58 #include <fs/tmpfs/tmpfs_vnops.h> 59 60 SYSCTL_NODE(_vfs, OID_AUTO, tmpfs, CTLFLAG_RW, 0, "tmpfs file system"); 61 62 /* --------------------------------------------------------------------- */ 63 64 /* 65 * Allocates a new node of type 'type' inside the 'tmp' mount point, with 66 * its owner set to 'uid', its group to 'gid' and its mode set to 'mode', 67 * using the credentials of the process 'p'. 68 * 69 * If the node type is set to 'VDIR', then the parent parameter must point 70 * to the parent directory of the node being created. It may only be NULL 71 * while allocating the root node. 72 * 73 * If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter 74 * specifies the device the node represents. 75 * 76 * If the node type is set to 'VLNK', then the parameter target specifies 77 * the file name of the target file for the symbolic link that is being 78 * created. 79 * 80 * Note that new nodes are retrieved from the available list if it has 81 * items or, if it is empty, from the node pool as long as there is enough 82 * space to create them. 83 * 84 * Returns zero on success or an appropriate error code on failure. 85 */ 86 int 87 tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, 88 uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *parent, 89 char *target, dev_t rdev, struct tmpfs_node **node) 90 { 91 struct tmpfs_node *nnode; 92 93 /* If the root directory of the 'tmp' file system is not yet 94 * allocated, this must be the request to do it. */ 95 MPASS(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR)); 96 97 MPASS(IFF(type == VLNK, target != NULL)); 98 MPASS(IFF(type == VBLK || type == VCHR, rdev != VNOVAL)); 99 100 if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max) 101 return (ENOSPC); 102 103 nnode = (struct tmpfs_node *)uma_zalloc_arg( 104 tmp->tm_node_pool, tmp, M_WAITOK); 105 106 /* Generic initialization. */ 107 nnode->tn_type = type; 108 vfs_timestamp(&nnode->tn_atime); 109 nnode->tn_birthtime = nnode->tn_ctime = nnode->tn_mtime = 110 nnode->tn_atime; 111 nnode->tn_uid = uid; 112 nnode->tn_gid = gid; 113 nnode->tn_mode = mode; 114 nnode->tn_id = alloc_unr(tmp->tm_ino_unr); 115 116 /* Type-specific initialization. */ 117 switch (nnode->tn_type) { 118 case VBLK: 119 case VCHR: 120 nnode->tn_rdev = rdev; 121 break; 122 123 case VDIR: 124 TAILQ_INIT(&nnode->tn_dir.tn_dirhead); 125 MPASS(parent != nnode); 126 MPASS(IMPLIES(parent == NULL, tmp->tm_root == NULL)); 127 nnode->tn_dir.tn_parent = (parent == NULL) ? nnode : parent; 128 nnode->tn_dir.tn_readdir_lastn = 0; 129 nnode->tn_dir.tn_readdir_lastp = NULL; 130 nnode->tn_links++; 131 TMPFS_NODE_LOCK(nnode->tn_dir.tn_parent); 132 nnode->tn_dir.tn_parent->tn_links++; 133 TMPFS_NODE_UNLOCK(nnode->tn_dir.tn_parent); 134 break; 135 136 case VFIFO: 137 /* FALLTHROUGH */ 138 case VSOCK: 139 break; 140 141 case VLNK: 142 MPASS(strlen(target) < MAXPATHLEN); 143 nnode->tn_size = strlen(target); 144 nnode->tn_link = malloc(nnode->tn_size, M_TMPFSNAME, 145 M_WAITOK); 146 memcpy(nnode->tn_link, target, nnode->tn_size); 147 break; 148 149 case VREG: 150 nnode->tn_reg.tn_aobj = 151 vm_pager_allocate(OBJT_SWAP, NULL, 0, VM_PROT_DEFAULT, 0, 152 NULL /* XXXKIB - tmpfs needs swap reservation */); 153 break; 154 155 default: 156 panic("tmpfs_alloc_node: type %p %d", nnode, (int)nnode->tn_type); 157 } 158 159 TMPFS_LOCK(tmp); 160 LIST_INSERT_HEAD(&tmp->tm_nodes_used, nnode, tn_entries); 161 tmp->tm_nodes_inuse++; 162 TMPFS_UNLOCK(tmp); 163 164 *node = nnode; 165 return 0; 166 } 167 168 /* --------------------------------------------------------------------- */ 169 170 /* 171 * Destroys the node pointed to by node from the file system 'tmp'. 172 * If the node does not belong to the given mount point, the results are 173 * unpredicted. 174 * 175 * If the node references a directory; no entries are allowed because 176 * their removal could need a recursive algorithm, something forbidden in 177 * kernel space. Furthermore, there is not need to provide such 178 * functionality (recursive removal) because the only primitives offered 179 * to the user are the removal of empty directories and the deletion of 180 * individual files. 181 * 182 * Note that nodes are not really deleted; in fact, when a node has been 183 * allocated, it cannot be deleted during the whole life of the file 184 * system. Instead, they are moved to the available list and remain there 185 * until reused. 186 */ 187 void 188 tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) 189 { 190 vm_object_t uobj; 191 192 #ifdef INVARIANTS 193 TMPFS_NODE_LOCK(node); 194 MPASS(node->tn_vnode == NULL); 195 MPASS((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0); 196 TMPFS_NODE_UNLOCK(node); 197 #endif 198 199 TMPFS_LOCK(tmp); 200 LIST_REMOVE(node, tn_entries); 201 tmp->tm_nodes_inuse--; 202 TMPFS_UNLOCK(tmp); 203 204 switch (node->tn_type) { 205 case VNON: 206 /* Do not do anything. VNON is provided to let the 207 * allocation routine clean itself easily by avoiding 208 * duplicating code in it. */ 209 /* FALLTHROUGH */ 210 case VBLK: 211 /* FALLTHROUGH */ 212 case VCHR: 213 /* FALLTHROUGH */ 214 case VDIR: 215 /* FALLTHROUGH */ 216 case VFIFO: 217 /* FALLTHROUGH */ 218 case VSOCK: 219 break; 220 221 case VLNK: 222 free(node->tn_link, M_TMPFSNAME); 223 break; 224 225 case VREG: 226 uobj = node->tn_reg.tn_aobj; 227 if (uobj != NULL) { 228 TMPFS_LOCK(tmp); 229 tmp->tm_pages_used -= uobj->size; 230 TMPFS_UNLOCK(tmp); 231 vm_object_deallocate(uobj); 232 } 233 break; 234 235 default: 236 panic("tmpfs_free_node: type %p %d", node, (int)node->tn_type); 237 } 238 239 free_unr(tmp->tm_ino_unr, node->tn_id); 240 uma_zfree(tmp->tm_node_pool, node); 241 } 242 243 /* --------------------------------------------------------------------- */ 244 245 /* 246 * Allocates a new directory entry for the node node with a name of name. 247 * The new directory entry is returned in *de. 248 * 249 * The link count of node is increased by one to reflect the new object 250 * referencing it. 251 * 252 * Returns zero on success or an appropriate error code on failure. 253 */ 254 int 255 tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, 256 const char *name, uint16_t len, struct tmpfs_dirent **de) 257 { 258 struct tmpfs_dirent *nde; 259 260 nde = (struct tmpfs_dirent *)uma_zalloc( 261 tmp->tm_dirent_pool, M_WAITOK); 262 nde->td_name = malloc(len, M_TMPFSNAME, M_WAITOK); 263 nde->td_namelen = len; 264 memcpy(nde->td_name, name, len); 265 266 nde->td_node = node; 267 if (node != NULL) 268 node->tn_links++; 269 270 *de = nde; 271 272 return 0; 273 } 274 275 /* --------------------------------------------------------------------- */ 276 277 /* 278 * Frees a directory entry. It is the caller's responsibility to destroy 279 * the node referenced by it if needed. 280 * 281 * The link count of node is decreased by one to reflect the removal of an 282 * object that referenced it. This only happens if 'node_exists' is true; 283 * otherwise the function will not access the node referred to by the 284 * directory entry, as it may already have been released from the outside. 285 */ 286 void 287 tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de, 288 boolean_t node_exists) 289 { 290 if (node_exists) { 291 struct tmpfs_node *node; 292 293 node = de->td_node; 294 if (node != NULL) { 295 MPASS(node->tn_links > 0); 296 node->tn_links--; 297 } 298 } 299 300 free(de->td_name, M_TMPFSNAME); 301 uma_zfree(tmp->tm_dirent_pool, de); 302 } 303 304 /* --------------------------------------------------------------------- */ 305 306 /* 307 * Allocates a new vnode for the node node or returns a new reference to 308 * an existing one if the node had already a vnode referencing it. The 309 * resulting locked vnode is returned in *vpp. 310 * 311 * Returns zero on success or an appropriate error code on failure. 312 */ 313 int 314 tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag, 315 struct vnode **vpp) 316 { 317 int error = 0; 318 struct vnode *vp; 319 320 loop: 321 TMPFS_NODE_LOCK(node); 322 if ((vp = node->tn_vnode) != NULL) { 323 MPASS((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0); 324 VI_LOCK(vp); 325 TMPFS_NODE_UNLOCK(node); 326 error = vget(vp, lkflag | LK_INTERLOCK, curthread); 327 if (error != 0) { 328 vp = NULL; 329 goto out; 330 } 331 332 /* 333 * Make sure the vnode is still there after 334 * getting the interlock to avoid racing a free. 335 */ 336 if (node->tn_vnode == NULL || node->tn_vnode != vp) { 337 vput(vp); 338 goto loop; 339 } 340 341 goto out; 342 } 343 344 if ((node->tn_vpstate & TMPFS_VNODE_DOOMED) || 345 (node->tn_type == VDIR && node->tn_dir.tn_parent == NULL)) { 346 TMPFS_NODE_UNLOCK(node); 347 error = ENOENT; 348 vp = NULL; 349 goto out; 350 } 351 352 /* 353 * otherwise lock the vp list while we call getnewvnode 354 * since that can block. 355 */ 356 if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) { 357 node->tn_vpstate |= TMPFS_VNODE_WANT; 358 error = msleep((caddr_t) &node->tn_vpstate, 359 TMPFS_NODE_MTX(node), PDROP | PCATCH, 360 "tmpfs_alloc_vp", 0); 361 if (error) 362 return error; 363 364 goto loop; 365 } else 366 node->tn_vpstate |= TMPFS_VNODE_ALLOCATING; 367 368 TMPFS_NODE_UNLOCK(node); 369 370 /* Get a new vnode and associate it with our node. */ 371 error = getnewvnode("tmpfs", mp, &tmpfs_vnodeop_entries, &vp); 372 if (error != 0) 373 goto unlock; 374 MPASS(vp != NULL); 375 376 (void) vn_lock(vp, lkflag | LK_RETRY); 377 378 vp->v_data = node; 379 vp->v_type = node->tn_type; 380 381 /* Type-specific initialization. */ 382 switch (node->tn_type) { 383 case VBLK: 384 /* FALLTHROUGH */ 385 case VCHR: 386 /* FALLTHROUGH */ 387 case VLNK: 388 /* FALLTHROUGH */ 389 case VREG: 390 /* FALLTHROUGH */ 391 case VSOCK: 392 break; 393 case VFIFO: 394 vp->v_op = &tmpfs_fifoop_entries; 395 break; 396 case VDIR: 397 MPASS(node->tn_dir.tn_parent != NULL); 398 if (node->tn_dir.tn_parent == node) 399 vp->v_vflag |= VV_ROOT; 400 break; 401 402 default: 403 panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type); 404 } 405 406 vnode_pager_setsize(vp, node->tn_size); 407 error = insmntque(vp, mp); 408 if (error) 409 vp = NULL; 410 411 unlock: 412 TMPFS_NODE_LOCK(node); 413 414 MPASS(node->tn_vpstate & TMPFS_VNODE_ALLOCATING); 415 node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING; 416 node->tn_vnode = vp; 417 418 if (node->tn_vpstate & TMPFS_VNODE_WANT) { 419 node->tn_vpstate &= ~TMPFS_VNODE_WANT; 420 TMPFS_NODE_UNLOCK(node); 421 wakeup((caddr_t) &node->tn_vpstate); 422 } else 423 TMPFS_NODE_UNLOCK(node); 424 425 out: 426 *vpp = vp; 427 428 #ifdef INVARIANTS 429 if (error == 0) { 430 MPASS(*vpp != NULL && VOP_ISLOCKED(*vpp)); 431 TMPFS_NODE_LOCK(node); 432 MPASS(*vpp == node->tn_vnode); 433 TMPFS_NODE_UNLOCK(node); 434 } 435 #endif 436 437 return error; 438 } 439 440 /* --------------------------------------------------------------------- */ 441 442 /* 443 * Destroys the association between the vnode vp and the node it 444 * references. 445 */ 446 void 447 tmpfs_free_vp(struct vnode *vp) 448 { 449 struct tmpfs_node *node; 450 451 node = VP_TO_TMPFS_NODE(vp); 452 453 mtx_assert(TMPFS_NODE_MTX(node), MA_OWNED); 454 node->tn_vnode = NULL; 455 vp->v_data = NULL; 456 } 457 458 /* --------------------------------------------------------------------- */ 459 460 /* 461 * Allocates a new file of type 'type' and adds it to the parent directory 462 * 'dvp'; this addition is done using the component name given in 'cnp'. 463 * The ownership of the new file is automatically assigned based on the 464 * credentials of the caller (through 'cnp'), the group is set based on 465 * the parent directory and the mode is determined from the 'vap' argument. 466 * If successful, *vpp holds a vnode to the newly created file and zero 467 * is returned. Otherwise *vpp is NULL and the function returns an 468 * appropriate error code. 469 */ 470 int 471 tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, 472 struct componentname *cnp, char *target) 473 { 474 int error; 475 struct tmpfs_dirent *de; 476 struct tmpfs_mount *tmp; 477 struct tmpfs_node *dnode; 478 struct tmpfs_node *node; 479 struct tmpfs_node *parent; 480 481 MPASS(VOP_ISLOCKED(dvp)); 482 MPASS(cnp->cn_flags & HASBUF); 483 484 tmp = VFS_TO_TMPFS(dvp->v_mount); 485 dnode = VP_TO_TMPFS_DIR(dvp); 486 *vpp = NULL; 487 488 /* If the entry we are creating is a directory, we cannot overflow 489 * the number of links of its parent, because it will get a new 490 * link. */ 491 if (vap->va_type == VDIR) { 492 /* Ensure that we do not overflow the maximum number of links 493 * imposed by the system. */ 494 MPASS(dnode->tn_links <= LINK_MAX); 495 if (dnode->tn_links == LINK_MAX) { 496 error = EMLINK; 497 goto out; 498 } 499 500 parent = dnode; 501 MPASS(parent != NULL); 502 } else 503 parent = NULL; 504 505 /* Allocate a node that represents the new file. */ 506 error = tmpfs_alloc_node(tmp, vap->va_type, cnp->cn_cred->cr_uid, 507 dnode->tn_gid, vap->va_mode, parent, target, vap->va_rdev, &node); 508 if (error != 0) 509 goto out; 510 511 /* Allocate a directory entry that points to the new file. */ 512 error = tmpfs_alloc_dirent(tmp, node, cnp->cn_nameptr, cnp->cn_namelen, 513 &de); 514 if (error != 0) { 515 tmpfs_free_node(tmp, node); 516 goto out; 517 } 518 519 /* Allocate a vnode for the new file. */ 520 error = tmpfs_alloc_vp(dvp->v_mount, node, LK_EXCLUSIVE, vpp); 521 if (error != 0) { 522 tmpfs_free_dirent(tmp, de, TRUE); 523 tmpfs_free_node(tmp, node); 524 goto out; 525 } 526 527 /* Now that all required items are allocated, we can proceed to 528 * insert the new node into the directory, an operation that 529 * cannot fail. */ 530 if (cnp->cn_flags & ISWHITEOUT) 531 tmpfs_dir_whiteout_remove(dvp, cnp); 532 tmpfs_dir_attach(dvp, de); 533 534 out: 535 536 return error; 537 } 538 539 /* --------------------------------------------------------------------- */ 540 541 /* 542 * Attaches the directory entry de to the directory represented by vp. 543 * Note that this does not change the link count of the node pointed by 544 * the directory entry, as this is done by tmpfs_alloc_dirent. 545 */ 546 void 547 tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de) 548 { 549 struct tmpfs_node *dnode; 550 551 ASSERT_VOP_ELOCKED(vp, __func__); 552 dnode = VP_TO_TMPFS_DIR(vp); 553 TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries); 554 dnode->tn_size += sizeof(struct tmpfs_dirent); 555 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 556 TMPFS_NODE_MODIFIED; 557 } 558 559 /* --------------------------------------------------------------------- */ 560 561 /* 562 * Detaches the directory entry de from the directory represented by vp. 563 * Note that this does not change the link count of the node pointed by 564 * the directory entry, as this is done by tmpfs_free_dirent. 565 */ 566 void 567 tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de) 568 { 569 struct tmpfs_node *dnode; 570 571 ASSERT_VOP_ELOCKED(vp, __func__); 572 dnode = VP_TO_TMPFS_DIR(vp); 573 574 if (dnode->tn_dir.tn_readdir_lastp == de) { 575 dnode->tn_dir.tn_readdir_lastn = 0; 576 dnode->tn_dir.tn_readdir_lastp = NULL; 577 } 578 579 TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries); 580 dnode->tn_size -= sizeof(struct tmpfs_dirent); 581 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 582 TMPFS_NODE_MODIFIED; 583 } 584 585 /* --------------------------------------------------------------------- */ 586 587 /* 588 * Looks for a directory entry in the directory represented by node. 589 * 'cnp' describes the name of the entry to look for. Note that the . 590 * and .. components are not allowed as they do not physically exist 591 * within directories. 592 * 593 * Returns a pointer to the entry when found, otherwise NULL. 594 */ 595 struct tmpfs_dirent * 596 tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, 597 struct componentname *cnp) 598 { 599 boolean_t found; 600 struct tmpfs_dirent *de; 601 602 MPASS(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.')); 603 MPASS(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' && 604 cnp->cn_nameptr[1] == '.'))); 605 TMPFS_VALIDATE_DIR(node); 606 607 found = 0; 608 TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { 609 if (f != NULL && de->td_node != f) 610 continue; 611 MPASS(cnp->cn_namelen < 0xffff); 612 if (de->td_namelen == (uint16_t)cnp->cn_namelen && 613 bcmp(de->td_name, cnp->cn_nameptr, de->td_namelen) == 0) { 614 found = 1; 615 break; 616 } 617 } 618 node->tn_status |= TMPFS_NODE_ACCESSED; 619 620 return found ? de : NULL; 621 } 622 623 /* --------------------------------------------------------------------- */ 624 625 /* 626 * Helper function for tmpfs_readdir. Creates a '.' entry for the given 627 * directory and returns it in the uio space. The function returns 0 628 * on success, -1 if there was not enough space in the uio structure to 629 * hold the directory entry or an appropriate error code if another 630 * error happens. 631 */ 632 int 633 tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio) 634 { 635 int error; 636 struct dirent dent; 637 638 TMPFS_VALIDATE_DIR(node); 639 MPASS(uio->uio_offset == TMPFS_DIRCOOKIE_DOT); 640 641 dent.d_fileno = node->tn_id; 642 dent.d_type = DT_DIR; 643 dent.d_namlen = 1; 644 dent.d_name[0] = '.'; 645 dent.d_name[1] = '\0'; 646 dent.d_reclen = GENERIC_DIRSIZ(&dent); 647 648 if (dent.d_reclen > uio->uio_resid) 649 error = -1; 650 else { 651 error = uiomove(&dent, dent.d_reclen, uio); 652 if (error == 0) 653 uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT; 654 } 655 656 node->tn_status |= TMPFS_NODE_ACCESSED; 657 658 return error; 659 } 660 661 /* --------------------------------------------------------------------- */ 662 663 /* 664 * Helper function for tmpfs_readdir. Creates a '..' entry for the given 665 * directory and returns it in the uio space. The function returns 0 666 * on success, -1 if there was not enough space in the uio structure to 667 * hold the directory entry or an appropriate error code if another 668 * error happens. 669 */ 670 int 671 tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) 672 { 673 int error; 674 struct dirent dent; 675 676 TMPFS_VALIDATE_DIR(node); 677 MPASS(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT); 678 679 /* 680 * Return ENOENT if the current node is already removed. 681 */ 682 TMPFS_ASSERT_LOCKED(node); 683 if (node->tn_dir.tn_parent == NULL) { 684 return (ENOENT); 685 } 686 687 TMPFS_NODE_LOCK(node->tn_dir.tn_parent); 688 dent.d_fileno = node->tn_dir.tn_parent->tn_id; 689 TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent); 690 691 dent.d_type = DT_DIR; 692 dent.d_namlen = 2; 693 dent.d_name[0] = '.'; 694 dent.d_name[1] = '.'; 695 dent.d_name[2] = '\0'; 696 dent.d_reclen = GENERIC_DIRSIZ(&dent); 697 698 if (dent.d_reclen > uio->uio_resid) 699 error = -1; 700 else { 701 error = uiomove(&dent, dent.d_reclen, uio); 702 if (error == 0) { 703 struct tmpfs_dirent *de; 704 705 de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); 706 if (de == NULL) 707 uio->uio_offset = TMPFS_DIRCOOKIE_EOF; 708 else 709 uio->uio_offset = tmpfs_dircookie(de); 710 } 711 } 712 713 node->tn_status |= TMPFS_NODE_ACCESSED; 714 715 return error; 716 } 717 718 /* --------------------------------------------------------------------- */ 719 720 /* 721 * Lookup a directory entry by its associated cookie. 722 */ 723 struct tmpfs_dirent * 724 tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie) 725 { 726 struct tmpfs_dirent *de; 727 728 if (cookie == node->tn_dir.tn_readdir_lastn && 729 node->tn_dir.tn_readdir_lastp != NULL) { 730 return node->tn_dir.tn_readdir_lastp; 731 } 732 733 TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { 734 if (tmpfs_dircookie(de) == cookie) { 735 break; 736 } 737 } 738 739 return de; 740 } 741 742 /* --------------------------------------------------------------------- */ 743 744 /* 745 * Helper function for tmpfs_readdir. Returns as much directory entries 746 * as can fit in the uio space. The read starts at uio->uio_offset. 747 * The function returns 0 on success, -1 if there was not enough space 748 * in the uio structure to hold the directory entry or an appropriate 749 * error code if another error happens. 750 */ 751 int 752 tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) 753 { 754 int error; 755 off_t startcookie; 756 struct tmpfs_dirent *de; 757 758 TMPFS_VALIDATE_DIR(node); 759 760 /* Locate the first directory entry we have to return. We have cached 761 * the last readdir in the node, so use those values if appropriate. 762 * Otherwise do a linear scan to find the requested entry. */ 763 startcookie = uio->uio_offset; 764 MPASS(startcookie != TMPFS_DIRCOOKIE_DOT); 765 MPASS(startcookie != TMPFS_DIRCOOKIE_DOTDOT); 766 if (startcookie == TMPFS_DIRCOOKIE_EOF) { 767 return 0; 768 } else { 769 de = tmpfs_dir_lookupbycookie(node, startcookie); 770 } 771 if (de == NULL) { 772 return EINVAL; 773 } 774 775 /* Read as much entries as possible; i.e., until we reach the end of 776 * the directory or we exhaust uio space. */ 777 do { 778 struct dirent d; 779 780 /* Create a dirent structure representing the current 781 * tmpfs_node and fill it. */ 782 if (de->td_node == NULL) { 783 d.d_fileno = 1; 784 d.d_type = DT_WHT; 785 } else { 786 d.d_fileno = de->td_node->tn_id; 787 switch (de->td_node->tn_type) { 788 case VBLK: 789 d.d_type = DT_BLK; 790 break; 791 792 case VCHR: 793 d.d_type = DT_CHR; 794 break; 795 796 case VDIR: 797 d.d_type = DT_DIR; 798 break; 799 800 case VFIFO: 801 d.d_type = DT_FIFO; 802 break; 803 804 case VLNK: 805 d.d_type = DT_LNK; 806 break; 807 808 case VREG: 809 d.d_type = DT_REG; 810 break; 811 812 case VSOCK: 813 d.d_type = DT_SOCK; 814 break; 815 816 default: 817 panic("tmpfs_dir_getdents: type %p %d", 818 de->td_node, (int)de->td_node->tn_type); 819 } 820 } 821 d.d_namlen = de->td_namelen; 822 MPASS(de->td_namelen < sizeof(d.d_name)); 823 (void)memcpy(d.d_name, de->td_name, de->td_namelen); 824 d.d_name[de->td_namelen] = '\0'; 825 d.d_reclen = GENERIC_DIRSIZ(&d); 826 827 /* Stop reading if the directory entry we are treating is 828 * bigger than the amount of data that can be returned. */ 829 if (d.d_reclen > uio->uio_resid) { 830 error = -1; 831 break; 832 } 833 834 /* Copy the new dirent structure into the output buffer and 835 * advance pointers. */ 836 error = uiomove(&d, d.d_reclen, uio); 837 if (error == 0) { 838 (*cntp)++; 839 de = TAILQ_NEXT(de, td_entries); 840 } 841 } while (error == 0 && uio->uio_resid > 0 && de != NULL); 842 843 /* Update the offset and cache. */ 844 if (de == NULL) { 845 uio->uio_offset = TMPFS_DIRCOOKIE_EOF; 846 node->tn_dir.tn_readdir_lastn = 0; 847 node->tn_dir.tn_readdir_lastp = NULL; 848 } else { 849 node->tn_dir.tn_readdir_lastn = uio->uio_offset = tmpfs_dircookie(de); 850 node->tn_dir.tn_readdir_lastp = de; 851 } 852 853 node->tn_status |= TMPFS_NODE_ACCESSED; 854 return error; 855 } 856 857 int 858 tmpfs_dir_whiteout_add(struct vnode *dvp, struct componentname *cnp) 859 { 860 struct tmpfs_dirent *de; 861 int error; 862 863 error = tmpfs_alloc_dirent(VFS_TO_TMPFS(dvp->v_mount), NULL, 864 cnp->cn_nameptr, cnp->cn_namelen, &de); 865 if (error != 0) 866 return (error); 867 tmpfs_dir_attach(dvp, de); 868 return (0); 869 } 870 871 void 872 tmpfs_dir_whiteout_remove(struct vnode *dvp, struct componentname *cnp) 873 { 874 struct tmpfs_dirent *de; 875 876 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); 877 MPASS(de != NULL && de->td_node == NULL); 878 tmpfs_dir_detach(dvp, de); 879 tmpfs_free_dirent(VFS_TO_TMPFS(dvp->v_mount), de, TRUE); 880 } 881 882 /* --------------------------------------------------------------------- */ 883 884 /* 885 * Resizes the aobj associated with the regular file pointed to by 'vp' to the 886 * size 'newsize'. 'vp' must point to a vnode that represents a regular file. 887 * 'newsize' must be positive. 888 * 889 * Returns zero on success or an appropriate error code on failure. 890 */ 891 int 892 tmpfs_reg_resize(struct vnode *vp, off_t newsize, boolean_t ignerr) 893 { 894 struct tmpfs_mount *tmp; 895 struct tmpfs_node *node; 896 vm_object_t uobj; 897 vm_page_t m, ma[1]; 898 vm_pindex_t idx, newpages, oldpages; 899 off_t oldsize; 900 int base, rv; 901 902 MPASS(vp->v_type == VREG); 903 MPASS(newsize >= 0); 904 905 node = VP_TO_TMPFS_NODE(vp); 906 uobj = node->tn_reg.tn_aobj; 907 tmp = VFS_TO_TMPFS(vp->v_mount); 908 909 /* 910 * Convert the old and new sizes to the number of pages needed to 911 * store them. It may happen that we do not need to do anything 912 * because the last allocated page can accommodate the change on 913 * its own. 914 */ 915 oldsize = node->tn_size; 916 oldpages = OFF_TO_IDX(oldsize + PAGE_MASK); 917 MPASS(oldpages == uobj->size); 918 newpages = OFF_TO_IDX(newsize + PAGE_MASK); 919 if (newpages > oldpages && 920 newpages - oldpages > TMPFS_PAGES_AVAIL(tmp)) 921 return (ENOSPC); 922 923 VM_OBJECT_LOCK(uobj); 924 if (newsize < oldsize) { 925 /* 926 * Zero the truncated part of the last page. 927 */ 928 base = newsize & PAGE_MASK; 929 if (base != 0) { 930 idx = OFF_TO_IDX(newsize); 931 retry: 932 m = vm_page_lookup(uobj, idx); 933 if (m != NULL) { 934 if ((m->oflags & VPO_BUSY) != 0 || 935 m->busy != 0) { 936 vm_page_sleep(m, "tmfssz"); 937 goto retry; 938 } 939 MPASS(m->valid == VM_PAGE_BITS_ALL); 940 } else if (vm_pager_has_page(uobj, idx, NULL, NULL)) { 941 m = vm_page_alloc(uobj, idx, VM_ALLOC_NORMAL); 942 if (m == NULL) { 943 VM_OBJECT_UNLOCK(uobj); 944 VM_WAIT; 945 VM_OBJECT_LOCK(uobj); 946 goto retry; 947 } else if (m->valid != VM_PAGE_BITS_ALL) { 948 ma[0] = m; 949 rv = vm_pager_get_pages(uobj, ma, 1, 0); 950 m = vm_page_lookup(uobj, idx); 951 } else 952 /* A cached page was reactivated. */ 953 rv = VM_PAGER_OK; 954 vm_page_lock(m); 955 if (rv == VM_PAGER_OK) { 956 vm_page_deactivate(m); 957 vm_page_unlock(m); 958 vm_page_wakeup(m); 959 } else { 960 vm_page_free(m); 961 vm_page_unlock(m); 962 if (ignerr) 963 m = NULL; 964 else { 965 VM_OBJECT_UNLOCK(uobj); 966 return (EIO); 967 } 968 } 969 } 970 if (m != NULL) { 971 pmap_zero_page_area(m, base, PAGE_SIZE - base); 972 vm_page_dirty(m); 973 vm_pager_page_unswapped(m); 974 } 975 } 976 977 /* 978 * Release any swap space and free any whole pages. 979 */ 980 if (newpages < oldpages) { 981 swap_pager_freespace(uobj, newpages, oldpages - 982 newpages); 983 vm_object_page_remove(uobj, newpages, 0, 0); 984 } 985 } 986 uobj->size = newpages; 987 VM_OBJECT_UNLOCK(uobj); 988 989 TMPFS_LOCK(tmp); 990 tmp->tm_pages_used += (newpages - oldpages); 991 TMPFS_UNLOCK(tmp); 992 993 node->tn_size = newsize; 994 vnode_pager_setsize(vp, newsize); 995 return (0); 996 } 997 998 /* --------------------------------------------------------------------- */ 999 1000 /* 1001 * Change flags of the given vnode. 1002 * Caller should execute tmpfs_update on vp after a successful execution. 1003 * The vnode must be locked on entry and remain locked on exit. 1004 */ 1005 int 1006 tmpfs_chflags(struct vnode *vp, int flags, struct ucred *cred, struct thread *p) 1007 { 1008 int error; 1009 struct tmpfs_node *node; 1010 1011 MPASS(VOP_ISLOCKED(vp)); 1012 1013 node = VP_TO_TMPFS_NODE(vp); 1014 1015 /* Disallow this operation if the file system is mounted read-only. */ 1016 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1017 return EROFS; 1018 1019 /* 1020 * Callers may only modify the file flags on objects they 1021 * have VADMIN rights for. 1022 */ 1023 if ((error = VOP_ACCESS(vp, VADMIN, cred, p))) 1024 return (error); 1025 /* 1026 * Unprivileged processes are not permitted to unset system 1027 * flags, or modify flags if any system flags are set. 1028 */ 1029 if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { 1030 if (node->tn_flags 1031 & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { 1032 error = securelevel_gt(cred, 0); 1033 if (error) 1034 return (error); 1035 } 1036 /* Snapshot flag cannot be set or cleared */ 1037 if (((flags & SF_SNAPSHOT) != 0 && 1038 (node->tn_flags & SF_SNAPSHOT) == 0) || 1039 ((flags & SF_SNAPSHOT) == 0 && 1040 (node->tn_flags & SF_SNAPSHOT) != 0)) 1041 return (EPERM); 1042 node->tn_flags = flags; 1043 } else { 1044 if (node->tn_flags 1045 & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || 1046 (flags & UF_SETTABLE) != flags) 1047 return (EPERM); 1048 node->tn_flags &= SF_SETTABLE; 1049 node->tn_flags |= (flags & UF_SETTABLE); 1050 } 1051 node->tn_status |= TMPFS_NODE_CHANGED; 1052 1053 MPASS(VOP_ISLOCKED(vp)); 1054 1055 return 0; 1056 } 1057 1058 /* --------------------------------------------------------------------- */ 1059 1060 /* 1061 * Change access mode on the given vnode. 1062 * Caller should execute tmpfs_update on vp after a successful execution. 1063 * The vnode must be locked on entry and remain locked on exit. 1064 */ 1065 int 1066 tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct thread *p) 1067 { 1068 int error; 1069 struct tmpfs_node *node; 1070 1071 MPASS(VOP_ISLOCKED(vp)); 1072 1073 node = VP_TO_TMPFS_NODE(vp); 1074 1075 /* Disallow this operation if the file system is mounted read-only. */ 1076 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1077 return EROFS; 1078 1079 /* Immutable or append-only files cannot be modified, either. */ 1080 if (node->tn_flags & (IMMUTABLE | APPEND)) 1081 return EPERM; 1082 1083 /* 1084 * To modify the permissions on a file, must possess VADMIN 1085 * for that file. 1086 */ 1087 if ((error = VOP_ACCESS(vp, VADMIN, cred, p))) 1088 return (error); 1089 1090 /* 1091 * Privileged processes may set the sticky bit on non-directories, 1092 * as well as set the setgid bit on a file with a group that the 1093 * process is not a member of. 1094 */ 1095 if (vp->v_type != VDIR && (mode & S_ISTXT)) { 1096 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 1097 return (EFTYPE); 1098 } 1099 if (!groupmember(node->tn_gid, cred) && (mode & S_ISGID)) { 1100 error = priv_check_cred(cred, PRIV_VFS_SETGID, 0); 1101 if (error) 1102 return (error); 1103 } 1104 1105 1106 node->tn_mode &= ~ALLPERMS; 1107 node->tn_mode |= mode & ALLPERMS; 1108 1109 node->tn_status |= TMPFS_NODE_CHANGED; 1110 1111 MPASS(VOP_ISLOCKED(vp)); 1112 1113 return 0; 1114 } 1115 1116 /* --------------------------------------------------------------------- */ 1117 1118 /* 1119 * Change ownership of the given vnode. At least one of uid or gid must 1120 * be different than VNOVAL. If one is set to that value, the attribute 1121 * is unchanged. 1122 * Caller should execute tmpfs_update on vp after a successful execution. 1123 * The vnode must be locked on entry and remain locked on exit. 1124 */ 1125 int 1126 tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, 1127 struct thread *p) 1128 { 1129 int error; 1130 struct tmpfs_node *node; 1131 uid_t ouid; 1132 gid_t ogid; 1133 1134 MPASS(VOP_ISLOCKED(vp)); 1135 1136 node = VP_TO_TMPFS_NODE(vp); 1137 1138 /* Assign default values if they are unknown. */ 1139 MPASS(uid != VNOVAL || gid != VNOVAL); 1140 if (uid == VNOVAL) 1141 uid = node->tn_uid; 1142 if (gid == VNOVAL) 1143 gid = node->tn_gid; 1144 MPASS(uid != VNOVAL && gid != VNOVAL); 1145 1146 /* Disallow this operation if the file system is mounted read-only. */ 1147 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1148 return EROFS; 1149 1150 /* Immutable or append-only files cannot be modified, either. */ 1151 if (node->tn_flags & (IMMUTABLE | APPEND)) 1152 return EPERM; 1153 1154 /* 1155 * To modify the ownership of a file, must possess VADMIN for that 1156 * file. 1157 */ 1158 if ((error = VOP_ACCESS(vp, VADMIN, cred, p))) 1159 return (error); 1160 1161 /* 1162 * To change the owner of a file, or change the group of a file to a 1163 * group of which we are not a member, the caller must have 1164 * privilege. 1165 */ 1166 if ((uid != node->tn_uid || 1167 (gid != node->tn_gid && !groupmember(gid, cred))) && 1168 (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0))) 1169 return (error); 1170 1171 ogid = node->tn_gid; 1172 ouid = node->tn_uid; 1173 1174 node->tn_uid = uid; 1175 node->tn_gid = gid; 1176 1177 node->tn_status |= TMPFS_NODE_CHANGED; 1178 1179 if ((node->tn_mode & (S_ISUID | S_ISGID)) && (ouid != uid || ogid != gid)) { 1180 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) 1181 node->tn_mode &= ~(S_ISUID | S_ISGID); 1182 } 1183 1184 MPASS(VOP_ISLOCKED(vp)); 1185 1186 return 0; 1187 } 1188 1189 /* --------------------------------------------------------------------- */ 1190 1191 /* 1192 * Change size of the given vnode. 1193 * Caller should execute tmpfs_update on vp after a successful execution. 1194 * The vnode must be locked on entry and remain locked on exit. 1195 */ 1196 int 1197 tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred, 1198 struct thread *p) 1199 { 1200 int error; 1201 struct tmpfs_node *node; 1202 1203 MPASS(VOP_ISLOCKED(vp)); 1204 1205 node = VP_TO_TMPFS_NODE(vp); 1206 1207 /* Decide whether this is a valid operation based on the file type. */ 1208 error = 0; 1209 switch (vp->v_type) { 1210 case VDIR: 1211 return EISDIR; 1212 1213 case VREG: 1214 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1215 return EROFS; 1216 break; 1217 1218 case VBLK: 1219 /* FALLTHROUGH */ 1220 case VCHR: 1221 /* FALLTHROUGH */ 1222 case VFIFO: 1223 /* Allow modifications of special files even if in the file 1224 * system is mounted read-only (we are not modifying the 1225 * files themselves, but the objects they represent). */ 1226 return 0; 1227 1228 default: 1229 /* Anything else is unsupported. */ 1230 return EOPNOTSUPP; 1231 } 1232 1233 /* Immutable or append-only files cannot be modified, either. */ 1234 if (node->tn_flags & (IMMUTABLE | APPEND)) 1235 return EPERM; 1236 1237 error = tmpfs_truncate(vp, size); 1238 /* tmpfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents 1239 * for us, as will update tn_status; no need to do that here. */ 1240 1241 MPASS(VOP_ISLOCKED(vp)); 1242 1243 return error; 1244 } 1245 1246 /* --------------------------------------------------------------------- */ 1247 1248 /* 1249 * Change access and modification times of the given vnode. 1250 * Caller should execute tmpfs_update on vp after a successful execution. 1251 * The vnode must be locked on entry and remain locked on exit. 1252 */ 1253 int 1254 tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime, 1255 struct timespec *birthtime, int vaflags, struct ucred *cred, struct thread *l) 1256 { 1257 int error; 1258 struct tmpfs_node *node; 1259 1260 MPASS(VOP_ISLOCKED(vp)); 1261 1262 node = VP_TO_TMPFS_NODE(vp); 1263 1264 /* Disallow this operation if the file system is mounted read-only. */ 1265 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1266 return EROFS; 1267 1268 /* Immutable or append-only files cannot be modified, either. */ 1269 if (node->tn_flags & (IMMUTABLE | APPEND)) 1270 return EPERM; 1271 1272 /* Determine if the user have proper privilege to update time. */ 1273 if (vaflags & VA_UTIMES_NULL) { 1274 error = VOP_ACCESS(vp, VADMIN, cred, l); 1275 if (error) 1276 error = VOP_ACCESS(vp, VWRITE, cred, l); 1277 } else 1278 error = VOP_ACCESS(vp, VADMIN, cred, l); 1279 if (error) 1280 return (error); 1281 1282 if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL) 1283 node->tn_status |= TMPFS_NODE_ACCESSED; 1284 1285 if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL) 1286 node->tn_status |= TMPFS_NODE_MODIFIED; 1287 1288 if (birthtime->tv_nsec != VNOVAL && birthtime->tv_nsec != VNOVAL) 1289 node->tn_status |= TMPFS_NODE_MODIFIED; 1290 1291 tmpfs_itimes(vp, atime, mtime); 1292 1293 if (birthtime->tv_nsec != VNOVAL && birthtime->tv_nsec != VNOVAL) 1294 node->tn_birthtime = *birthtime; 1295 MPASS(VOP_ISLOCKED(vp)); 1296 1297 return 0; 1298 } 1299 1300 /* --------------------------------------------------------------------- */ 1301 /* Sync timestamps */ 1302 void 1303 tmpfs_itimes(struct vnode *vp, const struct timespec *acc, 1304 const struct timespec *mod) 1305 { 1306 struct tmpfs_node *node; 1307 struct timespec now; 1308 1309 node = VP_TO_TMPFS_NODE(vp); 1310 1311 if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 1312 TMPFS_NODE_CHANGED)) == 0) 1313 return; 1314 1315 vfs_timestamp(&now); 1316 if (node->tn_status & TMPFS_NODE_ACCESSED) { 1317 if (acc == NULL) 1318 acc = &now; 1319 node->tn_atime = *acc; 1320 } 1321 if (node->tn_status & TMPFS_NODE_MODIFIED) { 1322 if (mod == NULL) 1323 mod = &now; 1324 node->tn_mtime = *mod; 1325 } 1326 if (node->tn_status & TMPFS_NODE_CHANGED) { 1327 node->tn_ctime = now; 1328 } 1329 node->tn_status &= 1330 ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED); 1331 } 1332 1333 /* --------------------------------------------------------------------- */ 1334 1335 void 1336 tmpfs_update(struct vnode *vp) 1337 { 1338 1339 tmpfs_itimes(vp, NULL, NULL); 1340 } 1341 1342 /* --------------------------------------------------------------------- */ 1343 1344 int 1345 tmpfs_truncate(struct vnode *vp, off_t length) 1346 { 1347 int error; 1348 struct tmpfs_node *node; 1349 1350 node = VP_TO_TMPFS_NODE(vp); 1351 1352 if (length < 0) { 1353 error = EINVAL; 1354 goto out; 1355 } 1356 1357 if (node->tn_size == length) { 1358 error = 0; 1359 goto out; 1360 } 1361 1362 if (length > VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) 1363 return (EFBIG); 1364 1365 error = tmpfs_reg_resize(vp, length, FALSE); 1366 if (error == 0) { 1367 node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1368 } 1369 1370 out: 1371 tmpfs_update(vp); 1372 1373 return error; 1374 } 1375