diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-11-22 15:13:48 -0500 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2012-01-13 12:48:50 -0500 |
commit | 6c303d3ab39f0dc69546f179c424ee1124f50906 (patch) | |
tree | 40fd551256229f2ac1f931c3f9e650ba67deefc7 | |
parent | 099469502f62fbe0d7e4f0b83a2f22538367f734 (diff) |
tracing: let trace_signal_generate() report more info, kill overflow_fail/lose_info
__send_signal()->trace_signal_generate() doesn't report enough info.
The users want to know was the signal actually delivered or not, and
they also need the shared/private info.
The patch moves trace_signal_generate() at the end of __send_signal()
and adds the 2 additional arguments.
This also allows us to kill trace_signal_overflow_fail/lose_info, we
can simply add the appropriate TRACE_SIGNAL_ "result" codes.
Reported-by: Seiji Aguchi <saguchi@redhat.com>
Reviewed-by: Seiji Aguchi <seiji.aguchi@hds.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
-rw-r--r-- | include/trace/events/signal.h | 85 | ||||
-rw-r--r-- | kernel/signal.c | 22 |
2 files changed, 36 insertions, 71 deletions
diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h index 17df43464df0..39a8a430d90f 100644 --- a/include/trace/events/signal.h +++ b/include/trace/events/signal.h | |||
@@ -23,11 +23,23 @@ | |||
23 | } \ | 23 | } \ |
24 | } while (0) | 24 | } while (0) |
25 | 25 | ||
26 | #ifndef TRACE_HEADER_MULTI_READ | ||
27 | enum { | ||
28 | TRACE_SIGNAL_DELIVERED, | ||
29 | TRACE_SIGNAL_IGNORED, | ||
30 | TRACE_SIGNAL_ALREADY_PENDING, | ||
31 | TRACE_SIGNAL_OVERFLOW_FAIL, | ||
32 | TRACE_SIGNAL_LOSE_INFO, | ||
33 | }; | ||
34 | #endif | ||
35 | |||
26 | /** | 36 | /** |
27 | * signal_generate - called when a signal is generated | 37 | * signal_generate - called when a signal is generated |
28 | * @sig: signal number | 38 | * @sig: signal number |
29 | * @info: pointer to struct siginfo | 39 | * @info: pointer to struct siginfo |
30 | * @task: pointer to struct task_struct | 40 | * @task: pointer to struct task_struct |
41 | * @group: shared or private | ||
42 | * @result: TRACE_SIGNAL_* | ||
31 | * | 43 | * |
32 | * Current process sends a 'sig' signal to 'task' process with | 44 | * Current process sends a 'sig' signal to 'task' process with |
33 | * 'info' siginfo. If 'info' is SEND_SIG_NOINFO or SEND_SIG_PRIV, | 45 | * 'info' siginfo. If 'info' is SEND_SIG_NOINFO or SEND_SIG_PRIV, |
@@ -37,9 +49,10 @@ | |||
37 | */ | 49 | */ |
38 | TRACE_EVENT(signal_generate, | 50 | TRACE_EVENT(signal_generate, |
39 | 51 | ||
40 | TP_PROTO(int sig, struct siginfo *info, struct task_struct *task), | 52 | TP_PROTO(int sig, struct siginfo *info, struct task_struct *task, |
53 | int group, int result), | ||
41 | 54 | ||
42 | TP_ARGS(sig, info, task), | 55 | TP_ARGS(sig, info, task, group, result), |
43 | 56 | ||
44 | TP_STRUCT__entry( | 57 | TP_STRUCT__entry( |
45 | __field( int, sig ) | 58 | __field( int, sig ) |
@@ -47,6 +60,8 @@ TRACE_EVENT(signal_generate, | |||
47 | __field( int, code ) | 60 | __field( int, code ) |
48 | __array( char, comm, TASK_COMM_LEN ) | 61 | __array( char, comm, TASK_COMM_LEN ) |
49 | __field( pid_t, pid ) | 62 | __field( pid_t, pid ) |
63 | __field( int, group ) | ||
64 | __field( int, result ) | ||
50 | ), | 65 | ), |
51 | 66 | ||
52 | TP_fast_assign( | 67 | TP_fast_assign( |
@@ -54,11 +69,14 @@ TRACE_EVENT(signal_generate, | |||
54 | TP_STORE_SIGINFO(__entry, info); | 69 | TP_STORE_SIGINFO(__entry, info); |
55 | memcpy(__entry->comm, task->comm, TASK_COMM_LEN); | 70 | memcpy(__entry->comm, task->comm, TASK_COMM_LEN); |
56 | __entry->pid = task->pid; | 71 | __entry->pid = task->pid; |
72 | __entry->group = group; | ||
73 | __entry->result = result; | ||
57 | ), | 74 | ), |
58 | 75 | ||
59 | TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d", | 76 | TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d grp=%d res=%d", |
60 | __entry->sig, __entry->errno, __entry->code, | 77 | __entry->sig, __entry->errno, __entry->code, |
61 | __entry->comm, __entry->pid) | 78 | __entry->comm, __entry->pid, __entry->group, |
79 | __entry->result) | ||
62 | ); | 80 | ); |
63 | 81 | ||
64 | /** | 82 | /** |
@@ -101,65 +119,6 @@ TRACE_EVENT(signal_deliver, | |||
101 | __entry->sa_handler, __entry->sa_flags) | 119 | __entry->sa_handler, __entry->sa_flags) |
102 | ); | 120 | ); |
103 | 121 | ||
104 | DECLARE_EVENT_CLASS(signal_queue_overflow, | ||
105 | |||
106 | TP_PROTO(int sig, int group, struct siginfo *info), | ||
107 | |||
108 | TP_ARGS(sig, group, info), | ||
109 | |||
110 | TP_STRUCT__entry( | ||
111 | __field( int, sig ) | ||
112 | __field( int, group ) | ||
113 | __field( int, errno ) | ||
114 | __field( int, code ) | ||
115 | ), | ||
116 | |||
117 | TP_fast_assign( | ||
118 | __entry->sig = sig; | ||
119 | __entry->group = group; | ||
120 | TP_STORE_SIGINFO(__entry, info); | ||
121 | ), | ||
122 | |||
123 | TP_printk("sig=%d group=%d errno=%d code=%d", | ||
124 | __entry->sig, __entry->group, __entry->errno, __entry->code) | ||
125 | ); | ||
126 | |||
127 | /** | ||
128 | * signal_overflow_fail - called when signal queue is overflow | ||
129 | * @sig: signal number | ||
130 | * @group: signal to process group or not (bool) | ||
131 | * @info: pointer to struct siginfo | ||
132 | * | ||
133 | * Kernel fails to generate 'sig' signal with 'info' siginfo, because | ||
134 | * siginfo queue is overflow, and the signal is dropped. | ||
135 | * 'group' is not 0 if the signal will be sent to a process group. | ||
136 | * 'sig' is always one of RT signals. | ||
137 | */ | ||
138 | DEFINE_EVENT(signal_queue_overflow, signal_overflow_fail, | ||
139 | |||
140 | TP_PROTO(int sig, int group, struct siginfo *info), | ||
141 | |||
142 | TP_ARGS(sig, group, info) | ||
143 | ); | ||
144 | |||
145 | /** | ||
146 | * signal_lose_info - called when siginfo is lost | ||
147 | * @sig: signal number | ||
148 | * @group: signal to process group or not (bool) | ||
149 | * @info: pointer to struct siginfo | ||
150 | * | ||
151 | * Kernel generates 'sig' signal but loses 'info' siginfo, because siginfo | ||
152 | * queue is overflow. | ||
153 | * 'group' is not 0 if the signal will be sent to a process group. | ||
154 | * 'sig' is always one of non-RT signals. | ||
155 | */ | ||
156 | DEFINE_EVENT(signal_queue_overflow, signal_lose_info, | ||
157 | |||
158 | TP_PROTO(int sig, int group, struct siginfo *info), | ||
159 | |||
160 | TP_ARGS(sig, group, info) | ||
161 | ); | ||
162 | |||
163 | #endif /* _TRACE_SIGNAL_H */ | 122 | #endif /* _TRACE_SIGNAL_H */ |
164 | 123 | ||
165 | /* This part must be outside protection */ | 124 | /* This part must be outside protection */ |
diff --git a/kernel/signal.c b/kernel/signal.c index c73c4284160e..1bd9e86fda1f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1054,13 +1054,13 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
1054 | struct sigpending *pending; | 1054 | struct sigpending *pending; |
1055 | struct sigqueue *q; | 1055 | struct sigqueue *q; |
1056 | int override_rlimit; | 1056 | int override_rlimit; |
1057 | 1057 | int ret = 0, result; | |
1058 | trace_signal_generate(sig, info, t); | ||
1059 | 1058 | ||
1060 | assert_spin_locked(&t->sighand->siglock); | 1059 | assert_spin_locked(&t->sighand->siglock); |
1061 | 1060 | ||
1061 | result = TRACE_SIGNAL_IGNORED; | ||
1062 | if (!prepare_signal(sig, t, from_ancestor_ns)) | 1062 | if (!prepare_signal(sig, t, from_ancestor_ns)) |
1063 | return 0; | 1063 | goto ret; |
1064 | 1064 | ||
1065 | pending = group ? &t->signal->shared_pending : &t->pending; | 1065 | pending = group ? &t->signal->shared_pending : &t->pending; |
1066 | /* | 1066 | /* |
@@ -1068,8 +1068,11 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
1068 | * exactly one non-rt signal, so that we can get more | 1068 | * exactly one non-rt signal, so that we can get more |
1069 | * detailed information about the cause of the signal. | 1069 | * detailed information about the cause of the signal. |
1070 | */ | 1070 | */ |
1071 | result = TRACE_SIGNAL_ALREADY_PENDING; | ||
1071 | if (legacy_queue(pending, sig)) | 1072 | if (legacy_queue(pending, sig)) |
1072 | return 0; | 1073 | goto ret; |
1074 | |||
1075 | result = TRACE_SIGNAL_DELIVERED; | ||
1073 | /* | 1076 | /* |
1074 | * fast-pathed signals for kernel-internal things like SIGSTOP | 1077 | * fast-pathed signals for kernel-internal things like SIGSTOP |
1075 | * or SIGKILL. | 1078 | * or SIGKILL. |
@@ -1127,14 +1130,15 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
1127 | * signal was rt and sent by user using something | 1130 | * signal was rt and sent by user using something |
1128 | * other than kill(). | 1131 | * other than kill(). |
1129 | */ | 1132 | */ |
1130 | trace_signal_overflow_fail(sig, group, info); | 1133 | result = TRACE_SIGNAL_OVERFLOW_FAIL; |
1131 | return -EAGAIN; | 1134 | ret = -EAGAIN; |
1135 | goto ret; | ||
1132 | } else { | 1136 | } else { |
1133 | /* | 1137 | /* |
1134 | * This is a silent loss of information. We still | 1138 | * This is a silent loss of information. We still |
1135 | * send the signal, but the *info bits are lost. | 1139 | * send the signal, but the *info bits are lost. |
1136 | */ | 1140 | */ |
1137 | trace_signal_lose_info(sig, group, info); | 1141 | result = TRACE_SIGNAL_LOSE_INFO; |
1138 | } | 1142 | } |
1139 | } | 1143 | } |
1140 | 1144 | ||
@@ -1142,7 +1146,9 @@ out_set: | |||
1142 | signalfd_notify(t, sig); | 1146 | signalfd_notify(t, sig); |
1143 | sigaddset(&pending->signal, sig); | 1147 | sigaddset(&pending->signal, sig); |
1144 | complete_signal(sig, t, group); | 1148 | complete_signal(sig, t, group); |
1145 | return 0; | 1149 | ret: |
1150 | trace_signal_generate(sig, info, t, group, result); | ||
1151 | return ret; | ||
1146 | } | 1152 | } |
1147 | 1153 | ||
1148 | static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | 1154 | static int send_signal(int sig, struct siginfo *info, struct task_struct *t, |