[RFC][PATCHv5 10/13] printk: force printk_kthread to offload printing

Sergey Senozhatsky
2017-08-15T03:00:48Z

As of now we don't `offload' printing from printk_kthread and
print all pending logbuf messages. This, however, may have a
negative effect. We still hold console_sem as long as we have
got messages to print, and there might be other console_lock()
callers sleeping on console_sem in TASK_UNINTERRUPTIBLE,
including user space processes (tty_open, drm IOCTL, etc.).
So we need to up() console_sem every once in a while, even if
current console_sem owner is printk_kthread, just in order to
wake up those other processes that can sleep on console_sem.

If there are no tasks skeeping on console_sem, then printk_kthread
will immediately return back to console_unclok(), because we don't
clear the PRINTK_PENDING_OUTPUT bit and printk_kthread checks it
before it decides to schedule().

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

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 71950bd85eac..6da4e21c3b45 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -600,15 +600,29 @@ static inline bool console_offload_printing(void)
return false;
}

- /* Once we offloaded to printk_ktread - keep printing */
- if (current == printk_kthread)
- return false;
-
adj_atomic_print_limit();

if (!time_after_eq(now, printing_start_ts + atomic_print_limit))
return false;

+ if (current == printk_kthread) {
+ /*
+ * All tasks are equal, all tasks must offload. However,
+ * printk_kthread may be the only process left willing to
+ * down(). So we may return here immediately after we leave,
+ * because of positive PRINTK_PENDING_OUTPUT check in
+ * printk_kthread_func() loop. However, we obviously don't
+ * want to declare printk emergency in this case, so that's
+ * why we update `printing_start_ts' here.
+ *
+ * In case if `printk_kthread' will immediately return
+ * back to console_unlock(), it will have another full
+ * `atomic_print_limit' time slice.
+ */
+ printing_start_ts = local_clock() >> 30LL;
+ return true;
+ }
+
/*
* A trivial emergency enforcement - give up on printk_kthread if
* we can't wake it up.
--
2.14.1