Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4248b0da authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds
Browse files

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: default avatarMel Gorman <mgorman@suse.de>
Reported-by: default avatarDave 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d3cd131d
Loading
Loading
Loading
Loading
+3 −10
Original line number Diff line number Diff line
@@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void)
	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,
			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

	dcache_init();
	inode_init();
	files_init(mempages);
	files_init();
	files_maxfiles_init();
	mnt_init();
	bdev_cache_init();
	chrdev_init();
+15 −9
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/hardirq.h>
#include <linux/task_work.h>
#include <linux/ima.h>
#include <linux/swap.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,
			SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
	percpu_counter_init(&nr_files, 0, GFP_KERNEL);
}

/*
	 * One file with associated inode and dcache is very roughly 1K.
	 * Per default don't use more than 10% of our memory for files. 
 * 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;

	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);
} 
+3 −2
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ struct vm_fault;

extern void __init inode_init(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 unsigned long get_max_files(void);
@@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);

/* fs/dcache.c */
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;

+1 −1
Original line number Diff line number Diff line
@@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
	key_init();
	security_init();
	dbg_late_init();
	vfs_caches_init(totalram_pages);
	vfs_caches_init();
	signals_init();
	/* rootfs populating might need page-writeback */
	page_writeback_init();
+3 −0
Original line number Diff line number Diff line
@@ -1201,6 +1201,9 @@ void __init page_alloc_init_late(void)

	/* Block until all are initialised */
	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 */