diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-05 03:32:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-10-25 21:18:20 -0400 |
commit | 7e360c38abe2c70eae3ba5a8a17f17671d8b77c5 (patch) | |
tree | 319034360c667ac704bce87b1a0856657bf67e4b /kernel/sysctl.c | |
parent | fde214d414218fb6cace35708730986bcc94fb53 (diff) |
fs: allow for more than 2^31 files
Andrew,
Could you please review this patch, you probably are the right guy to
take it, because it crosses fs and net trees.
Note : /proc/sys/fs/file-nr is a read-only file, so this patch doesnt
depend on previous patch (sysctl: fix min/max handling in
__do_proc_doulongvec_minmax())
Thanks !
[PATCH V4] fs: allow for more than 2^31 files
Robin Holt tried to boot a 16TB system and found af_unix was overflowing
a 32bit value :
<quote>
We were seeing a failure which prevented boot. The kernel was incapable
of creating either a named pipe or unix domain socket. This comes down
to a common kernel function called unix_create1() which does:
atomic_inc(&unix_nr_socks);
if (atomic_read(&unix_nr_socks) > 2 * get_max_files())
goto out;
The function get_max_files() is a simple return of files_stat.max_files.
files_stat.max_files is a signed integer and is computed in
fs/file_table.c's files_init().
n = (mempages * (PAGE_SIZE / 1024)) / 10;
files_stat.max_files = n;
In our case, mempages (total_ram_pages) is approx 3,758,096,384
(0xe0000000). That leaves max_files at approximately 1,503,238,553.
This causes 2 * get_max_files() to integer overflow.
</quote>
Fix is to let /proc/sys/fs/file-nr & /proc/sys/fs/file-max use long
integers, and change af_unix to use an atomic_long_t instead of
atomic_t.
get_max_files() is changed to return an unsigned long.
get_nr_files() is changed to return a long.
unix_nr_socks is changed from atomic_t to atomic_long_t, while not
strictly needed to address Robin problem.
Before patch (on a 64bit kernel) :
# echo 2147483648 >/proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
-18446744071562067968
After patch:
# echo 2147483648 >/proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
2147483648
# cat /proc/sys/fs/file-nr
704 0 2147483648
Reported-by: Robin Holt <holt@sgi.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: David Miller <davem@davemloft.net>
Reviewed-by: Robin Holt <holt@sgi.com>
Tested-by: Robin Holt <holt@sgi.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3a45c224770f..694b140852c2 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -1352,16 +1352,16 @@ static struct ctl_table fs_table[] = { | |||
1352 | { | 1352 | { |
1353 | .procname = "file-nr", | 1353 | .procname = "file-nr", |
1354 | .data = &files_stat, | 1354 | .data = &files_stat, |
1355 | .maxlen = 3*sizeof(int), | 1355 | .maxlen = sizeof(files_stat), |
1356 | .mode = 0444, | 1356 | .mode = 0444, |
1357 | .proc_handler = proc_nr_files, | 1357 | .proc_handler = proc_nr_files, |
1358 | }, | 1358 | }, |
1359 | { | 1359 | { |
1360 | .procname = "file-max", | 1360 | .procname = "file-max", |
1361 | .data = &files_stat.max_files, | 1361 | .data = &files_stat.max_files, |
1362 | .maxlen = sizeof(int), | 1362 | .maxlen = sizeof(files_stat.max_files), |
1363 | .mode = 0644, | 1363 | .mode = 0644, |
1364 | .proc_handler = proc_dointvec, | 1364 | .proc_handler = proc_doulongvec_minmax, |
1365 | }, | 1365 | }, |
1366 | { | 1366 | { |
1367 | .procname = "nr_open", | 1367 | .procname = "nr_open", |