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 37 #include <sys/kernel.h> 38 #include <sys/param.h> 39 #include <sys/namei.h> 40 #include <sys/priv.h> 41 #include <sys/proc.h> 42 #include <sys/stat.h> 43 #include <sys/systm.h> 44 #include <sys/vnode.h> 45 #include <sys/vmmeter.h> 46 47 #include <vm/vm.h> 48 #include <vm/vm_object.h> 49 #include <vm/vm_page.h> 50 #include <vm/vm_pager.h> 51 #include <vm/vm_extern.h> 52 53 #include <vfs/tmpfs/tmpfs.h> 54 #include <vfs/tmpfs/tmpfs_vnops.h> 55 56 static ino_t tmpfs_fetch_ino(struct tmpfs_mount *); 57 58 static int tmpfs_dirtree_compare(struct tmpfs_dirent *a, 59 struct tmpfs_dirent *b); 60 RB_GENERATE(tmpfs_dirtree, tmpfs_dirent, rb_node, tmpfs_dirtree_compare); 61 62 static int tmpfs_dirtree_compare_cookie(struct tmpfs_dirent *a, 63 struct tmpfs_dirent *b); 64 RB_GENERATE(tmpfs_dirtree_cookie, tmpfs_dirent, 65 rb_cookienode, tmpfs_dirtree_compare_cookie); 66 67 68 /* --------------------------------------------------------------------- */ 69 70 /* 71 * Allocates a new node of type 'type' inside the 'tmp' mount point, with 72 * its owner set to 'uid', its group to 'gid' and its mode set to 'mode', 73 * using the credentials of the process 'p'. 74 * 75 * If the node type is set to 'VDIR', then the parent parameter must point 76 * to the parent directory of the node being created. It may only be NULL 77 * while allocating the root node. 78 * 79 * If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter 80 * specifies the device the node represents. 81 * 82 * If the node type is set to 'VLNK', then the parameter target specifies 83 * the file name of the target file for the symbolic link that is being 84 * created. 85 * 86 * Note that new nodes are retrieved from the available list if it has 87 * items or, if it is empty, from the node pool as long as there is enough 88 * space to create them. 89 * 90 * Returns zero on success or an appropriate error code on failure. 91 */ 92 int 93 tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, 94 uid_t uid, gid_t gid, mode_t mode, 95 char *target, int rmajor, int rminor, 96 struct tmpfs_node **node) 97 { 98 struct tmpfs_node *nnode; 99 struct timespec ts; 100 udev_t rdev; 101 102 KKASSERT(IFF(type == VLNK, target != NULL)); 103 KKASSERT(IFF(type == VBLK || type == VCHR, rmajor != VNOVAL)); 104 105 if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max) 106 return (ENOSPC); 107 108 nnode = objcache_get(tmp->tm_node_pool, M_WAITOK | M_NULLOK); 109 if (nnode == NULL) 110 return (ENOSPC); 111 112 /* Generic initialization. */ 113 nnode->tn_type = type; 114 vfs_timestamp(&ts); 115 nnode->tn_ctime = nnode->tn_mtime = nnode->tn_atime 116 = ts.tv_sec; 117 nnode->tn_ctimensec = nnode->tn_mtimensec = nnode->tn_atimensec 118 = ts.tv_nsec; 119 nnode->tn_uid = uid; 120 nnode->tn_gid = gid; 121 nnode->tn_mode = mode; 122 nnode->tn_id = tmpfs_fetch_ino(tmp); 123 nnode->tn_advlock.init_done = 0; 124 KKASSERT(nnode->tn_links == 0); 125 126 /* Type-specific initialization. */ 127 switch (nnode->tn_type) { 128 case VBLK: 129 case VCHR: 130 rdev = makeudev(rmajor, rminor); 131 if (rdev == NOUDEV) { 132 objcache_put(tmp->tm_node_pool, nnode); 133 return(EINVAL); 134 } 135 nnode->tn_rdev = rdev; 136 break; 137 138 case VDIR: 139 RB_INIT(&nnode->tn_dir.tn_dirtree); 140 RB_INIT(&nnode->tn_dir.tn_cookietree); 141 nnode->tn_size = 0; 142 break; 143 144 case VFIFO: 145 /* FALLTHROUGH */ 146 case VSOCK: 147 break; 148 149 case VLNK: 150 nnode->tn_size = strlen(target); 151 nnode->tn_link = kmalloc(nnode->tn_size + 1, tmp->tm_name_zone, 152 M_WAITOK | M_NULLOK); 153 if (nnode->tn_link == NULL) { 154 objcache_put(tmp->tm_node_pool, nnode); 155 return (ENOSPC); 156 } 157 bcopy(target, nnode->tn_link, nnode->tn_size); 158 nnode->tn_link[nnode->tn_size] = '\0'; 159 break; 160 161 case VREG: 162 nnode->tn_reg.tn_aobj = 163 swap_pager_alloc(NULL, 0, VM_PROT_DEFAULT, 0); 164 nnode->tn_reg.tn_aobj_pages = 0; 165 nnode->tn_size = 0; 166 break; 167 168 default: 169 panic("tmpfs_alloc_node: type %p %d", nnode, (int)nnode->tn_type); 170 } 171 172 TMPFS_NODE_LOCK(nnode); 173 TMPFS_LOCK(tmp); 174 LIST_INSERT_HEAD(&tmp->tm_nodes_used, nnode, tn_entries); 175 tmp->tm_nodes_inuse++; 176 TMPFS_UNLOCK(tmp); 177 TMPFS_NODE_UNLOCK(nnode); 178 179 *node = nnode; 180 return 0; 181 } 182 183 /* --------------------------------------------------------------------- */ 184 185 /* 186 * Destroys the node pointed to by node from the file system 'tmp'. 187 * If the node does not belong to the given mount point, the results are 188 * unpredicted. 189 * 190 * If the node references a directory; no entries are allowed because 191 * their removal could need a recursive algorithm, something forbidden in 192 * kernel space. Furthermore, there is not need to provide such 193 * functionality (recursive removal) because the only primitives offered 194 * to the user are the removal of empty directories and the deletion of 195 * individual files. 196 * 197 * Note that nodes are not really deleted; in fact, when a node has been 198 * allocated, it cannot be deleted during the whole life of the file 199 * system. Instead, they are moved to the available list and remain there 200 * until reused. 201 * 202 * A caller must have TMPFS_NODE_LOCK(node) and this function unlocks it. 203 */ 204 void 205 tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) 206 { 207 vm_pindex_t pages = 0; 208 209 #ifdef INVARIANTS 210 TMPFS_ASSERT_ELOCKED(node); 211 KKASSERT(node->tn_vnode == NULL); 212 KKASSERT((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0); 213 #endif 214 215 TMPFS_LOCK(tmp); 216 LIST_REMOVE(node, tn_entries); 217 tmp->tm_nodes_inuse--; 218 TMPFS_UNLOCK(tmp); 219 TMPFS_NODE_UNLOCK(node); /* Caller has this lock */ 220 221 switch (node->tn_type) { 222 case VNON: 223 /* Do not do anything. VNON is provided to let the 224 * allocation routine clean itself easily by avoiding 225 * duplicating code in it. */ 226 /* FALLTHROUGH */ 227 case VBLK: 228 /* FALLTHROUGH */ 229 case VCHR: 230 /* FALLTHROUGH */ 231 break; 232 case VDIR: 233 /* 234 * The parent link can be NULL if this is the root 235 * node or if it is a directory node that was rmdir'd. 236 * 237 * XXX what if node is a directory which still contains 238 * directory entries (e.g. due to a forced umount) ? 239 */ 240 node->tn_size = 0; 241 KKASSERT(node->tn_dir.tn_parent == NULL); 242 243 /* 244 * If the root node is being destroyed don't leave a 245 * dangling pointer in tmpfs_mount. 246 */ 247 if (node == tmp->tm_root) 248 tmp->tm_root = NULL; 249 break; 250 case VFIFO: 251 /* FALLTHROUGH */ 252 case VSOCK: 253 break; 254 255 case VLNK: 256 kfree(node->tn_link, tmp->tm_name_zone); 257 node->tn_link = NULL; 258 node->tn_size = 0; 259 break; 260 261 case VREG: 262 if (node->tn_reg.tn_aobj != NULL) 263 vm_object_deallocate(node->tn_reg.tn_aobj); 264 node->tn_reg.tn_aobj = NULL; 265 pages = node->tn_reg.tn_aobj_pages; 266 break; 267 268 default: 269 panic("tmpfs_free_node: type %p %d", node, (int)node->tn_type); 270 } 271 272 /* 273 * Clean up fields for the next allocation. The objcache only ctors 274 * new allocations. 275 */ 276 tmpfs_node_ctor(node, NULL, 0); 277 objcache_put(tmp->tm_node_pool, node); 278 /* node is now invalid */ 279 280 if (pages) 281 atomic_add_long(&tmp->tm_pages_used, -(long)pages); 282 } 283 284 /* --------------------------------------------------------------------- */ 285 286 /* 287 * Allocates a new directory entry for the node node with a name of name. 288 * The new directory entry is returned in *de. 289 * 290 * The link count of node is increased by one to reflect the new object 291 * referencing it. 292 * 293 * Returns zero on success or an appropriate error code on failure. 294 */ 295 int 296 tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, 297 const char *name, uint16_t len, struct tmpfs_dirent **de) 298 { 299 struct tmpfs_dirent *nde; 300 301 nde = objcache_get(tmp->tm_dirent_pool, M_WAITOK); 302 nde->td_name = kmalloc(len + 1, tmp->tm_name_zone, M_WAITOK | M_NULLOK); 303 if (nde->td_name == NULL) { 304 objcache_put(tmp->tm_dirent_pool, nde); 305 *de = NULL; 306 return (ENOSPC); 307 } 308 nde->td_namelen = len; 309 bcopy(name, nde->td_name, len); 310 nde->td_name[len] = '\0'; 311 312 nde->td_node = node; 313 314 TMPFS_NODE_LOCK(node); 315 ++node->tn_links; 316 TMPFS_NODE_UNLOCK(node); 317 318 *de = nde; 319 320 return 0; 321 } 322 323 /* --------------------------------------------------------------------- */ 324 325 /* 326 * Frees a directory entry. It is the caller's responsibility to destroy 327 * the node referenced by it if needed. 328 * 329 * The link count of node is decreased by one to reflect the removal of an 330 * object that referenced it. This only happens if 'node_exists' is true; 331 * otherwise the function will not access the node referred to by the 332 * directory entry, as it may already have been released from the outside. 333 */ 334 void 335 tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de) 336 { 337 struct tmpfs_node *node; 338 339 node = de->td_node; 340 341 TMPFS_NODE_LOCK(node); 342 TMPFS_ASSERT_ELOCKED(node); 343 KKASSERT(node->tn_links > 0); 344 node->tn_links--; 345 TMPFS_NODE_UNLOCK(node); 346 347 kfree(de->td_name, tmp->tm_name_zone); 348 de->td_namelen = 0; 349 de->td_name = NULL; 350 de->td_node = NULL; 351 objcache_put(tmp->tm_dirent_pool, de); 352 } 353 354 /* --------------------------------------------------------------------- */ 355 356 /* 357 * Allocates a new vnode for the node node or returns a new reference to 358 * an existing one if the node had already a vnode referencing it. The 359 * resulting locked vnode is returned in *vpp. 360 * 361 * Returns zero on success or an appropriate error code on failure. 362 */ 363 int 364 tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag, 365 struct vnode **vpp) 366 { 367 int error = 0; 368 struct vnode *vp; 369 370 loop: 371 /* 372 * Interlocked extraction from node. This can race many things. 373 * We have to get a soft reference on the vnode while we hold 374 * the node locked, then acquire it properly and check for races. 375 */ 376 TMPFS_NODE_LOCK(node); 377 if ((vp = node->tn_vnode) != NULL) { 378 KKASSERT((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0); 379 vhold(vp); 380 TMPFS_NODE_UNLOCK(node); 381 382 if (vget(vp, lkflag | LK_EXCLUSIVE) != 0) { 383 vdrop(vp); 384 goto loop; 385 } 386 if (node->tn_vnode != vp) { 387 vput(vp); 388 vdrop(vp); 389 goto loop; 390 } 391 vdrop(vp); 392 goto out; 393 } 394 /* vp is NULL */ 395 396 /* 397 * This should never happen. 398 */ 399 if (node->tn_vpstate & TMPFS_VNODE_DOOMED) { 400 TMPFS_NODE_UNLOCK(node); 401 error = ENOENT; 402 goto out; 403 } 404 405 /* 406 * Interlock against other calls to tmpfs_alloc_vp() trying to 407 * allocate and assign a vp to node. 408 */ 409 if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) { 410 node->tn_vpstate |= TMPFS_VNODE_WANT; 411 error = tsleep(&node->tn_vpstate, PINTERLOCKED | PCATCH, 412 "tmpfs_alloc_vp", 0); 413 TMPFS_NODE_UNLOCK(node); 414 if (error) 415 return error; 416 goto loop; 417 } 418 node->tn_vpstate |= TMPFS_VNODE_ALLOCATING; 419 TMPFS_NODE_UNLOCK(node); 420 421 /* 422 * Allocate a new vnode (may block). The ALLOCATING flag should 423 * prevent a race against someone else assigning node->tn_vnode. 424 */ 425 error = getnewvnode(VT_TMPFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 426 if (error != 0) 427 goto unlock; 428 429 KKASSERT(node->tn_vnode == NULL); 430 KKASSERT(vp != NULL); 431 vp->v_data = node; 432 vp->v_type = node->tn_type; 433 434 /* Type-specific initialization. */ 435 switch (node->tn_type) { 436 case VBLK: 437 /* FALLTHROUGH */ 438 case VCHR: 439 /* FALLTHROUGH */ 440 case VSOCK: 441 break; 442 case VREG: 443 vinitvmio(vp, node->tn_size, TMPFS_BLKMASK, -1); 444 break; 445 case VLNK: 446 break; 447 case VFIFO: 448 vp->v_ops = &mp->mnt_vn_fifo_ops; 449 break; 450 case VDIR: 451 break; 452 453 default: 454 panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type); 455 } 456 457 458 unlock: 459 TMPFS_NODE_LOCK(node); 460 461 KKASSERT(node->tn_vpstate & TMPFS_VNODE_ALLOCATING); 462 node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING; 463 node->tn_vnode = vp; 464 465 if (node->tn_vpstate & TMPFS_VNODE_WANT) { 466 node->tn_vpstate &= ~TMPFS_VNODE_WANT; 467 TMPFS_NODE_UNLOCK(node); 468 wakeup(&node->tn_vpstate); 469 } else { 470 TMPFS_NODE_UNLOCK(node); 471 } 472 473 out: 474 *vpp = vp; 475 476 KKASSERT(IFF(error == 0, *vpp != NULL && vn_islocked(*vpp))); 477 #ifdef INVARIANTS 478 TMPFS_NODE_LOCK(node); 479 KKASSERT(*vpp == node->tn_vnode); 480 TMPFS_NODE_UNLOCK(node); 481 #endif 482 483 return error; 484 } 485 486 /* --------------------------------------------------------------------- */ 487 488 /* 489 * Destroys the association between the vnode vp and the node it 490 * references. 491 */ 492 void 493 tmpfs_free_vp(struct vnode *vp) 494 { 495 struct tmpfs_node *node; 496 497 node = VP_TO_TMPFS_NODE(vp); 498 499 TMPFS_NODE_LOCK(node); 500 KKASSERT(lockcount(TMPFS_NODE_MTX(node)) > 0); 501 node->tn_vnode = NULL; 502 vp->v_data = NULL; 503 TMPFS_NODE_UNLOCK(node); 504 } 505 506 /* --------------------------------------------------------------------- */ 507 508 /* 509 * Allocates a new file of type 'type' and adds it to the parent directory 510 * 'dvp'; this addition is done using the component name given in 'cnp'. 511 * The ownership of the new file is automatically assigned based on the 512 * credentials of the caller (through 'cnp'), the group is set based on 513 * the parent directory and the mode is determined from the 'vap' argument. 514 * If successful, *vpp holds a vnode to the newly created file and zero 515 * is returned. Otherwise *vpp is NULL and the function returns an 516 * appropriate error code. 517 */ 518 int 519 tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, 520 struct namecache *ncp, struct ucred *cred, char *target) 521 { 522 int error; 523 struct tmpfs_dirent *de; 524 struct tmpfs_mount *tmp; 525 struct tmpfs_node *dnode; 526 struct tmpfs_node *node; 527 528 tmp = VFS_TO_TMPFS(dvp->v_mount); 529 dnode = VP_TO_TMPFS_DIR(dvp); 530 *vpp = NULL; 531 532 /* 533 * If the directory was removed but a process was CD'd into it, 534 * we do not allow any more file/dir creation within it. Otherwise 535 * we will lose track of it. 536 */ 537 KKASSERT(dnode->tn_type == VDIR); 538 if (dnode != tmp->tm_root && dnode->tn_dir.tn_parent == NULL) 539 return ENOENT; 540 541 /* 542 * Make sure the link count does not overflow. 543 */ 544 if (vap->va_type == VDIR && dnode->tn_links >= LINK_MAX) 545 return EMLINK; 546 547 /* Allocate a node that represents the new file. */ 548 error = tmpfs_alloc_node(tmp, vap->va_type, cred->cr_uid, 549 dnode->tn_gid, vap->va_mode, target, 550 vap->va_rmajor, vap->va_rminor, &node); 551 if (error != 0) 552 return error; 553 TMPFS_NODE_LOCK(node); 554 555 /* Allocate a directory entry that points to the new file. */ 556 error = tmpfs_alloc_dirent(tmp, node, ncp->nc_name, ncp->nc_nlen, &de); 557 if (error != 0) { 558 tmpfs_free_node(tmp, node); 559 /* eats node lock */ 560 return error; 561 } 562 563 /* Allocate a vnode for the new file. */ 564 error = tmpfs_alloc_vp(dvp->v_mount, node, LK_EXCLUSIVE, vpp); 565 if (error != 0) { 566 tmpfs_free_dirent(tmp, de); 567 tmpfs_free_node(tmp, node); 568 /* eats node lock */ 569 return error; 570 } 571 572 /* 573 * Now that all required items are allocated, we can proceed to 574 * insert the new node into the directory, an operation that 575 * cannot fail. 576 */ 577 tmpfs_dir_attach(dnode, de); 578 TMPFS_NODE_UNLOCK(node); 579 580 return error; 581 } 582 583 /* --------------------------------------------------------------------- */ 584 585 /* 586 * Attaches the directory entry de to the directory represented by dnode. 587 * Note that this does not change the link count of the node pointed by 588 * the directory entry, as this is done by tmpfs_alloc_dirent. 589 */ 590 void 591 tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de) 592 { 593 struct tmpfs_node *node = de->td_node; 594 595 TMPFS_NODE_LOCK(dnode); 596 if (node && node->tn_type == VDIR) { 597 TMPFS_NODE_LOCK(node); 598 ++node->tn_links; 599 node->tn_status |= TMPFS_NODE_CHANGED; 600 node->tn_dir.tn_parent = dnode; 601 ++dnode->tn_links; 602 TMPFS_NODE_UNLOCK(node); 603 } 604 RB_INSERT(tmpfs_dirtree, &dnode->tn_dir.tn_dirtree, de); 605 RB_INSERT(tmpfs_dirtree_cookie, &dnode->tn_dir.tn_cookietree, de); 606 dnode->tn_size += sizeof(struct tmpfs_dirent); 607 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | 608 TMPFS_NODE_MODIFIED; 609 TMPFS_NODE_UNLOCK(dnode); 610 } 611 612 /* --------------------------------------------------------------------- */ 613 614 /* 615 * Detaches the directory entry de from the directory represented by dnode. 616 * Note that this does not change the link count of the node pointed by 617 * the directory entry, as this is done by tmpfs_free_dirent. 618 */ 619 void 620 tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de) 621 { 622 struct tmpfs_node *node = de->td_node; 623 624 TMPFS_NODE_LOCK(dnode); 625 RB_REMOVE(tmpfs_dirtree, &dnode->tn_dir.tn_dirtree, de); 626 RB_REMOVE(tmpfs_dirtree_cookie, &dnode->tn_dir.tn_cookietree, de); 627 dnode->tn_size -= sizeof(struct tmpfs_dirent); 628 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | 629 TMPFS_NODE_MODIFIED; 630 TMPFS_NODE_UNLOCK(dnode); 631 632 /* 633 * Clean out the tn_parent pointer immediately when removing a 634 * directory. 635 * 636 * Removal of the parent linkage also cleans out the extra tn_links 637 * count we had on both node and dnode. 638 * 639 * node can be NULL (typ during a forced umount), in which case 640 * the mount code is dealing with the linkages from a linked list 641 * scan. 642 */ 643 if (node && node->tn_type == VDIR && node->tn_dir.tn_parent) { 644 TMPFS_NODE_LOCK(dnode); 645 TMPFS_NODE_LOCK(node); 646 KKASSERT(node->tn_dir.tn_parent == dnode); 647 dnode->tn_links--; 648 node->tn_links--; 649 node->tn_dir.tn_parent = NULL; 650 TMPFS_NODE_UNLOCK(node); 651 TMPFS_NODE_UNLOCK(dnode); 652 } 653 } 654 655 /* --------------------------------------------------------------------- */ 656 657 /* 658 * Looks for a directory entry in the directory represented by node. 659 * 'ncp' describes the name of the entry to look for. Note that the . 660 * and .. components are not allowed as they do not physically exist 661 * within directories. 662 * 663 * Returns a pointer to the entry when found, otherwise NULL. 664 * 665 * Caller must hold the node locked (shared ok) 666 */ 667 struct tmpfs_dirent * 668 tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, 669 struct namecache *ncp) 670 { 671 struct tmpfs_dirent *de; 672 int len = ncp->nc_nlen; 673 struct tmpfs_dirent wanted; 674 675 wanted.td_namelen = len; 676 wanted.td_name = ncp->nc_name; 677 678 TMPFS_VALIDATE_DIR(node); 679 680 de = RB_FIND(tmpfs_dirtree, &node->tn_dir.tn_dirtree, &wanted); 681 682 KKASSERT(f == NULL || f == de->td_node); 683 684 return de; 685 } 686 687 /* --------------------------------------------------------------------- */ 688 689 /* 690 * Helper function for tmpfs_readdir. Creates a '.' entry for the given 691 * directory and returns it in the uio space. The function returns 0 692 * on success, -1 if there was not enough space in the uio structure to 693 * hold the directory entry or an appropriate error code if another 694 * error happens. 695 */ 696 int 697 tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio) 698 { 699 int error; 700 701 TMPFS_VALIDATE_DIR(node); 702 KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOT); 703 704 if (vop_write_dirent(&error, uio, node->tn_id, DT_DIR, 1, ".")) 705 return -1; 706 if (error == 0) 707 uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT; 708 return error; 709 } 710 711 /* --------------------------------------------------------------------- */ 712 713 /* 714 * Helper function for tmpfs_readdir. Creates a '..' entry for the given 715 * directory and returns it in the uio space. The function returns 0 716 * on success, -1 if there was not enough space in the uio structure to 717 * hold the directory entry or an appropriate error code if another 718 * error happens. 719 */ 720 int 721 tmpfs_dir_getdotdotdent(struct tmpfs_mount *tmp, struct tmpfs_node *node, 722 struct uio *uio) 723 { 724 int error; 725 ino_t d_ino; 726 727 TMPFS_VALIDATE_DIR(node); 728 KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT); 729 730 if (node->tn_dir.tn_parent) { 731 TMPFS_NODE_LOCK(node); 732 if (node->tn_dir.tn_parent) 733 d_ino = node->tn_dir.tn_parent->tn_id; 734 else 735 d_ino = tmp->tm_root->tn_id; 736 TMPFS_NODE_UNLOCK(node); 737 } else { 738 d_ino = tmp->tm_root->tn_id; 739 } 740 741 if (vop_write_dirent(&error, uio, d_ino, DT_DIR, 2, "..")) 742 return -1; 743 if (error == 0) { 744 struct tmpfs_dirent *de; 745 de = RB_MIN(tmpfs_dirtree_cookie, &node->tn_dir.tn_cookietree); 746 if (de == NULL) 747 uio->uio_offset = TMPFS_DIRCOOKIE_EOF; 748 else 749 uio->uio_offset = tmpfs_dircookie(de); 750 } 751 return error; 752 } 753 754 /* --------------------------------------------------------------------- */ 755 756 /* 757 * Lookup a directory entry by its associated cookie. 758 * 759 * Must be called with the directory node locked (shared ok) 760 */ 761 struct lubycookie_info { 762 off_t cookie; 763 struct tmpfs_dirent *de; 764 }; 765 766 static int 767 lubycookie_cmp(struct tmpfs_dirent *de, void *arg) 768 { 769 struct lubycookie_info *info = arg; 770 off_t cookie = tmpfs_dircookie(de); 771 772 if (cookie < info->cookie) 773 return(-1); 774 if (cookie > info->cookie) 775 return(1); 776 return(0); 777 } 778 779 static int 780 lubycookie_callback(struct tmpfs_dirent *de, void *arg) 781 { 782 struct lubycookie_info *info = arg; 783 784 if (tmpfs_dircookie(de) == info->cookie) { 785 info->de = de; 786 return(-1); 787 } 788 return(0); 789 } 790 791 struct tmpfs_dirent * 792 tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie) 793 { 794 struct lubycookie_info info; 795 796 info.cookie = cookie; 797 info.de = NULL; 798 RB_SCAN(tmpfs_dirtree_cookie, &node->tn_dir.tn_cookietree, 799 lubycookie_cmp, lubycookie_callback, &info); 800 return (info.de); 801 } 802 803 /* --------------------------------------------------------------------- */ 804 805 /* 806 * Helper function for tmpfs_readdir. Returns as much directory entries 807 * as can fit in the uio space. The read starts at uio->uio_offset. 808 * The function returns 0 on success, -1 if there was not enough space 809 * in the uio structure to hold the directory entry or an appropriate 810 * error code if another error happens. 811 * 812 * Caller must hold the node locked (shared ok) 813 */ 814 int 815 tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) 816 { 817 int error; 818 off_t startcookie; 819 struct tmpfs_dirent *de; 820 821 TMPFS_VALIDATE_DIR(node); 822 823 /* 824 * Locate the first directory entry we have to return. We have cached 825 * the last readdir in the node, so use those values if appropriate. 826 * Otherwise do a linear scan to find the requested entry. 827 */ 828 startcookie = uio->uio_offset; 829 KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOT); 830 KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOTDOT); 831 832 if (startcookie == TMPFS_DIRCOOKIE_EOF) 833 return 0; 834 835 de = tmpfs_dir_lookupbycookie(node, startcookie); 836 if (de == NULL) 837 return EINVAL; 838 839 /* 840 * Read as much entries as possible; i.e., until we reach the end of 841 * the directory or we exhaust uio space. 842 */ 843 do { 844 ino_t d_ino; 845 uint8_t d_type; 846 847 /* Create a dirent structure representing the current 848 * tmpfs_node and fill it. */ 849 d_ino = de->td_node->tn_id; 850 switch (de->td_node->tn_type) { 851 case VBLK: 852 d_type = DT_BLK; 853 break; 854 855 case VCHR: 856 d_type = DT_CHR; 857 break; 858 859 case VDIR: 860 d_type = DT_DIR; 861 break; 862 863 case VFIFO: 864 d_type = DT_FIFO; 865 break; 866 867 case VLNK: 868 d_type = DT_LNK; 869 break; 870 871 case VREG: 872 d_type = DT_REG; 873 break; 874 875 case VSOCK: 876 d_type = DT_SOCK; 877 break; 878 879 default: 880 panic("tmpfs_dir_getdents: type %p %d", 881 de->td_node, (int)de->td_node->tn_type); 882 } 883 KKASSERT(de->td_namelen < 256); /* 255 + 1 */ 884 885 if (vop_write_dirent(&error, uio, d_ino, d_type, 886 de->td_namelen, de->td_name)) { 887 error = -1; 888 break; 889 } 890 891 (*cntp)++; 892 de = RB_NEXT(tmpfs_dirtree_cookie, 893 node->tn_dir.tn_cookietree, de); 894 } while (error == 0 && uio->uio_resid > 0 && de != NULL); 895 896 /* Update the offset and cache. */ 897 if (de == NULL) { 898 uio->uio_offset = TMPFS_DIRCOOKIE_EOF; 899 } else { 900 uio->uio_offset = tmpfs_dircookie(de); 901 } 902 903 return error; 904 } 905 906 /* --------------------------------------------------------------------- */ 907 908 /* 909 * Resizes the aobj associated to the regular file pointed to by vp to 910 * the size newsize. 'vp' must point to a vnode that represents a regular 911 * file. 'newsize' must be positive. 912 * 913 * pass trivial as 1 when buf content will be overwritten, otherwise set 0 914 * to be zero filled. 915 * 916 * Returns zero on success or an appropriate error code on failure. 917 * 918 * Caller must hold the node exclusively locked. 919 */ 920 int 921 tmpfs_reg_resize(struct vnode *vp, off_t newsize, int trivial) 922 { 923 int error; 924 vm_pindex_t newpages, oldpages; 925 struct tmpfs_mount *tmp; 926 struct tmpfs_node *node; 927 off_t oldsize; 928 929 #ifdef INVARIANTS 930 KKASSERT(vp->v_type == VREG); 931 KKASSERT(newsize >= 0); 932 #endif 933 934 node = VP_TO_TMPFS_NODE(vp); 935 tmp = VFS_TO_TMPFS(vp->v_mount); 936 937 /* 938 * Convert the old and new sizes to the number of pages needed to 939 * store them. It may happen that we do not need to do anything 940 * because the last allocated page can accommodate the change on 941 * its own. 942 */ 943 oldsize = node->tn_size; 944 oldpages = round_page64(oldsize) / PAGE_SIZE; 945 KKASSERT(oldpages == node->tn_reg.tn_aobj_pages); 946 newpages = round_page64(newsize) / PAGE_SIZE; 947 948 if (newpages > oldpages && 949 tmp->tm_pages_used + newpages - oldpages > tmp->tm_pages_max) { 950 error = ENOSPC; 951 goto out; 952 } 953 node->tn_reg.tn_aobj_pages = newpages; 954 node->tn_size = newsize; 955 956 if (newpages != oldpages) 957 atomic_add_long(&tmp->tm_pages_used, (newpages - oldpages)); 958 959 /* 960 * When adjusting the vnode filesize and its VM object we must 961 * also adjust our backing VM object (aobj). The blocksize 962 * used must match the block sized we use for the buffer cache. 963 * 964 * The backing VM object contains no VM pages, only swap 965 * assignments. 966 */ 967 if (newsize < oldsize) { 968 vm_pindex_t osize; 969 vm_pindex_t nsize; 970 vm_object_t aobj; 971 972 error = nvtruncbuf(vp, newsize, TMPFS_BLKSIZE, -1, 0); 973 aobj = node->tn_reg.tn_aobj; 974 if (aobj) { 975 osize = aobj->size; 976 nsize = vp->v_object->size; 977 if (nsize < osize) { 978 aobj->size = osize; 979 swap_pager_freespace(aobj, nsize, 980 osize - nsize); 981 } 982 } 983 } else { 984 vm_object_t aobj; 985 986 error = nvextendbuf(vp, oldsize, newsize, 987 TMPFS_BLKSIZE, TMPFS_BLKSIZE, 988 -1, -1, trivial); 989 aobj = node->tn_reg.tn_aobj; 990 if (aobj) 991 aobj->size = vp->v_object->size; 992 } 993 994 out: 995 return error; 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 vaflags, struct ucred *cred) 1007 { 1008 int error; 1009 struct tmpfs_node *node; 1010 int flags; 1011 1012 KKASSERT(vn_islocked(vp)); 1013 1014 node = VP_TO_TMPFS_NODE(vp); 1015 flags = node->tn_flags; 1016 1017 /* Disallow this operation if the file system is mounted read-only. */ 1018 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1019 return EROFS; 1020 error = vop_helper_setattr_flags(&flags, vaflags, node->tn_uid, cred); 1021 1022 /* Actually change the flags on the node itself */ 1023 if (error == 0) { 1024 TMPFS_NODE_LOCK(node); 1025 node->tn_flags = flags; 1026 node->tn_status |= TMPFS_NODE_CHANGED; 1027 TMPFS_NODE_UNLOCK(node); 1028 } 1029 1030 KKASSERT(vn_islocked(vp)); 1031 1032 return error; 1033 } 1034 1035 /* --------------------------------------------------------------------- */ 1036 1037 /* 1038 * Change access mode on the given vnode. 1039 * Caller should execute tmpfs_update on vp after a successful execution. 1040 * The vnode must be locked on entry and remain locked on exit. 1041 */ 1042 int 1043 tmpfs_chmod(struct vnode *vp, mode_t vamode, struct ucred *cred) 1044 { 1045 struct tmpfs_node *node; 1046 mode_t cur_mode; 1047 int error; 1048 1049 KKASSERT(vn_islocked(vp)); 1050 1051 node = VP_TO_TMPFS_NODE(vp); 1052 1053 /* Disallow this operation if the file system is mounted read-only. */ 1054 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1055 return EROFS; 1056 1057 /* Immutable or append-only files cannot be modified, either. */ 1058 if (node->tn_flags & (IMMUTABLE | APPEND)) 1059 return EPERM; 1060 1061 cur_mode = node->tn_mode; 1062 error = vop_helper_chmod(vp, vamode, cred, node->tn_uid, node->tn_gid, 1063 &cur_mode); 1064 1065 if (error == 0 && 1066 (node->tn_mode & ALLPERMS) != (cur_mode & ALLPERMS)) { 1067 TMPFS_NODE_LOCK(node); 1068 node->tn_mode &= ~ALLPERMS; 1069 node->tn_mode |= cur_mode & ALLPERMS; 1070 1071 node->tn_status |= TMPFS_NODE_CHANGED; 1072 TMPFS_NODE_UNLOCK(node); 1073 } 1074 1075 KKASSERT(vn_islocked(vp)); 1076 1077 return 0; 1078 } 1079 1080 /* --------------------------------------------------------------------- */ 1081 1082 /* 1083 * Change ownership of the given vnode. At least one of uid or gid must 1084 * be different than VNOVAL. If one is set to that value, the attribute 1085 * is unchanged. 1086 * Caller should execute tmpfs_update on vp after a successful execution. 1087 * The vnode must be locked on entry and remain locked on exit. 1088 */ 1089 int 1090 tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred) 1091 { 1092 mode_t cur_mode; 1093 uid_t cur_uid; 1094 gid_t cur_gid; 1095 struct tmpfs_node *node; 1096 int error; 1097 1098 KKASSERT(vn_islocked(vp)); 1099 node = VP_TO_TMPFS_NODE(vp); 1100 1101 /* Disallow this operation if the file system is mounted read-only. */ 1102 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1103 return EROFS; 1104 1105 /* Immutable or append-only files cannot be modified, either. */ 1106 if (node->tn_flags & (IMMUTABLE | APPEND)) 1107 return EPERM; 1108 1109 cur_uid = node->tn_uid; 1110 cur_gid = node->tn_gid; 1111 cur_mode = node->tn_mode; 1112 error = vop_helper_chown(vp, uid, gid, cred, 1113 &cur_uid, &cur_gid, &cur_mode); 1114 1115 if (error == 0) { 1116 TMPFS_NODE_LOCK(node); 1117 if (cur_uid != node->tn_uid || 1118 cur_gid != node->tn_gid || 1119 cur_mode != node->tn_mode) { 1120 node->tn_uid = cur_uid; 1121 node->tn_gid = cur_gid; 1122 node->tn_mode = cur_mode; 1123 node->tn_status |= TMPFS_NODE_CHANGED; 1124 } 1125 TMPFS_NODE_UNLOCK(node); 1126 } 1127 1128 return error; 1129 } 1130 1131 /* --------------------------------------------------------------------- */ 1132 1133 /* 1134 * Change size of the given vnode. 1135 * Caller should execute tmpfs_update on vp after a successful execution. 1136 * The vnode must be locked on entry and remain locked on exit. 1137 */ 1138 int 1139 tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred) 1140 { 1141 int error; 1142 struct tmpfs_node *node; 1143 1144 KKASSERT(vn_islocked(vp)); 1145 1146 node = VP_TO_TMPFS_NODE(vp); 1147 1148 /* Decide whether this is a valid operation based on the file type. */ 1149 error = 0; 1150 switch (vp->v_type) { 1151 case VDIR: 1152 return EISDIR; 1153 1154 case VREG: 1155 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1156 return EROFS; 1157 break; 1158 1159 case VBLK: 1160 /* FALLTHROUGH */ 1161 case VCHR: 1162 /* FALLTHROUGH */ 1163 case VFIFO: 1164 /* Allow modifications of special files even if in the file 1165 * system is mounted read-only (we are not modifying the 1166 * files themselves, but the objects they represent). */ 1167 return 0; 1168 1169 default: 1170 /* Anything else is unsupported. */ 1171 return EOPNOTSUPP; 1172 } 1173 1174 /* Immutable or append-only files cannot be modified, either. */ 1175 if (node->tn_flags & (IMMUTABLE | APPEND)) 1176 return EPERM; 1177 1178 error = tmpfs_truncate(vp, size); 1179 /* tmpfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents 1180 * for us, as will update tn_status; no need to do that here. */ 1181 1182 KKASSERT(vn_islocked(vp)); 1183 1184 return error; 1185 } 1186 1187 /* --------------------------------------------------------------------- */ 1188 1189 /* 1190 * Change access and modification times of the given vnode. 1191 * Caller should execute tmpfs_update on vp after a successful execution. 1192 * The vnode must be locked on entry and remain locked on exit. 1193 */ 1194 int 1195 tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime, 1196 int vaflags, struct ucred *cred) 1197 { 1198 struct tmpfs_node *node; 1199 1200 KKASSERT(vn_islocked(vp)); 1201 1202 node = VP_TO_TMPFS_NODE(vp); 1203 1204 /* Disallow this operation if the file system is mounted read-only. */ 1205 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1206 return EROFS; 1207 1208 /* Immutable or append-only files cannot be modified, either. */ 1209 if (node->tn_flags & (IMMUTABLE | APPEND)) 1210 return EPERM; 1211 1212 TMPFS_NODE_LOCK(node); 1213 if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL) 1214 node->tn_status |= TMPFS_NODE_ACCESSED; 1215 1216 if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL) 1217 node->tn_status |= TMPFS_NODE_MODIFIED; 1218 1219 TMPFS_NODE_UNLOCK(node); 1220 1221 tmpfs_itimes(vp, atime, mtime); 1222 1223 KKASSERT(vn_islocked(vp)); 1224 1225 return 0; 1226 } 1227 1228 /* --------------------------------------------------------------------- */ 1229 /* Sync timestamps */ 1230 void 1231 tmpfs_itimes(struct vnode *vp, const struct timespec *acc, 1232 const struct timespec *mod) 1233 { 1234 struct tmpfs_node *node; 1235 struct timespec now; 1236 1237 node = VP_TO_TMPFS_NODE(vp); 1238 1239 if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 1240 TMPFS_NODE_CHANGED)) == 0) 1241 return; 1242 1243 vfs_timestamp(&now); 1244 1245 TMPFS_NODE_LOCK(node); 1246 if (node->tn_status & TMPFS_NODE_ACCESSED) { 1247 if (acc == NULL) 1248 acc = &now; 1249 node->tn_atime = acc->tv_sec; 1250 node->tn_atimensec = acc->tv_nsec; 1251 } 1252 if (node->tn_status & TMPFS_NODE_MODIFIED) { 1253 if (mod == NULL) 1254 mod = &now; 1255 node->tn_mtime = mod->tv_sec; 1256 node->tn_mtimensec = mod->tv_nsec; 1257 } 1258 if (node->tn_status & TMPFS_NODE_CHANGED) { 1259 node->tn_ctime = now.tv_sec; 1260 node->tn_ctimensec = now.tv_nsec; 1261 } 1262 node->tn_status &= 1263 ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED); 1264 TMPFS_NODE_UNLOCK(node); 1265 } 1266 1267 /* --------------------------------------------------------------------- */ 1268 1269 void 1270 tmpfs_update(struct vnode *vp) 1271 { 1272 tmpfs_itimes(vp, NULL, NULL); 1273 } 1274 1275 /* --------------------------------------------------------------------- */ 1276 1277 /* 1278 * Caller must hold an exclusive node lock. 1279 */ 1280 int 1281 tmpfs_truncate(struct vnode *vp, off_t length) 1282 { 1283 int error; 1284 struct tmpfs_node *node; 1285 1286 node = VP_TO_TMPFS_NODE(vp); 1287 1288 if (length < 0) { 1289 error = EINVAL; 1290 goto out; 1291 } 1292 1293 if (node->tn_size == length) { 1294 error = 0; 1295 goto out; 1296 } 1297 1298 if (length > VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) 1299 return (EFBIG); 1300 1301 1302 error = tmpfs_reg_resize(vp, length, 1); 1303 1304 if (error == 0) 1305 node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1306 1307 out: 1308 tmpfs_update(vp); 1309 1310 return error; 1311 } 1312 1313 /* --------------------------------------------------------------------- */ 1314 1315 static ino_t 1316 tmpfs_fetch_ino(struct tmpfs_mount *tmp) 1317 { 1318 ino_t ret; 1319 1320 TMPFS_LOCK(tmp); 1321 ret = tmp->tm_ino++; 1322 TMPFS_UNLOCK(tmp); 1323 1324 return (ret); 1325 } 1326 1327 static int 1328 tmpfs_dirtree_compare(struct tmpfs_dirent *a, struct tmpfs_dirent *b) 1329 { 1330 if (a->td_namelen > b->td_namelen) 1331 return 1; 1332 else if (a->td_namelen < b->td_namelen) 1333 return -1; 1334 else 1335 return strncmp(a->td_name, b->td_name, a->td_namelen); 1336 } 1337 1338 static int 1339 tmpfs_dirtree_compare_cookie(struct tmpfs_dirent *a, struct tmpfs_dirent *b) 1340 { 1341 if (a < b) 1342 return(-1); 1343 if (a > b) 1344 return(1); 1345 return 0; 1346 } 1347