The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/tmpfs/tmpfs_vfsops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_ddb.h"
   47 #include "opt_tmpfs.h"
   48 
   49 #include <sys/cdefs.h>
   50 __FBSDID("$FreeBSD$");
   51 
   52 #include <sys/param.h>
   53 #include <sys/systm.h>
   54 #include <sys/dirent.h>
   55 #include <sys/file.h>
   56 #include <sys/limits.h>
   57 #include <sys/lock.h>
   58 #include <sys/mount.h>
   59 #include <sys/mutex.h>
   60 #include <sys/proc.h>
   61 #include <sys/jail.h>
   62 #include <sys/kernel.h>
   63 #include <sys/rwlock.h>
   64 #include <sys/stat.h>
   65 #include <sys/sx.h>
   66 #include <sys/sysctl.h>
   67 #include <sys/vnode.h>
   68 
   69 #include <vm/vm.h>
   70 #include <vm/vm_param.h>
   71 #include <vm/pmap.h>
   72 #include <vm/vm_extern.h>
   73 #include <vm/vm_map.h>
   74 #include <vm/vm_object.h>
   75 #include <vm/vm_param.h>
   76 
   77 #include <fs/tmpfs/tmpfs.h>
   78 
   79 /*
   80  * Default permission for root node
   81  */
   82 #define TMPFS_DEFAULT_ROOT_MODE (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
   83 
   84 static MALLOC_DEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures");
   85 MALLOC_DEFINE(M_TMPFSNAME, "tmpfs name", "tmpfs file names");
   86 
   87 static int      tmpfs_mount(struct mount *);
   88 static int      tmpfs_unmount(struct mount *, int);
   89 static int      tmpfs_root(struct mount *, int flags, struct vnode **);
   90 static int      tmpfs_fhtovp(struct mount *, struct fid *, int,
   91                     struct vnode **);
   92 static int      tmpfs_statfs(struct mount *, struct statfs *);
   93 
   94 static const char *tmpfs_opts[] = {
   95         "from", "size", "maxfilesize", "inodes", "uid", "gid", "mode", "export",
   96         "union", "nonc", "nomtime", NULL
   97 };
   98 
   99 static const char *tmpfs_updateopts[] = {
  100         "from", "export", "nomtime", "size", NULL
  101 };
  102 
  103 static int
  104 tmpfs_update_mtime_lazy_filter(struct vnode *vp, void *arg)
  105 {
  106         struct vm_object *obj;
  107 
  108         if (vp->v_type != VREG)
  109                 return (0);
  110 
  111         obj = atomic_load_ptr(&vp->v_object);
  112         if (obj == NULL)
  113                 return (0);
  114 
  115         return (vm_object_mightbedirty_(obj));
  116 }
  117 
  118 static void
  119 tmpfs_update_mtime_lazy(struct mount *mp)
  120 {
  121         struct vnode *vp, *mvp;
  122 
  123         MNT_VNODE_FOREACH_LAZY(vp, mp, mvp, tmpfs_update_mtime_lazy_filter, NULL) {
  124                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK) != 0)
  125                         continue;
  126                 tmpfs_check_mtime(vp);
  127                 vput(vp);
  128         }
  129 }
  130 
  131 static void
  132 tmpfs_update_mtime_all(struct mount *mp)
  133 {
  134         struct vnode *vp, *mvp;
  135 
  136         if (VFS_TO_TMPFS(mp)->tm_nomtime)
  137                 return;
  138         MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
  139                 if (vp->v_type != VREG) {
  140                         VI_UNLOCK(vp);
  141                         continue;
  142                 }
  143                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK) != 0)
  144                         continue;
  145                 tmpfs_check_mtime(vp);
  146                 tmpfs_update(vp);
  147                 vput(vp);
  148         }
  149 }
  150 
  151 struct tmpfs_check_rw_maps_arg {
  152         bool found;
  153 };
  154 
  155 static bool
  156 tmpfs_check_rw_maps_cb(struct mount *mp __unused, vm_map_t map __unused,
  157     vm_map_entry_t entry __unused, void *arg)
  158 {
  159         struct tmpfs_check_rw_maps_arg *a;
  160 
  161         a = arg;
  162         a->found = true;
  163         return (true);
  164 }
  165 
  166 /*
  167  * Revoke write permissions from all mappings of regular files
  168  * belonging to the specified tmpfs mount.
  169  */
  170 static bool
  171 tmpfs_revoke_rw_maps_cb(struct mount *mp __unused, vm_map_t map,
  172     vm_map_entry_t entry, void *arg __unused)
  173 {
  174 
  175         /*
  176          * XXXKIB: might be invalidate the mapping
  177          * instead ?  The process is not going to be
  178          * happy in any case.
  179          */
  180         entry->max_protection &= ~VM_PROT_WRITE;
  181         if ((entry->protection & VM_PROT_WRITE) != 0) {
  182                 entry->protection &= ~VM_PROT_WRITE;
  183                 pmap_protect(map->pmap, entry->start, entry->end,
  184                     entry->protection);
  185         }
  186         return (false);
  187 }
  188 
  189 static void
  190 tmpfs_all_rw_maps(struct mount *mp, bool (*cb)(struct mount *mp, vm_map_t,
  191     vm_map_entry_t, void *), void *cb_arg)
  192 {
  193         struct proc *p;
  194         struct vmspace *vm;
  195         vm_map_t map;
  196         vm_map_entry_t entry;
  197         vm_object_t object;
  198         struct vnode *vp;
  199         int gen;
  200         bool terminate;
  201 
  202         terminate = false;
  203         sx_slock(&allproc_lock);
  204 again:
  205         gen = allproc_gen;
  206         FOREACH_PROC_IN_SYSTEM(p) {
  207                 PROC_LOCK(p);
  208                 if (p->p_state != PRS_NORMAL || (p->p_flag & (P_INEXEC |
  209                     P_SYSTEM | P_WEXIT)) != 0) {
  210                         PROC_UNLOCK(p);
  211                         continue;
  212                 }
  213                 vm = vmspace_acquire_ref(p);
  214                 _PHOLD_LITE(p);
  215                 PROC_UNLOCK(p);
  216                 if (vm == NULL) {
  217                         PRELE(p);
  218                         continue;
  219                 }
  220                 sx_sunlock(&allproc_lock);
  221                 map = &vm->vm_map;
  222 
  223                 vm_map_lock(map);
  224                 if (map->busy)
  225                         vm_map_wait_busy(map);
  226                 VM_MAP_ENTRY_FOREACH(entry, map) {
  227                         if ((entry->eflags & (MAP_ENTRY_GUARD |
  228                             MAP_ENTRY_IS_SUB_MAP | MAP_ENTRY_COW)) != 0 ||
  229                             (entry->max_protection & VM_PROT_WRITE) == 0)
  230                                 continue;
  231                         object = entry->object.vm_object;
  232                         if (object == NULL || object->type != tmpfs_pager_type)
  233                                 continue;
  234                         /*
  235                          * No need to dig into shadow chain, mapping
  236                          * of the object not at top is readonly.
  237                          */
  238 
  239                         VM_OBJECT_RLOCK(object);
  240                         if (object->type == OBJT_DEAD) {
  241                                 VM_OBJECT_RUNLOCK(object);
  242                                 continue;
  243                         }
  244                         MPASS(object->ref_count > 1);
  245                         if ((object->flags & OBJ_TMPFS) == 0) {
  246                                 VM_OBJECT_RUNLOCK(object);
  247                                 continue;
  248                         }
  249                         vp = VM_TO_TMPFS_VP(object);
  250                         if (vp->v_mount != mp) {
  251                                 VM_OBJECT_RUNLOCK(object);
  252                                 continue;
  253                         }
  254 
  255                         terminate = cb(mp, map, entry, cb_arg);
  256                         VM_OBJECT_RUNLOCK(object);
  257                         if (terminate)
  258                                 break;
  259                 }
  260                 vm_map_unlock(map);
  261 
  262                 vmspace_free(vm);
  263                 sx_slock(&allproc_lock);
  264                 PRELE(p);
  265                 if (terminate)
  266                         break;
  267         }
  268         if (!terminate && gen != allproc_gen)
  269                 goto again;
  270         sx_sunlock(&allproc_lock);
  271 }
  272 
  273 static bool
  274 tmpfs_check_rw_maps(struct mount *mp)
  275 {
  276         struct tmpfs_check_rw_maps_arg ca;
  277 
  278         ca.found = false;
  279         tmpfs_all_rw_maps(mp, tmpfs_check_rw_maps_cb, &ca);
  280         return (ca.found);
  281 }
  282 
  283 static int
  284 tmpfs_rw_to_ro(struct mount *mp)
  285 {
  286         int error, flags;
  287         bool forced;
  288 
  289         forced = (mp->mnt_flag & MNT_FORCE) != 0;
  290         flags = WRITECLOSE | (forced ? FORCECLOSE : 0);
  291 
  292         if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
  293                 return (error);
  294         error = vfs_write_suspend_umnt(mp);
  295         if (error != 0)
  296                 return (error);
  297         if (!forced && tmpfs_check_rw_maps(mp)) {
  298                 error = EBUSY;
  299                 goto out;
  300         }
  301         VFS_TO_TMPFS(mp)->tm_ronly = 1;
  302         MNT_ILOCK(mp);
  303         mp->mnt_flag |= MNT_RDONLY;
  304         MNT_IUNLOCK(mp);
  305         for (;;) {
  306                 tmpfs_all_rw_maps(mp, tmpfs_revoke_rw_maps_cb, NULL);
  307                 tmpfs_update_mtime_all(mp);
  308                 error = vflush(mp, 0, flags, curthread);
  309                 if (error != 0) {
  310                         VFS_TO_TMPFS(mp)->tm_ronly = 0;
  311                         MNT_ILOCK(mp);
  312                         mp->mnt_flag &= ~MNT_RDONLY;
  313                         MNT_IUNLOCK(mp);
  314                         goto out;
  315                 }
  316                 if (!tmpfs_check_rw_maps(mp))
  317                         break;
  318         }
  319 out:
  320         vfs_write_resume(mp, 0);
  321         return (error);
  322 }
  323 
  324 static int
  325 tmpfs_mount(struct mount *mp)
  326 {
  327         const size_t nodes_per_page = howmany(PAGE_SIZE,
  328             sizeof(struct tmpfs_dirent) + sizeof(struct tmpfs_node));
  329         struct tmpfs_mount *tmp;
  330         struct tmpfs_node *root;
  331         int error;
  332         bool nomtime, nonc;
  333         /* Size counters. */
  334         u_quad_t pages;
  335         off_t nodes_max, size_max, maxfilesize;
  336 
  337         /* Root node attributes. */
  338         uid_t root_uid;
  339         gid_t root_gid;
  340         mode_t root_mode;
  341 
  342         struct vattr va;
  343 
  344         if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts))
  345                 return (EINVAL);
  346 
  347         if (mp->mnt_flag & MNT_UPDATE) {
  348                 /* Only support update mounts for certain options. */
  349                 if (vfs_filteropt(mp->mnt_optnew, tmpfs_updateopts) != 0)
  350                         return (EOPNOTSUPP);
  351                 tmp = VFS_TO_TMPFS(mp);
  352                 if (vfs_getopt_size(mp->mnt_optnew, "size", &size_max) == 0) {
  353                         /*
  354                          * On-the-fly resizing is not supported (yet). We still
  355                          * need to have "size" listed as "supported", otherwise
  356                          * trying to update fs that is listed in fstab with size
  357                          * parameter, say trying to change rw to ro or vice
  358                          * versa, would cause vfs_filteropt() to bail.
  359                          */
  360                         if (size_max != tmp->tm_size_max)
  361                                 return (EOPNOTSUPP);
  362                 }
  363                 if (vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) &&
  364                     !tmp->tm_ronly) {
  365                         /* RW -> RO */
  366                         return (tmpfs_rw_to_ro(mp));
  367                 } else if (!vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) &&
  368                     tmp->tm_ronly) {
  369                         /* RO -> RW */
  370                         tmp->tm_ronly = 0;
  371                         MNT_ILOCK(mp);
  372                         mp->mnt_flag &= ~MNT_RDONLY;
  373                         MNT_IUNLOCK(mp);
  374                 }
  375                 tmp->tm_nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL,
  376                     0) == 0;
  377                 MNT_ILOCK(mp);
  378                 if ((mp->mnt_flag & MNT_UNION) == 0) {
  379                         mp->mnt_kern_flag |= MNTK_FPLOOKUP;
  380                 } else {
  381                         mp->mnt_kern_flag &= ~MNTK_FPLOOKUP;
  382                 }
  383                 MNT_IUNLOCK(mp);
  384                 return (0);
  385         }
  386 
  387         vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY);
  388         error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred);
  389         VOP_UNLOCK(mp->mnt_vnodecovered);
  390         if (error)
  391                 return (error);
  392 
  393         if (mp->mnt_cred->cr_ruid != 0 ||
  394             vfs_scanopt(mp->mnt_optnew, "gid", "%d", &root_gid) != 1)
  395                 root_gid = va.va_gid;
  396         if (mp->mnt_cred->cr_ruid != 0 ||
  397             vfs_scanopt(mp->mnt_optnew, "uid", "%d", &root_uid) != 1)
  398                 root_uid = va.va_uid;
  399         if (mp->mnt_cred->cr_ruid != 0 ||
  400             vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1)
  401                 root_mode = va.va_mode;
  402         if (vfs_getopt_size(mp->mnt_optnew, "inodes", &nodes_max) != 0)
  403                 nodes_max = 0;
  404         if (vfs_getopt_size(mp->mnt_optnew, "size", &size_max) != 0)
  405                 size_max = 0;
  406         if (vfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) != 0)
  407                 maxfilesize = 0;
  408         nonc = vfs_getopt(mp->mnt_optnew, "nonc", NULL, NULL) == 0;
  409         nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL, NULL) == 0;
  410 
  411         /* Do not allow mounts if we do not have enough memory to preserve
  412          * the minimum reserved pages. */
  413         if (tmpfs_mem_avail() < TMPFS_PAGES_MINRESERVED)
  414                 return (ENOSPC);
  415 
  416         /* Get the maximum number of memory pages this file system is
  417          * allowed to use, based on the maximum size the user passed in
  418          * the mount structure.  A value of zero is treated as if the
  419          * maximum available space was requested. */
  420         if (size_max == 0 || size_max > OFF_MAX - PAGE_SIZE ||
  421             (SIZE_MAX < OFF_MAX && size_max / PAGE_SIZE >= SIZE_MAX))
  422                 pages = SIZE_MAX;
  423         else {
  424                 size_max = roundup(size_max, PAGE_SIZE);
  425                 pages = howmany(size_max, PAGE_SIZE);
  426         }
  427         MPASS(pages > 0);
  428 
  429         if (nodes_max <= 3) {
  430                 if (pages < INT_MAX / nodes_per_page)
  431                         nodes_max = pages * nodes_per_page;
  432                 else
  433                         nodes_max = INT_MAX;
  434         }
  435         if (nodes_max > INT_MAX)
  436                 nodes_max = INT_MAX;
  437         MPASS(nodes_max >= 3);
  438 
  439         /* Allocate the tmpfs mount structure and fill it. */
  440         tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount),
  441             M_TMPFSMNT, M_WAITOK | M_ZERO);
  442 
  443         mtx_init(&tmp->tm_allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF);
  444         tmp->tm_nodes_max = nodes_max;
  445         tmp->tm_nodes_inuse = 0;
  446         tmp->tm_refcount = 1;
  447         tmp->tm_maxfilesize = maxfilesize > 0 ? maxfilesize : OFF_MAX;
  448         LIST_INIT(&tmp->tm_nodes_used);
  449 
  450         tmp->tm_size_max = size_max;
  451         tmp->tm_pages_max = pages;
  452         tmp->tm_pages_used = 0;
  453         new_unrhdr64(&tmp->tm_ino_unr, 2);
  454         tmp->tm_ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  455         tmp->tm_nonc = nonc;
  456         tmp->tm_nomtime = nomtime;
  457 
  458         /* Allocate the root node. */
  459         error = tmpfs_alloc_node(mp, tmp, VDIR, root_uid, root_gid,
  460             root_mode & ALLPERMS, NULL, NULL, VNOVAL, &root);
  461 
  462         if (error != 0 || root == NULL) {
  463                 free(tmp, M_TMPFSMNT);
  464                 return (error);
  465         }
  466         KASSERT(root->tn_id == 2,
  467             ("tmpfs root with invalid ino: %ju", (uintmax_t)root->tn_id));
  468         tmp->tm_root = root;
  469 
  470         MNT_ILOCK(mp);
  471         mp->mnt_flag |= MNT_LOCAL;
  472         mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
  473             MNTK_NOMSYNC;
  474         if (!nonc && (mp->mnt_flag & MNT_UNION) == 0)
  475                 mp->mnt_kern_flag |= MNTK_FPLOOKUP;
  476         MNT_IUNLOCK(mp);
  477 
  478         mp->mnt_data = tmp;
  479         mp->mnt_stat.f_namemax = MAXNAMLEN;
  480         vfs_getnewfsid(mp);
  481         vfs_mountedfrom(mp, "tmpfs");
  482 
  483         return (0);
  484 }
  485 
  486 /* ARGSUSED2 */
  487 static int
  488 tmpfs_unmount(struct mount *mp, int mntflags)
  489 {
  490         struct tmpfs_mount *tmp;
  491         struct tmpfs_node *node;
  492         int error, flags;
  493 
  494         flags = (mntflags & MNT_FORCE) != 0 ? FORCECLOSE : 0;
  495         tmp = VFS_TO_TMPFS(mp);
  496 
  497         /* Stop writers */
  498         error = vfs_write_suspend_umnt(mp);
  499         if (error != 0)
  500                 return (error);
  501         /*
  502          * At this point, nodes cannot be destroyed by any other
  503          * thread because write suspension is started.
  504          */
  505 
  506         for (;;) {
  507                 error = vflush(mp, 0, flags, curthread);
  508                 if (error != 0) {
  509                         vfs_write_resume(mp, VR_START_WRITE);
  510                         return (error);
  511                 }
  512                 MNT_ILOCK(mp);
  513                 if (mp->mnt_nvnodelistsize == 0) {
  514                         MNT_IUNLOCK(mp);
  515                         break;
  516                 }
  517                 MNT_IUNLOCK(mp);
  518                 if ((mntflags & MNT_FORCE) == 0) {
  519                         vfs_write_resume(mp, VR_START_WRITE);
  520                         return (EBUSY);
  521                 }
  522         }
  523 
  524         TMPFS_LOCK(tmp);
  525         while ((node = LIST_FIRST(&tmp->tm_nodes_used)) != NULL) {
  526                 TMPFS_NODE_LOCK(node);
  527                 if (node->tn_type == VDIR)
  528                         tmpfs_dir_destroy(tmp, node);
  529                 if (tmpfs_free_node_locked(tmp, node, true))
  530                         TMPFS_LOCK(tmp);
  531                 else
  532                         TMPFS_NODE_UNLOCK(node);
  533         }
  534 
  535         mp->mnt_data = NULL;
  536         tmpfs_free_tmp(tmp);
  537         vfs_write_resume(mp, VR_START_WRITE);
  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         /*
  557          * We cannot assert that tmp->tm_pages_used == 0 there,
  558          * because tmpfs vm_objects might be still mapped by some
  559          * process and outlive the mount due to reference counting.
  560          */
  561         MPASS(tmp->tm_nodes_inuse == 0);
  562 
  563         free(tmp, M_TMPFSMNT);
  564 }
  565 
  566 static int
  567 tmpfs_root(struct mount *mp, int flags, struct vnode **vpp)
  568 {
  569         int error;
  570 
  571         error = tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, flags, vpp);
  572         if (error == 0)
  573                 (*vpp)->v_vflag |= VV_ROOT;
  574         return (error);
  575 }
  576 
  577 static int
  578 tmpfs_fhtovp(struct mount *mp, struct fid *fhp, int flags,
  579     struct vnode **vpp)
  580 {
  581         struct tmpfs_fid_data tfd;
  582         struct tmpfs_mount *tmp;
  583         struct tmpfs_node *node;
  584         int error;
  585 
  586         if (fhp->fid_len != sizeof(tfd))
  587                 return (EINVAL);
  588 
  589         /*
  590          * Copy from fid_data onto the stack to avoid unaligned pointer use.
  591          * See the comment in sys/mount.h on struct fid for details.
  592          */
  593         memcpy(&tfd, fhp->fid_data, fhp->fid_len);
  594 
  595         tmp = VFS_TO_TMPFS(mp);
  596 
  597         if (tfd.tfd_id >= tmp->tm_nodes_max)
  598                 return (EINVAL);
  599 
  600         TMPFS_LOCK(tmp);
  601         LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
  602                 if (node->tn_id == tfd.tfd_id &&
  603                     node->tn_gen == tfd.tfd_gen) {
  604                         tmpfs_ref_node(node);
  605                         break;
  606                 }
  607         }
  608         TMPFS_UNLOCK(tmp);
  609 
  610         if (node != NULL) {
  611                 error = tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp);
  612                 tmpfs_free_node(tmp, node);
  613         } else
  614                 error = EINVAL;
  615         return (error);
  616 }
  617 
  618 /* ARGSUSED2 */
  619 static int
  620 tmpfs_statfs(struct mount *mp, struct statfs *sbp)
  621 {
  622         struct tmpfs_mount *tmp;
  623         size_t used;
  624 
  625         tmp = VFS_TO_TMPFS(mp);
  626 
  627         sbp->f_iosize = PAGE_SIZE;
  628         sbp->f_bsize = PAGE_SIZE;
  629 
  630         used = tmpfs_pages_used(tmp);
  631         if (tmp->tm_pages_max != ULONG_MAX)
  632                  sbp->f_blocks = tmp->tm_pages_max;
  633         else
  634                  sbp->f_blocks = used + tmpfs_mem_avail();
  635         if (sbp->f_blocks <= used)
  636                 sbp->f_bavail = 0;
  637         else
  638                 sbp->f_bavail = sbp->f_blocks - used;
  639         sbp->f_bfree = sbp->f_bavail;
  640         used = tmp->tm_nodes_inuse;
  641         sbp->f_files = tmp->tm_nodes_max;
  642         if (sbp->f_files <= used)
  643                 sbp->f_ffree = 0;
  644         else
  645                 sbp->f_ffree = sbp->f_files - used;
  646         /* sbp->f_owner = tmp->tn_uid; */
  647 
  648         return (0);
  649 }
  650 
  651 static int
  652 tmpfs_sync(struct mount *mp, int waitfor)
  653 {
  654 
  655         if (waitfor == MNT_SUSPEND) {
  656                 MNT_ILOCK(mp);
  657                 mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED;
  658                 MNT_IUNLOCK(mp);
  659         } else if (waitfor == MNT_LAZY) {
  660                 tmpfs_update_mtime_lazy(mp);
  661         }
  662         return (0);
  663 }
  664 
  665 static int
  666 tmpfs_init(struct vfsconf *conf)
  667 {
  668         int res;
  669 
  670         res = tmpfs_subr_init();
  671         if (res != 0)
  672                 return (res);
  673         memcpy(&tmpfs_fnops, &vnops, sizeof(struct fileops));
  674         tmpfs_fnops.fo_close = tmpfs_fo_close;
  675         return (0);
  676 }
  677 
  678 static int
  679 tmpfs_uninit(struct vfsconf *conf)
  680 {
  681         tmpfs_subr_uninit();
  682         return (0);
  683 }
  684 
  685 /*
  686  * tmpfs vfs operations.
  687  */
  688 struct vfsops tmpfs_vfsops = {
  689         .vfs_mount =                    tmpfs_mount,
  690         .vfs_unmount =                  tmpfs_unmount,
  691         .vfs_root =                     vfs_cache_root,
  692         .vfs_cachedroot =               tmpfs_root,
  693         .vfs_statfs =                   tmpfs_statfs,
  694         .vfs_fhtovp =                   tmpfs_fhtovp,
  695         .vfs_sync =                     tmpfs_sync,
  696         .vfs_init =                     tmpfs_init,
  697         .vfs_uninit =                   tmpfs_uninit,
  698 };
  699 VFS_SET(tmpfs_vfsops, tmpfs, VFCF_JAIL);
  700 
  701 #ifdef DDB
  702 #include <ddb/ddb.h>
  703 
  704 static void
  705 db_print_tmpfs(struct mount *mp, struct tmpfs_mount *tmp)
  706 {
  707         db_printf("mp %p (%s) tmp %p\n", mp,
  708             mp->mnt_stat.f_mntonname, tmp);
  709         db_printf(
  710             "\tsize max %ju pages max %lu pages used %lu\n"
  711             "\tinodes max %ju inodes inuse %ju refcount %ju\n"
  712             "\tmaxfilesize %ju r%c %snamecache %smtime\n",
  713             (uintmax_t)tmp->tm_size_max, tmp->tm_pages_max, tmp->tm_pages_used,
  714             (uintmax_t)tmp->tm_nodes_max, (uintmax_t)tmp->tm_nodes_inuse,
  715             (uintmax_t)tmp->tm_refcount, (uintmax_t)tmp->tm_maxfilesize,
  716             tmp->tm_ronly ? 'o' : 'w', tmp->tm_nonc ? "no" : "",
  717             tmp->tm_nomtime ? "no" : "");
  718 }
  719 
  720 DB_SHOW_COMMAND(tmpfs, db_show_tmpfs)
  721 {
  722         struct mount *mp;
  723         struct tmpfs_mount *tmp;
  724 
  725         if (have_addr) {
  726                 mp = (struct mount *)addr;
  727                 tmp = VFS_TO_TMPFS(mp);
  728                 db_print_tmpfs(mp, tmp);
  729                 return;
  730         }
  731 
  732         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
  733                 if (strcmp(mp->mnt_stat.f_fstypename, tmpfs_vfsconf.vfc_name) ==
  734                     0) {
  735                         tmp = VFS_TO_TMPFS(mp);
  736                         db_print_tmpfs(mp, tmp);
  737                 }
  738         }
  739 }
  740 #endif  /* DDB */

Cache object: dd01c3ad0a9228eea7a95a417ea69032


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.