From: Matthew Dillon Date: Thu, 18 Feb 2010 18:04:36 +0000 (-0800) Subject: kernel - TMPFS - Parse tmpfs_args from mount() X-Git-Tag: v2.7.0~177 X-Git-Url: https://gitweb.dragonflybsd.org/~nant/dragonfly.git/commitdiff_plain/29ffeb2816b19dccdc5f4a994e9255f69e2a589d kernel - TMPFS - Parse tmpfs_args from mount() * 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). --- diff --git a/sys/vfs/tmpfs/tmpfs.h b/sys/vfs/tmpfs/tmpfs.h index 4c1b03da53..38aab4a0a5 100644 --- a/sys/vfs/tmpfs/tmpfs.h +++ b/sys/vfs/tmpfs/tmpfs.h @@ -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 /* --------------------------------------------------------------------- */ diff --git a/sys/vfs/tmpfs/tmpfs_subr.c b/sys/vfs/tmpfs/tmpfs_subr.c index b228248de9..6771160dfb 100644 --- a/sys/vfs/tmpfs/tmpfs_subr.c +++ b/sys/vfs/tmpfs/tmpfs_subr.c @@ -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; } diff --git a/sys/vfs/tmpfs/tmpfs_vfsops.c b/sys/vfs/tmpfs/tmpfs_vfsops.c index 66179d99f7..074d34d22c 100644 --- a/sys/vfs/tmpfs/tmpfs_vfsops.c +++ b/sys/vfs/tmpfs/tmpfs_vfsops.c @@ -58,6 +58,7 @@ #include #include +#include /* * 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;