diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-06-26 03:25:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:25 -0400 |
commit | 99f895518368252ba862cc15ce4eb98ebbe1bec6 (patch) | |
tree | a9dcc01963221d1fd6a7e357b95d361ebfe91c6d /fs/proc/inode.c | |
parent | 8578cea7509cbdec25b31d08b48a92fcc3b1a9e3 (diff) |
[PATCH] proc: don't lock task_structs indefinitely
Every inode in /proc holds a reference to a struct task_struct. If a
directory or file is opened and remains open after the the task exits this
pinning continues. With 8K stacks on a 32bit machine the amount pinned per
file descriptor is about 10K.
Normally I would figure a reasonable per user process limit is about 100
processes. With 80 processes, with a 1000 file descriptors each I can trigger
the 00M killer on a 32bit kernel, because I have pinned about 800MB of useless
data.
This patch replaces the struct task_struct pointer with a pointer to a struct
task_ref which has a struct task_struct pointer. The so the pinning of dead
tasks does not happen.
The code now has to contend with the fact that the task may now exit at any
time. Which is a little but not muh more complicated.
With this change it takes about 1000 processes each opening up 1000 file
descriptors before I can trigger the OOM killer. Much better.
[mlp@google.com: task_mmu small fixes]
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: Paul Jackson <pj@sgi.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Albert Cahalan <acahalan@gmail.com>
Signed-off-by: Prasanna Meda <mlp@google.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/proc/inode.c')
-rw-r--r-- | fs/proc/inode.c | 9 |
1 files changed, 3 insertions, 6 deletions
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index fbc94df138a7..31e0475c6cb9 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -58,14 +58,11 @@ static void de_put(struct proc_dir_entry *de) | |||
58 | static void proc_delete_inode(struct inode *inode) | 58 | static void proc_delete_inode(struct inode *inode) |
59 | { | 59 | { |
60 | struct proc_dir_entry *de; | 60 | struct proc_dir_entry *de; |
61 | struct task_struct *tsk; | ||
62 | 61 | ||
63 | truncate_inode_pages(&inode->i_data, 0); | 62 | truncate_inode_pages(&inode->i_data, 0); |
64 | 63 | ||
65 | /* Let go of any associated process */ | 64 | /* Stop tracking associated processes */ |
66 | tsk = PROC_I(inode)->task; | 65 | tref_put(PROC_I(inode)->tref); |
67 | if (tsk) | ||
68 | put_task_struct(tsk); | ||
69 | 66 | ||
70 | /* Let go of any associated proc directory entry */ | 67 | /* Let go of any associated proc directory entry */ |
71 | de = PROC_I(inode)->pde; | 68 | de = PROC_I(inode)->pde; |
@@ -94,7 +91,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
94 | ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL); | 91 | ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL); |
95 | if (!ei) | 92 | if (!ei) |
96 | return NULL; | 93 | return NULL; |
97 | ei->task = NULL; | 94 | ei->tref = NULL; |
98 | ei->fd = 0; | 95 | ei->fd = 0; |
99 | ei->op.proc_get_link = NULL; | 96 | ei->op.proc_get_link = NULL; |
100 | ei->pde = NULL; | 97 | ei->pde = NULL; |