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]
Message-Id: <20171204134825.7822-11-sergey.senozhatsky@gmail.com>
Date:   Mon,  4 Dec 2017 22:48:23 +0900
From:   Sergey Senozhatsky <sergey.senozhatsky@...il.com>
To:     Steven Rostedt <rostedt@...dmis.org>,
        Petr Mladek <pmladek@...e.com>
Cc:     Jan Kara <jack@...e.cz>, Andrew Morton <akpm@...ux-foundation.org>,
        Peter Zijlstra <peterz@...radead.org>,
        Rafael Wysocki <rjw@...ysocki.net>,
        Pavel Machek <pavel@....cz>,
        Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>,
        Tejun Heo <tj@...nel.org>, linux-kernel@...r.kernel.org,
        Sergey Senozhatsky <sergey.senozhatsky.work@...il.com>,
        Sergey Senozhatsky <sergey.senozhatsky@...il.com>
Subject: [RFC][PATCHv6 10/12] printk: move offloading logic to per-cpu

We have a global offloading state and make the offloading
decision based on printing task pointer and elapsed time.
If we keep seeing the same task performing printing for too
long we request offloading; otherwise, when we see that
printing is now performed by another task, we reset the
printing task pointer and its elapsed counter.

This, however, will not work in the following case:

===============================================================================

CPU0						CPU1
//taskA						//taskB
preempt_disable()				preempt_disable()

 printk()
  console_trylock()
  console_unlock()
   printing_task = taskA
  up()
						printk()
						 console_trylock()
						 console_unlock()
						  printing_task = taskB
						  ^^^ reset offloading control
						up()
 printk()
  console_trylock()
  console_unlock()
   printing_task = taskA
   ^^^ reset offloading control
  up()
						printk()
						 console_trylock()
						 console_unlock()
						  printing_task = taskB
						  ^^^ reset offloading control
						up()
...
===============================================================================

So this printk ping-pong confuses our offloading control logic.
Move it to per-CPU area and have a separate offloading control
on every CPU.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@...il.com>
---
 kernel/printk/printk.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2a12d4c02da1..2f9697c71cf1 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -560,12 +560,12 @@ static inline int offloading_threshold(void)
  * amount of time a process can print from console_unlock().
  *
  * This function must be called from 'printk_safe' context under
- * console_sem lock.
+ * console_sem lock with preemption disabled.
  */
 static inline bool should_handoff_printing(u64 printing_start_ts)
 {
+	static DEFINE_PER_CPU(u64, printing_elapsed);
 	static struct task_struct *printing_task;
-	static u64 printing_elapsed;
 	u64 now = local_clock();
 	bool emergency = !printk_offloading_enabled();
 
@@ -578,19 +578,26 @@ static inline bool should_handoff_printing(u64 printing_start_ts)
 
 	/* A new task - reset the counters. */
 	if (printing_task != current) {
+		__this_cpu_write(printing_elapsed, 0);
 		printing_task = current;
-		printing_elapsed = 0;
 		return false;
 	}
 
-	if (time_after_eq64(now, printing_start_ts))
-		printing_elapsed += now - printing_start_ts;
+	if (time_after_eq64(now, printing_start_ts)) {
+		u64 t = __this_cpu_read(printing_elapsed);
+
+		t += now - printing_start_ts;
+		__this_cpu_write(printing_elapsed, t);
+	}
 
 	/* Shrink down to seconds and check the offloading threshold */
-	if ((printing_elapsed >> 30LL) < offloading_threshold())
+	if ((__this_cpu_read(printing_elapsed) >> 30LL) <
+			offloading_threshold())
 		return false;
 
 	if (current == printk_kthread) {
+		unsigned int cpu;
+
 		/*
 		 * All tasks must offload - we don't want to keep console_sem
 		 * locked for too long. However, printk_kthread may be the
@@ -603,7 +610,8 @@ static inline bool should_handoff_printing(u64 printing_start_ts)
 		 * console_unlock(), it will have another full
 		 * `offloading_threshold()' time slice.
 		 */
-		printing_elapsed = 0;
+		for_each_possible_cpu(cpu)
+			per_cpu(printing_elapsed, cpu) = 0;
 		return true;
 	}
 
-- 
2.15.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ