diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-12-10 18:55:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 20:41:17 -0500 |
commit | 1109909c7df08f55ff9104276bb9db1ee2e6e53d (patch) | |
tree | 8a8d8c701988e74bfea253b7f83f674fcc40cf35 /kernel/exit.c | |
parent | 175aed3f8d38b87d3287bb765c794205f2b511de (diff) |
exit: reparent: introduce find_child_reaper()
find_new_reaper() does 2 completely different things. Not only it finds a
reaper, it also updates pid_ns->child_reaper or kills the whole namespace
if the caller is ->child_reaper.
Now that has_child_subreaper logic doesn't depend on child_reaper check we
can move that pid_ns code into a separate helper. IMHO this makes the
code more clean, and this allows the next changes.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Kay Sievers <kay@vrfy.org>
Cc: Lennart Poettering <lennart@poettering.net>
Cc: Sterling Alexander <stalexan@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 576949ce5665..930fbe1b5ee2 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -459,6 +459,34 @@ static void exit_mm(struct task_struct *tsk) | |||
459 | clear_thread_flag(TIF_MEMDIE); | 459 | clear_thread_flag(TIF_MEMDIE); |
460 | } | 460 | } |
461 | 461 | ||
462 | static struct task_struct *find_child_reaper(struct task_struct *father) | ||
463 | __releases(&tasklist_lock) | ||
464 | __acquires(&tasklist_lock) | ||
465 | { | ||
466 | struct pid_namespace *pid_ns = task_active_pid_ns(father); | ||
467 | struct task_struct *reaper = pid_ns->child_reaper; | ||
468 | |||
469 | if (likely(reaper != father)) | ||
470 | return reaper; | ||
471 | |||
472 | for_each_thread(father, reaper) { | ||
473 | if (reaper->flags & PF_EXITING) | ||
474 | continue; | ||
475 | pid_ns->child_reaper = reaper; | ||
476 | return reaper; | ||
477 | } | ||
478 | |||
479 | write_unlock_irq(&tasklist_lock); | ||
480 | if (unlikely(pid_ns == &init_pid_ns)) { | ||
481 | panic("Attempted to kill init! exitcode=0x%08x\n", | ||
482 | father->signal->group_exit_code ?: father->exit_code); | ||
483 | } | ||
484 | zap_pid_ns_processes(pid_ns); | ||
485 | write_lock_irq(&tasklist_lock); | ||
486 | |||
487 | return father; | ||
488 | } | ||
489 | |||
462 | /* | 490 | /* |
463 | * When we die, we re-parent all our children, and try to: | 491 | * When we die, we re-parent all our children, and try to: |
464 | * 1. give them to another thread in our thread group, if such a member exists | 492 | * 1. give them to another thread in our thread group, if such a member exists |
@@ -466,33 +494,17 @@ static void exit_mm(struct task_struct *tsk) | |||
466 | * child_subreaper for its children (like a service manager) | 494 | * child_subreaper for its children (like a service manager) |
467 | * 3. give it to the init process (PID 1) in our pid namespace | 495 | * 3. give it to the init process (PID 1) in our pid namespace |
468 | */ | 496 | */ |
469 | static struct task_struct *find_new_reaper(struct task_struct *father) | 497 | static struct task_struct *find_new_reaper(struct task_struct *father, |
470 | __releases(&tasklist_lock) | 498 | struct task_struct *child_reaper) |
471 | __acquires(&tasklist_lock) | ||
472 | { | 499 | { |
473 | struct pid_namespace *pid_ns = task_active_pid_ns(father); | ||
474 | struct task_struct *thread; | 500 | struct task_struct *thread; |
475 | 501 | ||
476 | for_each_thread(father, thread) { | 502 | for_each_thread(father, thread) { |
477 | if (thread->flags & PF_EXITING) | 503 | if (thread->flags & PF_EXITING) |
478 | continue; | 504 | continue; |
479 | if (unlikely(pid_ns->child_reaper == father)) | ||
480 | pid_ns->child_reaper = thread; | ||
481 | return thread; | 505 | return thread; |
482 | } | 506 | } |
483 | 507 | ||
484 | if (unlikely(pid_ns->child_reaper == father)) { | ||
485 | write_unlock_irq(&tasklist_lock); | ||
486 | if (unlikely(pid_ns == &init_pid_ns)) { | ||
487 | panic("Attempted to kill init! exitcode=0x%08x\n", | ||
488 | father->signal->group_exit_code ?: | ||
489 | father->exit_code); | ||
490 | } | ||
491 | |||
492 | zap_pid_ns_processes(pid_ns); | ||
493 | write_lock_irq(&tasklist_lock); | ||
494 | } | ||
495 | |||
496 | if (father->signal->has_child_subreaper) { | 508 | if (father->signal->has_child_subreaper) { |
497 | struct task_struct *reaper; | 509 | struct task_struct *reaper; |
498 | /* | 510 | /* |
@@ -501,7 +513,7 @@ static struct task_struct *find_new_reaper(struct task_struct *father) | |||
501 | * namespace, this is safe because all its threads are dead. | 513 | * namespace, this is safe because all its threads are dead. |
502 | */ | 514 | */ |
503 | for (reaper = father; | 515 | for (reaper = father; |
504 | !same_thread_group(reaper, pid_ns->child_reaper); | 516 | !same_thread_group(reaper, child_reaper); |
505 | reaper = reaper->real_parent) { | 517 | reaper = reaper->real_parent) { |
506 | /* call_usermodehelper() descendants need this check */ | 518 | /* call_usermodehelper() descendants need this check */ |
507 | if (reaper == &init_task) | 519 | if (reaper == &init_task) |
@@ -515,7 +527,7 @@ static struct task_struct *find_new_reaper(struct task_struct *father) | |||
515 | } | 527 | } |
516 | } | 528 | } |
517 | 529 | ||
518 | return pid_ns->child_reaper; | 530 | return child_reaper; |
519 | } | 531 | } |
520 | 532 | ||
521 | /* | 533 | /* |
@@ -552,7 +564,9 @@ static void forget_original_parent(struct task_struct *father) | |||
552 | exit_ptrace(father, &dead_children); | 564 | exit_ptrace(father, &dead_children); |
553 | 565 | ||
554 | /* Can drop and reacquire tasklist_lock */ | 566 | /* Can drop and reacquire tasklist_lock */ |
555 | reaper = find_new_reaper(father); | 567 | reaper = find_child_reaper(father); |
568 | |||
569 | reaper = find_new_reaper(father, reaper); | ||
556 | list_for_each_entry(p, &father->children, sibling) { | 570 | list_for_each_entry(p, &father->children, sibling) { |
557 | for_each_thread(p, t) { | 571 | for_each_thread(p, t) { |
558 | t->real_parent = reaper; | 572 | t->real_parent = reaper; |