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);
+}

Reply via email to