diff --git a/share/man/man5/tmpfs.5 b/share/man/man5/tmpfs.5 --- a/share/man/man5/tmpfs.5 +++ b/share/man/man5/tmpfs.5 @@ -164,6 +164,24 @@ Refer to .Xr mount 8 . .El +.Sh SYSCTL VARIABLES +The following +.Xr sysctl 8 +variables are available: +.Bl -tag -width indent +.It Va vfs.tmpfs.memory_percent +The percentage of memory plus swap space available at kernel file system +initialization that can be used by a file system with a size of 0. +When this amount of space in use is reached, new files cannot be created +and files cannot be extended. +The default is 95%. +Changing this value also changes +.Va vfs.tmpfs.memory_reserved . +.It Va vfs.tmpfs.memory_reserved +The currently-reserved amount of memory plus swap space +based on the memory percentage. +The minimum is compiled into the system, and defaults to 4 MB. +.El .Sh EXAMPLES Mount a .Nm diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -543,6 +543,14 @@ #define TMPFS_PAGES_MINRESERVED (4 * 1024 * 1024 / PAGE_SIZE) #endif +/* + * Percent of available memory + swap available to use by tmpfs file systems + * without a size limit. + */ +#if !defined(TMPFS_MEM_PERCENT) +#define TMPFS_MEM_PERCENT 95 +#endif + /* * Amount of memory to reserve for extended attributes. */ diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -73,6 +73,9 @@ "tmpfs file system"); static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED; +static long tmpfs_pages_avail_init; +static int tmpfs_mem_percent = TMPFS_MEM_PERCENT; +static void tmpfs_set_reserve_from_percent(void); MALLOC_DEFINE(M_TMPFSDIR, "tmpfs dir", "tmpfs dirent structure"); static uma_zone_t tmpfs_node_pool; @@ -367,6 +370,9 @@ sizeof(struct tmpfs_node), tmpfs_node_ctor, tmpfs_node_dtor, tmpfs_node_init, tmpfs_node_fini, UMA_ALIGN_PTR, 0); VFS_SMR_ZONE_SET(tmpfs_node_pool); + + tmpfs_pages_avail_init = tmpfs_mem_avail(); + tmpfs_set_reserve_from_percent(); return (0); } @@ -401,10 +407,42 @@ } SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, memory_reserved, - CTLTYPE_LONG|CTLFLAG_MPSAFE|CTLFLAG_RW, &tmpfs_pages_reserved, 0, + CTLTYPE_LONG | CTLFLAG_MPSAFE | CTLFLAG_RW, &tmpfs_pages_reserved, 0, sysctl_mem_reserved, "L", "Amount of available memory and swap below which tmpfs growth stops"); +static int +sysctl_mem_percent(SYSCTL_HANDLER_ARGS) +{ + int error, percent; + + percent = *(int *)arg1; + error = sysctl_handle_int(oidp, &percent, 0, req); + if (error || !req->newptr) + return (error); + + if ((unsigned) percent > 100) + return (EINVAL); + + *(long *)arg1 = percent; + tmpfs_set_reserve_from_percent(); + return (0); +} + +static void +tmpfs_set_reserve_from_percent(void) +{ + size_t reserved; + + reserved = tmpfs_pages_avail_init * (100 - tmpfs_mem_percent) / 100; + tmpfs_pages_reserved = max(reserved, TMPFS_PAGES_MINRESERVED); +} + +SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, memory_percent, + CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &tmpfs_mem_percent, 0, + sysctl_mem_percent, "I", + "Percent of available memory that can be used if no size limit"); + static __inline int tmpfs_dirtree_cmp(struct tmpfs_dirent *a, struct tmpfs_dirent *b); RB_PROTOTYPE_STATIC(tmpfs_dir, tmpfs_dirent, uh.td_entries, tmpfs_dirtree_cmp);