fs, file table: reinit files_stat.max_files after deferred memory initialisation
Dave Hansen reported the following; My laptop has been behaving strangely with 4.2-rc2. Once I log in to my X session, I start getting all kinds of strange errors from applications and see this in my dmesg: VFS: file-max limit 8192 reached The problem is that the file-max is calculated before memory is fully initialised and miscalculates how much memory the kernel is using. This patch recalculates file-max after deferred memory initialisation. Note that using memory hotplug infrastructure would not have avoided this problem as the value is not recalculated after memory hot-add. 4.1: files_stat.max_files = 6582781 4.2-rc2: files_stat.max_files = 8192 4.2-rc2 patched: files_stat.max_files = 6562467 Small differences with the patch applied and 4.1 but not enough to matter. Signed-off-by: Mel Gorman <mgorman@suse.de> Reported-by: Dave Hansen <dave.hansen@intel.com> Cc: Nicolai Stange <nicstange@gmail.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Alex Ng <alexng@microsoft.com> Cc: Fengguang Wu <fengguang.wu@intel.com> Cc: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d3cd131d93
commit
4248b0da46
5 changed files with 27 additions and 24 deletions
13
fs/dcache.c
13
fs/dcache.c
|
@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void)
|
||||||
inode_init_early();
|
inode_init_early();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init vfs_caches_init(unsigned long mempages)
|
void __init vfs_caches_init(void)
|
||||||
{
|
{
|
||||||
unsigned long reserve;
|
|
||||||
|
|
||||||
/* Base hash sizes on available memory, with a reserve equal to
|
|
||||||
150% of current kernel size */
|
|
||||||
|
|
||||||
reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
|
|
||||||
mempages -= reserve;
|
|
||||||
|
|
||||||
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
|
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
|
||||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
|
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
|
||||||
|
|
||||||
dcache_init();
|
dcache_init();
|
||||||
inode_init();
|
inode_init();
|
||||||
files_init(mempages);
|
files_init();
|
||||||
|
files_maxfiles_init();
|
||||||
mnt_init();
|
mnt_init();
|
||||||
bdev_cache_init();
|
bdev_cache_init();
|
||||||
chrdev_init();
|
chrdev_init();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/task_work.h>
|
#include <linux/task_work.h>
|
||||||
#include <linux/ima.h>
|
#include <linux/ima.h>
|
||||||
|
#include <linux/swap.h>
|
||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
|
@ -308,19 +309,24 @@ void put_filp(struct file *file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init files_init(unsigned long mempages)
|
void __init files_init(void)
|
||||||
{
|
{
|
||||||
unsigned long n;
|
|
||||||
|
|
||||||
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
|
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
|
||||||
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
|
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
* One file with associated inode and dcache is very roughly 1K.
|
|
||||||
* Per default don't use more than 10% of our memory for files.
|
|
||||||
*/
|
|
||||||
|
|
||||||
n = (mempages * (PAGE_SIZE / 1024)) / 10;
|
|
||||||
files_stat.max_files = max_t(unsigned long, n, NR_FILE);
|
|
||||||
percpu_counter_init(&nr_files, 0, GFP_KERNEL);
|
percpu_counter_init(&nr_files, 0, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One file with associated inode and dcache is very roughly 1K. Per default
|
||||||
|
* do not use more than 10% of our memory for files.
|
||||||
|
*/
|
||||||
|
void __init files_maxfiles_init(void)
|
||||||
|
{
|
||||||
|
unsigned long n;
|
||||||
|
unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2;
|
||||||
|
|
||||||
|
memreserve = min(memreserve, totalram_pages - 1);
|
||||||
|
n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
|
||||||
|
|
||||||
|
files_stat.max_files = max_t(unsigned long, n, NR_FILE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ struct vm_fault;
|
||||||
|
|
||||||
extern void __init inode_init(void);
|
extern void __init inode_init(void);
|
||||||
extern void __init inode_init_early(void);
|
extern void __init inode_init_early(void);
|
||||||
extern void __init files_init(unsigned long);
|
extern void __init files_init(void);
|
||||||
|
extern void __init files_maxfiles_init(void);
|
||||||
|
|
||||||
extern struct files_stat_struct files_stat;
|
extern struct files_stat_struct files_stat;
|
||||||
extern unsigned long get_max_files(void);
|
extern unsigned long get_max_files(void);
|
||||||
|
@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);
|
||||||
|
|
||||||
/* fs/dcache.c */
|
/* fs/dcache.c */
|
||||||
extern void __init vfs_caches_init_early(void);
|
extern void __init vfs_caches_init_early(void);
|
||||||
extern void __init vfs_caches_init(unsigned long);
|
extern void __init vfs_caches_init(void);
|
||||||
|
|
||||||
extern struct kmem_cache *names_cachep;
|
extern struct kmem_cache *names_cachep;
|
||||||
|
|
||||||
|
|
|
@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
|
||||||
key_init();
|
key_init();
|
||||||
security_init();
|
security_init();
|
||||||
dbg_late_init();
|
dbg_late_init();
|
||||||
vfs_caches_init(totalram_pages);
|
vfs_caches_init();
|
||||||
signals_init();
|
signals_init();
|
||||||
/* rootfs populating might need page-writeback */
|
/* rootfs populating might need page-writeback */
|
||||||
page_writeback_init();
|
page_writeback_init();
|
||||||
|
|
|
@ -1201,6 +1201,9 @@ void __init page_alloc_init_late(void)
|
||||||
|
|
||||||
/* Block until all are initialised */
|
/* Block until all are initialised */
|
||||||
wait_for_completion(&pgdat_init_all_done_comp);
|
wait_for_completion(&pgdat_init_all_done_comp);
|
||||||
|
|
||||||
|
/* Reinit limits that are based on free pages after the kernel is up */
|
||||||
|
files_maxfiles_init();
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
|
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue