From: John Ogness <john.ogness@linutronix.de>
To: Petr Mladek <pmladek@suse.com>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>,
Steven Rostedt <rostedt@goodmis.org>,
Thomas Gleixner <tglx@linutronix.de>,
linux-kernel@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH printk v1 10/13] printk: add kthread console printers
Date: Mon, 7 Feb 2022 20:49:20 +0106 [thread overview]
Message-ID: <20220207194323.273637-11-john.ogness@linutronix.de> (raw)
In-Reply-To: <20220207194323.273637-1-john.ogness@linutronix.de>
Create a kthread for each console to perform console printing. During
normal operation (@system_state == SYSTEM_RUNNING), the kthread
printers are responsible for all printing on their respective
consoles.
During non-normal operation, console printing is done as it has been:
within the context of the printk caller or within irq work triggered
by the printk caller.
Console printers synchronize against each other and against console
lockers by taking the console lock for each message that is printed.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
include/linux/console.h | 2 +
kernel/printk/printk.c | 159 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 56a6669471a6..0f94b1771df8 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -153,6 +153,8 @@ struct console {
uint ospeed;
u64 seq;
unsigned long dropped;
+ struct task_struct *thread;
+
void *data;
struct console *next;
};
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 719b05e6ce3b..e182f31fec58 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -347,6 +347,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
static DEFINE_MUTEX(syslog_lock);
+/*
+ * A flag to signify if printk_late_init() has already started the kthread
+ * printers. If true, any later registered consoles must start their own
+ * kthread directly. The flag is write protected by the console_lock.
+ */
+static bool kthreads_started;
+
#ifdef CONFIG_PRINTK
static atomic_t printk_direct = ATOMIC_INIT(0);
@@ -373,6 +380,14 @@ void printk_direct_exit(void)
atomic_dec(&printk_direct);
}
+static inline bool allow_direct_printing(void)
+{
+ return (!kthreads_started ||
+ system_state != SYSTEM_RUNNING ||
+ oops_in_progress ||
+ atomic_read(&printk_direct));
+}
+
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
/* the next printk record to read by syslog(READ) or /proc/kmsg */
@@ -2225,7 +2240,7 @@ asmlinkage int vprintk_emit(int facility, int level,
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
/* If called from the scheduler, we can not call up(). */
- if (!in_sched) {
+ if (!in_sched && allow_direct_printing()) {
/*
* Disable preemption to avoid being preempted while holding
* console_sem which would prevent anyone from printing to
@@ -2266,6 +2281,8 @@ asmlinkage __visible int _printk(const char *fmt, ...)
}
EXPORT_SYMBOL(_printk);
+static void start_printk_kthread(struct console *con);
+
#else /* CONFIG_PRINTK */
#define CONSOLE_LOG_MAX 0
@@ -2299,6 +2316,8 @@ static void call_console_driver(struct console *con, const char *text, size_t le
}
static bool suppress_message_printing(int level) { return false; }
static void printk_delay(int level) {}
+static void start_printk_kthread(struct console *con) {}
+static bool allow_direct_printing(void) { return true; }
#endif /* CONFIG_PRINTK */
@@ -2487,6 +2506,10 @@ void resume_console(void)
down_console_sem();
console_suspended = 0;
console_unlock();
+
+ /* Wake the kthread printers. */
+ wake_up_klogd();
+
pr_flush(1000, true);
}
@@ -2702,6 +2725,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
*handover = false;
do {
+ /* Let the kthread printers do the work if they can. */
+ if (!allow_direct_printing())
+ break;
+
any_progress = false;
for_each_console(con) {
@@ -2910,6 +2937,10 @@ void console_start(struct console *console)
console_lock();
console->flags |= CON_ENABLED;
console_unlock();
+
+ /* Wake the kthread printers. */
+ wake_up_klogd();
+
pr_flush(1000, true);
}
EXPORT_SYMBOL(console_start);
@@ -3114,6 +3145,8 @@ void register_console(struct console *newcon)
/* Begin with next message. */
newcon->seq = prb_next_seq(prb);
}
+ if (kthreads_started)
+ start_printk_kthread(newcon);
console_unlock();
console_sysfs_notify();
@@ -3170,6 +3203,11 @@ int unregister_console(struct console *console)
}
}
+ if (console->thread) {
+ kthread_stop(console->thread);
+ console->thread = NULL;
+ }
+
if (res)
goto out_disable_unlock;
@@ -3275,6 +3313,13 @@ static int __init printk_late_init(void)
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "printk:online",
console_cpu_notify, NULL);
WARN_ON(ret < 0);
+
+ console_lock();
+ for_each_console(con)
+ start_printk_kthread(con);
+ kthreads_started = true;
+ console_unlock();
+
return 0;
}
late_initcall(printk_late_init);
@@ -3345,6 +3390,116 @@ bool pr_flush(int timeout_ms, bool reset_on_progress)
}
EXPORT_SYMBOL(pr_flush);
+static bool printer_should_wake(struct console *con, u64 seq)
+{
+ short flags;
+
+ if (kthread_should_stop())
+ return true;
+
+ if (console_suspended)
+ return false;
+
+ /*
+ * This is an unsafe read to con->flags, but false positives
+ * are not an issue as long as they are rare.
+ */
+ flags = data_race(READ_ONCE(con->flags));
+ if (!(flags & CON_ENABLED))
+ return false;
+
+ return prb_read_valid(prb, seq, NULL);
+}
+
+static int printk_kthread_func(void *data)
+{
+ struct console *con = data;
+ char *dropped_text = NULL;
+ char *ext_text = NULL;
+ bool progress;
+ bool handover;
+ u64 seq = 0;
+ char *text;
+ int error;
+
+ pr_info("%sconsole [%s%d]: printing thread started\n",
+ (con->flags & CON_BOOT) ? "boot" : "",
+ con->name, con->index);
+
+ text = kmalloc(CONSOLE_LOG_MAX, GFP_KERNEL);
+ if (!text)
+ goto out;
+
+ if (con->flags & CON_EXTENDED) {
+ ext_text = kmalloc(CONSOLE_EXT_LOG_MAX, GFP_KERNEL);
+ if (!ext_text)
+ goto out;
+ } else {
+ dropped_text = kmalloc(DROPPED_TEXT_MAX, GFP_KERNEL);
+ if (!dropped_text)
+ goto out;
+ }
+
+ for (;;) {
+ error = wait_event_interruptible(log_wait, printer_should_wake(con, seq));
+
+ if (kthread_should_stop())
+ break;
+
+ if (error)
+ continue;
+
+ do {
+ console_lock();
+ if (console_suspended) {
+ console_unlock();
+ break;
+ }
+
+ /*
+ * Even though the printk kthread is always preemptible, it is
+ * still not allowed to call cond_resched() from within
+ * console drivers. The task may become non-preemptible in the
+ * console driver call chain. For example, vt_console_print()
+ * takes a spinlock and then can call into fbcon_redraw(),
+ * which can conditionally invoke cond_resched().
+ */
+ console_may_schedule = 0;
+ progress = console_emit_next_record(con, text, ext_text,
+ dropped_text, &handover);
+ if (handover)
+ break;
+
+ seq = con->seq;
+
+ /* Unlock console without invoking direct printing. */
+ __console_unlock();
+ } while (progress);
+ }
+out:
+ kfree(dropped_text);
+ kfree(ext_text);
+ kfree(text);
+ pr_info("%sconsole [%s%d]: printing thread stopped\n",
+ (con->flags & CON_BOOT) ? "boot" : "",
+ con->name, con->index);
+ return 0;
+}
+
+/* Must be called within console_lock(). */
+static void start_printk_kthread(struct console *con)
+{
+ con->thread = kthread_run(printk_kthread_func, con,
+ "pr/%s%d", con->name, con->index);
+ if (IS_ERR(con->thread)) {
+ con->thread = NULL;
+ pr_err("%sconsole [%s%d]: unable to start printing thread\n",
+ (con->flags & CON_BOOT) ? "boot" : "",
+ con->name, con->index);
+ return;
+ }
+}
+
/*
* Delayed printk version, for scheduler-internal messages:
*/
@@ -3371,7 +3526,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
}
if (pending & PRINTK_PENDING_WAKEUP)
- wake_up_interruptible(&log_wait);
+ wake_up_interruptible_all(&log_wait);
}
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) =
--
2.30.2
next prev parent reply other threads:[~2022-02-07 19:45 UTC|newest]
Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-07 19:43 [PATCH printk v1 00/13] implement threaded console printing John Ogness
2022-02-07 19:43 ` [PATCH printk v1 01/13] printk: rename cpulock functions John Ogness
2022-02-11 12:44 ` Petr Mladek
2022-02-11 14:42 ` John Ogness
2022-02-11 20:57 ` Steven Rostedt
2022-02-11 21:04 ` Peter Zijlstra
2022-02-15 9:32 ` Petr Mladek
2022-02-15 9:13 ` Petr Mladek
2022-02-14 6:49 ` Sergey Senozhatsky
2022-02-14 9:45 ` John Ogness
2022-02-15 9:29 ` Petr Mladek
2022-02-16 3:27 ` Sergey Senozhatsky
2022-02-17 14:34 ` John Ogness
2022-02-07 19:43 ` [PATCH printk v1 02/13] printk: cpu sync always disable interrupts John Ogness
2022-02-11 12:58 ` Petr Mladek
2022-02-14 6:36 ` Sergey Senozhatsky
2022-02-07 19:43 ` [PATCH printk v1 03/13] printk: use percpu flag instead of cpu_online() John Ogness
2022-02-11 16:05 ` Petr Mladek
2022-02-14 7:08 ` Sergey Senozhatsky
2022-02-14 7:35 ` Sergey Senozhatsky
2022-02-15 10:38 ` Petr Mladek
2022-02-16 3:29 ` Sergey Senozhatsky
2022-03-02 14:21 ` John Ogness
2022-03-04 15:56 ` Petr Mladek
2022-03-05 17:05 ` Jason A. Donenfeld
2022-03-07 16:14 ` Petr Mladek
2022-02-16 13:58 ` two locations: was: " Petr Mladek
2022-03-02 14:49 ` John Ogness
2022-03-04 16:14 ` Petr Mladek
2022-03-07 10:06 ` John Ogness
2022-03-08 16:08 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 04/13] printk: get caller_id/timestamp after migration disable John Ogness
2022-02-15 5:53 ` Sergey Senozhatsky
2022-02-15 11:56 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 05/13] printk: call boot_delay_msec() in printk_delay() John Ogness
2022-02-15 5:58 ` Sergey Senozhatsky
2022-02-15 14:59 ` Petr Mladek
2022-02-16 3:21 ` Sergey Senozhatsky
2022-02-15 15:03 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 06/13] printk: refactor and rework printing logic John Ogness
2022-02-16 15:43 ` Petr Mladek
2022-03-02 16:10 ` John Ogness
2022-02-07 19:43 ` [PATCH printk v1 07/13] printk: move buffer definitions into console_emit_next_record() caller John Ogness
2022-02-16 16:10 ` Petr Mladek
2022-03-02 16:25 ` John Ogness
2022-02-07 19:43 ` [PATCH printk v1 08/13] printk: add pr_flush() John Ogness
2022-02-17 10:11 ` Petr Mladek
2022-03-02 17:23 ` John Ogness
2022-03-04 13:24 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 09/13] printk: add functions to allow direct printing John Ogness
2022-02-17 12:52 ` Petr Mladek
2022-02-18 9:00 ` David Laight
2022-02-18 12:52 ` Petr Mladek
2022-03-03 14:37 ` John Ogness
2022-02-07 19:43 ` John Ogness [this message]
2022-02-18 9:00 ` early start: was: Re: [PATCH printk v1 10/13] printk: add kthread console printers Petr Mladek
2022-02-18 9:04 ` start&stop: " Petr Mladek
2022-02-18 9:08 ` main loop: " Petr Mladek
2022-02-18 9:12 ` wake_up_all: " Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 11/13] printk: reimplement console_lock for proper kthread support John Ogness
2022-02-18 16:20 ` Petr Mladek
2022-02-18 21:41 ` John Ogness
2022-02-18 22:03 ` John Ogness
2022-02-22 11:42 ` Petr Mladek
2022-02-23 17:20 ` John Ogness
2022-02-24 8:27 ` Petr Mladek
2022-02-23 10:19 ` Petr Mladek
2022-03-09 13:56 ` John Ogness
2022-03-10 14:34 ` Petr Mladek
2022-03-10 16:08 ` John Ogness
2022-03-11 10:26 ` Petr Mladek
2022-03-11 13:28 ` John Ogness
2022-03-11 16:17 ` Petr Mladek
2022-03-11 22:21 ` John Ogness
2022-03-14 14:08 ` Petr Mladek
2022-03-14 14:43 ` John Ogness
2022-03-14 15:53 ` Petr Mladek
2022-03-11 18:41 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 12/13] printk: remove @console_locked John Ogness
2022-02-23 12:17 ` Petr Mladek
2022-02-07 19:43 ` [PATCH printk v1 13/13] console: introduce CON_MIGHT_SLEEP for vt John Ogness
2022-02-23 13:37 ` Petr Mladek
2022-02-23 18:31 ` Greg Kroah-Hartman
[not found] ` <20220208083620.2736-1-hdanton@sina.com>
2022-02-08 11:08 ` [PATCH printk v1 10/13] printk: add kthread console printers John Ogness
2022-02-08 14:53 ` Petr Mladek
2022-02-14 6:12 ` Sergey Senozhatsky
2022-02-14 10:02 ` Petr Mladek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220207194323.273637-11-john.ogness@linutronix.de \
--to=john.ogness@linutronix.de \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=senozhatsky@chromium.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®