Merge branch 'linus' into core/softlockup
Conflicts: kernel/softlockup.c Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
@@ -443,7 +443,6 @@ config DEBUG_LOCKING_API_SELFTESTS
|
||||
|
||||
config STACKTRACE
|
||||
bool
|
||||
depends on DEBUG_KERNEL
|
||||
depends on STACKTRACE_SUPPORT
|
||||
|
||||
config DEBUG_KOBJECT
|
||||
@@ -587,6 +586,9 @@ config BACKTRACE_SELF_TEST
|
||||
for distributions or general kernels, but only for kernel
|
||||
developers working on architecture code.
|
||||
|
||||
Note that if you want to also test saved backtraces, you will
|
||||
have to enable STACKTRACE as well.
|
||||
|
||||
Say N if you are unsure.
|
||||
|
||||
config LKDTM
|
||||
@@ -658,6 +660,8 @@ config LATENCYTOP
|
||||
Enable this option if you want to use the LatencyTOP tool
|
||||
to find out which userspace is blocking on what kernel operations.
|
||||
|
||||
source kernel/trace/Kconfig
|
||||
|
||||
config PROVIDE_OHCI1394_DMA_INIT
|
||||
bool "Remote debugging over FireWire early on boot"
|
||||
depends on PCI && X86
|
||||
|
@@ -8,6 +8,15 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
|
||||
sha1.o irq_regs.o reciprocal_div.o argv_split.o \
|
||||
proportions.o prio_heap.o ratelimit.o
|
||||
|
||||
ifdef CONFIG_FTRACE
|
||||
# Do not profile string.o, since it may be used in early boot or vdso
|
||||
CFLAGS_REMOVE_string.o = -pg
|
||||
# Also do not profile any debug utilities
|
||||
CFLAGS_REMOVE_spinlock_debug.o = -pg
|
||||
CFLAGS_REMOVE_list_debug.o = -pg
|
||||
CFLAGS_REMOVE_debugobjects.o = -pg
|
||||
endif
|
||||
|
||||
lib-$(CONFIG_MMU) += ioremap.o
|
||||
lib-$(CONFIG_SMP) += cpumask.o
|
||||
|
||||
|
@@ -37,6 +37,7 @@
|
||||
*/
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
@@ -149,6 +150,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
|
||||
(void *)bugaddr);
|
||||
|
||||
show_regs(regs);
|
||||
add_taint(TAINT_WARN);
|
||||
return BUG_TRAP_TYPE_WARN;
|
||||
}
|
||||
|
||||
|
@@ -68,6 +68,7 @@ static int fill_pool(void)
|
||||
{
|
||||
gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
|
||||
struct debug_obj *new;
|
||||
unsigned long flags;
|
||||
|
||||
if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
|
||||
return obj_pool_free;
|
||||
@@ -81,10 +82,10 @@ static int fill_pool(void)
|
||||
if (!new)
|
||||
return obj_pool_free;
|
||||
|
||||
spin_lock(&pool_lock);
|
||||
spin_lock_irqsave(&pool_lock, flags);
|
||||
hlist_add_head(&new->node, &obj_pool);
|
||||
obj_pool_free++;
|
||||
spin_unlock(&pool_lock);
|
||||
spin_unlock_irqrestore(&pool_lock, flags);
|
||||
}
|
||||
return obj_pool_free;
|
||||
}
|
||||
@@ -110,16 +111,13 @@ static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new object. If the pool is empty and no refill possible,
|
||||
* switch off the debugger.
|
||||
* Allocate a new object. If the pool is empty, switch off the debugger.
|
||||
*/
|
||||
static struct debug_obj *
|
||||
alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
|
||||
{
|
||||
struct debug_obj *obj = NULL;
|
||||
int retry = 0;
|
||||
|
||||
repeat:
|
||||
spin_lock(&pool_lock);
|
||||
if (obj_pool.first) {
|
||||
obj = hlist_entry(obj_pool.first, typeof(*obj), node);
|
||||
@@ -141,9 +139,6 @@ repeat:
|
||||
}
|
||||
spin_unlock(&pool_lock);
|
||||
|
||||
if (fill_pool() && !obj && !retry++)
|
||||
goto repeat;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -261,6 +256,8 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
|
||||
struct debug_obj *obj;
|
||||
unsigned long flags;
|
||||
|
||||
fill_pool();
|
||||
|
||||
db = get_bucket((unsigned long) addr);
|
||||
|
||||
spin_lock_irqsave(&db->lock, flags);
|
||||
|
@@ -52,7 +52,7 @@ EXPORT_SYMBOL(__percpu_counter_add);
|
||||
* Add up all the per-cpu counts, return the result. This is a more accurate
|
||||
* but much slower version of percpu_counter_read_positive()
|
||||
*/
|
||||
s64 __percpu_counter_sum(struct percpu_counter *fbc)
|
||||
s64 __percpu_counter_sum(struct percpu_counter *fbc, int set)
|
||||
{
|
||||
s64 ret;
|
||||
int cpu;
|
||||
@@ -62,7 +62,12 @@ s64 __percpu_counter_sum(struct percpu_counter *fbc)
|
||||
for_each_online_cpu(cpu) {
|
||||
s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
|
||||
ret += *pcount;
|
||||
if (set)
|
||||
*pcount = 0;
|
||||
}
|
||||
if (set)
|
||||
fbc->count = ret;
|
||||
|
||||
spin_unlock(&fbc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Momchil Velikov
|
||||
* Portions Copyright (C) 2001 Christoph Hellwig
|
||||
* Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
|
||||
* Copyright (C) 2005 SGI, Christoph Lameter
|
||||
* Copyright (C) 2006 Nick Piggin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@@ -7,7 +7,7 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
unsigned int debug_smp_processor_id(void)
|
||||
notrace unsigned int debug_smp_processor_id(void)
|
||||
{
|
||||
unsigned long preempt_count = preempt_count();
|
||||
int this_cpu = raw_smp_processor_id();
|
||||
@@ -37,7 +37,7 @@ unsigned int debug_smp_processor_id(void)
|
||||
/*
|
||||
* Avoid recursion:
|
||||
*/
|
||||
preempt_disable();
|
||||
preempt_disable_notrace();
|
||||
|
||||
if (!printk_ratelimit())
|
||||
goto out_enable;
|
||||
@@ -49,7 +49,7 @@ unsigned int debug_smp_processor_id(void)
|
||||
dump_stack();
|
||||
|
||||
out_enable:
|
||||
preempt_enable_no_resched();
|
||||
preempt_enable_no_resched_notrace();
|
||||
out:
|
||||
return this_cpu;
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ static unsigned int bm_find(struct ts_config *conf, struct ts_state *state)
|
||||
struct ts_bm *bm = ts_config_priv(conf);
|
||||
unsigned int i, text_len, consumed = state->offset;
|
||||
const u8 *text;
|
||||
int shift = bm->patlen, bs;
|
||||
int shift = bm->patlen - 1, bs;
|
||||
|
||||
for (;;) {
|
||||
text_len = conf->get_next_block(consumed, &text, conf, state);
|
||||
|
128
lib/vsprintf.c
128
lib/vsprintf.c
@@ -22,6 +22,8 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/page.h> /* for PAGE_SIZE */
|
||||
#include <asm/div64.h>
|
||||
@@ -482,6 +484,89 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags)
|
||||
{
|
||||
int len, i;
|
||||
|
||||
if ((unsigned long)s < PAGE_SIZE)
|
||||
s = "<NULL>";
|
||||
|
||||
len = strnlen(s, precision);
|
||||
|
||||
if (!(flags & LEFT)) {
|
||||
while (len < field_width--) {
|
||||
if (buf < end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (buf < end)
|
||||
*buf = *s;
|
||||
++buf; ++s;
|
||||
}
|
||||
while (len < field_width--) {
|
||||
if (buf < end)
|
||||
*buf = ' ';
|
||||
++buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline void *dereference_function_descriptor(void *ptr)
|
||||
{
|
||||
#if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
|
||||
void *p;
|
||||
if (!probe_kernel_address(ptr, p))
|
||||
ptr = p;
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
|
||||
{
|
||||
unsigned long value = (unsigned long) ptr;
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
char sym[KSYM_SYMBOL_LEN];
|
||||
sprint_symbol(sym, value);
|
||||
return string(buf, end, sym, field_width, precision, flags);
|
||||
#else
|
||||
field_width = 2*sizeof(void *);
|
||||
flags |= SPECIAL | SMALL | ZEROPAD;
|
||||
return number(buf, end, value, 16, field_width, precision, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a '%p' thing. A kernel extension is that the '%p' is followed
|
||||
* by an extra set of alphanumeric characters that are extended format
|
||||
* specifiers.
|
||||
*
|
||||
* Right now we just handle 'F' (for symbolic Function descriptor pointers)
|
||||
* and 'S' (for Symbolic direct pointers), but this can easily be
|
||||
* extended in the future (network address types etc).
|
||||
*
|
||||
* The difference between 'S' and 'F' is that on ia64 and ppc64 function
|
||||
* pointers are really function descriptors, which contain a pointer the
|
||||
* real address.
|
||||
*/
|
||||
static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
|
||||
{
|
||||
switch (*fmt) {
|
||||
case 'F':
|
||||
ptr = dereference_function_descriptor(ptr);
|
||||
/* Fallthrough */
|
||||
case 'S':
|
||||
return symbol_string(buf, end, ptr, field_width, precision, flags);
|
||||
}
|
||||
flags |= SMALL;
|
||||
if (field_width == -1) {
|
||||
field_width = 2*sizeof(void *);
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vsnprintf - Format a string and place it in a buffer
|
||||
* @buf: The buffer to place the result into
|
||||
@@ -502,11 +587,9 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int
|
||||
*/
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
unsigned long long num;
|
||||
int i, base;
|
||||
int base;
|
||||
char *str, *end, c;
|
||||
const char *s;
|
||||
|
||||
int flags; /* flags to number() */
|
||||
|
||||
@@ -622,43 +705,18 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
||||
continue;
|
||||
|
||||
case 's':
|
||||
s = va_arg(args, char *);
|
||||
if ((unsigned long)s < PAGE_SIZE)
|
||||
s = "<NULL>";
|
||||
|
||||
len = strnlen(s, precision);
|
||||
|
||||
if (!(flags & LEFT)) {
|
||||
while (len < field_width--) {
|
||||
if (str < end)
|
||||
*str = ' ';
|
||||
++str;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (str < end)
|
||||
*str = *s;
|
||||
++str; ++s;
|
||||
}
|
||||
while (len < field_width--) {
|
||||
if (str < end)
|
||||
*str = ' ';
|
||||
++str;
|
||||
}
|
||||
str = string(str, end, va_arg(args, char *), field_width, precision, flags);
|
||||
continue;
|
||||
|
||||
case 'p':
|
||||
flags |= SMALL;
|
||||
if (field_width == -1) {
|
||||
field_width = 2*sizeof(void *);
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = number(str, end,
|
||||
(unsigned long) va_arg(args, void *),
|
||||
16, field_width, precision, flags);
|
||||
str = pointer(fmt+1, str, end,
|
||||
va_arg(args, void *),
|
||||
field_width, precision, flags);
|
||||
/* Skip all alphanumeric pointer suffixes */
|
||||
while (isalnum(fmt[1]))
|
||||
fmt++;
|
||||
continue;
|
||||
|
||||
|
||||
case 'n':
|
||||
/* FIXME:
|
||||
* What does C99 say about the overflow case here? */
|
||||
|
Reference in New Issue
Block a user