kernel - TMPFS - Parse tmpfs_args from mount()
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 18 Feb 2010 18:04:36 +0000 (10:04 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 18 Feb 2010 18:04:36 +0000 (10:04 -0800)
* Parse tmpfs_args from mount() to set max size and inodes.

* Allow a fixed percentage of memory + swap to be used, do not attempt
  to calculate actual free memory + swap (because its impossible to do
  correctly).

sys/vfs/tmpfs/tmpfs.h
sys/vfs/tmpfs/tmpfs_subr.c
sys/vfs/tmpfs/tmpfs_vfsops.c

index 4c1b03d..38aab4a 100644 (file)
@@ -343,11 +343,11 @@ struct tmpfs_mount {
         * used directly as it may be bigger than the current amount of
         * free memory; in the extreme case, it will hold the SIZE_MAX
         * value.  Instead, use the TMPFS_PAGES_MAX macro. */
-       size_t                  tm_pages_max;
+       vm_pindex_t             tm_pages_max;
 
        /* Number of pages in use by the file system.  Cannot be bigger
         * than the value returned by TMPFS_PAGES_MAX in any case. */
-       size_t                  tm_pages_used;
+       vm_pindex_t             tm_pages_used;
 
        /* Pointer to the node representing the root directory of this
         * file system. */
@@ -485,71 +485,6 @@ int        tmpfs_node_ctor(void *obj, void *privdata, int flags);
     KKASSERT((node)->tn_dir.tn_readdir_lastp == NULL || \
        tmpfs_dircookie((node)->tn_dir.tn_readdir_lastp) == (node)->tn_dir.tn_readdir_lastn);
 
-/* --------------------------------------------------------------------- */
-
-/*
- * Memory management stuff.
- */
-
-/* Amount of memory pages to reserve for the system (e.g., to not use by
- * tmpfs).
- * XXX: Should this be tunable through sysctl, for instance? */
-#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
-
-/*
- * Returns information about the number of available memory pages,
- * including physical and virtual ones.
- *
- * If 'total' is TRUE, the value returned is the total amount of memory
- * pages configured for the system (either in use or free).
- * If it is FALSE, the value returned is the amount of free memory pages.
- *
- * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
- * excessive memory usage.
- *
- */
-static __inline size_t
-tmpfs_mem_info(void)
-{
-       size_t size;
-
-       size = vm_swap_size + vmstats.v_free_count + vmstats.v_inactive_count;
-       size -= size > vmstats.v_wire_count ? vmstats.v_wire_count : size;
-       return size;
-}
-
-/* Returns the maximum size allowed for a tmpfs file system.  This macro
- * must be used instead of directly retrieving the value from tm_pages_max.
- * The reason is that the size of a tmpfs file system is dynamic: it lets
- * the user store files as long as there is enough free memory (including
- * physical memory and swap space).  Therefore, the amount of memory to be
- * used is either the limit imposed by the user during mount time or the
- * amount of available memory, whichever is lower.  To avoid consuming all
- * the memory for a given mount point, the system will always reserve a
- * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account
- * by this macro (see above). */
-static __inline size_t
-TMPFS_PAGES_MAX(struct tmpfs_mount *tmp)
-{
-       size_t freepages;
-
-       freepages = tmpfs_mem_info();
-       freepages -= freepages < TMPFS_PAGES_RESERVED ?
-           freepages : TMPFS_PAGES_RESERVED;
-
-       return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used);
-}
-
-/* Returns the available space for the given file system. */
-#define TMPFS_META_PAGES(tmp) (howmany((tmp)->tm_nodes_inuse * (sizeof(struct tmpfs_node) \
-                               + sizeof(struct tmpfs_dirent)), PAGE_SIZE))
-#define TMPFS_FILE_PAGES(tmp) ((tmp)->tm_pages_used)
-
-#define TMPFS_PAGES_AVAIL(tmp) (TMPFS_PAGES_MAX(tmp) > \
-                       TMPFS_META_PAGES(tmp)+TMPFS_FILE_PAGES(tmp)? \
-                       TMPFS_PAGES_MAX(tmp) - TMPFS_META_PAGES(tmp) \
-                       - TMPFS_FILE_PAGES(tmp):0)
-
 #endif
 
 /* --------------------------------------------------------------------- */
index b228248..6771160 100644 (file)
@@ -205,7 +205,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
 void
 tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
 {
-       size_t pages = 0;
+       vm_pindex_t pages = 0;
 
 #ifdef INVARIANTS
        TMPFS_ASSERT_ELOCKED(node);
@@ -921,7 +921,7 @@ int
 tmpfs_reg_resize(struct vnode *vp, off_t newsize, int trivial)
 {
        int error;
-       size_t newpages, oldpages;
+       vm_pindex_t newpages, oldpages;
        struct tmpfs_mount *tmp;
        struct tmpfs_node *node;
        off_t oldsize;
@@ -939,12 +939,12 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize, int trivial)
         * because the last allocated page can accommodate the change on
         * its own. */
        oldsize = node->tn_size;
-       oldpages = round_page(oldsize) / PAGE_SIZE;
+       oldpages = round_page64(oldsize) / PAGE_SIZE;
        KKASSERT(oldpages == node->tn_reg.tn_aobj_pages);
-       newpages = round_page(newsize) / PAGE_SIZE;
+       newpages = round_page64(newsize) / PAGE_SIZE;
 
        if (newpages > oldpages &&
-           newpages - oldpages > TMPFS_PAGES_AVAIL(tmp)) {
+          tmp->tm_pages_used + newpages - oldpages > tmp->tm_pages_max) {
                error = ENOSPC;
                goto out;
        }
index 66179d9..074d34d 100644 (file)
@@ -58,6 +58,7 @@
 
 #include <vfs/tmpfs/tmpfs.h>
 #include <vfs/tmpfs/tmpfs_vnops.h>
+#include <vfs/tmpfs/tmpfs_args.h>
 
 /*
  * Default permission for root node
@@ -77,53 +78,6 @@ static int   tmpfs_root(struct mount *, struct vnode **);
 static int     tmpfs_fhtovp(struct mount *, struct vnode *, struct fid *, struct vnode **);
 static int     tmpfs_statfs(struct mount *, struct statfs *, struct ucred *cred);
 
-/* --------------------------------------------------------------------- */
-
-#define SWI_MAXMIB     3
-static u_int
-get_swpgtotal(void)
-{
-       struct swdevt swinfo;
-       char *sname = "vm.swap_info";
-       int soid[SWI_MAXMIB], oid[2];
-       u_int unswdev, total, dmmax, nswapdev;
-       size_t mibi, len;
-
-       total = 0;
-
-       len = sizeof(dmmax);
-       if (kernel_sysctlbyname("vm.dmmax", &dmmax, &len,
-                               NULL, 0, NULL) != 0)
-               return total;
-
-       len = sizeof(nswapdev);
-       if (kernel_sysctlbyname("vm.nswapdev", &nswapdev, &len,
-                               NULL, 0, NULL) != 0)
-               return total;
-
-       mibi = (SWI_MAXMIB - 1) * sizeof(int);
-       oid[0] = 0;
-       oid[1] = 3;
-
-       if (kernel_sysctl(oid, 2,
-                       soid, &mibi, (void *)sname, strlen(sname),
-                       NULL) != 0)
-               return total;
-
-       mibi = (SWI_MAXMIB - 1);
-       for (unswdev = 0; unswdev < nswapdev; ++unswdev) {
-               soid[mibi] = unswdev;
-               len = sizeof(struct swdevt);
-               if (kernel_sysctl(soid, mibi + 1, &swinfo, &len, NULL, 0,
-                               NULL) != 0)
-                       return total;
-               if (len == sizeof(struct swdevt))
-                       total += (swinfo.sw_nblks - dmmax);
-       }
-
-       return total;
-}
-
 /* --------------------------------------------------------------------- */
 int
 tmpfs_node_ctor(void *obj, void *privdata, int flags)
@@ -180,13 +134,15 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
 {
        struct tmpfs_mount *tmp;
        struct tmpfs_node *root;
-       size_t pages, mem_size;
+       struct tmpfs_args args;
+       vm_pindex_t pages;
+       vm_pindex_t pages_limit;
        ino_t nodes;
        int error;
        /* Size counters. */
-       ino_t   nodes_max = 0;
-       size_t  size_max = 0;
-       size_t size;
+       ino_t   nodes_max;
+       off_t   size_max;
+       size_t  size;
 
        /* Root node attributes. */
        uid_t   root_uid = cred->cr_uid;
@@ -200,12 +156,22 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
                return EOPNOTSUPP;
        }
 
-       /* Do not allow mounts if we do not have enough memory to preserve
-        * the minimum reserved pages. */
-       mem_size = vmstats.v_free_count + vmstats.v_inactive_count + get_swpgtotal();
-       mem_size -= mem_size > vmstats.v_wire_count ? vmstats.v_wire_count : mem_size;
-       if (mem_size < TMPFS_PAGES_RESERVED)
-               return ENOSPC;
+       /*
+        * mount info
+        */
+       bzero(&args, sizeof(args));
+       size_max  = 0;
+       nodes_max = 0;
+
+       if (path) {
+               if (data) {
+                       error = copyin(data, &args, sizeof(args));
+                       if (error)
+                               return (error);
+               }
+               size_max = args.ta_size_max;
+               nodes_max = args.ta_nodes_max;
+       }
 
        /*
         * If mount by non-root, then verify that user has necessary
@@ -217,34 +183,38 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
                        root_mode |= VWRITE;
        }
 
-       /* Get the maximum number of memory pages this file system is
-        * allowed to use, based on the maximum size the user passed in
-        * the mount structure.  A value of zero is treated as if the
-        * maximum available space was requested. */
-       if (size_max < PAGE_SIZE || size_max >= SIZE_MAX)
-               pages = SIZE_MAX;
+       pages_limit = vm_swap_max + vmstats.v_page_count / 2;
+
+       if (size_max == 0)
+               pages = pages_limit / 2;
+       else if (size_max < PAGE_SIZE)
+               pages = 1;
+       else if (OFF_TO_IDX(size_max) > pages_limit)
+               pages = pages_limit;
        else
-               pages = howmany(size_max, PAGE_SIZE);
-       KKASSERT(pages > 0);
+               pages = OFF_TO_IDX(size_max);
 
-       if (nodes_max <= 3)
+       if (nodes_max == 0)
                nodes = 3 + pages * PAGE_SIZE / 1024;
+       else if (nodes_max < 3)
+               nodes = 3;
+       else if (nodes_max > pages)
+               nodes = pages;
        else
                nodes = nodes_max;
-       KKASSERT(nodes >= 3);
 
        /* Allocate the tmpfs mount structure and fill it. */
-       tmp = (struct tmpfs_mount *)kmalloc(sizeof(struct tmpfs_mount),
-           M_TMPFSMNT, M_WAITOK | M_ZERO);
+       tmp = kmalloc(sizeof(*tmp), M_TMPFSMNT, M_WAITOK | M_ZERO);
 
        lockinit(&(tmp->allnode_lock), "tmpfs allnode lock", 0, LK_CANRECURSE);
        tmp->tm_nodes_max = nodes;
        tmp->tm_nodes_inuse = 0;
-       tmp->tm_maxfilesize = (u_int64_t)(vmstats.v_page_count + get_swpgtotal()) * PAGE_SIZE;
+       tmp->tm_maxfilesize = IDX_TO_OFF(pages_limit);
        LIST_INIT(&tmp->tm_nodes_used);
 
        tmp->tm_pages_max = pages;
        tmp->tm_pages_used = 0;
+
        tmp->tm_dirent_pool =  objcache_create( "tmpfs dirent cache",
            0, 0,
            NULL, NULL, NULL,
@@ -471,11 +441,11 @@ tmpfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
        sbp->f_iosize = PAGE_SIZE;
        sbp->f_bsize = PAGE_SIZE;
 
-       sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
-       sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
+       sbp->f_blocks = tmp->tm_pages_max;
+       sbp->f_bavail = tmp->tm_pages_max - tmp->tm_pages_used;
+       sbp->f_bfree = sbp->f_bavail;
 
-       freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse,
-           TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
+       freenodes = tmp->tm_nodes_max - tmp->tm_nodes_inuse;
 
        sbp->f_files = freenodes + tmp->tm_nodes_inuse;
        sbp->f_ffree = freenodes;