Eric W. Biederman
2023-May-18 03:49 UTC
[RFC PATCH 1/8] signal: Dequeue SIGKILL even if SIGNAL_GROUP_EXIT/group_exec_task is set
Long story short. In the patch below the first hunk is a noop. The code you are bypassing was added to ensure that process termination (aka SIGKILL) is processed before any other signals. Other than signal processing order there are not any substantive differences in the two code paths. With all signals except SIGSTOP == 19 and SIGKILL == 9 blocked SIGKILL should always be processed before SIGSTOP. Can you try patch with just the last hunk that does s/PF_IO_WORKER/PF_USER_WORKER/ and see if that is enough? I have no objections to the final hunk. Mike Christie <michael.christie at oracle.com> writes:> This has us deqeue SIGKILL even if SIGNAL_GROUP_EXIT/group_exec_task is > set when we are dealing with PF_USER_WORKER tasks. > > When a vhost_task gets a SIGKILL, we could have outstanding IO in flight. > We can easily stop new work/IO from being queued to the vhost_task, but > for IO that's already been sent to something like the block layer we > need to wait for the response then process it. These type of IO > completions use the vhost_task to process the completion so we can't > exit immediately. > > We need to handle wait for then handle those completions from the > vhost_task, but when we have a SIGKLL pending, functions like > schedule() return immediately so we can't wait like normal. Functions > like vhost_worker() degrade to just a while(1); loop. > > This patch has get_signal drop down to the normal code path when > SIGNAL_GROUP_EXIT/group_exec_task is set so the caller can still detect > there is a SIGKILL but still perform some blocking cleanup. > > Note that in that chunk I'm now bypassing that does: > > sigdelset(¤t->pending.signal, SIGKILL); > > we look to be ok, because in the places we set SIGNAL_GROUP_EXIT/ > group_exec_task we are already doing that on the threads in the > group. > > Signed-off-by: Mike Christie <michael.christie at oracle.com> > --- > kernel/signal.c | 19 ++++++++++++++----- > 1 file changed, 14 insertions(+), 5 deletions(-) > > diff --git a/kernel/signal.c b/kernel/signal.c > index 8f6330f0e9ca..ae4972eea5db 100644 > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -2705,9 +2705,18 @@ bool get_signal(struct ksignal *ksig) > struct k_sigaction *ka; > enum pid_type type; > > - /* Has this task already been marked for death? */ > - if ((signal->flags & SIGNAL_GROUP_EXIT) || > - signal->group_exec_task) { > + /* > + * Has this task already been marked for death? > + * > + * If this is a PF_USER_WORKER then the task may need to do > + * extra work that requires waiting on running work, so we want > + * to dequeue the signal below and tell the caller its time to > + * start its exit procedure. When the work has completed then > + * the task will exit. > + */ > + if (!(current->flags & PF_USER_WORKER) && > + ((signal->flags & SIGNAL_GROUP_EXIT) || > + signal->group_exec_task)) { > clear_siginfo(&ksig->info); > ksig->info.si_signo = signr = SIGKILL; > sigdelset(¤t->pending.signal, SIGKILL);This hunk is a confusing no-op.> @@ -2861,11 +2870,11 @@ bool get_signal(struct ksignal *ksig) > } > > /* > - * PF_IO_WORKER threads will catch and exit on fatal signals > + * PF_USER_WORKER threads will catch and exit on fatal signals > * themselves. They have cleanup that must be performed, so > * we cannot call do_exit() on their behalf. > */ > - if (current->flags & PF_IO_WORKER) > + if (current->flags & PF_USER_WORKER) > goto out; > > /*This hunk is good and makes sense. Eric
Mike Christie
2023-May-18 15:21 UTC
[RFC PATCH 1/8] signal: Dequeue SIGKILL even if SIGNAL_GROUP_EXIT/group_exec_task is set
On 5/17/23 10:49 PM, Eric W. Biederman wrote:> > Long story short. > > In the patch below the first hunk is a noop. > > The code you are bypassing was added to ensure that process termination > (aka SIGKILL) is processed before any other signals. Other than signal > processing order there are not any substantive differences in the two > code paths. With all signals except SIGSTOP == 19 and SIGKILL == 9 > blocked SIGKILL should always be processed before SIGSTOP. > > Can you try patch with just the last hunk that does > s/PF_IO_WORKER/PF_USER_WORKER/ and see if that is enough? >If I just have the last hunk and then we get SIGKILL what happens is in code like: vhost_worker() schedule() if (has IO) handle_IO() The schedule() calls will hit the signal_pending_state check for signal_pending or __fatal_signal_pending and so instead of waiting for whatever wake_up call we normally waited for we tend to just return immediately. If you just run Qemu (the parent of the vhost_task) and send SIGKILL then sometimes the vhost_task just spins and it would look like the task has taken over the CPU (this is what I hit when I tested Linus's patch). With the first hunk of the patch, we will end up dequeuing the SIGKILL and clearing TIF_SIGPENDING, so the vhost_task can still do some work before it exits. In the other patches we do: if (get_signal(ksig)) start_exit_cleanup_by_stopping_newIO() flush running IO() exit() But to do the flush running IO() part of this I need to wait for it so that's why I wanted to be able to dequeue the SIGKILL and clear the TIF_SIGPENDING bit. Or I don't need this specifically. In patch 0/8 I said I knew you guys would not like it :) If I just have a: if (fatal_signal()) clear_fatal_signal() then it would work for me.