diff options
author | David Ahern <dsahern@gmail.com> | 2011-07-30 06:53:20 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-08-05 00:47:56 -0400 |
commit | b59a1bfcc2406ea75346977ad016cfe909a762ac (patch) | |
tree | d21496dc9b1bf9cd78bf7d5d4a7d2815533823b9 /arch | |
parent | 501d238633a3f9869f4e777b3b281ca7660b7156 (diff) |
powerpc/perf: Disable pagefaults during callchain stack read
Panic observed on an older kernel when collecting call chains for
the context-switch software event:
[<b0180e00>]rb_erase+0x1b4/0x3e8
[<b00430f4>]__dequeue_entity+0x50/0xe8
[<b0043304>]set_next_entity+0x178/0x1bc
[<b0043440>]pick_next_task_fair+0xb0/0x118
[<b02ada80>]schedule+0x500/0x614
[<b02afaa8>]rwsem_down_failed_common+0xf0/0x264
[<b02afca0>]rwsem_down_read_failed+0x34/0x54
[<b02aed4c>]down_read+0x3c/0x54
[<b0023b58>]do_page_fault+0x114/0x5e8
[<b001e350>]handle_page_fault+0xc/0x80
[<b0022dec>]perf_callchain+0x224/0x31c
[<b009ba70>]perf_prepare_sample+0x240/0x2fc
[<b009d760>]__perf_event_overflow+0x280/0x398
[<b009d914>]perf_swevent_overflow+0x9c/0x10c
[<b009db54>]perf_swevent_ctx_event+0x1d0/0x230
[<b009dc38>]do_perf_sw_event+0x84/0xe4
[<b009dde8>]perf_sw_event_context_switch+0x150/0x1b4
[<b009de90>]perf_event_task_sched_out+0x44/0x2d4
[<b02ad840>]schedule+0x2c0/0x614
[<b0047dc0>]__cond_resched+0x34/0x90
[<b02adcc8>]_cond_resched+0x4c/0x68
[<b00bccf8>]move_page_tables+0xb0/0x418
[<b00d7ee0>]setup_arg_pages+0x184/0x2a0
[<b0110914>]load_elf_binary+0x394/0x1208
[<b00d6e28>]search_binary_handler+0xe0/0x2c4
[<b00d834c>]do_execve+0x1bc/0x268
[<b0015394>]sys_execve+0x84/0xc8
[<b001df10>]ret_from_syscall+0x0/0x3c
A page fault occurred walking the callchain while creating a perf
sample for the context-switch event. To handle the page fault the
mmap_sem is needed, but it is currently held by setup_arg_pages.
(setup_arg_pages calls shift_arg_pages with the mmap_sem held.
shift_arg_pages then calls move_page_tables which has a cond_resched
at the top of its for loop - hitting that cond_resched is what caused
the context switch.)
This is an extension of Anton's proposed patch:
https://lkml.org/lkml/2011/7/24/151
adding case for 32-bit ppc.
Tested on the system that first generated the panic and then again
with latest kernel using a PPC VM. I am not able to test the 64-bit
path - I do not have H/W for it and 64-bit PPC VMs (qemu on Intel)
is horribly slow.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/perf_callchain.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c index d05ae4204bbf..564c1d8bdb5c 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/kernel/perf_callchain.c | |||
@@ -154,8 +154,12 @@ static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret) | |||
154 | ((unsigned long)ptr & 7)) | 154 | ((unsigned long)ptr & 7)) |
155 | return -EFAULT; | 155 | return -EFAULT; |
156 | 156 | ||
157 | if (!__get_user_inatomic(*ret, ptr)) | 157 | pagefault_disable(); |
158 | if (!__get_user_inatomic(*ret, ptr)) { | ||
159 | pagefault_enable(); | ||
158 | return 0; | 160 | return 0; |
161 | } | ||
162 | pagefault_enable(); | ||
159 | 163 | ||
160 | return read_user_stack_slow(ptr, ret, 8); | 164 | return read_user_stack_slow(ptr, ret, 8); |
161 | } | 165 | } |
@@ -166,8 +170,12 @@ static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) | |||
166 | ((unsigned long)ptr & 3)) | 170 | ((unsigned long)ptr & 3)) |
167 | return -EFAULT; | 171 | return -EFAULT; |
168 | 172 | ||
169 | if (!__get_user_inatomic(*ret, ptr)) | 173 | pagefault_disable(); |
174 | if (!__get_user_inatomic(*ret, ptr)) { | ||
175 | pagefault_enable(); | ||
170 | return 0; | 176 | return 0; |
177 | } | ||
178 | pagefault_enable(); | ||
171 | 179 | ||
172 | return read_user_stack_slow(ptr, ret, 4); | 180 | return read_user_stack_slow(ptr, ret, 4); |
173 | } | 181 | } |
@@ -294,11 +302,17 @@ static inline int current_is_64bit(void) | |||
294 | */ | 302 | */ |
295 | static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) | 303 | static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) |
296 | { | 304 | { |
305 | int rc; | ||
306 | |||
297 | if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) || | 307 | if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) || |
298 | ((unsigned long)ptr & 3)) | 308 | ((unsigned long)ptr & 3)) |
299 | return -EFAULT; | 309 | return -EFAULT; |
300 | 310 | ||
301 | return __get_user_inatomic(*ret, ptr); | 311 | pagefault_disable(); |
312 | rc = __get_user_inatomic(*ret, ptr); | ||
313 | pagefault_enable(); | ||
314 | |||
315 | return rc; | ||
302 | } | 316 | } |
303 | 317 | ||
304 | static inline void perf_callchain_user_64(struct perf_callchain_entry *entry, | 318 | static inline void perf_callchain_user_64(struct perf_callchain_entry *entry, |