1 /* $NetBSD: tmpfs_vfsops.c,v 1.10 2005/12/11 12:24:29 christos Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 * 6 * Copyright (c) 2005 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 11 * 2005 program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Efficient memory file system. 37 * 38 * tmpfs is a file system that uses FreeBSD's virtual memory 39 * sub-system to store file data and metadata in an efficient way. 40 * This means that it does not follow the structure of an on-disk file 41 * system because it simply does not need to. Instead, it uses 42 * memory-specific data structures and algorithms to automatically 43 * allocate and release resources. 44 */ 45 46 #include "opt_tmpfs.h" 47 48 #include <sys/cdefs.h> 49 __FBSDID("$FreeBSD$"); 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/dirent.h> 54 #include <sys/file.h> 55 #include <sys/limits.h> 56 #include <sys/lock.h> 57 #include <sys/mount.h> 58 #include <sys/mutex.h> 59 #include <sys/proc.h> 60 #include <sys/jail.h> 61 #include <sys/kernel.h> 62 #include <sys/rwlock.h> 63 #include <sys/stat.h> 64 #include <sys/sx.h> 65 #include <sys/sysctl.h> 66 #include <sys/vnode.h> 67 68 #include <vm/vm.h> 69 #include <vm/vm_param.h> 70 #include <vm/pmap.h> 71 #include <vm/vm_extern.h> 72 #include <vm/vm_map.h> 73 #include <vm/vm_object.h> 74 #include <vm/vm_param.h> 75 76 #include <fs/tmpfs/tmpfs.h> 77 78 /* 79 * Default permission for root node 80 */ 81 #define TMPFS_DEFAULT_ROOT_MODE (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 82 83 static MALLOC_DEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures"); 84 MALLOC_DEFINE(M_TMPFSNAME, "tmpfs name", "tmpfs file names"); 85 86 static int tmpfs_mount(struct mount *); 87 static int tmpfs_unmount(struct mount *, int); 88 static int tmpfs_root(struct mount *, int flags, struct vnode **); 89 static int tmpfs_fhtovp(struct mount *, struct fid *, int, 90 struct vnode **); 91 static int tmpfs_statfs(struct mount *, struct statfs *); 92 93 static const char *tmpfs_opts[] = { 94 "from", "size", "maxfilesize", "inodes", "uid", "gid", "mode", "export", 95 "union", "nonc", "nomtime", NULL 96 }; 97 98 static const char *tmpfs_updateopts[] = { 99 "from", "export", "nomtime", "size", NULL 100 }; 101 102 /* 103 * Handle updates of time from writes to mmaped regions, if allowed. 104 * Use MNT_VNODE_FOREACH_ALL instead of MNT_VNODE_FOREACH_LAZY, since 105 * unmap of the tmpfs-backed vnode does not call vinactive(), due to 106 * vm object type is OBJT_SWAP. If lazy, only handle delayed update 107 * of mtime due to the writes to mapped files. 108 */ 109 static void 110 tmpfs_update_mtime(struct mount *mp, bool lazy) 111 { 112 struct vnode *vp, *mvp; 113 struct vm_object *obj; 114 115 if (VFS_TO_TMPFS(mp)->tm_nomtime) 116 return; 117 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 118 if (vp->v_type != VREG) { 119 VI_UNLOCK(vp); 120 continue; 121 } 122 obj = vp->v_object; 123 MPASS(obj->type == OBJT_SWAP_TMPFS); 124 MPASS((obj->flags & OBJ_TMPFS) != 0); 125 126 /* 127 * In lazy case, do unlocked read, avoid taking vnode 128 * lock if not needed. Lost update will be handled on 129 * the next call. 130 * For non-lazy case, we must flush all pending 131 * metadata changes now. 132 */ 133 if (!lazy || obj->generation != obj->cleangeneration) { 134 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK) != 0) 135 continue; 136 tmpfs_check_mtime(vp); 137 if (!lazy) 138 tmpfs_update(vp); 139 vput(vp); 140 } else { 141 VI_UNLOCK(vp); 142 continue; 143 } 144 } 145 } 146 147 struct tmpfs_check_rw_maps_arg { 148 bool found; 149 }; 150 151 static bool 152 tmpfs_check_rw_maps_cb(struct mount *mp __unused, vm_map_t map __unused, 153 vm_map_entry_t entry __unused, void *arg) 154 { 155 struct tmpfs_check_rw_maps_arg *a; 156 157 a = arg; 158 a->found = true; 159 return (true); 160 } 161 162 /* 163 * Revoke write permissions from all mappings of regular files 164 * belonging to the specified tmpfs mount. 165 */ 166 static bool 167 tmpfs_revoke_rw_maps_cb(struct mount *mp __unused, vm_map_t map, 168 vm_map_entry_t entry, void *arg __unused) 169 { 170 171 /* 172 * XXXKIB: might be invalidate the mapping 173 * instead ? The process is not going to be 174 * happy in any case. 175 */ 176 entry->max_protection &= ~VM_PROT_WRITE; 177 if ((entry->protection & VM_PROT_WRITE) != 0) { 178 entry->protection &= ~VM_PROT_WRITE; 179 pmap_protect(map->pmap, entry->start, entry->end, 180 entry->protection); 181 } 182 return (false); 183 } 184 185 static void 186 tmpfs_all_rw_maps(struct mount *mp, bool (*cb)(struct mount *mp, vm_map_t, 187 vm_map_entry_t, void *), void *cb_arg) 188 { 189 struct proc *p; 190 struct vmspace *vm; 191 vm_map_t map; 192 vm_map_entry_t entry; 193 vm_object_t object; 194 struct vnode *vp; 195 int gen; 196 bool terminate; 197 198 terminate = false; 199 sx_slock(&allproc_lock); 200 again: 201 gen = allproc_gen; 202 FOREACH_PROC_IN_SYSTEM(p) { 203 PROC_LOCK(p); 204 if (p->p_state != PRS_NORMAL || (p->p_flag & (P_INEXEC | 205 P_SYSTEM | P_WEXIT)) != 0) { 206 PROC_UNLOCK(p); 207 continue; 208 } 209 vm = vmspace_acquire_ref(p); 210 _PHOLD_LITE(p); 211 PROC_UNLOCK(p); 212 if (vm == NULL) { 213 PRELE(p); 214 continue; 215 } 216 sx_sunlock(&allproc_lock); 217 map = &vm->vm_map; 218 219 vm_map_lock(map); 220 if (map->busy) 221 vm_map_wait_busy(map); 222 VM_MAP_ENTRY_FOREACH(entry, map) { 223 if ((entry->eflags & (MAP_ENTRY_GUARD | 224 MAP_ENTRY_IS_SUB_MAP | MAP_ENTRY_COW)) != 0 || 225 (entry->max_protection & VM_PROT_WRITE) == 0) 226 continue; 227 object = entry->object.vm_object; 228 if (object == NULL || object->type != OBJT_SWAP_TMPFS) 229 continue; 230 /* 231 * No need to dig into shadow chain, mapping 232 * of the object not at top is readonly. 233 */ 234 235 VM_OBJECT_RLOCK(object); 236 if (object->type == OBJT_DEAD) { 237 VM_OBJECT_RUNLOCK(object); 238 continue; 239 } 240 MPASS(object->ref_count > 1); 241 if ((object->flags & OBJ_TMPFS) == 0) { 242 VM_OBJECT_RUNLOCK(object); 243 continue; 244 } 245 vp = object->un_pager.swp.swp_tmpfs; 246 if (vp->v_mount != mp) { 247 VM_OBJECT_RUNLOCK(object); 248 continue; 249 } 250 251 terminate = cb(mp, map, entry, cb_arg); 252 VM_OBJECT_RUNLOCK(object); 253 if (terminate) 254 break; 255 } 256 vm_map_unlock(map); 257 258 vmspace_free(vm); 259 sx_slock(&allproc_lock); 260 PRELE(p); 261 if (terminate) 262 break; 263 } 264 if (!terminate && gen != allproc_gen) 265 goto again; 266 sx_sunlock(&allproc_lock); 267 } 268 269 static bool 270 tmpfs_check_rw_maps(struct mount *mp) 271 { 272 struct tmpfs_check_rw_maps_arg ca; 273 274 ca.found = false; 275 tmpfs_all_rw_maps(mp, tmpfs_check_rw_maps_cb, &ca); 276 return (ca.found); 277 } 278 279 static int 280 tmpfs_rw_to_ro(struct mount *mp) 281 { 282 int error, flags; 283 bool forced; 284 285 forced = (mp->mnt_flag & MNT_FORCE) != 0; 286 flags = WRITECLOSE | (forced ? FORCECLOSE : 0); 287 288 if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) 289 return (error); 290 error = vfs_write_suspend_umnt(mp); 291 if (error != 0) 292 return (error); 293 if (!forced && tmpfs_check_rw_maps(mp)) { 294 error = EBUSY; 295 goto out; 296 } 297 VFS_TO_TMPFS(mp)->tm_ronly = 1; 298 MNT_ILOCK(mp); 299 mp->mnt_flag |= MNT_RDONLY; 300 MNT_IUNLOCK(mp); 301 for (;;) { 302 tmpfs_all_rw_maps(mp, tmpfs_revoke_rw_maps_cb, NULL); 303 tmpfs_update_mtime(mp, false); 304 error = vflush(mp, 0, flags, curthread); 305 if (error != 0) { 306 VFS_TO_TMPFS(mp)->tm_ronly = 0; 307 MNT_ILOCK(mp); 308 mp->mnt_flag &= ~MNT_RDONLY; 309 MNT_IUNLOCK(mp); 310 goto out; 311 } 312 if (!tmpfs_check_rw_maps(mp)) 313 break; 314 } 315 out: 316 vfs_write_resume(mp, 0); 317 return (error); 318 } 319 320 static int 321 tmpfs_mount(struct mount *mp) 322 { 323 const size_t nodes_per_page = howmany(PAGE_SIZE, 324 sizeof(struct tmpfs_dirent) + sizeof(struct tmpfs_node)); 325 struct tmpfs_mount *tmp; 326 struct tmpfs_node *root; 327 int error; 328 bool nomtime, nonc; 329 /* Size counters. */ 330 u_quad_t pages; 331 off_t nodes_max, size_max, maxfilesize; 332 333 /* Root node attributes. */ 334 uid_t root_uid; 335 gid_t root_gid; 336 mode_t root_mode; 337 338 struct vattr va; 339 340 if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts)) 341 return (EINVAL); 342 343 if (mp->mnt_flag & MNT_UPDATE) { 344 /* Only support update mounts for certain options. */ 345 if (vfs_filteropt(mp->mnt_optnew, tmpfs_updateopts) != 0) 346 return (EOPNOTSUPP); 347 tmp = VFS_TO_TMPFS(mp); 348 if (vfs_getopt_size(mp->mnt_optnew, "size", &size_max) == 0) { 349 /* 350 * On-the-fly resizing is not supported (yet). We still 351 * need to have "size" listed as "supported", otherwise 352 * trying to update fs that is listed in fstab with size 353 * parameter, say trying to change rw to ro or vice 354 * versa, would cause vfs_filteropt() to bail. 355 */ 356 if (size_max != tmp->tm_size_max) 357 return (EOPNOTSUPP); 358 } 359 if (vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) && 360 !tmp->tm_ronly) { 361 /* RW -> RO */ 362 return (tmpfs_rw_to_ro(mp)); 363 } else if (!vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) && 364 tmp->tm_ronly) { 365 /* RO -> RW */ 366 tmp->tm_ronly = 0; 367 MNT_ILOCK(mp); 368 mp->mnt_flag &= ~MNT_RDONLY; 369 MNT_IUNLOCK(mp); 370 } 371 tmp->tm_nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL, 372 0) == 0; 373 MNT_ILOCK(mp); 374 if ((mp->mnt_flag & MNT_UNION) == 0) { 375 mp->mnt_kern_flag |= MNTK_FPLOOKUP; 376 } else { 377 mp->mnt_kern_flag &= ~MNTK_FPLOOKUP; 378 } 379 MNT_IUNLOCK(mp); 380 return (0); 381 } 382 383 vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY); 384 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred); 385 VOP_UNLOCK(mp->mnt_vnodecovered); 386 if (error) 387 return (error); 388 389 if (mp->mnt_cred->cr_ruid != 0 || 390 vfs_scanopt(mp->mnt_optnew, "gid", "%d", &root_gid) != 1) 391 root_gid = va.va_gid; 392 if (mp->mnt_cred->cr_ruid != 0 || 393 vfs_scanopt(mp->mnt_optnew, "uid", "%d", &root_uid) != 1) 394 root_uid = va.va_uid; 395 if (mp->mnt_cred->cr_ruid != 0 || 396 vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1) 397 root_mode = va.va_mode; 398 if (vfs_getopt_size(mp->mnt_optnew, "inodes", &nodes_max) != 0) 399 nodes_max = 0; 400 if (vfs_getopt_size(mp->mnt_optnew, "size", &size_max) != 0) 401 size_max = 0; 402 if (vfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) != 0) 403 maxfilesize = 0; 404 nonc = vfs_getopt(mp->mnt_optnew, "nonc", NULL, NULL) == 0; 405 nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL, NULL) == 0; 406 407 /* Do not allow mounts if we do not have enough memory to preserve 408 * the minimum reserved pages. */ 409 if (tmpfs_mem_avail() < TMPFS_PAGES_MINRESERVED) 410 return (ENOSPC); 411 412 /* Get the maximum number of memory pages this file system is 413 * allowed to use, based on the maximum size the user passed in 414 * the mount structure. A value of zero is treated as if the 415 * maximum available space was requested. */ 416 if (size_max == 0 || size_max > OFF_MAX - PAGE_SIZE || 417 (SIZE_MAX < OFF_MAX && size_max / PAGE_SIZE >= SIZE_MAX)) 418 pages = SIZE_MAX; 419 else { 420 size_max = roundup(size_max, PAGE_SIZE); 421 pages = howmany(size_max, PAGE_SIZE); 422 } 423 MPASS(pages > 0); 424 425 if (nodes_max <= 3) { 426 if (pages < INT_MAX / nodes_per_page) 427 nodes_max = pages * nodes_per_page; 428 else 429 nodes_max = INT_MAX; 430 } 431 if (nodes_max > INT_MAX) 432 nodes_max = INT_MAX; 433 MPASS(nodes_max >= 3); 434 435 /* Allocate the tmpfs mount structure and fill it. */ 436 tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount), 437 M_TMPFSMNT, M_WAITOK | M_ZERO); 438 439 mtx_init(&tmp->tm_allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF); 440 tmp->tm_nodes_max = nodes_max; 441 tmp->tm_nodes_inuse = 0; 442 tmp->tm_refcount = 1; 443 tmp->tm_maxfilesize = maxfilesize > 0 ? maxfilesize : OFF_MAX; 444 LIST_INIT(&tmp->tm_nodes_used); 445 446 tmp->tm_size_max = size_max; 447 tmp->tm_pages_max = pages; 448 tmp->tm_pages_used = 0; 449 new_unrhdr64(&tmp->tm_ino_unr, 2); 450 tmp->tm_ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 451 tmp->tm_nonc = nonc; 452 tmp->tm_nomtime = nomtime; 453 454 /* Allocate the root node. */ 455 error = tmpfs_alloc_node(mp, tmp, VDIR, root_uid, root_gid, 456 root_mode & ALLPERMS, NULL, NULL, VNOVAL, &root); 457 458 if (error != 0 || root == NULL) { 459 free(tmp, M_TMPFSMNT); 460 return (error); 461 } 462 KASSERT(root->tn_id == 2, 463 ("tmpfs root with invalid ino: %ju", (uintmax_t)root->tn_id)); 464 tmp->tm_root = root; 465 466 MNT_ILOCK(mp); 467 mp->mnt_flag |= MNT_LOCAL; 468 mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | 469 MNTK_TEXT_REFS | MNTK_NOMSYNC; 470 if (!nonc && (mp->mnt_flag & MNT_UNION) == 0) 471 mp->mnt_kern_flag |= MNTK_FPLOOKUP; 472 MNT_IUNLOCK(mp); 473 474 mp->mnt_data = tmp; 475 mp->mnt_stat.f_namemax = MAXNAMLEN; 476 vfs_getnewfsid(mp); 477 vfs_mountedfrom(mp, "tmpfs"); 478 479 return 0; 480 } 481 482 /* ARGSUSED2 */ 483 static int 484 tmpfs_unmount(struct mount *mp, int mntflags) 485 { 486 struct tmpfs_mount *tmp; 487 struct tmpfs_node *node; 488 int error, flags; 489 490 flags = (mntflags & MNT_FORCE) != 0 ? FORCECLOSE : 0; 491 tmp = VFS_TO_TMPFS(mp); 492 493 /* Stop writers */ 494 error = vfs_write_suspend_umnt(mp); 495 if (error != 0) 496 return (error); 497 /* 498 * At this point, nodes cannot be destroyed by any other 499 * thread because write suspension is started. 500 */ 501 502 for (;;) { 503 error = vflush(mp, 0, flags, curthread); 504 if (error != 0) { 505 vfs_write_resume(mp, VR_START_WRITE); 506 return (error); 507 } 508 MNT_ILOCK(mp); 509 if (mp->mnt_nvnodelistsize == 0) { 510 MNT_IUNLOCK(mp); 511 break; 512 } 513 MNT_IUNLOCK(mp); 514 if ((mntflags & MNT_FORCE) == 0) { 515 vfs_write_resume(mp, VR_START_WRITE); 516 return (EBUSY); 517 } 518 } 519 520 TMPFS_LOCK(tmp); 521 while ((node = LIST_FIRST(&tmp->tm_nodes_used)) != NULL) { 522 TMPFS_NODE_LOCK(node); 523 if (node->tn_type == VDIR) 524 tmpfs_dir_destroy(tmp, node); 525 if (tmpfs_free_node_locked(tmp, node, true)) 526 TMPFS_LOCK(tmp); 527 else 528 TMPFS_NODE_UNLOCK(node); 529 } 530 531 mp->mnt_data = NULL; 532 tmpfs_free_tmp(tmp); 533 vfs_write_resume(mp, VR_START_WRITE); 534 535 MNT_ILOCK(mp); 536 mp->mnt_flag &= ~MNT_LOCAL; 537 MNT_IUNLOCK(mp); 538 539 return (0); 540 } 541 542 void 543 tmpfs_free_tmp(struct tmpfs_mount *tmp) 544 { 545 TMPFS_MP_ASSERT_LOCKED(tmp); 546 MPASS(tmp->tm_refcount > 0); 547 548 tmp->tm_refcount--; 549 if (tmp->tm_refcount > 0) { 550 TMPFS_UNLOCK(tmp); 551 return; 552 } 553 TMPFS_UNLOCK(tmp); 554 555 mtx_destroy(&tmp->tm_allnode_lock); 556 MPASS(tmp->tm_pages_used == 0); 557 MPASS(tmp->tm_nodes_inuse == 0); 558 559 free(tmp, M_TMPFSMNT); 560 } 561 562 static int 563 tmpfs_root(struct mount *mp, int flags, struct vnode **vpp) 564 { 565 int error; 566 567 error = tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, flags, vpp); 568 if (error == 0) 569 (*vpp)->v_vflag |= VV_ROOT; 570 return (error); 571 } 572 573 static int 574 tmpfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, 575 struct vnode **vpp) 576 { 577 struct tmpfs_fid_data tfd; 578 struct tmpfs_mount *tmp; 579 struct tmpfs_node *node; 580 int error; 581 582 if (fhp->fid_len != sizeof(tfd)) 583 return (EINVAL); 584 585 /* 586 * Copy from fid_data onto the stack to avoid unaligned pointer use. 587 * See the comment in sys/mount.h on struct fid for details. 588 */ 589 memcpy(&tfd, fhp->fid_data, fhp->fid_len); 590 591 tmp = VFS_TO_TMPFS(mp); 592 593 if (tfd.tfd_id >= tmp->tm_nodes_max) 594 return (EINVAL); 595 596 TMPFS_LOCK(tmp); 597 LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) { 598 if (node->tn_id == tfd.tfd_id && 599 node->tn_gen == tfd.tfd_gen) { 600 tmpfs_ref_node(node); 601 break; 602 } 603 } 604 TMPFS_UNLOCK(tmp); 605 606 if (node != NULL) { 607 error = tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp); 608 tmpfs_free_node(tmp, node); 609 } else 610 error = EINVAL; 611 return (error); 612 } 613 614 /* ARGSUSED2 */ 615 static int 616 tmpfs_statfs(struct mount *mp, struct statfs *sbp) 617 { 618 struct tmpfs_mount *tmp; 619 size_t used; 620 621 tmp = VFS_TO_TMPFS(mp); 622 623 sbp->f_iosize = PAGE_SIZE; 624 sbp->f_bsize = PAGE_SIZE; 625 626 used = tmpfs_pages_used(tmp); 627 if (tmp->tm_pages_max != ULONG_MAX) 628 sbp->f_blocks = tmp->tm_pages_max; 629 else 630 sbp->f_blocks = used + tmpfs_mem_avail(); 631 if (sbp->f_blocks <= used) 632 sbp->f_bavail = 0; 633 else 634 sbp->f_bavail = sbp->f_blocks - used; 635 sbp->f_bfree = sbp->f_bavail; 636 used = tmp->tm_nodes_inuse; 637 sbp->f_files = tmp->tm_nodes_max; 638 if (sbp->f_files <= used) 639 sbp->f_ffree = 0; 640 else 641 sbp->f_ffree = sbp->f_files - used; 642 /* sbp->f_owner = tmp->tn_uid; */ 643 644 return 0; 645 } 646 647 static int 648 tmpfs_sync(struct mount *mp, int waitfor) 649 { 650 651 if (waitfor == MNT_SUSPEND) { 652 MNT_ILOCK(mp); 653 mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED; 654 MNT_IUNLOCK(mp); 655 } else if (waitfor == MNT_LAZY) { 656 tmpfs_update_mtime(mp, true); 657 } 658 return (0); 659 } 660 661 static int 662 tmpfs_init(struct vfsconf *conf) 663 { 664 tmpfs_subr_init(); 665 memcpy(&tmpfs_fnops, &vnops, sizeof(struct fileops)); 666 tmpfs_fnops.fo_close = tmpfs_fo_close; 667 return (0); 668 } 669 670 static int 671 tmpfs_uninit(struct vfsconf *conf) 672 { 673 tmpfs_subr_uninit(); 674 return (0); 675 } 676 677 /* 678 * tmpfs vfs operations. 679 */ 680 struct vfsops tmpfs_vfsops = { 681 .vfs_mount = tmpfs_mount, 682 .vfs_unmount = tmpfs_unmount, 683 .vfs_root = vfs_cache_root, 684 .vfs_cachedroot = tmpfs_root, 685 .vfs_statfs = tmpfs_statfs, 686 .vfs_fhtovp = tmpfs_fhtovp, 687 .vfs_sync = tmpfs_sync, 688 .vfs_init = tmpfs_init, 689 .vfs_uninit = tmpfs_uninit, 690 }; 691 VFS_SET(tmpfs_vfsops, tmpfs, VFCF_JAIL); 692