aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/exit.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-03-23 18:01:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 19:58:32 -0400
commitebec18a6d3aa1e7d84aab16225e87fd25170ec2b (patch)
treefd329dcd5173c252fc7aed64cab9c2a51575dcec /kernel/exit.c
parent953326cb60c1dff1bd3458d6468d16d75f2bcd61 (diff)
prctl: add PR_{SET,GET}_CHILD_SUBREAPER to allow simple process supervision
Userspace service managers/supervisors need to track their started services. Many services daemonize by double-forking and get implicitly re-parented to PID 1. The service manager will no longer be able to receive the SIGCHLD signals for them, and is no longer in charge of reaping the children with wait(). All information about the children is lost at the moment PID 1 cleans up the re-parented processes. With this prctl, a service manager process can mark itself as a sort of 'sub-init', able to stay as the parent for all orphaned processes created by the started services. All SIGCHLD signals will be delivered to the service manager. Receiving SIGCHLD and doing wait() is in cases of a service-manager much preferred over any possible asynchronous notification about specific PIDs, because the service manager has full access to the child process data in /proc and the PID can not be re-used until the wait(), the service-manager itself is in charge of, has happened. As a side effect, the relevant parent PID information does not get lost by a double-fork, which results in a more elaborate process tree and 'ps' output: before: # ps afx 253 ? Ss 0:00 /bin/dbus-daemon --system --nofork 294 ? Sl 0:00 /usr/libexec/polkit-1/polkitd 328 ? S 0:00 /usr/sbin/modem-manager 608 ? Sl 0:00 /usr/libexec/colord 658 ? Sl 0:00 /usr/libexec/upowerd 819 ? Sl 0:00 /usr/libexec/imsettings-daemon 916 ? Sl 0:00 /usr/libexec/udisks-daemon 917 ? S 0:00 \_ udisks-daemon: not polling any devices after: # ps afx 294 ? Ss 0:00 /bin/dbus-daemon --system --nofork 426 ? Sl 0:00 \_ /usr/libexec/polkit-1/polkitd 449 ? S 0:00 \_ /usr/sbin/modem-manager 635 ? Sl 0:00 \_ /usr/libexec/colord 705 ? Sl 0:00 \_ /usr/libexec/upowerd 959 ? Sl 0:00 \_ /usr/libexec/udisks-daemon 960 ? S 0:00 | \_ udisks-daemon: not polling any devices 977 ? Sl 0:00 \_ /usr/libexec/packagekitd This prctl is orthogonal to PID namespaces. PID namespaces are isolated from each other, while a service management process usually requires the services to live in the same namespace, to be able to talk to each other. Users of this will be the systemd per-user instance, which provides init-like functionality for the user's login session and D-Bus, which activates bus services on-demand. Both need init-like capabilities to be able to properly keep track of the services they start. Many thanks to Oleg for several rounds of review and insights. [akpm@linux-foundation.org: fix comment layout and spelling] [akpm@linux-foundation.org: add lengthy code comment from Oleg] Reviewed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Lennart Poettering <lennart@poettering.net> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Acked-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> 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.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 16b07bfac22..456329fd4ea 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -687,11 +687,11 @@ static void exit_mm(struct task_struct * tsk)
687} 687}
688 688
689/* 689/*
690 * When we die, we re-parent all our children. 690 * When we die, we re-parent all our children, and try to:
691 * 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
692 * 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
693 * the child reaper process (ie "init") in our pid 693 * child_subreaper for its children (like a service manager)
694 * space. 694 * 3. give it to the init process (PID 1) in our pid namespace
695 */ 695 */
696static struct task_struct *find_new_reaper(struct task_struct *father) 696static struct task_struct *find_new_reaper(struct task_struct *father)
697 __releases(&tasklist_lock) 697 __releases(&tasklist_lock)
@@ -722,6 +722,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
722 * forget_original_parent() must move them somewhere. 722 * forget_original_parent() must move them somewhere.
723 */ 723 */
724 pid_ns->child_reaper = init_pid_ns.child_reaper; 724 pid_ns->child_reaper = init_pid_ns.child_reaper;
725 } else if (father->signal->has_child_subreaper) {
726 struct task_struct *reaper;
727
728 /*
729 * Find the first ancestor marked as child_subreaper.
730 * Note that the code below checks same_thread_group(reaper,
731 * pid_ns->child_reaper). This is what we need to DTRT in a
732 * PID namespace. However we still need the check above, see
733 * http://marc.info/?l=linux-kernel&m=131385460420380
734 */
735 for (reaper = father->real_parent;
736 reaper != &init_task;
737 reaper = reaper->real_parent) {
738 if (same_thread_group(reaper, pid_ns->child_reaper))
739 break;
740 if (!reaper->signal->is_child_subreaper)
741 continue;
742 thread = reaper;
743 do {
744 if (!(thread->flags & PF_EXITING))
745 return reaper;
746 } while_each_thread(reaper, thread);
747 }
725 } 748 }
726 749
727 return pid_ns->child_reaper; 750 return pid_ns->child_reaper;