diff options
author | Oleg Nesterov <oleg@redhat.com> | 2009-09-22 19:45:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:40 -0400 |
commit | 9b4d1cbef8f41aff2b3e4ca31f566c071fe601de (patch) | |
tree | fc64d537b5142646d917ad928e3fb1df4caf4655 /fs/proc | |
parent | cff4edb591c153a779a27a3fd8e7bc1217f2f6b8 (diff) |
proc_flush_task: flush /proc/tid/task/pid when a sub-thread exits
The exiting sub-thread flushes /proc/pid only, but this doesn't buy too
much: ps and friends mostly use /proc/tid/task/pid.
Remove "if (thread_group_leader())" checks from proc_flush_task() path,
this means we always remove /proc/tid/task/pid dentry on exit, and this
actually matches the comment above proc_flush_task().
The test-case:
static void* tfunc(void *arg)
{
char name[256];
sprintf(name, "/proc/%d/task/%ld/status", getpid(), gettid());
close(open(name, O_RDONLY));
return NULL;
}
int main(void)
{
pthread_t t;
for (;;) {
if (!pthread_create(&t, NULL, &tfunc, NULL))
pthread_join(t, NULL);
}
}
slabtop shows that pid/proc_inode_cache/etc grow quickly and
"indefinitely" until the task is killed or shrink_slab() is called, not
good. And the main thread needs a lot of time to exit.
The same can happen if something like "ps -efL" runs continuously, while
some application spawns short-living threads.
Reported-by: "James M. Leddy" <jleddy@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Dominic Duval <dduval@redhat.com>
Cc: Frank Hirtz <fhirtz@redhat.com>
Cc: "Fuller, Johnray" <Johnray.Fuller@gs.com>
Cc: Larry Woodman <lwoodman@redhat.com>
Cc: Paul Batkowski <pbatkowski@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 10 |
1 files changed, 3 insertions, 7 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 69bb70351b9b..5bc587049b37 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2604,9 +2604,6 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) | |||
2604 | dput(dentry); | 2604 | dput(dentry); |
2605 | } | 2605 | } |
2606 | 2606 | ||
2607 | if (tgid == 0) | ||
2608 | goto out; | ||
2609 | |||
2610 | name.name = buf; | 2607 | name.name = buf; |
2611 | name.len = snprintf(buf, sizeof(buf), "%d", tgid); | 2608 | name.len = snprintf(buf, sizeof(buf), "%d", tgid); |
2612 | leader = d_hash_and_lookup(mnt->mnt_root, &name); | 2609 | leader = d_hash_and_lookup(mnt->mnt_root, &name); |
@@ -2663,17 +2660,16 @@ out: | |||
2663 | void proc_flush_task(struct task_struct *task) | 2660 | void proc_flush_task(struct task_struct *task) |
2664 | { | 2661 | { |
2665 | int i; | 2662 | int i; |
2666 | struct pid *pid, *tgid = NULL; | 2663 | struct pid *pid, *tgid; |
2667 | struct upid *upid; | 2664 | struct upid *upid; |
2668 | 2665 | ||
2669 | pid = task_pid(task); | 2666 | pid = task_pid(task); |
2670 | if (thread_group_leader(task)) | 2667 | tgid = task_tgid(task); |
2671 | tgid = task_tgid(task); | ||
2672 | 2668 | ||
2673 | for (i = 0; i <= pid->level; i++) { | 2669 | for (i = 0; i <= pid->level; i++) { |
2674 | upid = &pid->numbers[i]; | 2670 | upid = &pid->numbers[i]; |
2675 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, | 2671 | proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, |
2676 | tgid ? tgid->numbers[i].nr : 0); | 2672 | tgid->numbers[i].nr); |
2677 | } | 2673 | } |
2678 | 2674 | ||
2679 | upid = &pid->numbers[pid->level]; | 2675 | upid = &pid->numbers[pid->level]; |