On 3/26/21 4:35 PM, Eric W. Biederman wrote: > Jens Axboe <axboe@xxxxxxxxx> writes: > >> On 3/26/21 4:23 PM, Eric W. Biederman wrote: >>> Jens Axboe <axboe@xxxxxxxxx> writes: >>> >>>> On 3/26/21 2:29 PM, Eric W. Biederman wrote: >>>>> Jens Axboe <axboe@xxxxxxxxx> writes: >>>>> >>>>>> We go through various hoops to disallow signals for the IO threads, but >>>>>> there's really no reason why we cannot just allow them. The IO threads >>>>>> never return to userspace like a normal thread, and hence don't go through >>>>>> normal signal processing. Instead, just check for a pending signal as part >>>>>> of the work loop, and call get_signal() to handle it for us if anything >>>>>> is pending. >>>>>> >>>>>> With that, we can support receiving signals, including special ones like >>>>>> SIGSTOP. >>>>>> >>>>>> Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> >>>>>> --- >>>>>> fs/io-wq.c | 24 +++++++++++++++++------- >>>>>> fs/io_uring.c | 12 ++++++++---- >>>>>> 2 files changed, 25 insertions(+), 11 deletions(-) >>>>>> >>>>>> diff --git a/fs/io-wq.c b/fs/io-wq.c >>>>>> index b7c1fa932cb3..3e2f059a1737 100644 >>>>>> --- a/fs/io-wq.c >>>>>> +++ b/fs/io-wq.c >>>>>> @@ -16,7 +16,6 @@ >>>>>> #include <linux/rculist_nulls.h> >>>>>> #include <linux/cpu.h> >>>>>> #include <linux/tracehook.h> >>>>>> -#include <linux/freezer.h> >>>>>> >>>>>> #include "../kernel/sched/sched.h" >>>>>> #include "io-wq.h" >>>>>> @@ -503,10 +502,16 @@ static int io_wqe_worker(void *data) >>>>>> if (io_flush_signals()) >>>>>> continue; >>>>>> ret = schedule_timeout(WORKER_IDLE_TIMEOUT); >>>>>> - if (try_to_freeze() || ret) >>>>>> + if (signal_pending(current)) { >>>>>> + struct ksignal ksig; >>>>>> + >>>>>> + if (fatal_signal_pending(current)) >>>>>> + break; >>>>>> + if (get_signal(&ksig)) >>>>>> + continue; >>>>> ^^^^^^^^^^^^^^^^^^^^^^ >>>>> >>>>> That is wrong. You are promising to deliver a signal to signal >>>>> handler and them simply discarding it. Perhaps: >>>>> >>>>> if (!get_signal(&ksig)) >>>>> continue; >>>>> WARN_ON(!sig_kernel_stop(ksig->sig)); >>>>> break; >>>> >>>> Thanks, updated. >>> >>> Gah. Kill the WARN_ON. >>> >>> I was thinking "WARN_ON(!sig_kernel_fatal(ksig->sig));" >>> The function sig_kernel_fatal does not exist. >>> >>> Fatal is the state that is left when a signal is neither >>> ignored nor a stop signal, and does not have a handler. >>> >>> The rest of the logic still works. >> >> I've just come to the same conclusion myself after testing it. >> Of the 3 cases, most of them can do the continue, but doesn't >> really matter with the way the loop is structured. Anyway, looks >> like this now: > > This idiom in the code: >> + if (signal_pending(current)) { >> + struct ksignal ksig; >> + >> + if (fatal_signal_pending(current)) >> + break; >> + if (!get_signal(&ksig)) >> + continue; >> } > > Needs to be: >> + if (signal_pending(current)) { >> + struct ksignal ksig; >> + >> + if (!get_signal(&ksig)) >> + continue; >> + break; >> } > > Because any signal returned from get_signal is fatal in this case. > It might make sense to "WARN_ON(ksig->ka.sa.sa_handler != SIG_DFL)". > As the io workers don't handle that case. > > It won't happen because you have everything blocked. > > The extra fatal_signal_pending(current) logic is just confusing in this > case. OK good point, and follows the same logic even if it won't make a difference in my case. I'll make the change. -- Jens Axboe