提交 19feeff1 编写于 作者: S Sergey Senozhatsky 提交者: Linus Torvalds

printk/nmi: avoid direct printk()-s from __printk_nmi_flush()

__printk_nmi_flush() can be called from nmi_panic(), therefore it has to
test whether it's executed in NMI context and thus must route the
messages through deferred printk() or via direct printk().

This is to avoid potential deadlocks, as described in commit
cf9b1106 ("printk/nmi: flush NMI messages on the system panic").

However there remain two places where __printk_nmi_flush() does
unconditional direct printk() calls:

 - pr_err("printk_nmi_flush: internal error ...")
 - pr_cont("\n")

Factor out print_nmi_seq_line() parts into a new printk_nmi_flush_line()
function, which takes care of in_nmi(), and use it in
__printk_nmi_flush() for printing and error-reporting.

Link: http://lkml.kernel.org/r/20160830161354.581-1-sergey.senozhatsky@gmail.comSigned-off-by: NSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 7e932159
......@@ -99,26 +99,32 @@ static int vprintk_nmi(const char *fmt, va_list args)
return add;
}
/*
* printk one line from the temporary buffer from @start index until
* and including the @end index.
*/
static void print_nmi_seq_line(struct nmi_seq_buf *s, int start, int end)
static void printk_nmi_flush_line(const char *text, int len)
{
const char *buf = s->buffer + start;
/*
* The buffers are flushed in NMI only on panic. The messages must
* go only into the ring buffer at this stage. Consoles will get
* explicitly called later when a crashdump is not generated.
*/
if (in_nmi())
printk_deferred("%.*s", (end - start) + 1, buf);
printk_deferred("%.*s", len, text);
else
printk("%.*s", (end - start) + 1, buf);
printk("%.*s", len, text);
}
/*
* printk one line from the temporary buffer from @start index until
* and including the @end index.
*/
static void printk_nmi_flush_seq_line(struct nmi_seq_buf *s,
int start, int end)
{
const char *buf = s->buffer + start;
printk_nmi_flush_line(buf, (end - start) + 1);
}
/*
* Flush data from the associated per_CPU buffer. The function
* can be called either via IRQ work or independently.
......@@ -150,9 +156,11 @@ static void __printk_nmi_flush(struct irq_work *work)
* the buffer an unexpected way. If we printed something then
* @len must only increase.
*/
if (i && i >= len)
pr_err("printk_nmi_flush: internal error: i=%d >= len=%zu\n",
i, len);
if (i && i >= len) {
const char *msg = "printk_nmi_flush: internal error\n";
printk_nmi_flush_line(msg, strlen(msg));
}
if (!len)
goto out; /* Someone else has already flushed the buffer. */
......@@ -166,14 +174,14 @@ static void __printk_nmi_flush(struct irq_work *work)
/* Print line by line. */
for (; i < size; i++) {
if (s->buffer[i] == '\n') {
print_nmi_seq_line(s, last_i, i);
printk_nmi_flush_seq_line(s, last_i, i);
last_i = i + 1;
}
}
/* Check if there was a partial line. */
if (last_i < size) {
print_nmi_seq_line(s, last_i, size - 1);
pr_cont("\n");
printk_nmi_flush_seq_line(s, last_i, size - 1);
printk_nmi_flush_line("\n", strlen("\n"));
}
/*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册