Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32a76006 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

printk: make printk more robust by not allowing recursion



make printk more robust by allowing recursion only if there's a crash
going on. Also add recursion detection.

I've tested it with an artificially injected printk recursion - instead
of a lockup or spontaneous reboot or other crash, the output was a well
controlled:

[   41.057335] SysRq : <2>BUG: recent printk recursion!
[   41.057335] loglevel0-8 reBoot Crashdump show-all-locks(D) tErm Full kIll saK showMem Nice powerOff showPc show-all-timers(Q) unRaw Sync showTasks Unmount shoW-blocked-tasks

also do all this printk-debug logic with irqs disabled.

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Reviewed-by: default avatarNick Piggin <npiggin@suse.de>
parent b47711bf
Loading
Loading
Loading
Loading
+38 −10
Original line number Original line Diff line number Diff line
@@ -628,30 +628,57 @@ asmlinkage int printk(const char *fmt, ...)
/* cpu currently holding logbuf_lock */
/* cpu currently holding logbuf_lock */
static volatile unsigned int printk_cpu = UINT_MAX;
static volatile unsigned int printk_cpu = UINT_MAX;


const char printk_recursion_bug_msg [] =
			KERN_CRIT "BUG: recent printk recursion!\n";
static int printk_recursion_bug;

asmlinkage int vprintk(const char *fmt, va_list args)
asmlinkage int vprintk(const char *fmt, va_list args)
{
{
	static int log_level_unknown = 1;
	static char printk_buf[1024];

	unsigned long flags;
	unsigned long flags;
	int printed_len;
	int printed_len = 0;
	int this_cpu;
	char *p;
	char *p;
	static char printk_buf[1024];
	static int log_level_unknown = 1;


	boot_delay_msec();
	boot_delay_msec();


	preempt_disable();
	preempt_disable();
	if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
		/* If a crash is occurring during printk() on this CPU,
		 * make sure we can't deadlock */
		zap_locks();

	/* This stops the holder of console_sem just where we want him */
	/* This stops the holder of console_sem just where we want him */
	raw_local_irq_save(flags);
	raw_local_irq_save(flags);
	this_cpu = smp_processor_id();

	/*
	 * Ouch, printk recursed into itself!
	 */
	if (unlikely(printk_cpu == this_cpu)) {
		/*
		 * If a crash is occurring during printk() on this CPU,
		 * then try to get the crash message out but make sure
		 * we can't deadlock. Otherwise just return to avoid the
		 * recursion and return - but flag the recursion so that
		 * it can be printed at the next appropriate moment:
		 */
		if (!oops_in_progress) {
			printk_recursion_bug = 1;
			goto out_restore_irqs;
		}
		zap_locks();
	}

	lockdep_off();
	lockdep_off();
	spin_lock(&logbuf_lock);
	spin_lock(&logbuf_lock);
	printk_cpu = smp_processor_id();
	printk_cpu = this_cpu;


	if (printk_recursion_bug) {
		printk_recursion_bug = 0;
		strcpy(printk_buf, printk_recursion_bug_msg);
		printed_len = sizeof(printk_recursion_bug_msg);
	}
	/* Emit the output into the temporary buffer */
	/* Emit the output into the temporary buffer */
	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
	printed_len += vscnprintf(printk_buf + printed_len,
				  sizeof(printk_buf), fmt, args);


	/*
	/*
	 * Copy the output into log_buf.  If the caller didn't provide
	 * Copy the output into log_buf.  If the caller didn't provide
@@ -744,6 +771,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
		printk_cpu = UINT_MAX;
		printk_cpu = UINT_MAX;
		spin_unlock(&logbuf_lock);
		spin_unlock(&logbuf_lock);
		lockdep_on();
		lockdep_on();
out_restore_irqs:
		raw_local_irq_restore(flags);
		raw_local_irq_restore(flags);
	}
	}