summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2012-05-10 04:32:53 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-09 20:29:59 -0700
commit5c5d5ca51abd728c8de3be43ffd6bb00f977bfcd (patch)
tree737f0efbb6971c7055d7b07dacc79a2922bd19c7
parent7f3a781d6fd81e397c3928c9af33f1fc63232db6 (diff)
downloadlinux-5c5d5ca51abd728c8de3be43ffd6bb00f977bfcd.tar.bz2
printk() - do not merge continuation lines of different threads
This prevents the merging of printk() continuation lines of different threads, in the case they race against each other. It should properly isolate "atomic" single-line printk() users from continuation users, to make sure the single-line users will never be merged with the racy continuation ones. Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Kay Sievers <kay@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/printk.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 7b432951f91e..301fb0f09fbf 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1230,12 +1230,13 @@ asmlinkage int vprintk_emit(int facility, int level,
static size_t buflen;
static int buflevel;
static char textbuf[LOG_LINE_MAX];
+ static struct task_struct *cont;
char *text = textbuf;
size_t textlen;
unsigned long flags;
int this_cpu;
bool newline = false;
- bool cont = false;
+ bool prefix = false;
int printed_len = 0;
boot_delay_msec();
@@ -1295,20 +1296,16 @@ asmlinkage int vprintk_emit(int facility, int level,
case '0' ... '7':
if (level == -1)
level = text[1] - '0';
- text += 3;
- textlen -= 3;
- break;
- case 'c': /* KERN_CONT */
- cont = true;
case 'd': /* KERN_DEFAULT */
+ prefix = true;
+ case 'c': /* KERN_CONT */
text += 3;
textlen -= 3;
- break;
}
}
- if (buflen && (!cont || dict)) {
- /* no continuation; flush existing buffer */
+ if (buflen && (prefix || dict || cont != current)) {
+ /* flush existing buffer */
log_store(facility, buflevel, NULL, 0, buf, buflen);
printed_len += buflen;
buflen = 0;
@@ -1342,6 +1339,10 @@ asmlinkage int vprintk_emit(int facility, int level,
dict, dictlen, text, textlen);
printed_len += textlen;
}
+ cont = NULL;
+ } else {
+ /* remember thread which filled the buffer */
+ cont = current;
}
/*