diff options
-rw-r--r-- | include/linux/perf_event.h | 5 | ||||
-rw-r--r-- | kernel/events/callchain.c | 38 |
2 files changed, 28 insertions, 15 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index d1d25f6a5e24..297ca3db6b4a 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -268,7 +268,10 @@ struct perf_event_attr { | |||
268 | exclude_host : 1, /* don't count in host */ | 268 | exclude_host : 1, /* don't count in host */ |
269 | exclude_guest : 1, /* don't count in guest */ | 269 | exclude_guest : 1, /* don't count in guest */ |
270 | 270 | ||
271 | __reserved_1 : 43; | 271 | exclude_callchain_kernel : 1, /* exclude kernel callchains */ |
272 | exclude_callchain_user : 1, /* exclude user callchains */ | ||
273 | |||
274 | __reserved_1 : 41; | ||
272 | 275 | ||
273 | union { | 276 | union { |
274 | __u32 wakeup_events; /* wakeup every n events */ | 277 | __u32 wakeup_events; /* wakeup every n events */ |
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 98d4597f43d6..c77206184b8b 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c | |||
@@ -159,6 +159,11 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) | |||
159 | int rctx; | 159 | int rctx; |
160 | struct perf_callchain_entry *entry; | 160 | struct perf_callchain_entry *entry; |
161 | 161 | ||
162 | int kernel = !event->attr.exclude_callchain_kernel; | ||
163 | int user = !event->attr.exclude_callchain_user; | ||
164 | |||
165 | if (!kernel && !user) | ||
166 | return NULL; | ||
162 | 167 | ||
163 | entry = get_callchain_entry(&rctx); | 168 | entry = get_callchain_entry(&rctx); |
164 | if (rctx == -1) | 169 | if (rctx == -1) |
@@ -169,24 +174,29 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) | |||
169 | 174 | ||
170 | entry->nr = 0; | 175 | entry->nr = 0; |
171 | 176 | ||
172 | if (!user_mode(regs)) { | 177 | if (kernel && !user_mode(regs)) { |
173 | perf_callchain_store(entry, PERF_CONTEXT_KERNEL); | 178 | perf_callchain_store(entry, PERF_CONTEXT_KERNEL); |
174 | perf_callchain_kernel(entry, regs); | 179 | perf_callchain_kernel(entry, regs); |
175 | if (current->mm) | ||
176 | regs = task_pt_regs(current); | ||
177 | else | ||
178 | regs = NULL; | ||
179 | } | 180 | } |
180 | 181 | ||
181 | if (regs) { | 182 | if (user) { |
182 | /* | 183 | if (!user_mode(regs)) { |
183 | * Disallow cross-task user callchains. | 184 | if (current->mm) |
184 | */ | 185 | regs = task_pt_regs(current); |
185 | if (event->ctx->task && event->ctx->task != current) | 186 | else |
186 | goto exit_put; | 187 | regs = NULL; |
187 | 188 | } | |
188 | perf_callchain_store(entry, PERF_CONTEXT_USER); | 189 | |
189 | perf_callchain_user(entry, regs); | 190 | if (regs) { |
191 | /* | ||
192 | * Disallow cross-task user callchains. | ||
193 | */ | ||
194 | if (event->ctx->task && event->ctx->task != current) | ||
195 | goto exit_put; | ||
196 | |||
197 | perf_callchain_store(entry, PERF_CONTEXT_USER); | ||
198 | perf_callchain_user(entry, regs); | ||
199 | } | ||
190 | } | 200 | } |
191 | 201 | ||
192 | exit_put: | 202 | exit_put: |