diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-06-26 03:26:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:27 -0400 |
commit | 7b1c6154fa8bb937e0b1b4f2adbb315d70270f10 (patch) | |
tree | 1d58e5e7da61330639ebe62671fb666596d1b00a /fs/exec.c | |
parent | d5f70c00ad24cd1158d3678b44ff969b4c971d49 (diff) |
[PATCH] coredump: don't take tasklist_lock
This patch removes tasklist_lock from zap_threads().
This is safe wrt:
do_exit:
The caller holds mm->mmap_sem. This means that task which
shares the same ->mm can't pass exit_mm(), so it can't be
unhashed from init_task.tasks or ->thread_group lists.
fork:
None of sub-threads can fork after zap_process(leader). All
processes which were created before this point should be
visible to zap_threads() because copy_process() adds the new
process to the tail of init_task.tasks list, and ->siglock
lock/unlock provides a memory barrier.
de_thread:
It does list_replace_rcu(&leader->tasks, ¤t->tasks).
So zap_threads() will see either old or new leader, it does
not matter. However, it can change p->sighand, so we should
use lock_task_sighand() in zap_process().
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 12 |
1 files changed, 8 insertions, 4 deletions
@@ -1373,7 +1373,11 @@ static void zap_process(struct task_struct *start) | |||
1373 | struct task_struct *t; | 1373 | struct task_struct *t; |
1374 | unsigned long flags; | 1374 | unsigned long flags; |
1375 | 1375 | ||
1376 | spin_lock_irqsave(&start->sighand->siglock, flags); | 1376 | /* |
1377 | * start->sighand can't disappear, but may be | ||
1378 | * changed by de_thread() | ||
1379 | */ | ||
1380 | lock_task_sighand(start, &flags); | ||
1377 | start->signal->flags = SIGNAL_GROUP_EXIT; | 1381 | start->signal->flags = SIGNAL_GROUP_EXIT; |
1378 | start->signal->group_stop_count = 0; | 1382 | start->signal->group_stop_count = 0; |
1379 | 1383 | ||
@@ -1386,7 +1390,7 @@ static void zap_process(struct task_struct *start) | |||
1386 | } | 1390 | } |
1387 | } while ((t = next_thread(t)) != start); | 1391 | } while ((t = next_thread(t)) != start); |
1388 | 1392 | ||
1389 | spin_unlock_irqrestore(&start->sighand->siglock, flags); | 1393 | unlock_task_sighand(start, &flags); |
1390 | } | 1394 | } |
1391 | 1395 | ||
1392 | static void zap_threads(struct mm_struct *mm) | 1396 | static void zap_threads(struct mm_struct *mm) |
@@ -1404,7 +1408,7 @@ static void zap_threads(struct mm_struct *mm) | |||
1404 | complete(vfork_done); | 1408 | complete(vfork_done); |
1405 | } | 1409 | } |
1406 | 1410 | ||
1407 | read_lock(&tasklist_lock); | 1411 | rcu_read_lock(); |
1408 | for_each_process(g) { | 1412 | for_each_process(g) { |
1409 | p = g; | 1413 | p = g; |
1410 | do { | 1414 | do { |
@@ -1415,7 +1419,7 @@ static void zap_threads(struct mm_struct *mm) | |||
1415 | } | 1419 | } |
1416 | } while ((p = next_thread(p)) != g); | 1420 | } while ((p = next_thread(p)) != g); |
1417 | } | 1421 | } |
1418 | read_unlock(&tasklist_lock); | 1422 | rcu_read_unlock(); |
1419 | } | 1423 | } |
1420 | 1424 | ||
1421 | static void coredump_wait(struct mm_struct *mm) | 1425 | static void coredump_wait(struct mm_struct *mm) |