diff options
author | Jiri Kosina <jkosina@suse.cz> | 2013-07-25 12:30:27 +0200 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-07-25 12:30:49 +0200 |
commit | a3f8612700507a10ad7186fd77e9f46c7af88335 (patch) | |
tree | f00be0b726748113ffeb4e1caf7ade7ef33cfabe /lib/dump_stack.c | |
parent | 8ecada16512c90ae782b00f15ebff0c32e4cd92a (diff) | |
parent | 07bc9dc1b01bad7084fed3d2659e5d83317869bc (diff) |
Merge branch 'master' into for-next
Sync with Linus' master to be able to apply
trivial patche to newer code.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'lib/dump_stack.c')
-rw-r--r-- | lib/dump_stack.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/lib/dump_stack.c b/lib/dump_stack.c index 53bad099ebd6..c03154173cc7 100644 --- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -6,15 +6,58 @@ #include <linux/kernel.h> #include <linux/export.h> #include <linux/sched.h> +#include <linux/smp.h> +#include <linux/atomic.h> + +static void __dump_stack(void) +{ + dump_stack_print_info(KERN_DEFAULT); + show_stack(NULL, NULL); +} /** * dump_stack - dump the current task information and its stack trace * * Architectures can override this implementation by implementing its own. */ +#ifdef CONFIG_SMP +static atomic_t dump_lock = ATOMIC_INIT(-1); + void dump_stack(void) { - dump_stack_print_info(KERN_DEFAULT); - show_stack(NULL, NULL); + int was_locked; + int old; + int cpu; + + /* + * Permit this cpu to perform nested stack dumps while serialising + * against other CPUs + */ + preempt_disable(); + +retry: + cpu = smp_processor_id(); + old = atomic_cmpxchg(&dump_lock, -1, cpu); + if (old == -1) { + was_locked = 0; + } else if (old == cpu) { + was_locked = 1; + } else { + cpu_relax(); + goto retry; + } + + __dump_stack(); + + if (!was_locked) + atomic_set(&dump_lock, -1); + + preempt_enable(); +} +#else +void dump_stack(void) +{ + __dump_stack(); } +#endif EXPORT_SYMBOL(dump_stack); |