Module Name: src
Committed By: rmind
Date: Tue Jun 22 18:32:08 UTC 2010
Modified Files:
src/sys/fs/tmpfs: TODO files.tmpfs tmpfs.h tmpfs_subr.c tmpfs_vfsops.c
tmpfs_vnops.c
src/sys/modules/tmpfs: Makefile
src/sys/rump/fs/lib/libtmpfs: Makefile
Added Files:
src/sys/fs/tmpfs: tmpfs_mem.c
Removed Files:
src/sys/fs/tmpfs: tmpfs_pool.c tmpfs_pool.h
Log Message:
Replace tmpfs_pool custom allocator code with a simpler layer for memory
accounting. Use wired memory (which can be limited) for meta-data, and
kmem(9) for string allocations.
Close PR/31944. Fix PR/38361 while here. OK a...@.
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/fs/tmpfs/TODO
cvs rdiff -u -r1.3 -r1.4 src/sys/fs/tmpfs/files.tmpfs
cvs rdiff -u -r1.37 -r1.38 src/sys/fs/tmpfs/tmpfs.h
cvs rdiff -u -r0 -r1.1 src/sys/fs/tmpfs/tmpfs_mem.c
cvs rdiff -u -r1.14 -r0 src/sys/fs/tmpfs/tmpfs_pool.c
cvs rdiff -u -r1.7 -r0 src/sys/fs/tmpfs/tmpfs_pool.h
cvs rdiff -u -r1.56 -r1.57 src/sys/fs/tmpfs/tmpfs_subr.c
cvs rdiff -u -r1.44 -r1.45 src/sys/fs/tmpfs/tmpfs_vfsops.c
cvs rdiff -u -r1.69 -r1.70 src/sys/fs/tmpfs/tmpfs_vnops.c
cvs rdiff -u -r1.1 -r1.2 src/sys/modules/tmpfs/Makefile
cvs rdiff -u -r1.3 -r1.4 src/sys/rump/fs/lib/libtmpfs/Makefile
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/fs/tmpfs/TODO
diff -u src/sys/fs/tmpfs/TODO:1.6 src/sys/fs/tmpfs/TODO:1.7
--- src/sys/fs/tmpfs/TODO:1.6 Thu Nov 9 15:06:03 2006
+++ src/sys/fs/tmpfs/TODO Tue Jun 22 18:32:07 2010
@@ -1,8 +1,3 @@
-- File meta-data is stored using memory pools. These use, at the moment,
- wired kernel memory, which is not acceptable because it is easy to turn
- the system unstable by exhausting it. Therefore, a pool allocator that
- uses anonymous memory has to be written.
-
- Verify that file holes work (they should, but must be checked). Add a
regression test for this feature.
Index: src/sys/fs/tmpfs/files.tmpfs
diff -u src/sys/fs/tmpfs/files.tmpfs:1.3 src/sys/fs/tmpfs/files.tmpfs:1.4
--- src/sys/fs/tmpfs/files.tmpfs:1.3 Tue Mar 2 16:43:48 2010
+++ src/sys/fs/tmpfs/files.tmpfs Tue Jun 22 18:32:07 2010
@@ -1,9 +1,9 @@
-# $NetBSD: files.tmpfs,v 1.3 2010/03/02 16:43:48 pooka Exp $
+# $NetBSD: files.tmpfs,v 1.4 2010/06/22 18:32:07 rmind Exp $
deffs TMPFS
file fs/tmpfs/tmpfs_fifoops.c tmpfs
-file fs/tmpfs/tmpfs_pool.c tmpfs
+file fs/tmpfs/tmpfs_mem.c tmpfs
file fs/tmpfs/tmpfs_specops.c tmpfs
file fs/tmpfs/tmpfs_subr.c tmpfs
file fs/tmpfs/tmpfs_vfsops.c tmpfs
Index: src/sys/fs/tmpfs/tmpfs.h
diff -u src/sys/fs/tmpfs/tmpfs.h:1.37 src/sys/fs/tmpfs/tmpfs.h:1.38
--- src/sys/fs/tmpfs/tmpfs.h:1.37 Tue Jul 29 09:10:09 2008
+++ src/sys/fs/tmpfs/tmpfs.h Tue Jun 22 18:32:07 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs.h,v 1.37 2008/07/29 09:10:09 pooka Exp $ */
+/* $NetBSD: tmpfs.h,v 1.38 2010/06/22 18:32:07 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -35,19 +35,10 @@
#include <sys/dirent.h>
#include <sys/mount.h>
+#include <sys/pool.h>
#include <sys/queue.h>
#include <sys/vnode.h>
-/* --------------------------------------------------------------------- */
-/* For the kernel and anyone who likes peeking into kernel memory */
-/* --------------------------------------------------------------------- */
-
-#if defined(_KERNEL)
-#include <fs/tmpfs/tmpfs_pool.h>
-#endif /* defined(_KERNEL) */
-
-/* --------------------------------------------------------------------- */
-
/*
* Internal representation of a tmpfs directory entry.
*/
@@ -281,16 +272,10 @@
* Internal representation of a tmpfs mount point.
*/
struct tmpfs_mount {
- /* Maximum number of memory pages available for use by the file
- * system, set during mount time. This variable must never be
- * 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. */
- unsigned int 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. */
- unsigned int tm_pages_used;
+ /* Limit and number of bytes in use by the file system. */
+ uint64_t tm_mem_limit;
+ uint64_t tm_bytes_used;
+ kmutex_t tm_acc_lock;
/* Pointer to the node representing the root directory of this
* file system. */
@@ -313,12 +298,10 @@
kmutex_t tm_lock;
struct tmpfs_node_list tm_nodes;
- /* Pools used to store file system meta data. These are not shared
- * across several instances of tmpfs for the reasons described in
- * tmpfs_pool.c. */
- struct tmpfs_pool tm_dirent_pool;
- struct tmpfs_pool tm_node_pool;
- struct tmpfs_str_pool tm_str_pool;
+ char tm_dwchan[32];
+ struct pool tm_dirent_pool;
+ char tm_nwchan[32];
+ struct pool tm_node_pool;
};
/* --------------------------------------------------------------------- */
@@ -361,7 +344,6 @@
struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
int tmpfs_reg_resize(struct vnode *, off_t);
-size_t tmpfs_mem_info(bool);
int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *);
int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *);
@@ -376,6 +358,29 @@
const struct timespec *, const struct timespec *, int);
int tmpfs_truncate(struct vnode *, off_t);
+/*
+ * Prototypes for tmpfs_mem.c.
+ */
+
+void tmpfs_mntmem_init(struct tmpfs_mount *, uint64_t);
+void tmpfs_mntmem_destroy(struct tmpfs_mount *);
+
+size_t tmpfs_mem_info(bool);
+uint64_t tmpfs_bytes_max(struct tmpfs_mount *);
+size_t tmpfs_pages_avail(struct tmpfs_mount *);
+bool tmpfs_mem_incr(struct tmpfs_mount *, size_t);
+void tmpfs_mem_decr(struct tmpfs_mount *, size_t);
+
+struct tmpfs_dirent *tmpfs_dirent_get(struct tmpfs_mount *);
+void tmpfs_dirent_put(struct tmpfs_mount *, struct tmpfs_dirent *);
+
+struct tmpfs_node *tmpfs_node_get(struct tmpfs_mount *);
+void tmpfs_node_put(struct tmpfs_mount *, struct tmpfs_node *);
+
+char * tmpfs_strname_alloc(struct tmpfs_mount *, size_t);
+void tmpfs_strname_free(struct tmpfs_mount *, char *, size_t);
+bool tmpfs_strname_neqlen(struct componentname *, struct componentname *);
+
/* --------------------------------------------------------------------- */
/*
@@ -418,36 +423,6 @@
* XXX: Should this be tunable through sysctl, for instance? */
#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_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(false);
- if (freepages < TMPFS_PAGES_RESERVED)
- freepages = 0;
- else
- 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_PAGES_AVAIL(tmp) \
- ((ssize_t)(TMPFS_PAGES_MAX(tmp) - (tmp)->tm_pages_used))
-
-/* --------------------------------------------------------------------- */
-
/*
* Macros/functions to convert from generic data structures to tmpfs
* specific ones.
Index: src/sys/fs/tmpfs/tmpfs_subr.c
diff -u src/sys/fs/tmpfs/tmpfs_subr.c:1.56 src/sys/fs/tmpfs/tmpfs_subr.c:1.57
--- src/sys/fs/tmpfs/tmpfs_subr.c:1.56 Wed Nov 11 09:59:41 2009
+++ src/sys/fs/tmpfs/tmpfs_subr.c Tue Jun 22 18:32:08 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_subr.c,v 1.56 2009/11/11 09:59:41 rmind Exp $ */
+/* $NetBSD: tmpfs_subr.c,v 1.57 2010/06/22 18:32:08 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.56 2009/11/11 09:59:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.57 2010/06/22 18:32:08 rmind Exp $");
#include <sys/param.h>
#include <sys/dirent.h>
@@ -107,7 +107,7 @@
return ENOSPC;
}
- nnode = (struct tmpfs_node *)TMPFS_POOL_GET(&tmp->tm_node_pool, 0);
+ nnode = tmpfs_node_get(tmp);
if (nnode == NULL) {
atomic_dec_uint(&tmp->tm_nodes_cnt);
return ENOSPC;
@@ -164,10 +164,10 @@
KASSERT(strlen(target) < MAXPATHLEN);
nnode->tn_size = strlen(target);
nnode->tn_spec.tn_lnk.tn_link =
- tmpfs_str_pool_get(&tmp->tm_str_pool, nnode->tn_size, 0);
+ tmpfs_strname_alloc(tmp, nnode->tn_size);
if (nnode->tn_spec.tn_lnk.tn_link == NULL) {
atomic_dec_uint(&tmp->tm_nodes_cnt);
- TMPFS_POOL_PUT(&tmp->tm_node_pool, nnode);
+ tmpfs_node_put(tmp, nnode);
return ENOSPC;
}
memcpy(nnode->tn_spec.tn_lnk.tn_link, target, nnode->tn_size);
@@ -215,33 +215,37 @@
void
tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
{
+ size_t objsz;
- if (node->tn_type == VREG) {
- atomic_add_int(&tmp->tm_pages_used,
- -node->tn_spec.tn_reg.tn_aobj_pages);
- }
- atomic_dec_uint(&tmp->tm_nodes_cnt);
mutex_enter(&tmp->tm_lock);
LIST_REMOVE(node, tn_entries);
mutex_exit(&tmp->tm_lock);
+ atomic_dec_uint(&tmp->tm_nodes_cnt);
switch (node->tn_type) {
case VLNK:
- tmpfs_str_pool_put(&tmp->tm_str_pool,
- node->tn_spec.tn_lnk.tn_link, node->tn_size);
+ tmpfs_strname_free(tmp, node->tn_spec.tn_lnk.tn_link,
+ node->tn_size);
break;
-
case VREG:
- if (node->tn_spec.tn_reg.tn_aobj != NULL)
+ /*
+ * Calculate the size of node data, decrease the used-memory
+ * counter, and destroy the memory object (if any).
+ */
+ objsz = PAGE_SIZE * node->tn_spec.tn_reg.tn_aobj_pages;
+ if (objsz != 0) {
+ tmpfs_mem_decr(tmp, objsz);
+ }
+ if (node->tn_spec.tn_reg.tn_aobj != NULL) {
uao_detach(node->tn_spec.tn_reg.tn_aobj);
+ }
break;
-
default:
break;
}
mutex_destroy(&node->tn_vlock);
- TMPFS_POOL_PUT(&tmp->tm_node_pool, node);
+ tmpfs_node_put(tmp, node);
}
/* --------------------------------------------------------------------- */
@@ -262,13 +266,13 @@
{
struct tmpfs_dirent *nde;
- nde = (struct tmpfs_dirent *)TMPFS_POOL_GET(&tmp->tm_dirent_pool, 0);
+ nde = tmpfs_dirent_get(tmp);
if (nde == NULL)
return ENOSPC;
- nde->td_name = tmpfs_str_pool_get(&tmp->tm_str_pool, len, 0);
+ nde->td_name = tmpfs_strname_alloc(tmp, len);
if (nde->td_name == NULL) {
- TMPFS_POOL_PUT(&tmp->tm_dirent_pool, nde);
+ tmpfs_dirent_put(tmp, nde);
return ENOSPC;
}
nde->td_namelen = len;
@@ -317,8 +321,8 @@
NOTE_LINK);
}
- tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, de->td_namelen);
- TMPFS_POOL_PUT(&tmp->tm_dirent_pool, de);
+ tmpfs_strname_free(tmp, de->td_name, de->td_namelen);
+ tmpfs_dirent_put(tmp, de);
}
/* --------------------------------------------------------------------- */
@@ -855,8 +859,7 @@
int
tmpfs_reg_resize(struct vnode *vp, off_t newsize)
{
- int error;
- unsigned int newpages, oldpages;
+ size_t newpages, oldpages;
struct tmpfs_mount *tmp;
struct tmpfs_node *node;
off_t oldsize;
@@ -867,29 +870,20 @@
node = VP_TO_TMPFS_NODE(vp);
tmp = VFS_TO_TMPFS(vp->v_mount);
- /* Convert the old and new sizes to the number of pages needed to
- * store them. It may happen that we do not need to do anything
- * because the last allocated page can accommodate the change on
- * its own. */
oldsize = node->tn_size;
- oldpages = round_page(oldsize) / PAGE_SIZE;
+ oldpages = round_page(oldsize) >> PAGE_SHIFT;
+ newpages = round_page(newsize) >> PAGE_SHIFT;
KASSERT(oldpages == node->tn_spec.tn_reg.tn_aobj_pages);
- newpages = round_page(newsize) / PAGE_SIZE;
- if (newpages > oldpages &&
- (ssize_t)(newpages - oldpages) > TMPFS_PAGES_AVAIL(tmp)) {
- error = ENOSPC;
- goto out;
- }
- atomic_add_int(&tmp->tm_pages_used, newpages - oldpages);
-
- if (newsize < oldsize) {
+ if (newpages > oldpages) {
+ /* Increase the used-memory counter if getting extra pages. */
+ if (!tmpfs_mem_incr(tmp, (newpages - oldpages) << PAGE_SHIFT)) {
+ return ENOSPC;
+ }
+ } else if (newsize < oldsize) {
int zerolen = MIN(round_page(newsize), node->tn_size) - newsize;
- /*
- * zero out the truncated part of the last page.
- */
-
+ /* Zero out the truncated part of the last page. */
uvm_vnp_zerorange(vp, newsize, zerolen);
}
@@ -898,9 +892,8 @@
uvm_vnp_setsize(vp, newsize);
/*
- * free "backing store"
+ * Free "backing store".
*/
-
if (newpages < oldpages) {
struct uvm_object *uobj;
@@ -909,54 +902,17 @@
mutex_enter(&uobj->vmobjlock);
uao_dropswap_range(uobj, newpages, oldpages);
mutex_exit(&uobj->vmobjlock);
- }
- error = 0;
+ /* Decrease the used-memory counter. */
+ tmpfs_mem_decr(tmp, (oldpages - newpages) << PAGE_SHIFT);
+ }
if (newsize > oldsize)
VN_KNOTE(vp, NOTE_EXTEND);
-out:
- return error;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * 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.
- *
- */
-size_t
-tmpfs_mem_info(bool total)
-{
- size_t size;
-
- size = 0;
- size += uvmexp.swpgavail;
- if (!total) {
- size -= uvmexp.swpgonly;
- }
- size += uvmexp.free;
- size += uvmexp.filepages;
- if (size > uvmexp.wired) {
- size -= uvmexp.wired;
- } else {
- size = 0;
- }
-
- return size;
+ return 0;
}
-/* --------------------------------------------------------------------- */
-
/*
* Change flags of the given vnode.
* Caller should execute tmpfs_update on vp after a successful execution.
Index: src/sys/fs/tmpfs/tmpfs_vfsops.c
diff -u src/sys/fs/tmpfs/tmpfs_vfsops.c:1.44 src/sys/fs/tmpfs/tmpfs_vfsops.c:1.45
--- src/sys/fs/tmpfs/tmpfs_vfsops.c:1.44 Tue Jul 29 09:10:09 2008
+++ src/sys/fs/tmpfs/tmpfs_vfsops.c Tue Jun 22 18:32:08 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_vfsops.c,v 1.44 2008/07/29 09:10:09 pooka Exp $ */
+/* $NetBSD: tmpfs_vfsops.c,v 1.45 2010/06/22 18:32:08 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.44 2008/07/29 09:10:09 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.45 2010/06/22 18:32:08 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -81,13 +81,12 @@
static int
tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
{
- struct lwp *l = curlwp;
- int error;
- ino_t nodes;
- size_t pages;
struct tmpfs_mount *tmp;
struct tmpfs_node *root;
struct tmpfs_args *args = data;
+ uint64_t memlimit;
+ ino_t nodes;
+ int error;
if (*data_len < sizeof *args)
return EINVAL;
@@ -100,14 +99,14 @@
args->ta_version = TMPFS_ARGS_VERSION;
args->ta_nodes_max = tmp->tm_nodes_max;
- args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE;
+ args->ta_size_max = tmp->tm_mem_limit;
root = tmp->tm_root;
args->ta_root_uid = root->tn_uid;
args->ta_root_gid = root->tn_gid;
args->ta_root_mode = root->tn_mode;
- *data_len = sizeof *args;
+ *data_len = sizeof(*args);
return 0;
}
@@ -126,25 +125,20 @@
if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
return EINVAL;
- /* 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 (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX)
- pages = SIZE_MAX;
- else
- pages = args->ta_size_max / PAGE_SIZE +
- (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1);
- if (pages > INT_MAX)
- pages = INT_MAX;
- KASSERT(pages > 0);
-
- if (args->ta_nodes_max <= 3)
- nodes = 3 + pages * PAGE_SIZE / 1024;
- else
+ /* Get the memory usage limit for this file-system. */
+ if (args->ta_size_max < PAGE_SIZE) {
+ memlimit = UINT64_MAX;
+ } else {
+ memlimit = args->ta_size_max;
+ }
+ KASSERT(memlimit > 0);
+
+ if (args->ta_nodes_max <= 3) {
+ nodes = 3 + (memlimit / 1024);
+ } else {
nodes = args->ta_nodes_max;
- if (nodes > INT_MAX)
- nodes = INT_MAX;
+ }
+ nodes = MIN(nodes, INT_MAX);
KASSERT(nodes >= 3);
/* Allocate the tmpfs mount structure and fill it. */
@@ -157,14 +151,7 @@
LIST_INIT(&tmp->tm_nodes);
mutex_init(&tmp->tm_lock, MUTEX_DEFAULT, IPL_NONE);
-
- tmp->tm_pages_max = pages;
- tmp->tm_pages_used = 0;
- tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent),
- "dirent", tmp);
- tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node),
- "node", tmp);
- tmpfs_str_pool_init(&tmp->tm_str_pool, tmp);
+ tmpfs_mntmem_init(tmp, memlimit);
/* Allocate the root node. */
error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
@@ -183,7 +170,7 @@
vfs_getnewfsid(mp);
return set_statvfs_info(path, UIO_USERSPACE, "tmpfs", UIO_SYSSPACE,
- mp->mnt_op->vfs_name, mp, l);
+ mp->mnt_op->vfs_name, mp, curlwp);
}
/* --------------------------------------------------------------------- */
@@ -245,13 +232,8 @@
node = next;
}
- tmpfs_pool_destroy(&tmp->tm_dirent_pool);
- tmpfs_pool_destroy(&tmp->tm_node_pool);
- tmpfs_str_pool_destroy(&tmp->tm_str_pool);
-
- KASSERT(tmp->tm_pages_used == 0);
-
/* Throw away the tmpfs_mount structure. */
+ tmpfs_mntmem_destroy(tmp);
mutex_destroy(&tmp->tm_lock);
kmem_free(tmp, sizeof(*tmp));
mp->mnt_data = NULL;
@@ -340,7 +322,6 @@
/* --------------------------------------------------------------------- */
-/* ARGSUSED2 */
static int
tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
{
@@ -351,12 +332,12 @@
sbp->f_iosize = sbp->f_frsize = 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 = (tmpfs_bytes_max(tmp) >> PAGE_SHIFT);
+ sbp->f_bavail = sbp->f_bfree = tmpfs_pages_avail(tmp);
sbp->f_bresvd = 0;
freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_cnt,
- TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
+ tmpfs_pages_avail(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
sbp->f_files = tmp->tm_nodes_cnt + freenodes;
sbp->f_favail = sbp->f_ffree = freenodes;
Index: src/sys/fs/tmpfs/tmpfs_vnops.c
diff -u src/sys/fs/tmpfs/tmpfs_vnops.c:1.69 src/sys/fs/tmpfs/tmpfs_vnops.c:1.70
--- src/sys/fs/tmpfs/tmpfs_vnops.c:1.69 Fri Apr 23 15:38:47 2010
+++ src/sys/fs/tmpfs/tmpfs_vnops.c Tue Jun 22 18:32:08 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $ */
+/* $NetBSD: tmpfs_vnops.c,v 1.70 2010/06/22 18:32:08 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.70 2010/06/22 18:32:08 rmind Exp $");
#include <sys/param.h>
#include <sys/dirent.h>
@@ -861,6 +861,16 @@
goto out_unlocked;
}
+ /* Allocate memory, if necessary, for a new name. */
+ namelen = tcnp->cn_namelen;
+ if (tmpfs_strname_neqlen(fcnp, tcnp)) {
+ newname = tmpfs_strname_alloc(tmp, namelen);
+ if (newname == NULL) {
+ error = ENOSPC;
+ goto out_unlocked;
+ }
+ }
+
/* If we need to move the directory between entries, lock the
* source so that we can safely operate on it. */
@@ -910,18 +920,6 @@
}
}
- /* Ensure that we have enough memory to hold the new name, if it
- * has to be changed. */
- namelen = tcnp->cn_namelen;
- if (fcnp->cn_namelen != tcnp->cn_namelen ||
- memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
- newname = tmpfs_str_pool_get(&tmp->tm_str_pool, namelen, 0);
- if (newname == NULL) {
- error = ENOSPC;
- goto out;
- }
- }
-
/* If the node is being moved to another directory, we have to do
* the move. */
if (fdnode != tdnode) {
@@ -989,8 +987,7 @@
KASSERT(tcnp->cn_namelen < MAXNAMLEN);
KASSERT(tcnp->cn_namelen < 0xffff);
- tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name,
- de->td_namelen);
+ tmpfs_strname_free(tmp, de->td_name, de->td_namelen);
de->td_namelen = (uint16_t)namelen;
memcpy(newname, tcnp->cn_nameptr, namelen);
de->td_name = newname;
@@ -1025,9 +1022,9 @@
vrele(fdvp);
vrele(fvp);
- if (newname != NULL)
- tmpfs_str_pool_put(&tmp->tm_str_pool, newname, namelen);
-
+ if (newname != NULL) {
+ tmpfs_strname_free(tmp, newname, namelen);
+ }
return error;
}
Index: src/sys/modules/tmpfs/Makefile
diff -u src/sys/modules/tmpfs/Makefile:1.1 src/sys/modules/tmpfs/Makefile:1.2
--- src/sys/modules/tmpfs/Makefile:1.1 Sat Jun 28 16:11:36 2008
+++ src/sys/modules/tmpfs/Makefile Tue Jun 22 18:32:08 2010
@@ -1,11 +1,11 @@
-# $NetBSD: Makefile,v 1.1 2008/06/28 16:11:36 rumble Exp $
+# $NetBSD: Makefile,v 1.2 2010/06/22 18:32:08 rmind Exp $
.include "../Makefile.inc"
.PATH: ${S}/fs/tmpfs
KMOD= tmpfs
-SRCS= tmpfs_fifoops.c tmpfs_pool.c tmpfs_specops.c tmpfs_subr.c \
+SRCS= tmpfs_fifoops.c tmpfs_mem.c tmpfs_specops.c tmpfs_subr.c \
tmpfs_vfsops.c tmpfs_vnops.c
.include <bsd.kmodule.mk>
Index: src/sys/rump/fs/lib/libtmpfs/Makefile
diff -u src/sys/rump/fs/lib/libtmpfs/Makefile:1.3 src/sys/rump/fs/lib/libtmpfs/Makefile:1.4
--- src/sys/rump/fs/lib/libtmpfs/Makefile:1.3 Tue Jul 29 13:17:43 2008
+++ src/sys/rump/fs/lib/libtmpfs/Makefile Tue Jun 22 18:32:08 2010
@@ -1,11 +1,11 @@
-# $NetBSD: Makefile,v 1.3 2008/07/29 13:17:43 pooka Exp $
+# $NetBSD: Makefile,v 1.4 2010/06/22 18:32:08 rmind Exp $
#
.PATH: ${.CURDIR}/../../../../fs/tmpfs
LIB= rumpfs_tmpfs
-SRCS= tmpfs_fifoops.c tmpfs_specops.c tmpfs_vfsops.c tmpfs_pool.c \
+SRCS= tmpfs_fifoops.c tmpfs_specops.c tmpfs_vfsops.c tmpfs_mem.c \
tmpfs_subr.c tmpfs_vnops.c
.include <bsd.lib.mk>
Added files:
Index: src/sys/fs/tmpfs/tmpfs_mem.c
diff -u /dev/null src/sys/fs/tmpfs/tmpfs_mem.c:1.1
--- /dev/null Tue Jun 22 18:32:08 2010
+++ src/sys/fs/tmpfs/tmpfs_mem.c Tue Jun 22 18:32:07 2010
@@ -0,0 +1,219 @@
+/* $NetBSD: tmpfs_mem.c,v 1.1 2010/06/22 18:32:07 rmind Exp $ */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * tmpfs memory allocation routines.
+ * Implements memory usage accounting and limiting.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: tmpfs_mem.c,v 1.1 2010/06/22 18:32:07 rmind Exp $");
+
+#include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/kmem.h>
+#include <sys/namei.h>
+#include <sys/pool.h>
+
+#include <fs/tmpfs/tmpfs.h>
+
+void
+tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit)
+{
+
+ sprintf(mp->tm_dwchan, "tmpfs_dirent_%p", mp);
+ pool_init(&mp->tm_dirent_pool, sizeof(struct tmpfs_dirent), 0, 0, 0,
+ mp->tm_dwchan, &pool_allocator_nointr, IPL_NONE);
+
+ sprintf(mp->tm_nwchan, "tmpfs_node_%p", mp);
+ pool_init(&mp->tm_node_pool, sizeof(struct tmpfs_node), 0, 0, 0,
+ mp->tm_dwchan, &pool_allocator_nointr, IPL_NONE);
+
+ mutex_init(&mp->tm_acc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mp->tm_mem_limit = memlimit;
+ mp->tm_bytes_used = 0;
+}
+
+void
+tmpfs_mntmem_destroy(struct tmpfs_mount *mp)
+{
+
+ KASSERT(mp->tm_bytes_used == 0);
+ mutex_destroy(&mp->tm_acc_lock);
+ pool_destroy(&mp->tm_dirent_pool);
+ pool_destroy(&mp->tm_node_pool);
+}
+
+/*
+ * tmpfs_mem_info: return the number of available memory pages.
+ *
+ * => If 'total' is true, then return _total_ amount of pages.
+ * => If false, then return the amount of _free_ memory pages.
+ *
+ * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
+ * excessive memory usage.
+ */
+size_t
+tmpfs_mem_info(bool total)
+{
+ size_t size = 0;
+
+ /* XXX: unlocked */
+ size += uvmexp.swpgavail;
+ if (!total) {
+ size -= uvmexp.swpgonly;
+ }
+ size += uvmexp.free;
+ size += uvmexp.filepages;
+ if (size > uvmexp.wired) {
+ size -= uvmexp.wired;
+ } else {
+ size = 0;
+ }
+ return size;
+}
+
+uint64_t
+tmpfs_bytes_max(struct tmpfs_mount *mp)
+{
+ size_t freepages = tmpfs_mem_info(false);
+ uint64_t avail_mem;
+
+ if (freepages < TMPFS_PAGES_RESERVED) {
+ freepages = 0;
+ } else {
+ freepages -= TMPFS_PAGES_RESERVED;
+ }
+ avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT);
+ return min(mp->tm_mem_limit, avail_mem);
+}
+
+size_t
+tmpfs_pages_avail(struct tmpfs_mount *mp)
+{
+
+ return (tmpfs_bytes_max(mp) - mp->tm_bytes_used) >> PAGE_SHIFT;
+}
+
+bool
+tmpfs_mem_incr(struct tmpfs_mount *mp, size_t sz)
+{
+ const uint64_t lim = tmpfs_bytes_max(mp);
+
+ mutex_enter(&mp->tm_acc_lock);
+ if (mp->tm_bytes_used + sz >= lim) {
+ mutex_exit(&mp->tm_acc_lock);
+ return false;
+ }
+ mp->tm_bytes_used += sz;
+ mutex_exit(&mp->tm_acc_lock);
+ return true;
+}
+
+void
+tmpfs_mem_decr(struct tmpfs_mount *mp, size_t sz)
+{
+
+ mutex_enter(&mp->tm_acc_lock);
+ KASSERT(mp->tm_bytes_used >= sz);
+ mp->tm_bytes_used -= sz;
+ mutex_exit(&mp->tm_acc_lock);
+}
+
+struct tmpfs_dirent *
+tmpfs_dirent_get(struct tmpfs_mount *mp)
+{
+
+ if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_dirent))) {
+ return NULL;
+ }
+ return pool_get(&mp->tm_dirent_pool, PR_WAITOK);
+}
+
+void
+tmpfs_dirent_put(struct tmpfs_mount *mp, struct tmpfs_dirent *de)
+{
+
+ tmpfs_mem_decr(mp, sizeof(struct tmpfs_dirent));
+ pool_put(&mp->tm_dirent_pool, de);
+}
+
+struct tmpfs_node *
+tmpfs_node_get(struct tmpfs_mount *mp)
+{
+
+ if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_node))) {
+ return NULL;
+ }
+ return pool_get(&mp->tm_node_pool, PR_WAITOK);
+}
+
+void
+tmpfs_node_put(struct tmpfs_mount *mp, struct tmpfs_node *tn)
+{
+
+ tmpfs_mem_decr(mp, sizeof(struct tmpfs_node));
+ pool_put(&mp->tm_node_pool, tn);
+}
+
+/*
+ * Quantum size to round-up the tmpfs names in order to reduce re-allocations.
+ */
+
+#define TMPFS_NAME_QUANTUM (32)
+
+char *
+tmpfs_strname_alloc(struct tmpfs_mount *mp, size_t len)
+{
+ const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
+
+ KASSERT(sz > 0 && sz <= 1024);
+ if (!tmpfs_mem_incr(mp, sz)) {
+ return NULL;
+ }
+ return kmem_alloc(sz, KM_SLEEP);
+}
+
+void
+tmpfs_strname_free(struct tmpfs_mount *mp, char *str, size_t len)
+{
+ const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);
+
+ KASSERT(sz > 0 && sz <= 1024);
+ tmpfs_mem_decr(mp, sz);
+ kmem_free(str, sz);
+}
+
+bool
+tmpfs_strname_neqlen(struct componentname *fcnp, struct componentname *tcnp)
+{
+ const size_t fln = roundup2(fcnp->cn_namelen, TMPFS_NAME_QUANTUM);
+ const size_t tln = roundup2(tcnp->cn_namelen, TMPFS_NAME_QUANTUM);
+
+ return (fln != tln) || memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fln);
+}