diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 2c634010cc7b..5e4194e12a7d 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -348,6 +348,12 @@ extern void sigqueue_free(struct sigqueue *); extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type); extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *); +static inline void clear_notify_signal(void) +{ + clear_thread_flag(TIF_NOTIFY_SIGNAL); + smp_mb__after_atomic(); +} + static inline int restart_syscall(void) { set_tsk_thread_flag(current, TIF_SIGPENDING); diff --git a/kernel/signal.c b/kernel/signal.c index e487c4660921..bfc1da526ebb 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2464,6 +2464,14 @@ static void do_freezer_trap(void) spin_unlock_irq(¤t->sighand->siglock); cgroup_enter_frozen(); freezable_schedule(); + + /* + * We could've been woken by task_work, run it to clear + * TIF_NOTIFY_SIGNAL. The caller will retry if necessary. + */ + clear_notify_signal(); + if (unlikely(READ_ONCE(current->task_works))) + task_work_run(); } static int ptrace_signal(int signr, kernel_siginfo_t *info)