diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_sysprof.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index 7f6fcccffb88..f9a09fe705b0 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c | |||
@@ -37,21 +37,26 @@ struct stack_frame { | |||
37 | 37 | ||
38 | static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) | 38 | static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) |
39 | { | 39 | { |
40 | int ret; | ||
41 | |||
40 | if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) | 42 | if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) |
41 | return 0; | 43 | return 0; |
42 | 44 | ||
43 | if (__copy_from_user_inatomic(frame, frame_pointer, sizeof(*frame))) | 45 | ret = 1; |
44 | return 0; | 46 | pagefault_disable(); |
47 | if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) | ||
48 | ret = 0; | ||
49 | pagefault_enable(); | ||
45 | 50 | ||
46 | return 1; | 51 | return ret; |
47 | } | 52 | } |
48 | 53 | ||
49 | static void timer_notify(struct pt_regs *regs, int cpu) | 54 | static void timer_notify(struct pt_regs *regs, int cpu) |
50 | { | 55 | { |
51 | const void __user *frame_pointer; | ||
52 | struct trace_array_cpu *data; | 56 | struct trace_array_cpu *data; |
53 | struct stack_frame frame; | 57 | struct stack_frame frame; |
54 | struct trace_array *tr; | 58 | struct trace_array *tr; |
59 | const void __user *fp; | ||
55 | int is_user; | 60 | int is_user; |
56 | int i; | 61 | int i; |
57 | 62 | ||
@@ -77,21 +82,26 @@ static void timer_notify(struct pt_regs *regs, int cpu) | |||
77 | 82 | ||
78 | trace_special(tr, data, 0, current->pid, regs->ip); | 83 | trace_special(tr, data, 0, current->pid, regs->ip); |
79 | 84 | ||
80 | frame_pointer = (void __user *)regs->bp; | 85 | fp = (void __user *)regs->bp; |
81 | 86 | ||
82 | for (i = 0; i < sample_max_depth; i++) { | 87 | for (i = 0; i < sample_max_depth; i++) { |
83 | if (!copy_stack_frame(frame_pointer, &frame)) | 88 | frame.next_fp = 0; |
89 | frame.return_address = 0; | ||
90 | if (!copy_stack_frame(fp, &frame)) | ||
84 | break; | 91 | break; |
85 | if ((unsigned long)frame_pointer < regs->sp) | 92 | if ((unsigned long)fp < regs->sp) |
86 | break; | 93 | break; |
87 | 94 | ||
88 | trace_special(tr, data, 1, frame.return_address, | 95 | trace_special(tr, data, 1, frame.return_address, |
89 | (unsigned long)frame_pointer); | 96 | (unsigned long)fp); |
90 | frame_pointer = frame.next_fp; | 97 | fp = frame.next_fp; |
91 | } | 98 | } |
92 | 99 | ||
93 | trace_special(tr, data, 2, current->pid, i); | 100 | trace_special(tr, data, 2, current->pid, i); |
94 | 101 | ||
102 | /* | ||
103 | * Special trace entry if we overflow the max depth: | ||
104 | */ | ||
95 | if (i == sample_max_depth) | 105 | if (i == sample_max_depth) |
96 | trace_special(tr, data, -1, -1, -1); | 106 | trace_special(tr, data, -1, -1, -1); |
97 | } | 107 | } |