forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk
Pull printk updates from Petr Mladek: - Store printk() messages into the main log buffer directly even in NMI when the lock is available. It is the best effort to print even large chunk of text. It is handy, for example, when all ftrace messages are printed during the system panic in NMI. - Add missing annotations to calm down compiler warnings * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk: printk: add __printf attributes to internal functions printk: Use the main logbuf in NMI when logbuf_lock is available
This commit is contained in:
commit
eed1fc8779
@ -18,12 +18,14 @@
|
||||
|
||||
#ifdef CONFIG_PRINTK
|
||||
|
||||
#define PRINTK_SAFE_CONTEXT_MASK 0x7fffffff
|
||||
#define PRINTK_NMI_CONTEXT_MASK 0x80000000
|
||||
#define PRINTK_SAFE_CONTEXT_MASK 0x3fffffff
|
||||
#define PRINTK_NMI_DEFERRED_CONTEXT_MASK 0x40000000
|
||||
#define PRINTK_NMI_CONTEXT_MASK 0x80000000
|
||||
|
||||
extern raw_spinlock_t logbuf_lock;
|
||||
|
||||
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
|
||||
__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args);
|
||||
__printf(1, 0) int vprintk_func(const char *fmt, va_list args);
|
||||
void __printk_safe_enter(void);
|
||||
void __printk_safe_exit(void);
|
||||
|
@ -2720,20 +2720,29 @@ void wake_up_klogd(void)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
int vprintk_deferred(const char *fmt, va_list args)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
|
||||
|
||||
preempt_disable();
|
||||
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
|
||||
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
|
||||
preempt_enable();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int printk_deferred(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int r;
|
||||
|
||||
preempt_disable();
|
||||
va_start(args, fmt);
|
||||
r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
|
||||
r = vprintk_deferred(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
|
||||
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
|
||||
preempt_enable();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,8 @@ static void queue_flush_work(struct printk_safe_seq_buf *s)
|
||||
* happen, printk_safe_log_store() will notice the buffer->len mismatch
|
||||
* and repeat the write.
|
||||
*/
|
||||
static int printk_safe_log_store(struct printk_safe_seq_buf *s,
|
||||
const char *fmt, va_list args)
|
||||
static __printf(2, 0) int printk_safe_log_store(struct printk_safe_seq_buf *s,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
int add;
|
||||
size_t len;
|
||||
@ -299,7 +299,7 @@ void printk_safe_flush_on_panic(void)
|
||||
* one writer running. But the buffer might get flushed from another
|
||||
* CPU, so we need to be careful.
|
||||
*/
|
||||
static int vprintk_nmi(const char *fmt, va_list args)
|
||||
static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args)
|
||||
{
|
||||
struct printk_safe_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
|
||||
|
||||
@ -308,17 +308,29 @@ static int vprintk_nmi(const char *fmt, va_list args)
|
||||
|
||||
void printk_nmi_enter(void)
|
||||
{
|
||||
this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
|
||||
/*
|
||||
* The size of the extra per-CPU buffer is limited. Use it only when
|
||||
* the main one is locked. If this CPU is not in the safe context,
|
||||
* the lock must be taken on another CPU and we could wait for it.
|
||||
*/
|
||||
if ((this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) &&
|
||||
raw_spin_is_locked(&logbuf_lock)) {
|
||||
this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
|
||||
} else {
|
||||
this_cpu_or(printk_context, PRINTK_NMI_DEFERRED_CONTEXT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
void printk_nmi_exit(void)
|
||||
{
|
||||
this_cpu_and(printk_context, ~PRINTK_NMI_CONTEXT_MASK);
|
||||
this_cpu_and(printk_context,
|
||||
~(PRINTK_NMI_CONTEXT_MASK |
|
||||
PRINTK_NMI_DEFERRED_CONTEXT_MASK));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int vprintk_nmi(const char *fmt, va_list args)
|
||||
static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -330,7 +342,7 @@ static int vprintk_nmi(const char *fmt, va_list args)
|
||||
* into itself. It uses a per-CPU buffer to store the message, just like
|
||||
* NMI.
|
||||
*/
|
||||
static int vprintk_safe(const char *fmt, va_list args)
|
||||
static __printf(1, 0) int vprintk_safe(const char *fmt, va_list args)
|
||||
{
|
||||
struct printk_safe_seq_buf *s = this_cpu_ptr(&safe_print_seq);
|
||||
|
||||
@ -351,12 +363,22 @@ void __printk_safe_exit(void)
|
||||
|
||||
__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
|
||||
{
|
||||
/* Use extra buffer in NMI when logbuf_lock is taken or in safe mode. */
|
||||
if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK)
|
||||
return vprintk_nmi(fmt, args);
|
||||
|
||||
/* Use extra buffer to prevent a recursion deadlock in safe mode. */
|
||||
if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK)
|
||||
return vprintk_safe(fmt, args);
|
||||
|
||||
/*
|
||||
* Use the main logbuf when logbuf_lock is available in NMI.
|
||||
* But avoid calling console drivers that might have their own locks.
|
||||
*/
|
||||
if (this_cpu_read(printk_context) & PRINTK_NMI_DEFERRED_CONTEXT_MASK)
|
||||
return vprintk_deferred(fmt, args);
|
||||
|
||||
/* No obstacles. */
|
||||
return vprintk_default(fmt, args);
|
||||
}
|
||||
|
||||
|
@ -86,9 +86,11 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
|
||||
|
||||
bool nmi_cpu_backtrace(struct pt_regs *regs)
|
||||
{
|
||||
static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
|
||||
arch_spin_lock(&lock);
|
||||
if (regs && cpu_in_idle(instruction_pointer(regs))) {
|
||||
pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n",
|
||||
cpu, instruction_pointer(regs));
|
||||
@ -99,6 +101,7 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
|
||||
else
|
||||
dump_stack();
|
||||
}
|
||||
arch_spin_unlock(&lock);
|
||||
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user