From owner-svn-src-all@FreeBSD.ORG Sat Apr 7 15:23:52 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 794D5106566C; Sat, 7 Apr 2012 15:23:52 +0000 (UTC) (envelope-from gleb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 638488FC08; Sat, 7 Apr 2012 15:23:52 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q37FNq2l067633; Sat, 7 Apr 2012 15:23:52 GMT (envelope-from gleb@svn.freebsd.org) Received: (from gleb@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q37FNqxN067629; Sat, 7 Apr 2012 15:23:52 GMT (envelope-from gleb@svn.freebsd.org) Message-Id: <201204071523.q37FNqxN067629@svn.freebsd.org> From: Gleb Kurtsou Date: Sat, 7 Apr 2012 15:23:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r233998 - head/sys/fs/tmpfs X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Apr 2012 15:23:52 -0000 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;