diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 4db020015f14..d8bd3b425fa7 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/hw_breakpoint.h> | 52 | #include <linux/hw_breakpoint.h> |
53 | #include <linux/oom.h> | 53 | #include <linux/oom.h> |
54 | #include <linux/writeback.h> | 54 | #include <linux/writeback.h> |
55 | #include <linux/shm.h> | ||
55 | 56 | ||
56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
57 | #include <asm/unistd.h> | 58 | #include <asm/unistd.h> |
@@ -424,7 +425,7 @@ void daemonize(const char *name, ...) | |||
424 | */ | 425 | */ |
425 | exit_mm(current); | 426 | exit_mm(current); |
426 | /* | 427 | /* |
427 | * We don't want to have TIF_FREEZE set if the system-wide hibernation | 428 | * We don't want to get frozen, in case system-wide hibernation |
428 | * or suspend transition begins right now. | 429 | * or suspend transition begins right now. |
429 | */ | 430 | */ |
430 | current->flags |= (PF_NOFREEZE | PF_KTHREAD); | 431 | current->flags |= (PF_NOFREEZE | PF_KTHREAD); |
@@ -686,11 +687,11 @@ static void exit_mm(struct task_struct * tsk) | |||
686 | } | 687 | } |
687 | 688 | ||
688 | /* | 689 | /* |
689 | * When we die, we re-parent all our children. | 690 | * When we die, we re-parent all our children, and try to: |
690 | * Try to give them to another thread in our thread | 691 | * 1. give them to another thread in our thread group, if such a member exists |
691 | * group, and if no such member exists, give it to | 692 | * 2. give it to the first ancestor process which prctl'd itself as a |
692 | * the child reaper process (ie "init") in our pid | 693 | * child_subreaper for its children (like a service manager) |
693 | * space. | 694 | * 3. give it to the init process (PID 1) in our pid namespace |
694 | */ | 695 | */ |
695 | static struct task_struct *find_new_reaper(struct task_struct *father) | 696 | static struct task_struct *find_new_reaper(struct task_struct *father) |
696 | __releases(&tasklist_lock) | 697 | __releases(&tasklist_lock) |
@@ -710,8 +711,11 @@ static struct task_struct *find_new_reaper(struct task_struct *father) | |||
710 | 711 | ||
711 | if (unlikely(pid_ns->child_reaper == father)) { | 712 | if (unlikely(pid_ns->child_reaper == father)) { |
712 | write_unlock_irq(&tasklist_lock); | 713 | write_unlock_irq(&tasklist_lock); |
713 | if (unlikely(pid_ns == &init_pid_ns)) | 714 | if (unlikely(pid_ns == &init_pid_ns)) { |
714 | panic("Attempted to kill init!"); | 715 | panic("Attempted to kill init! exitcode=0x%08x\n", |
716 | father->signal->group_exit_code ?: | ||
717 | father->exit_code); | ||
718 | } | ||
715 | 719 | ||
716 | zap_pid_ns_processes(pid_ns); | 720 | zap_pid_ns_processes(pid_ns); |
717 | write_lock_irq(&tasklist_lock); | 721 | write_lock_irq(&tasklist_lock); |
@@ -721,6 +725,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father) | |||
721 | * forget_original_parent() must move them somewhere. | 725 | * forget_original_parent() must move them somewhere. |
722 | */ | 726 | */ |
723 | pid_ns->child_reaper = init_pid_ns.child_reaper; | 727 | pid_ns->child_reaper = init_pid_ns.child_reaper; |
728 | } else if (father->signal->has_child_subreaper) { | ||
729 | struct task_struct *reaper; | ||
730 | |||
731 | /* | ||
732 | * Find the first ancestor marked as child_subreaper. | ||
733 | * Note that the code below checks same_thread_group(reaper, | ||
734 | * pid_ns->child_reaper). This is what we need to DTRT in a | ||
735 | * PID namespace. However we still need the check above, see | ||
736 | * http://marc.info/?l=linux-kernel&m=131385460420380 | ||
737 | */ | ||
738 | for (reaper = father->real_parent; | ||
739 | reaper != &init_task; | ||
740 | reaper = reaper->real_parent) { | ||
741 | if (same_thread_group(reaper, pid_ns->child_reaper)) | ||
742 | break; | ||
743 | if (!reaper->signal->is_child_subreaper) | ||
744 | continue; | ||
745 | thread = reaper; | ||
746 | do { | ||
747 | if (!(thread->flags & PF_EXITING)) | ||
748 | return reaper; | ||
749 | } while_each_thread(reaper, thread); | ||
750 | } | ||
724 | } | 751 | } |
725 | 752 | ||
726 | return pid_ns->child_reaper; | 753 | return pid_ns->child_reaper; |
@@ -818,25 +845,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
818 | if (group_dead) | 845 | if (group_dead) |
819 | kill_orphaned_pgrp(tsk->group_leader, NULL); | 846 | kill_orphaned_pgrp(tsk->group_leader, NULL); |
820 | 847 | ||
821 | /* Let father know we died | ||
822 | * | ||
823 | * Thread signals are configurable, but you aren't going to use | ||
824 | * that to send signals to arbitrary processes. | ||
825 | * That stops right now. | ||
826 | * | ||
827 | * If the parent exec id doesn't match the exec id we saved | ||
828 | * when we started then we know the parent has changed security | ||
829 | * domain. | ||
830 | * | ||
831 | * If our self_exec id doesn't match our parent_exec_id then | ||
832 | * we have changed execution domain as these two values started | ||
833 | * the same after a fork. | ||
834 | */ | ||
835 | if (thread_group_leader(tsk) && tsk->exit_signal != SIGCHLD && | ||
836 | (tsk->parent_exec_id != tsk->real_parent->self_exec_id || | ||
837 | tsk->self_exec_id != tsk->parent_exec_id)) | ||
838 | tsk->exit_signal = SIGCHLD; | ||
839 | |||
840 | if (unlikely(tsk->ptrace)) { | 848 | if (unlikely(tsk->ptrace)) { |
841 | int sig = thread_group_leader(tsk) && | 849 | int sig = thread_group_leader(tsk) && |
842 | thread_group_empty(tsk) && | 850 | thread_group_empty(tsk) && |
@@ -935,8 +943,6 @@ void do_exit(long code) | |||
935 | schedule(); | 943 | schedule(); |
936 | } | 944 | } |
937 | 945 | ||
938 | exit_irq_thread(); | ||
939 | |||
940 | exit_signals(tsk); /* sets PF_EXITING */ | 946 | exit_signals(tsk); /* sets PF_EXITING */ |
941 | /* | 947 | /* |
942 | * tsk->flags are checked in the futex code to protect against | 948 | * tsk->flags are checked in the futex code to protect against |
@@ -945,6 +951,8 @@ void do_exit(long code) | |||
945 | smp_mb(); | 951 | smp_mb(); |
946 | raw_spin_unlock_wait(&tsk->pi_lock); | 952 | raw_spin_unlock_wait(&tsk->pi_lock); |
947 | 953 | ||
954 | exit_irq_thread(); | ||
955 | |||
948 | if (unlikely(in_atomic())) | 956 | if (unlikely(in_atomic())) |
949 | printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", | 957 | printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", |
950 | current->comm, task_pid_nr(current), | 958 | current->comm, task_pid_nr(current), |
@@ -953,7 +961,7 @@ void do_exit(long code) | |||
953 | acct_update_integrals(tsk); | 961 | acct_update_integrals(tsk); |
954 | /* sync mm's RSS info before statistics gathering */ | 962 | /* sync mm's RSS info before statistics gathering */ |
955 | if (tsk->mm) | 963 | if (tsk->mm) |
956 | sync_mm_rss(tsk, tsk->mm); | 964 | sync_mm_rss(tsk->mm); |
957 | group_dead = atomic_dec_and_test(&tsk->signal->live); | 965 | group_dead = atomic_dec_and_test(&tsk->signal->live); |
958 | if (group_dead) { | 966 | if (group_dead) { |
959 | hrtimer_cancel(&tsk->signal->real_timer); | 967 | hrtimer_cancel(&tsk->signal->real_timer); |