]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - rt-patches/0048-signal-x86-Delay-calling-signals-in-atomic.patch
rt_patches: required rebase due to printk change
[hercules2020/nv-tegra/linux-4.4.git] / rt-patches / 0048-signal-x86-Delay-calling-signals-in-atomic.patch
1 From 703ef32f8ce6b0be47e05861a7eedccde862973c Mon Sep 17 00:00:00 2001
2 From: Oleg Nesterov <oleg@redhat.com>
3 Date: Tue, 14 Jul 2015 14:26:34 +0200
4 Subject: [PATCH 048/366] signal/x86: Delay calling signals in atomic
5
6 On x86_64 we must disable preemption before we enable interrupts
7 for stack faults, int3 and debugging, because the current task is using
8 a per CPU debug stack defined by the IST. If we schedule out, another task
9 can come in and use the same stack and cause the stack to be corrupted
10 and crash the kernel on return.
11
12 When CONFIG_PREEMPT_RT_FULL is enabled, spin_locks become mutexes, and
13 one of these is the spin lock used in signal handling.
14
15 Some of the debug code (int3) causes do_trap() to send a signal.
16 This function calls a spin lock that has been converted to a mutex
17 and has the possibility to sleep. If this happens, the above issues with
18 the corrupted stack is possible.
19
20 Instead of calling the signal right away, for PREEMPT_RT and x86_64,
21 the signal information is stored on the stacks task_struct and
22 TIF_NOTIFY_RESUME is set. Then on exit of the trap, the signal resume
23 code will send the signal when preemption is enabled.
24
25 [ rostedt: Switched from #ifdef CONFIG_PREEMPT_RT_FULL to
26   ARCH_RT_DELAYS_SIGNAL_SEND and added comments to the code. ]
27
28 Signed-off-by: Oleg Nesterov <oleg@redhat.com>
29 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
30 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
31 ---
32  arch/x86/entry/common.c       |  7 +++++++
33  arch/x86/include/asm/signal.h | 13 +++++++++++++
34  include/linux/sched.h         |  4 ++++
35  kernel/signal.c               | 37 +++++++++++++++++++++++++++++++++++--
36  4 files changed, 59 insertions(+), 2 deletions(-)
37
38 diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
39 index 1a4477c..d6db3ad 100644
40 --- a/arch/x86/entry/common.c
41 +++ b/arch/x86/entry/common.c
42 @@ -239,6 +239,13 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
43                 if (cached_flags & _TIF_NEED_RESCHED)
44                         schedule();
45  
46 +#ifdef ARCH_RT_DELAYS_SIGNAL_SEND
47 +               if (unlikely(current->forced_info.si_signo)) {
48 +                       struct task_struct *t = current;
49 +                       force_sig_info(t->forced_info.si_signo, &t->forced_info, t);
50 +                       t->forced_info.si_signo = 0;
51 +               }
52 +#endif
53                 if (cached_flags & _TIF_UPROBE)
54                         uprobe_notify_resume(regs);
55  
56 diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
57 index 2138c9a..a32fe27 100644
58 --- a/arch/x86/include/asm/signal.h
59 +++ b/arch/x86/include/asm/signal.h
60 @@ -23,6 +23,19 @@ typedef struct {
61         unsigned long sig[_NSIG_WORDS];
62  } sigset_t;
63  
64 +/*
65 + * Because some traps use the IST stack, we must keep preemption
66 + * disabled while calling do_trap(), but do_trap() may call
67 + * force_sig_info() which will grab the signal spin_locks for the
68 + * task, which in PREEMPT_RT_FULL are mutexes.  By defining
69 + * ARCH_RT_DELAYS_SIGNAL_SEND the force_sig_info() will set
70 + * TIF_NOTIFY_RESUME and set up the signal to be sent on exit of the
71 + * trap.
72 + */
73 +#if defined(CONFIG_PREEMPT_RT_FULL) && defined(CONFIG_X86_64)
74 +#define ARCH_RT_DELAYS_SIGNAL_SEND
75 +#endif
76 +
77  #ifndef CONFIG_COMPAT
78  typedef sigset_t compat_sigset_t;
79  #endif
80 diff --git a/include/linux/sched.h b/include/linux/sched.h
81 index b08d1ca..fb5ee52 100644
82 --- a/include/linux/sched.h
83 +++ b/include/linux/sched.h
84 @@ -1591,6 +1591,10 @@ struct task_struct {
85         sigset_t blocked, real_blocked;
86         sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
87         struct sigpending pending;
88 +#ifdef CONFIG_PREEMPT_RT_FULL
89 +       /* TODO: move me into ->restart_block ? */
90 +       struct siginfo forced_info;
91 +#endif
92  
93         unsigned long sas_ss_sp;
94         size_t sas_ss_size;
95 diff --git a/kernel/signal.c b/kernel/signal.c
96 index 575bcb4..bc2c990 100644
97 --- a/kernel/signal.c
98 +++ b/kernel/signal.c
99 @@ -1216,8 +1216,8 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
100   * We don't want to have recursive SIGSEGV's etc, for example,
101   * that is why we also clear SIGNAL_UNKILLABLE.
102   */
103 -int
104 -force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
105 +static int
106 +do_force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
107  {
108         unsigned long int flags;
109         int ret, blocked, ignored;
110 @@ -1242,6 +1242,39 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
111         return ret;
112  }
113  
114 +int force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
115 +{
116 +/*
117 + * On some archs, PREEMPT_RT has to delay sending a signal from a trap
118 + * since it can not enable preemption, and the signal code's spin_locks
119 + * turn into mutexes. Instead, it must set TIF_NOTIFY_RESUME which will
120 + * send the signal on exit of the trap.
121 + */
122 +#ifdef ARCH_RT_DELAYS_SIGNAL_SEND
123 +       if (in_atomic()) {
124 +               if (WARN_ON_ONCE(t != current))
125 +                       return 0;
126 +               if (WARN_ON_ONCE(t->forced_info.si_signo))
127 +                       return 0;
128 +
129 +               if (is_si_special(info)) {
130 +                       WARN_ON_ONCE(info != SEND_SIG_PRIV);
131 +                       t->forced_info.si_signo = sig;
132 +                       t->forced_info.si_errno = 0;
133 +                       t->forced_info.si_code = SI_KERNEL;
134 +                       t->forced_info.si_pid = 0;
135 +                       t->forced_info.si_uid = 0;
136 +               } else {
137 +                       t->forced_info = *info;
138 +               }
139 +
140 +               set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
141 +               return 0;
142 +       }
143 +#endif
144 +       return do_force_sig_info(sig, info, t);
145 +}
146 +
147  /*
148   * Nuke all other threads in the group.
149   */
150 -- 
151 1.9.1
152