aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorNaohiro Ooiwa <nooiwa@miraclelinux.com>2009-11-08 10:46:42 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-09 03:44:26 -0500
commitf84d49b218b7d4c6cba2e0b41f24bd4045403962 (patch)
treed62ed0c15152c1a0a78fb75feac649dafc05b041 /kernel/signal.c
parent2a855dd01bc1539111adb7233f587c5c468732ac (diff)
signal: Print warning message when dropping signals
When the system has too many timers or too many aggregate queued signals, the EAGAIN error is returned to application from kernel, including timer_create() [POSIX.1b]. It means that the app exceeded the limit of pending signals, but in general application writers do not expect this outcome and the current silent failure can cause rare app failures under very high load. This patch adds a new message when we reach the limit and if print_fatal_signals is enabled: task/1234: reached RLIMIT_SIGPENDING, dropping signal If you see this message and your system behaved unexpectedly, you can run following command to lift the limit: # ulimit -i unlimited With help from Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>. Signed-off-by: Naohiro Ooiwa <nooiwa@miraclelinux.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com> Cc: Roland McGrath <roland@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: oleg@redhat.com LKML-Reference: <4AF6E7E2.9080406@miraclelinux.com> [ Modified a few small details, gave surrounding code some love. ] Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 6705320784fd..fe08008133da 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -22,6 +22,7 @@
22#include <linux/ptrace.h> 22#include <linux/ptrace.h>
23#include <linux/signal.h> 23#include <linux/signal.h>
24#include <linux/signalfd.h> 24#include <linux/signalfd.h>
25#include <linux/ratelimit.h>
25#include <linux/tracehook.h> 26#include <linux/tracehook.h>
26#include <linux/capability.h> 27#include <linux/capability.h>
27#include <linux/freezer.h> 28#include <linux/freezer.h>
@@ -41,6 +42,8 @@
41 42
42static struct kmem_cache *sigqueue_cachep; 43static struct kmem_cache *sigqueue_cachep;
43 44
45int print_fatal_signals __read_mostly;
46
44static void __user *sig_handler(struct task_struct *t, int sig) 47static void __user *sig_handler(struct task_struct *t, int sig)
45{ 48{
46 return t->sighand->action[sig - 1].sa.sa_handler; 49 return t->sighand->action[sig - 1].sa.sa_handler;
@@ -159,7 +162,7 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
159{ 162{
160 unsigned long i, *s, *m, x; 163 unsigned long i, *s, *m, x;
161 int sig = 0; 164 int sig = 0;
162 165
163 s = pending->signal.sig; 166 s = pending->signal.sig;
164 m = mask->sig; 167 m = mask->sig;
165 switch (_NSIG_WORDS) { 168 switch (_NSIG_WORDS) {
@@ -184,17 +187,31 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
184 sig = ffz(~x) + 1; 187 sig = ffz(~x) + 1;
185 break; 188 break;
186 } 189 }
187 190
188 return sig; 191 return sig;
189} 192}
190 193
194static inline void print_dropped_signal(int sig)
195{
196 static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
197
198 if (!print_fatal_signals)
199 return;
200
201 if (!__ratelimit(&ratelimit_state))
202 return;
203
204 printk(KERN_INFO "%s/%d: reached RLIMIT_SIGPENDING, dropped signal %d\n",
205 current->comm, current->pid, sig);
206}
207
191/* 208/*
192 * allocate a new signal queue record 209 * allocate a new signal queue record
193 * - this may be called without locks if and only if t == current, otherwise an 210 * - this may be called without locks if and only if t == current, otherwise an
194 * appopriate lock must be held to stop the target task from exiting 211 * appopriate lock must be held to stop the target task from exiting
195 */ 212 */
196static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, 213static struct sigqueue *
197 int override_rlimit) 214__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit)
198{ 215{
199 struct sigqueue *q = NULL; 216 struct sigqueue *q = NULL;
200 struct user_struct *user; 217 struct user_struct *user;
@@ -207,10 +224,15 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
207 */ 224 */
208 user = get_uid(__task_cred(t)->user); 225 user = get_uid(__task_cred(t)->user);
209 atomic_inc(&user->sigpending); 226 atomic_inc(&user->sigpending);
227
210 if (override_rlimit || 228 if (override_rlimit ||
211 atomic_read(&user->sigpending) <= 229 atomic_read(&user->sigpending) <=
212 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) 230 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) {
213 q = kmem_cache_alloc(sigqueue_cachep, flags); 231 q = kmem_cache_alloc(sigqueue_cachep, flags);
232 } else {
233 print_dropped_signal(sig);
234 }
235
214 if (unlikely(q == NULL)) { 236 if (unlikely(q == NULL)) {
215 atomic_dec(&user->sigpending); 237 atomic_dec(&user->sigpending);
216 free_uid(user); 238 free_uid(user);
@@ -869,7 +891,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
869 else 891 else
870 override_rlimit = 0; 892 override_rlimit = 0;
871 893
872 q = __sigqueue_alloc(t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE, 894 q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,
873 override_rlimit); 895 override_rlimit);
874 if (q) { 896 if (q) {
875 list_add_tail(&q->list, &pending->list); 897 list_add_tail(&q->list, &pending->list);
@@ -925,8 +947,6 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
925 return __send_signal(sig, info, t, group, from_ancestor_ns); 947 return __send_signal(sig, info, t, group, from_ancestor_ns);
926} 948}
927 949
928int print_fatal_signals;
929
930static void print_fatal_signal(struct pt_regs *regs, int signr) 950static void print_fatal_signal(struct pt_regs *regs, int signr)
931{ 951{
932 printk("%s/%d: potentially unexpected fatal signal %d.\n", 952 printk("%s/%d: potentially unexpected fatal signal %d.\n",
@@ -1293,19 +1313,19 @@ EXPORT_SYMBOL(kill_pid);
1293 * These functions support sending signals using preallocated sigqueue 1313 * These functions support sending signals using preallocated sigqueue
1294 * structures. This is needed "because realtime applications cannot 1314 * structures. This is needed "because realtime applications cannot
1295 * afford to lose notifications of asynchronous events, like timer 1315 * afford to lose notifications of asynchronous events, like timer
1296 * expirations or I/O completions". In the case of Posix Timers 1316 * expirations or I/O completions". In the case of Posix Timers
1297 * we allocate the sigqueue structure from the timer_create. If this 1317 * we allocate the sigqueue structure from the timer_create. If this
1298 * allocation fails we are able to report the failure to the application 1318 * allocation fails we are able to report the failure to the application
1299 * with an EAGAIN error. 1319 * with an EAGAIN error.
1300 */ 1320 */
1301
1302struct sigqueue *sigqueue_alloc(void) 1321struct sigqueue *sigqueue_alloc(void)
1303{ 1322{
1304 struct sigqueue *q; 1323 struct sigqueue *q = __sigqueue_alloc(-1, current, GFP_KERNEL, 0);
1305 1324
1306 if ((q = __sigqueue_alloc(current, GFP_KERNEL, 0))) 1325 if (q)
1307 q->flags |= SIGQUEUE_PREALLOC; 1326 q->flags |= SIGQUEUE_PREALLOC;
1308 return(q); 1327
1328 return q;
1309} 1329}
1310 1330
1311void sigqueue_free(struct sigqueue *q) 1331void sigqueue_free(struct sigqueue *q)