#ifdef CONFIG_PRINTK
 
 #define PRINTK_SAFE_CONTEXT_MASK        0x3fffffff
-#define PRINTK_NMI_DEFERRED_CONTEXT_MASK 0x40000000
+#define PRINTK_NMI_DIRECT_CONTEXT_MASK  0x40000000
 #define PRINTK_NMI_CONTEXT_MASK                 0x80000000
 
 extern raw_spinlock_t logbuf_lock;
 
+__printf(5, 0)
+int vprintk_store(int facility, int level,
+                 const char *dict, size_t dictlen,
+                 const char *fmt, va_list args);
+
 __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);
                local_irq_enable();             \
        } while (0)
 
+void defer_console_output(void);
+
 #else
 
 __printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; }
 
 
 void printk_nmi_enter(void)
 {
-       /*
-        * 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);
-       }
+       this_cpu_or(printk_context, PRINTK_NMI_CONTEXT_MASK);
 }
 
 void printk_nmi_exit(void)
 {
-       this_cpu_and(printk_context,
-                    ~(PRINTK_NMI_CONTEXT_MASK |
-                      PRINTK_NMI_DEFERRED_CONTEXT_MASK));
+       this_cpu_and(printk_context, ~PRINTK_NMI_CONTEXT_MASK);
+}
+
+/*
+ * Marks a code that might produce many messages in NMI context
+ * and the risk of losing them is more critical than eventual
+ * reordering.
+ *
+ * It has effect only when called in NMI context. Then printk()
+ * will try to store the messages into the main logbuf directly
+ * and use the per-CPU buffers only as a fallback when the lock
+ * is not available.
+ */
+void printk_nmi_direct_enter(void)
+{
+       if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK)
+               this_cpu_or(printk_context, PRINTK_NMI_DIRECT_CONTEXT_MASK);
+}
+
+void printk_nmi_direct_exit(void)
+{
+       this_cpu_and(printk_context, ~PRINTK_NMI_DIRECT_CONTEXT_MASK);
 }
 
 #else
 
 __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
 {
+       /*
+        * Try to use the main logbuf even in NMI. But avoid calling console
+        * drivers that might have their own locks.
+        */
+       if ((this_cpu_read(printk_context) & PRINTK_NMI_DIRECT_CONTEXT_MASK) &&
+           raw_spin_trylock(&logbuf_lock)) {
+               int len;
+
+               len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
+               raw_spin_unlock(&logbuf_lock);
+               defer_console_output();
+               return len;
+       }
+
        /* 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);
        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);
 }
 
        tracing_off();
 
        local_irq_save(flags);
+       printk_nmi_direct_enter();
 
        /* Simulate the iterator */
        trace_init_global_iter(&iter);
        for_each_tracing_cpu(cpu) {
                atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
        }
-       atomic_dec(&dump_running);
+       atomic_dec(&dump_running);
+       printk_nmi_direct_exit();
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(ftrace_dump);
 
 
 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 %pS\n",
                                cpu, (void *)instruction_pointer(regs));
                        else
                                dump_stack();
                }
-               arch_spin_unlock(&lock);
                cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
                return true;
        }