lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 15 Jul 2016 18:59:02 +0200
From:	Petr Mladek <pmladek@...e.com>
To:	Andrew Morton <akpm@...ux-foundation.org>,
	Sergey Senozhatsky <sergey.senozhatsky.work@...il.com>
Cc:	Jiri Kosina <jkosina@...e.com>, Jan Kara <jack@...e.com>,
	Tejun Heo <tj@...nel.org>,
	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>,
	Byungchul Park <byungchul.park@....com>,
	linux-kernel@...r.kernel.org, Petr Mladek <pmladek@...e.com>
Subject: [PATCH POC 4/4] printk: Correctly replay buffer log for a new console

There are several problems with replying the log buffer
when a new console is added.

Only the end of partially flushed line is printed on
the new console. But this end of the line is not longer
printed on the other consoles. In fact, any new line
are printed only on the new console until the replay
is finished.

This patch tries to fix all the above mentioned problems.
The replay finishes when the original sequence number
is reached. Only the already printed piece of the
continuous line is printed. The rest will be printed
when all consoles are enabled again.

Signed-off-by: Petr Mladek <pmladek@...e.com>
---
 kernel/printk/printk.c | 68 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 52 insertions(+), 16 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index a920cc36c24e..d117e7b1244d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -134,9 +134,11 @@ static int __down_trylock_console_sem(unsigned long ip)
 static int console_locked, console_suspended;
 
 /*
- * If exclusive_console is non-NULL then only this console is to be printed to.
+ * If exclusive_console is non-NULL then only this console is to be printed to
+ * and only until the given sequence number.
  */
 static struct console *exclusive_console;
+static u64 exclusive_console_seq_stop;
 
 /*
  *	Array of consoles built from command line options (console=)
@@ -2177,14 +2179,15 @@ static inline int can_use_console(void)
 	return cpu_online(raw_smp_processor_id()) || have_callable_console();
 }
 
-static void console_cont_flush(char *text, size_t size)
+static void console_cont_flush(struct cont *cont,char *text, size_t size)
 {
 	unsigned long flags;
+	u8 level;
 	size_t len;
 
 	raw_spin_lock_irqsave(&logbuf_lock, flags);
 
-	if (!cont.msg->text_len)
+	if (!cont->msg->text_len)
 		goto out;
 
 	/*
@@ -2194,10 +2197,11 @@ static void console_cont_flush(char *text, size_t size)
 	if (console_seq < log_next_seq)
 		goto out;
 
-	len = cont_print_text(&cont, text, size);
+	len = cont_print_text(cont, text, size);
+	level = cont->msg->level;
 	raw_spin_unlock(&logbuf_lock);
 	stop_critical_timings();
-	call_console_drivers(cont.msg->level, NULL, 0, text, len);
+	call_console_drivers(level, NULL, 0, text, len);
 	start_critical_timings();
 	local_irq_restore(flags);
 	return;
@@ -2282,18 +2286,19 @@ again:
 			len = 0;
 		}
 
+		if (exclusive_console &&
+		    console_seq == exclusive_console_seq_stop)
+			break;
+
 		if (console_seq == log_next_seq)
 			break;
 
 		msg = log_from_idx(console_idx);
 		level = msg->level;
 
-		/*
-		 * The line might be already partially printed from the cont
-		 * buffer. In this case, flush the rest using a fake
-		 * cont buffer.
-		 */
-		if (cont_console_len && cont_console_seq == console_seq) {
+		if (cont_console_len &&
+		    cont_console_seq == console_seq &&
+		    !exclusive_console) {
 			struct cont fake_cont;
 
 			fake_cont.owner = NULL;
@@ -2317,7 +2322,6 @@ again:
 							      log_text(msg), msg->text_len);
 			}
 		}
-
 		console_idx = log_next(console_idx);
 		console_seq++;
 		console_prev = msg->flags;
@@ -2334,12 +2338,43 @@ again:
 
 	raw_spin_unlock(&logbuf_lock);
 
-	/* flush buffered message fragment immediately to console */
-	console_cont_flush(text, sizeof(text));
+	if (unlikely(exclusive_console)) {
+		/* Replay also the partially flushed cont buffer */
+		if (cont_console_seq) {
+			struct printk_log fake_msg;
+			struct printk_log *msg;
+			struct cont fake_cont;
+			size_t len;
+			int level;
+
+			raw_spin_lock(&logbuf_lock);
+			if (console_seq == log_next_seq) {
+				memcpy(&fake_msg, &cont_msg, sizeof(fake_msg));
+				fake_cont.buf = cont_buf;
+			} else {
+				msg = log_from_idx(console_idx);
+				memcpy(&fake_msg, msg, sizeof(fake_msg));
+				fake_cont.buf = log_text(msg);
+			}
+			fake_cont.msg = &fake_msg;
+			fake_msg.text_len = cont_console_len;
+			cont_console_len = 0;
+
+			len = cont_print_text(&fake_cont, text, sizeof(text));
+			level = fake_msg.level;
+
+			raw_spin_unlock(&logbuf_lock);
+
+			stop_critical_timings();	/* don't trace print latency */
+			call_console_drivers(level, NULL, 0, text, len);
+			start_critical_timings();
+		}
 
-	/* Release the exclusive_console once it is used */
-	if (unlikely(exclusive_console))
 		exclusive_console = NULL;
+	} else {
+		/* Flush buffered message fragment immediately to console */
+		console_cont_flush(&cont, text, sizeof(text));
+	}
 
 	console_locked = 0;
 	up_console_sem();
@@ -2626,6 +2661,7 @@ void register_console(struct console *newcon)
 		 * the already-registered consoles.
 		 */
 		exclusive_console = newcon;
+		exclusive_console_seq_stop = console_seq;
 	}
 	console_unlock();
 	console_sysfs_notify();
-- 
1.8.5.6

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ