diff options
Diffstat (limited to 'kernel/trace/trace_stack.c')
| -rw-r--r-- | kernel/trace/trace_stack.c | 92 |
1 files changed, 49 insertions, 43 deletions
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 8abf1ba18085..dda9e6742950 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
| @@ -16,24 +16,22 @@ | |||
| 16 | 16 | ||
| 17 | #include "trace.h" | 17 | #include "trace.h" |
| 18 | 18 | ||
| 19 | #define STACK_TRACE_ENTRIES 500 | ||
| 20 | |||
| 21 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = | 19 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = |
| 22 | { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; | 20 | { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; |
| 23 | static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; | 21 | unsigned stack_trace_index[STACK_TRACE_ENTRIES]; |
| 24 | 22 | ||
| 25 | /* | 23 | /* |
| 26 | * Reserve one entry for the passed in ip. This will allow | 24 | * Reserve one entry for the passed in ip. This will allow |
| 27 | * us to remove most or all of the stack size overhead | 25 | * us to remove most or all of the stack size overhead |
| 28 | * added by the stack tracer itself. | 26 | * added by the stack tracer itself. |
| 29 | */ | 27 | */ |
| 30 | static struct stack_trace max_stack_trace = { | 28 | struct stack_trace stack_trace_max = { |
| 31 | .max_entries = STACK_TRACE_ENTRIES - 1, | 29 | .max_entries = STACK_TRACE_ENTRIES - 1, |
| 32 | .entries = &stack_dump_trace[0], | 30 | .entries = &stack_dump_trace[0], |
| 33 | }; | 31 | }; |
| 34 | 32 | ||
| 35 | static unsigned long max_stack_size; | 33 | unsigned long stack_trace_max_size; |
| 36 | static arch_spinlock_t max_stack_lock = | 34 | arch_spinlock_t stack_trace_max_lock = |
| 37 | (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; | 35 | (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; |
| 38 | 36 | ||
| 39 | static DEFINE_PER_CPU(int, trace_active); | 37 | static DEFINE_PER_CPU(int, trace_active); |
| @@ -42,30 +40,38 @@ static DEFINE_MUTEX(stack_sysctl_mutex); | |||
| 42 | int stack_tracer_enabled; | 40 | int stack_tracer_enabled; |
| 43 | static int last_stack_tracer_enabled; | 41 | static int last_stack_tracer_enabled; |
| 44 | 42 | ||
| 45 | static inline void print_max_stack(void) | 43 | void stack_trace_print(void) |
| 46 | { | 44 | { |
| 47 | long i; | 45 | long i; |
| 48 | int size; | 46 | int size; |
| 49 | 47 | ||
| 50 | pr_emerg(" Depth Size Location (%d entries)\n" | 48 | pr_emerg(" Depth Size Location (%d entries)\n" |
| 51 | " ----- ---- --------\n", | 49 | " ----- ---- --------\n", |
| 52 | max_stack_trace.nr_entries); | 50 | stack_trace_max.nr_entries); |
| 53 | 51 | ||
| 54 | for (i = 0; i < max_stack_trace.nr_entries; i++) { | 52 | for (i = 0; i < stack_trace_max.nr_entries; i++) { |
| 55 | if (stack_dump_trace[i] == ULONG_MAX) | 53 | if (stack_dump_trace[i] == ULONG_MAX) |
| 56 | break; | 54 | break; |
| 57 | if (i+1 == max_stack_trace.nr_entries || | 55 | if (i+1 == stack_trace_max.nr_entries || |
| 58 | stack_dump_trace[i+1] == ULONG_MAX) | 56 | stack_dump_trace[i+1] == ULONG_MAX) |
| 59 | size = stack_dump_index[i]; | 57 | size = stack_trace_index[i]; |
| 60 | else | 58 | else |
| 61 | size = stack_dump_index[i] - stack_dump_index[i+1]; | 59 | size = stack_trace_index[i] - stack_trace_index[i+1]; |
| 62 | 60 | ||
| 63 | pr_emerg("%3ld) %8d %5d %pS\n", i, stack_dump_index[i], | 61 | pr_emerg("%3ld) %8d %5d %pS\n", i, stack_trace_index[i], |
| 64 | size, (void *)stack_dump_trace[i]); | 62 | size, (void *)stack_dump_trace[i]); |
| 65 | } | 63 | } |
| 66 | } | 64 | } |
| 67 | 65 | ||
| 68 | static inline void | 66 | /* |
| 67 | * When arch-specific code overides this function, the following | ||
| 68 | * data should be filled up, assuming stack_trace_max_lock is held to | ||
| 69 | * prevent concurrent updates. | ||
| 70 | * stack_trace_index[] | ||
| 71 | * stack_trace_max | ||
| 72 | * stack_trace_max_size | ||
| 73 | */ | ||
| 74 | void __weak | ||
| 69 | check_stack(unsigned long ip, unsigned long *stack) | 75 | check_stack(unsigned long ip, unsigned long *stack) |
| 70 | { | 76 | { |
| 71 | unsigned long this_size, flags; unsigned long *p, *top, *start; | 77 | unsigned long this_size, flags; unsigned long *p, *top, *start; |
| @@ -78,7 +84,7 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 78 | /* Remove the frame of the tracer */ | 84 | /* Remove the frame of the tracer */ |
| 79 | this_size -= frame_size; | 85 | this_size -= frame_size; |
| 80 | 86 | ||
| 81 | if (this_size <= max_stack_size) | 87 | if (this_size <= stack_trace_max_size) |
| 82 | return; | 88 | return; |
| 83 | 89 | ||
| 84 | /* we do not handle interrupt stacks yet */ | 90 | /* we do not handle interrupt stacks yet */ |
| @@ -90,7 +96,7 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 90 | return; | 96 | return; |
| 91 | 97 | ||
| 92 | local_irq_save(flags); | 98 | local_irq_save(flags); |
| 93 | arch_spin_lock(&max_stack_lock); | 99 | arch_spin_lock(&stack_trace_max_lock); |
| 94 | 100 | ||
| 95 | /* | 101 | /* |
| 96 | * RCU may not be watching, make it see us. | 102 | * RCU may not be watching, make it see us. |
| @@ -103,18 +109,18 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 103 | this_size -= tracer_frame; | 109 | this_size -= tracer_frame; |
| 104 | 110 | ||
| 105 | /* a race could have already updated it */ | 111 | /* a race could have already updated it */ |
| 106 | if (this_size <= max_stack_size) | 112 | if (this_size <= stack_trace_max_size) |
| 107 | goto out; | 113 | goto out; |
| 108 | 114 | ||
| 109 | max_stack_size = this_size; | 115 | stack_trace_max_size = this_size; |
| 110 | 116 | ||
| 111 | max_stack_trace.nr_entries = 0; | 117 | stack_trace_max.nr_entries = 0; |
| 112 | max_stack_trace.skip = 3; | 118 | stack_trace_max.skip = 3; |
| 113 | 119 | ||
| 114 | save_stack_trace(&max_stack_trace); | 120 | save_stack_trace(&stack_trace_max); |
| 115 | 121 | ||
| 116 | /* Skip over the overhead of the stack tracer itself */ | 122 | /* Skip over the overhead of the stack tracer itself */ |
| 117 | for (i = 0; i < max_stack_trace.nr_entries; i++) { | 123 | for (i = 0; i < stack_trace_max.nr_entries; i++) { |
| 118 | if (stack_dump_trace[i] == ip) | 124 | if (stack_dump_trace[i] == ip) |
| 119 | break; | 125 | break; |
| 120 | } | 126 | } |
| @@ -134,18 +140,18 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 134 | * loop will only happen once. This code only takes place | 140 | * loop will only happen once. This code only takes place |
| 135 | * on a new max, so it is far from a fast path. | 141 | * on a new max, so it is far from a fast path. |
| 136 | */ | 142 | */ |
| 137 | while (i < max_stack_trace.nr_entries) { | 143 | while (i < stack_trace_max.nr_entries) { |
| 138 | int found = 0; | 144 | int found = 0; |
| 139 | 145 | ||
| 140 | stack_dump_index[x] = this_size; | 146 | stack_trace_index[x] = this_size; |
| 141 | p = start; | 147 | p = start; |
| 142 | 148 | ||
| 143 | for (; p < top && i < max_stack_trace.nr_entries; p++) { | 149 | for (; p < top && i < stack_trace_max.nr_entries; p++) { |
| 144 | if (stack_dump_trace[i] == ULONG_MAX) | 150 | if (stack_dump_trace[i] == ULONG_MAX) |
| 145 | break; | 151 | break; |
| 146 | if (*p == stack_dump_trace[i]) { | 152 | if (*p == stack_dump_trace[i]) { |
| 147 | stack_dump_trace[x] = stack_dump_trace[i++]; | 153 | stack_dump_trace[x] = stack_dump_trace[i++]; |
| 148 | this_size = stack_dump_index[x++] = | 154 | this_size = stack_trace_index[x++] = |
| 149 | (top - p) * sizeof(unsigned long); | 155 | (top - p) * sizeof(unsigned long); |
| 150 | found = 1; | 156 | found = 1; |
| 151 | /* Start the search from here */ | 157 | /* Start the search from here */ |
| @@ -160,7 +166,7 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 160 | if (unlikely(!tracer_frame)) { | 166 | if (unlikely(!tracer_frame)) { |
| 161 | tracer_frame = (p - stack) * | 167 | tracer_frame = (p - stack) * |
| 162 | sizeof(unsigned long); | 168 | sizeof(unsigned long); |
| 163 | max_stack_size -= tracer_frame; | 169 | stack_trace_max_size -= tracer_frame; |
| 164 | } | 170 | } |
| 165 | } | 171 | } |
| 166 | } | 172 | } |
| @@ -169,18 +175,18 @@ check_stack(unsigned long ip, unsigned long *stack) | |||
| 169 | i++; | 175 | i++; |
| 170 | } | 176 | } |
| 171 | 177 | ||
| 172 | max_stack_trace.nr_entries = x; | 178 | stack_trace_max.nr_entries = x; |
| 173 | for (; x < i; x++) | 179 | for (; x < i; x++) |
| 174 | stack_dump_trace[x] = ULONG_MAX; | 180 | stack_dump_trace[x] = ULONG_MAX; |
| 175 | 181 | ||
| 176 | if (task_stack_end_corrupted(current)) { | 182 | if (task_stack_end_corrupted(current)) { |
| 177 | print_max_stack(); | 183 | stack_trace_print(); |
| 178 | BUG(); | 184 | BUG(); |
| 179 | } | 185 | } |
| 180 | 186 | ||
| 181 | out: | 187 | out: |
| 182 | rcu_irq_exit(); | 188 | rcu_irq_exit(); |
| 183 | arch_spin_unlock(&max_stack_lock); | 189 | arch_spin_unlock(&stack_trace_max_lock); |
| 184 | local_irq_restore(flags); | 190 | local_irq_restore(flags); |
| 185 | } | 191 | } |
| 186 | 192 | ||
| @@ -251,9 +257,9 @@ stack_max_size_write(struct file *filp, const char __user *ubuf, | |||
| 251 | cpu = smp_processor_id(); | 257 | cpu = smp_processor_id(); |
| 252 | per_cpu(trace_active, cpu)++; | 258 | per_cpu(trace_active, cpu)++; |
| 253 | 259 | ||
| 254 | arch_spin_lock(&max_stack_lock); | 260 | arch_spin_lock(&stack_trace_max_lock); |
| 255 | *ptr = val; | 261 | *ptr = val; |
| 256 | arch_spin_unlock(&max_stack_lock); | 262 | arch_spin_unlock(&stack_trace_max_lock); |
| 257 | 263 | ||
| 258 | per_cpu(trace_active, cpu)--; | 264 | per_cpu(trace_active, cpu)--; |
| 259 | local_irq_restore(flags); | 265 | local_irq_restore(flags); |
| @@ -273,7 +279,7 @@ __next(struct seq_file *m, loff_t *pos) | |||
| 273 | { | 279 | { |
| 274 | long n = *pos - 1; | 280 | long n = *pos - 1; |
| 275 | 281 | ||
| 276 | if (n > max_stack_trace.nr_entries || stack_dump_trace[n] == ULONG_MAX) | 282 | if (n > stack_trace_max.nr_entries || stack_dump_trace[n] == ULONG_MAX) |
| 277 | return NULL; | 283 | return NULL; |
| 278 | 284 | ||
| 279 | m->private = (void *)n; | 285 | m->private = (void *)n; |
| @@ -296,7 +302,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
| 296 | cpu = smp_processor_id(); | 302 | cpu = smp_processor_id(); |
| 297 | per_cpu(trace_active, cpu)++; | 303 | per_cpu(trace_active, cpu)++; |
| 298 | 304 | ||
| 299 | arch_spin_lock(&max_stack_lock); | 305 | arch_spin_lock(&stack_trace_max_lock); |
| 300 | 306 | ||
| 301 | if (*pos == 0) | 307 | if (*pos == 0) |
| 302 | return SEQ_START_TOKEN; | 308 | return SEQ_START_TOKEN; |
| @@ -308,7 +314,7 @@ static void t_stop(struct seq_file *m, void *p) | |||
| 308 | { | 314 | { |
| 309 | int cpu; | 315 | int cpu; |
| 310 | 316 | ||
| 311 | arch_spin_unlock(&max_stack_lock); | 317 | arch_spin_unlock(&stack_trace_max_lock); |
| 312 | 318 | ||
| 313 | cpu = smp_processor_id(); | 319 | cpu = smp_processor_id(); |
| 314 | per_cpu(trace_active, cpu)--; | 320 | per_cpu(trace_active, cpu)--; |
| @@ -343,9 +349,9 @@ static int t_show(struct seq_file *m, void *v) | |||
| 343 | seq_printf(m, " Depth Size Location" | 349 | seq_printf(m, " Depth Size Location" |
| 344 | " (%d entries)\n" | 350 | " (%d entries)\n" |
| 345 | " ----- ---- --------\n", | 351 | " ----- ---- --------\n", |
| 346 | max_stack_trace.nr_entries); | 352 | stack_trace_max.nr_entries); |
| 347 | 353 | ||
| 348 | if (!stack_tracer_enabled && !max_stack_size) | 354 | if (!stack_tracer_enabled && !stack_trace_max_size) |
| 349 | print_disabled(m); | 355 | print_disabled(m); |
| 350 | 356 | ||
| 351 | return 0; | 357 | return 0; |
| @@ -353,17 +359,17 @@ static int t_show(struct seq_file *m, void *v) | |||
| 353 | 359 | ||
| 354 | i = *(long *)v; | 360 | i = *(long *)v; |
| 355 | 361 | ||
| 356 | if (i >= max_stack_trace.nr_entries || | 362 | if (i >= stack_trace_max.nr_entries || |
| 357 | stack_dump_trace[i] == ULONG_MAX) | 363 | stack_dump_trace[i] == ULONG_MAX) |
| 358 | return 0; | 364 | return 0; |
| 359 | 365 | ||
| 360 | if (i+1 == max_stack_trace.nr_entries || | 366 | if (i+1 == stack_trace_max.nr_entries || |
| 361 | stack_dump_trace[i+1] == ULONG_MAX) | 367 | stack_dump_trace[i+1] == ULONG_MAX) |
| 362 | size = stack_dump_index[i]; | 368 | size = stack_trace_index[i]; |
| 363 | else | 369 | else |
| 364 | size = stack_dump_index[i] - stack_dump_index[i+1]; | 370 | size = stack_trace_index[i] - stack_trace_index[i+1]; |
| 365 | 371 | ||
| 366 | seq_printf(m, "%3ld) %8d %5d ", i, stack_dump_index[i], size); | 372 | seq_printf(m, "%3ld) %8d %5d ", i, stack_trace_index[i], size); |
| 367 | 373 | ||
| 368 | trace_lookup_stack(m, i); | 374 | trace_lookup_stack(m, i); |
| 369 | 375 | ||
| @@ -453,7 +459,7 @@ static __init int stack_trace_init(void) | |||
| 453 | return 0; | 459 | return 0; |
| 454 | 460 | ||
| 455 | trace_create_file("stack_max_size", 0644, d_tracer, | 461 | trace_create_file("stack_max_size", 0644, d_tracer, |
| 456 | &max_stack_size, &stack_max_size_fops); | 462 | &stack_trace_max_size, &stack_max_size_fops); |
| 457 | 463 | ||
| 458 | trace_create_file("stack_trace", 0444, d_tracer, | 464 | trace_create_file("stack_trace", 0444, d_tracer, |
| 459 | NULL, &stack_trace_fops); | 465 | NULL, &stack_trace_fops); |
