<p dir="ltr"></p>
<p dir="ltr">On Jul 22, 2016 5:17 AM, &quot;Pavel Emelyanov&quot; &lt;<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a>&gt; wrote:<br>
&gt;<br>
&gt; On 07/13/2016 06:10 PM, Tycho Andersen wrote:<br>
&gt; &gt; For example, if a zombie has a helper that sets up its session id, the<br>
&gt; &gt; zombie will be reparented to the init task, which will then potentially get<br>
&gt; &gt; a SIGCHLD for a task which isn&#39;t its direct child zombie, which we didn&#39;t<br>
&gt; &gt; handle. Instead, let&#39;s recursively find all the zombies for the init task,<br>
&gt; &gt; in case they get reparented this way.<br>
&gt; &gt;<br>
&gt; &gt; This commit is a little ugly: we are now passing three lists of pids<br>
&gt; &gt; (helpers, zombies, and things that are allowed to die) to the restorer blob<br>
&gt; &gt; for each task. We do need to have some way to distinguish, because:<br>
&gt; &gt;<br>
&gt; &gt; * we want to wait on helpers<br>
&gt; &gt; * we don&#39;t want to wait on zombies (i.e. we want to keep the pid dead), but<br>
&gt; &gt;   confirm that it actually died<br>
&gt; &gt; * we don&#39;t want to wait on anything that gets reparented, but we don&#39;t want<br>
&gt; &gt;   to error out if we get a SIGCHLD for it<br>
&gt; &gt;<br>
&gt; &gt; We could introduce a new struct:<br>
&gt; &gt;<br>
&gt; &gt; struct pid_info {<br>
&gt; &gt;   pid_t pid;<br>
&gt; &gt;   bool  zombie;<br>
&gt; &gt;   bool  direct_child;<br>
&gt; &gt; }<br>
&gt;<br>
&gt; Let&#39;s try to go this route, but slightly ... modified.<br>
&gt;<br>
&gt; struct restorer_pid_info {<br>
&gt;         pid_t pid;<br>
&gt;         unsigned type;<br>
&gt; }<br>
&gt;<br>
&gt; The type would be ZOMBIE, HELPER or OTHER.<br>
&gt;<br>
&gt; Next, instead of calling collect_zombie_pids, collect_helper_pids and<br>
&gt; collect_allowed_to_die_pids, let&#39;s call one collect_restorer_pids()<br>
&gt; that would fill the array of restorer_pid_info-s with types and, if<br>
&gt; the caller is root_item, would dive into recursion only collecting for<br>
&gt; TASK_DEAD entries.<br>
&gt;<br>
&gt; In the restorer itself we would need to merge wait_zombies() and<br>
&gt; wait_helpers() to only walk the list once and tune the sigchild helper<br>
&gt; to allow for sigchilds from any pid in the array.<br>
&gt;<br>
&gt; What do you think?</p>
<p dir="ltr">Sounds good, except I am on vacation starting today and through the end of next week :-). Feel free to revert the failing test and I can resend both when I finish this.</p>
<p dir="ltr">Tycho <br>
&gt;<br>
&gt; -- Pavel<br>
&gt;<br>
&gt; &gt; to handle this instead of the three separate lists. I&#39;m not sure which is<br>
&gt; &gt; cleaner, but I&#39;d be happy to refactor to the other way if that&#39;s better.<br>
&gt; &gt;<br>
&gt; &gt; v2: only the zombies need to be recursively collected, helpers wait on<br>
&gt; &gt;     their children before they exit and will never be reparented<br>
&gt; &gt;<br>
&gt; &gt; Signed-off-by: Tycho Andersen &lt;<a href="mailto:tycho.andersen@canonical.com">tycho.andersen@canonical.com</a>&gt;<br>
&gt; &gt; ---<br>
&gt; &gt;  criu/cr-restore.c       | 31 ++++++++++++++++++++++++++-----<br>
&gt; &gt;  criu/include/restorer.h |  3 +++<br>
&gt; &gt;  criu/pie/restorer.c     | 20 ++++++--------------<br>
&gt; &gt;  3 files changed, 35 insertions(+), 19 deletions(-)<br>
&gt; &gt;<br>
&gt; &gt; diff --git a/criu/cr-restore.c b/criu/cr-restore.c<br>
&gt; &gt; index 977e049..d8e4cf1 100644<br>
&gt; &gt; --- a/criu/cr-restore.c<br>
&gt; &gt; +++ b/criu/cr-restore.c<br>
&gt; &gt; @@ -487,14 +487,16 @@ static int prepare_sigactions(void)<br>
&gt; &gt;       return ret;<br>
&gt; &gt;  }<br>
&gt; &gt;<br>
&gt; &gt; -static int collect_child_pids(int state, unsigned int *n)<br>
&gt; &gt; +static int collect_child_pids(struct pstree_item *root, int state, unsigned int *n, bool recurse)<br>
&gt; &gt;  {<br>
&gt; &gt;       struct pstree_item *pi;<br>
&gt; &gt;<br>
&gt; &gt; -     *n = 0;<br>
&gt; &gt; -     list_for_each_entry(pi, &amp;current-&gt;children, sibling) {<br>
&gt; &gt; +     list_for_each_entry(pi, &amp;root-&gt;children, sibling) {<br>
&gt; &gt;               pid_t *child;<br>
&gt; &gt;<br>
&gt; &gt; +             if (recurse &amp;&amp; collect_child_pids(pi, state, n, recurse) &lt; 0)<br>
&gt; &gt; +                     return -1;<br>
&gt; &gt; +<br>
&gt; &gt;               if (pi-&gt;pid.state != state)<br>
&gt; &gt;                       continue;<br>
&gt; &gt;<br>
&gt; &gt; @@ -512,13 +514,28 @@ static int collect_child_pids(int state, unsigned int *n)<br>
&gt; &gt;  static int collect_helper_pids(struct task_restore_args *ta)<br>
&gt; &gt;  {<br>
&gt; &gt;       ta-&gt;helpers = (pid_t *)rst_mem_align_cpos(RM_PRIVATE);<br>
&gt; &gt; -     return collect_child_pids(TASK_HELPER, &amp;ta-&gt;helpers_n);<br>
&gt; &gt; +     ta-&gt;helpers_n = 0;<br>
&gt; &gt; +     return collect_child_pids(current, TASK_HELPER, &amp;ta-&gt;helpers_n, false);<br>
&gt; &gt;  }<br>
&gt; &gt;<br>
&gt; &gt;  static int collect_zombie_pids(struct task_restore_args *ta)<br>
&gt; &gt;  {<br>
&gt; &gt;       ta-&gt;zombies = (pid_t *)rst_mem_align_cpos(RM_PRIVATE);<br>
&gt; &gt; -     return collect_child_pids(TASK_DEAD, &amp;ta-&gt;zombies_n);<br>
&gt; &gt; +     ta-&gt;zombies_n = 0;<br>
&gt; &gt; +     return collect_child_pids(current, TASK_DEAD, &amp;ta-&gt;zombies_n, false);<br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt; +static int collect_allowed_to_die_pids(struct task_restore_args *ta)<br>
&gt; &gt; +{<br>
&gt; &gt; +     ta-&gt;allowed_to_die = (pid_t *)rst_mem_align_cpos(RM_PRIVATE);<br>
&gt; &gt; +     ta-&gt;allowed_to_die_n = 0;<br>
&gt; &gt; +<br>
&gt; &gt; +     if (collect_child_pids(current, TASK_DEAD, &amp;ta-&gt;allowed_to_die_n, current == root_item) &lt; 0)<br>
&gt; &gt; +             return -1;<br>
&gt; &gt; +     if (collect_child_pids(current, TASK_HELPER, &amp;ta-&gt;allowed_to_die_n, false) &lt; 0)<br>
&gt; &gt; +             return -1;<br>
&gt; &gt; +<br>
&gt; &gt; +     return 0;<br>
&gt; &gt;  }<br>
&gt; &gt;<br>
&gt; &gt;  static int open_core(int pid, CoreEntry **pcore)<br>
&gt; &gt; @@ -655,6 +672,9 @@ static int restore_one_alive_task(int pid, CoreEntry *core)<br>
&gt; &gt;       if (collect_zombie_pids(ta) &lt; 0)<br>
&gt; &gt;               return -1;<br>
&gt; &gt;<br>
&gt; &gt; +     if (collect_allowed_to_die_pids(ta) &lt; 0)<br>
&gt; &gt; +             return -1;<br>
&gt; &gt; +<br>
&gt; &gt;       if (inherit_fd_fini() &lt; 0)<br>
&gt; &gt;               return -1;<br>
&gt; &gt;<br>
&gt; &gt; @@ -3003,6 +3023,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns<br>
&gt; &gt;       RST_MEM_FIXUP_PPTR(task_args-&gt;helpers);<br>
&gt; &gt;       RST_MEM_FIXUP_PPTR(task_args-&gt;zombies);<br>
&gt; &gt;       RST_MEM_FIXUP_PPTR(task_args-&gt;seccomp_filters);<br>
&gt; &gt; +     RST_MEM_FIXUP_PPTR(task_args-&gt;allowed_to_die);<br>
&gt; &gt;<br>
&gt; &gt;       if (core-&gt;tc-&gt;has_seccomp_mode)<br>
&gt; &gt;               task_args-&gt;seccomp_mode = core-&gt;tc-&gt;seccomp_mode;<br>
&gt; &gt; diff --git a/criu/include/restorer.h b/criu/include/restorer.h<br>
&gt; &gt; index 7c0336e..ac50bf0 100644<br>
&gt; &gt; --- a/criu/include/restorer.h<br>
&gt; &gt; +++ b/criu/include/restorer.h<br>
&gt; &gt; @@ -149,6 +149,9 @@ struct task_restore_args {<br>
&gt; &gt;       struct sock_fprog               *seccomp_filters;<br>
&gt; &gt;       unsigned int                    seccomp_filters_n;<br>
&gt; &gt;<br>
&gt; &gt; +     pid_t                           *allowed_to_die;<br>
&gt; &gt; +     unsigned int                    allowed_to_die_n;<br>
&gt; &gt; +<br>
&gt; &gt;       /* * * * * * * * * * * * * * * * * * * * */<br>
&gt; &gt;<br>
&gt; &gt;       unsigned long                   task_size;<br>
&gt; &gt; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c<br>
&gt; &gt; index 424ccf3..d3a24d8 100644<br>
&gt; &gt; --- a/criu/pie/restorer.c<br>
&gt; &gt; +++ b/criu/pie/restorer.c<br>
&gt; &gt; @@ -57,10 +57,8 @@<br>
&gt; &gt;<br>
&gt; &gt;  static struct task_entries *task_entries;<br>
&gt; &gt;  static futex_t thread_inprogress;<br>
&gt; &gt; -static pid_t *helpers;<br>
&gt; &gt; -static int n_helpers;<br>
&gt; &gt; -static pid_t *zombies;<br>
&gt; &gt; -static int n_zombies;<br>
&gt; &gt; +static pid_t *allowed_to_die;<br>
&gt; &gt; +static int n_allowed_to_die;<br>
&gt; &gt;<br>
&gt; &gt;  extern void cr_restore_rt (void) asm (&quot;__cr_restore_rt&quot;)<br>
&gt; &gt;                       __attribute__ ((visibility (&quot;hidden&quot;)));<br>
&gt; &gt; @@ -72,12 +70,8 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)<br>
&gt; &gt;<br>
&gt; &gt;       /* We can ignore helpers that die, we expect them to after<br>
&gt; &gt;        * CR_STATE_RESTORE is finished. */<br>
&gt; &gt; -     for (i = 0; i &lt; n_helpers; i++)<br>
&gt; &gt; -             if (siginfo-&gt;si_pid == helpers[i])<br>
&gt; &gt; -                     return;<br>
&gt; &gt; -<br>
&gt; &gt; -     for (i = 0; i &lt; n_zombies; i++)<br>
&gt; &gt; -             if (siginfo-&gt;si_pid == zombies[i])<br>
&gt; &gt; +     for (i = 0; i &lt; n_allowed_to_die; i++)<br>
&gt; &gt; +             if (siginfo-&gt;si_pid == allowed_to_die[i])<br>
&gt; &gt;                       return;<br>
&gt; &gt;<br>
&gt; &gt;       if (siginfo-&gt;si_code &amp; CLD_EXITED)<br>
&gt; &gt; @@ -1106,10 +1100,8 @@ long __export_restore_task(struct task_restore_args *args)<br>
&gt; &gt;  #endif<br>
&gt; &gt;<br>
&gt; &gt;       task_entries = args-&gt;task_entries;<br>
&gt; &gt; -     helpers = args-&gt;helpers;<br>
&gt; &gt; -     n_helpers = args-&gt;helpers_n;<br>
&gt; &gt; -     zombies = args-&gt;zombies;<br>
&gt; &gt; -     n_zombies = args-&gt;zombies_n;<br>
&gt; &gt; +     allowed_to_die = args-&gt;allowed_to_die;<br>
&gt; &gt; +     n_allowed_to_die = args-&gt;allowed_to_die_n;<br>
&gt; &gt;       *args-&gt;breakpoint = rst_sigreturn;<br>
&gt; &gt;<br>
&gt; &gt;       ksigfillset(&amp;act.rt_sa_mask);<br>
&gt; &gt;<br>
&gt;</p>