Skip to content

Commit a5707ee

Browse files
committed
Merge branch 'for-4.13' into for-linus
2 parents dc0cf5a + f4e981c commit a5707ee

File tree

4 files changed

+50
-14
lines changed

4 files changed

+50
-14
lines changed

kernel/printk/internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818

1919
#ifdef CONFIG_PRINTK
2020

21-
#define PRINTK_SAFE_CONTEXT_MASK 0x7fffffff
22-
#define PRINTK_NMI_CONTEXT_MASK 0x80000000
21+
#define PRINTK_SAFE_CONTEXT_MASK 0x3fffffff
22+
#define PRINTK_NMI_DEFERRED_CONTEXT_MASK 0x40000000
23+
#define PRINTK_NMI_CONTEXT_MASK 0x80000000
2324

2425
extern raw_spinlock_t logbuf_lock;
2526

2627
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
28+
__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args);
2729
__printf(1, 0) int vprintk_func(const char *fmt, va_list args);
2830
void __printk_safe_enter(void);
2931
void __printk_safe_exit(void);

kernel/printk/printk.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,23 +2720,32 @@ void wake_up_klogd(void)
27202720
preempt_enable();
27212721
}
27222722

2723-
int printk_deferred(const char *fmt, ...)
2723+
int vprintk_deferred(const char *fmt, va_list args)
27242724
{
2725-
va_list args;
27262725
int r;
27272726

2728-
preempt_disable();
2729-
va_start(args, fmt);
27302727
r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
2731-
va_end(args);
27322728

2729+
preempt_disable();
27332730
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
27342731
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
27352732
preempt_enable();
27362733

27372734
return r;
27382735
}
27392736

2737+
int printk_deferred(const char *fmt, ...)
2738+
{
2739+
va_list args;
2740+
int r;
2741+
2742+
va_start(args, fmt);
2743+
r = vprintk_deferred(fmt, args);
2744+
va_end(args);
2745+
2746+
return r;
2747+
}
2748+
27402749
/*
27412750
* printk rate limiting, lifted from the networking subsystem.
27422751
*

kernel/printk/printk_safe.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ static void queue_flush_work(struct printk_safe_seq_buf *s)
8080
* happen, printk_safe_log_store() will notice the buffer->len mismatch
8181
* and repeat the write.
8282
*/
83-
static int printk_safe_log_store(struct printk_safe_seq_buf *s,
84-
const char *fmt, va_list args)
83+
static __printf(2, 0) int printk_safe_log_store(struct printk_safe_seq_buf *s,
84+
const char *fmt, va_list args)
8585
{
8686
int add;
8787
size_t len;
@@ -299,7 +299,7 @@ void printk_safe_flush_on_panic(void)
299299
* one writer running. But the buffer might get flushed from another
300300
* CPU, so we need to be careful.
301301
*/
302-
static int vprintk_nmi(const char *fmt, va_list args)
302+
static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args)
303303
{
304304
struct printk_safe_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
305305

@@ -308,17 +308,29 @@ static int vprintk_nmi(const char *fmt, va_list args)
308308

309309
void printk_nmi_enter(void)
310310
{
311-
this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
311+
/*
312+
* The size of the extra per-CPU buffer is limited. Use it only when
313+
* the main one is locked. If this CPU is not in the safe context,
314+
* the lock must be taken on another CPU and we could wait for it.
315+
*/
316+
if ((this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) &&
317+
raw_spin_is_locked(&logbuf_lock)) {
318+
this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
319+
} else {
320+
this_cpu_or(printk_context, PRINTK_NMI_DEFERRED_CONTEXT_MASK);
321+
}
312322
}
313323

314324
void printk_nmi_exit(void)
315325
{
316-
this_cpu_and(printk_context, ~PRINTK_NMI_CONTEXT_MASK);
326+
this_cpu_and(printk_context,
327+
~(PRINTK_NMI_CONTEXT_MASK |
328+
PRINTK_NMI_DEFERRED_CONTEXT_MASK));
317329
}
318330

319331
#else
320332

321-
static int vprintk_nmi(const char *fmt, va_list args)
333+
static __printf(1, 0) int vprintk_nmi(const char *fmt, va_list args)
322334
{
323335
return 0;
324336
}
@@ -330,7 +342,7 @@ static int vprintk_nmi(const char *fmt, va_list args)
330342
* into itself. It uses a per-CPU buffer to store the message, just like
331343
* NMI.
332344
*/
333-
static int vprintk_safe(const char *fmt, va_list args)
345+
static __printf(1, 0) int vprintk_safe(const char *fmt, va_list args)
334346
{
335347
struct printk_safe_seq_buf *s = this_cpu_ptr(&safe_print_seq);
336348

@@ -351,12 +363,22 @@ void __printk_safe_exit(void)
351363

352364
__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
353365
{
366+
/* Use extra buffer in NMI when logbuf_lock is taken or in safe mode. */
354367
if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK)
355368
return vprintk_nmi(fmt, args);
356369

370+
/* Use extra buffer to prevent a recursion deadlock in safe mode. */
357371
if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK)
358372
return vprintk_safe(fmt, args);
359373

374+
/*
375+
* Use the main logbuf when logbuf_lock is available in NMI.
376+
* But avoid calling console drivers that might have their own locks.
377+
*/
378+
if (this_cpu_read(printk_context) & PRINTK_NMI_DEFERRED_CONTEXT_MASK)
379+
return vprintk_deferred(fmt, args);
380+
381+
/* No obstacles. */
360382
return vprintk_default(fmt, args);
361383
}
362384

lib/nmi_backtrace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
8686

8787
bool nmi_cpu_backtrace(struct pt_regs *regs)
8888
{
89+
static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
8990
int cpu = smp_processor_id();
9091

9192
if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
93+
arch_spin_lock(&lock);
9294
if (regs && cpu_in_idle(instruction_pointer(regs))) {
9395
pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n",
9496
cpu, instruction_pointer(regs));
@@ -99,6 +101,7 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
99101
else
100102
dump_stack();
101103
}
104+
arch_spin_unlock(&lock);
102105
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
103106
return true;
104107
}

0 commit comments

Comments
 (0)