Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Apr 2012 15:23:52 +0000 (UTC)
From:      Gleb Kurtsou <gleb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r233998 - head/sys/fs/tmpfs
Message-ID:  <201204071523.q37FNqxN067629@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gleb
Date: Sat Apr  7 15:23:51 2012
New Revision: 233998
URL: http://svn.freebsd.org/changeset/base/233998

Log:
  Add reserved memory limit sysctl to tmpfs.
  
  Cleanup availble and used memory functions.
  Check if free pages available before allocating new node.
  
  Discussed with:	delphij

Modified:
  head/sys/fs/tmpfs/tmpfs.h
  head/sys/fs/tmpfs/tmpfs_subr.c
  head/sys/fs/tmpfs/tmpfs_vfsops.c

Modified: head/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- head/sys/fs/tmpfs/tmpfs.h	Sat Apr  7 12:47:12 2012	(r233997)
+++ head/sys/fs/tmpfs/tmpfs.h	Sat Apr  7 15:23:51 2012	(r233998)
@@ -337,11 +337,10 @@ struct tmpfs_mount {
 	 * 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. */
+	 * value. */
 	size_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. */
+	/* Number of pages in use by the file system. */
 	size_t			tm_pages_used;
 
 	/* Pointer to the node representing the root directory of this
@@ -486,57 +485,15 @@ int	tmpfs_truncate(struct vnode *, off_t
  * 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.
- *
- * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
- * excessive memory usage.
- *
+ * Amount of memory pages to reserve for the system (e.g., to not use by
+ * tmpfs).
  */
-static __inline size_t
-tmpfs_mem_info(void)
-{
-
-	return (swap_pager_avail + cnt.v_free_count + cnt.v_cache_count);
-}
-
-/* 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;
+#define TMPFS_PAGES_MINRESERVED		(4 * 1024 * 1024 / PAGE_SIZE)
 
-	freepages = tmpfs_mem_info();
-	freepages -= freepages < TMPFS_PAGES_RESERVED ?
-	    freepages : TMPFS_PAGES_RESERVED;
-
-	return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used);
-}
+size_t tmpfs_mem_avail(void);
 
-/* 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)
+size_t tmpfs_pages_used(struct tmpfs_mount *tmp);
 
 #endif
 

Modified: head/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_subr.c	Sat Apr  7 12:47:12 2012	(r233997)
+++ head/sys/fs/tmpfs/tmpfs_subr.c	Sat Apr  7 15:23:51 2012	(r233998)
@@ -59,6 +59,69 @@ __FBSDID("$FreeBSD$");
 
 SYSCTL_NODE(_vfs, OID_AUTO, tmpfs, CTLFLAG_RW, 0, "tmpfs file system");
 
+static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED;
+
+static int
+sysctl_mem_reserved(SYSCTL_HANDLER_ARGS)
+{
+	int error;
+	long pages, bytes;
+
+	pages = *(long *)arg1;
+	bytes = pages * PAGE_SIZE;
+
+	error = sysctl_handle_long(oidp, &bytes, 0, req);
+	if (error || !req->newptr)
+		return (error);
+
+	pages = bytes / PAGE_SIZE;
+	if (pages < TMPFS_PAGES_MINRESERVED)
+		return (EINVAL);
+
+	*(long *)arg1 = pages;
+	return (0);
+}
+
+SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, memory_reserved, CTLTYPE_LONG|CTLFLAG_RW,
+    &tmpfs_pages_reserved, 0, sysctl_mem_reserved, "L", "reserved memory");
+
+size_t
+tmpfs_mem_avail(void)
+{
+	vm_ooffset_t avail;
+
+	avail = swap_pager_avail + cnt.v_free_count + cnt.v_cache_count -
+	    tmpfs_pages_reserved;
+	if (__predict_false(avail < 0))
+		avail = 0;
+	return (avail);
+}
+
+size_t
+tmpfs_pages_used(struct tmpfs_mount *tmp)
+{
+	const size_t node_size = sizeof(struct tmpfs_node) +
+	    sizeof(struct tmpfs_dirent);
+	size_t meta_pages;
+
+	meta_pages = howmany((uintmax_t)tmp->tm_nodes_inuse * node_size,
+	    PAGE_SIZE);
+	return (meta_pages + tmp->tm_pages_used);
+}
+
+static size_t
+tmpfs_pages_check_avail(struct tmpfs_mount *tmp, size_t req_pages)
+{
+	if (tmpfs_mem_avail() < req_pages)
+		return (0);
+
+	if (tmp->tm_pages_max != SIZE_MAX &&
+	    tmp->tm_pages_max < req_pages + tmpfs_pages_used(tmp))
+			return (0);
+
+	return (1);
+}
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -99,6 +162,8 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
 
 	if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max)
 		return (ENOSPC);
+	if (tmpfs_pages_check_avail(tmp, 1) == 0)
+		return (ENOSPC);
 
 	nnode = (struct tmpfs_node *)uma_zalloc_arg(
 				tmp->tm_node_pool, tmp, M_WAITOK);
@@ -917,7 +982,7 @@ tmpfs_reg_resize(struct vnode *vp, off_t
 	MPASS(oldpages == uobj->size);
 	newpages = OFF_TO_IDX(newsize + PAGE_MASK);
 	if (newpages > oldpages &&
-	    newpages - oldpages > TMPFS_PAGES_AVAIL(tmp))
+	    tmpfs_pages_check_avail(tmp, newpages - oldpages) == 0)
 		return (ENOSPC);
 
 	VM_OBJECT_LOCK(uobj);

Modified: head/sys/fs/tmpfs/tmpfs_vfsops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vfsops.c	Sat Apr  7 12:47:12 2012	(r233997)
+++ head/sys/fs/tmpfs/tmpfs_vfsops.c	Sat Apr  7 15:23:51 2012	(r233998)
@@ -183,7 +183,7 @@ tmpfs_mount(struct mount *mp)
 
 	/* Do not allow mounts if we do not have enough memory to preserve
 	 * the minimum reserved pages. */
-	if (tmpfs_mem_info() < TMPFS_PAGES_RESERVED)
+	if (tmpfs_mem_avail() < TMPFS_PAGES_MINRESERVED)
 		return ENOSPC;
 
 	/* Get the maximum number of memory pages this file system is
@@ -382,22 +382,30 @@ tmpfs_fhtovp(struct mount *mp, struct fi
 static int
 tmpfs_statfs(struct mount *mp, struct statfs *sbp)
 {
-	fsfilcnt_t freenodes;
 	struct tmpfs_mount *tmp;
+	size_t used;
 
 	tmp = VFS_TO_TMPFS(mp);
 
 	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);
-
-	freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse,
-	    TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
-
-	sbp->f_files = freenodes + tmp->tm_nodes_inuse;
-	sbp->f_ffree = freenodes;
+	used = tmpfs_pages_used(tmp);
+	if (tmp->tm_pages_max != SIZE_MAX)
+		 sbp->f_blocks = tmp->tm_pages_max;
+	else
+		 sbp->f_blocks = used + tmpfs_mem_avail();
+	if (sbp->f_blocks <= used)
+		sbp->f_bavail = 0;
+	else
+		sbp->f_bavail = sbp->f_blocks - used;
+	sbp->f_bfree = sbp->f_bavail;
+	used = tmp->tm_nodes_inuse;
+	sbp->f_files = tmp->tm_nodes_max;
+	if (sbp->f_files <= used)
+		sbp->f_ffree = 0;
+	else
+		sbp->f_ffree = sbp->f_files - used;
 	/* sbp->f_owner = tmp->tn_uid; */
 
 	return 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204071523.q37FNqxN067629>