diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:11:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-07 13:11:49 +0000 |
commit | f25552c1068a054f2d99afd67a671d5991bf19c1 (patch) | |
tree | d70de5c7262ad572f8323fc4184b8a10522e81ec /debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch | |
parent | Merging upstream version 6.9.7. (diff) | |
download | linux-f25552c1068a054f2d99afd67a671d5991bf19c1.tar.xz linux-f25552c1068a054f2d99afd67a671d5991bf19c1.zip |
Merging debian version 6.9.7-1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch')
-rw-r--r-- | debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch | 472 |
1 files changed, 0 insertions, 472 deletions
diff --git a/debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch b/debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch deleted file mode 100644 index 12f69b52fc..0000000000 --- a/debian/patches-rt/0033-printk-nbcon-Introduce-printing-kthreads.patch +++ /dev/null @@ -1,472 +0,0 @@ -From: Thomas Gleixner <tglx@linutronix.de> -Date: Fri, 22 Sep 2023 14:12:21 +0000 -Subject: [PATCH 33/48] printk: nbcon: Introduce printing kthreads -Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.8/older/patches-6.8.2-rt11.tar.xz - -Provide the main implementation for running a printer kthread -per nbcon console that is takeover/handover aware. - -Co-developed-by: John Ogness <john.ogness@linutronix.de> -Signed-off-by: John Ogness <john.ogness@linutronix.de> -Signed-off-by: Thomas Gleixner (Intel) <tglx@linutronix.de> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - include/linux/console.h | 26 ++++++ - kernel/printk/internal.h | 28 +++++++ - kernel/printk/nbcon.c | 187 +++++++++++++++++++++++++++++++++++++++++++++-- - kernel/printk/printk.c | 33 ++++++++ - 4 files changed, 269 insertions(+), 5 deletions(-) - ---- a/include/linux/console.h -+++ b/include/linux/console.h -@@ -17,6 +17,7 @@ - #include <linux/atomic.h> - #include <linux/bits.h> - #include <linux/rculist.h> -+#include <linux/rcuwait.h> - #include <linux/types.h> - - struct vc_data; -@@ -324,6 +325,8 @@ struct nbcon_drvdata { - * @nbcon_state: State for nbcon consoles - * @nbcon_seq: Sequence number of the next record for nbcon to print - * @pbufs: Pointer to nbcon private buffer -+ * @kthread: Printer kthread for this console -+ * @rcuwait: RCU-safe wait object for @kthread waking - */ - struct console { - char name[16]; -@@ -372,6 +375,27 @@ struct console { - void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt); - - /** -+ * @write_thread: -+ * -+ * NBCON callback to write out text in task context. (Optional) -+ * -+ * This callback is called with the console already acquired. Any -+ * additional driver synchronization should have been performed by -+ * device_lock(). -+ * -+ * This callback is always called from task context but with migration -+ * disabled. -+ * -+ * The same criteria for console ownership verification and unsafe -+ * sections applies as with write_atomic(). The difference between -+ * this callback and write_atomic() is that this callback is used -+ * during normal operation and is always called from task context. -+ * This provides drivers with a relatively relaxed locking context -+ * for synchronizing output to the hardware. -+ */ -+ void (*write_thread)(struct console *con, struct nbcon_write_context *wctxt); -+ -+ /** - * @device_lock: - * - * NBCON callback to begin synchronization with driver code. -@@ -431,6 +455,8 @@ struct console { - struct nbcon_drvdata *nbcon_drvdata; - - struct printk_buffers *pbufs; -+ struct task_struct *kthread; -+ struct rcuwait rcuwait; - }; - - #ifdef CONFIG_LOCKDEP ---- a/kernel/printk/internal.h -+++ b/kernel/printk/internal.h -@@ -90,6 +90,7 @@ enum nbcon_prio nbcon_get_default_prio(v - void nbcon_atomic_flush_pending(void); - bool nbcon_legacy_emit_next_record(struct console *con, bool *handover, - int cookie); -+void nbcon_kthread_create(struct console *con); - - /* - * Check if the given console is currently capable and allowed to print -@@ -108,6 +109,8 @@ static inline bool console_is_usable(str - if (flags & CON_NBCON) { - if (!con->write_atomic) - return false; -+ if (!con->write_thread) -+ return false; - } else { - if (!con->write) - return false; -@@ -124,12 +127,35 @@ static inline bool console_is_usable(str - return true; - } - -+/** -+ * nbcon_kthread_wake - Wake up a printk thread -+ * @con: Console to operate on -+ */ -+static inline void nbcon_kthread_wake(struct console *con) -+{ -+ /* -+ * Guarantee any new records can be seen by tasks preparing to wait -+ * before this context checks if the rcuwait is empty. -+ * -+ * The full memory barrier in rcuwait_wake_up() pairs with the full -+ * memory barrier within set_current_state() of -+ * ___rcuwait_wait_event(), which is called after prepare_to_rcuwait() -+ * adds the waiter but before it has checked the wait condition. -+ * -+ * This pairs with nbcon_kthread_func:A. -+ */ -+ rcuwait_wake_up(&con->rcuwait); /* LMM(nbcon_kthread_wake:A) */ -+} -+ - #else - - #define PRINTK_PREFIX_MAX 0 - #define PRINTK_MESSAGE_MAX 0 - #define PRINTKRB_RECORD_MAX 0 - -+static inline void nbcon_kthread_wake(struct console *con) { } -+static inline void nbcon_kthread_create(struct console *con) { } -+ - /* - * In !PRINTK builds we still export console_sem - * semaphore and some of console functions (console_unlock()/etc.), so -@@ -153,6 +179,8 @@ static inline bool console_is_usable(str - - #endif /* CONFIG_PRINTK */ - -+extern bool have_boot_console; -+ - extern struct printk_buffers printk_shared_pbufs; - - /** ---- a/kernel/printk/nbcon.c -+++ b/kernel/printk/nbcon.c -@@ -10,6 +10,7 @@ - #include <linux/export.h> - #include <linux/init.h> - #include <linux/irqflags.h> -+#include <linux/kthread.h> - #include <linux/minmax.h> - #include <linux/percpu.h> - #include <linux/preempt.h> -@@ -837,6 +838,7 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); - /** - * nbcon_emit_next_record - Emit a record in the acquired context - * @wctxt: The write context that will be handed to the write function -+ * @use_atomic: True if the write_atomic callback is to be used - * - * Return: True if this context still owns the console. False if - * ownership was handed over or taken. -@@ -850,7 +852,7 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); - * When true is returned, @wctxt->ctxt.backlog indicates whether there are - * still records pending in the ringbuffer, - */ --static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) -+static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_atomic) - { - struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); - struct console *con = ctxt->console; -@@ -899,8 +901,14 @@ static bool nbcon_emit_next_record(struc - nbcon_state_read(con, &cur); - wctxt->unsafe_takeover = cur.unsafe_takeover; - -- if (con->write_atomic) { -+ if (use_atomic && -+ con->write_atomic) { - con->write_atomic(con, wctxt); -+ -+ } else if (!use_atomic && -+ con->write_thread) { -+ con->write_thread(con, wctxt); -+ - } else { - /* - * This function should never be called for legacy consoles. -@@ -936,6 +944,118 @@ static bool nbcon_emit_next_record(struc - return nbcon_context_exit_unsafe(ctxt); - } - -+/** -+ * nbcon_kthread_should_wakeup - Check whether a printer thread should wakeup -+ * @con: Console to operate on -+ * @ctxt: The acquire context that contains the state -+ * at console_acquire() -+ * -+ * Return: True if the thread should shutdown or if the console is -+ * allowed to print and a record is available. False otherwise. -+ * -+ * After the thread wakes up, it must first check if it should shutdown before -+ * attempting any printing. -+ */ -+static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_context *ctxt) -+{ -+ bool ret = false; -+ short flags; -+ int cookie; -+ -+ if (kthread_should_stop()) -+ return true; -+ -+ cookie = console_srcu_read_lock(); -+ -+ flags = console_srcu_read_flags(con); -+ if (console_is_usable(con, flags)) { -+ /* Bring the sequence in @ctxt up to date */ -+ ctxt->seq = nbcon_seq_read(con); -+ -+ ret = prb_read_valid(prb, ctxt->seq, NULL); -+ } -+ -+ console_srcu_read_unlock(cookie); -+ return ret; -+} -+ -+/** -+ * nbcon_kthread_func - The printer thread function -+ * @__console: Console to operate on -+ */ -+static int nbcon_kthread_func(void *__console) -+{ -+ struct console *con = __console; -+ struct nbcon_write_context wctxt = { -+ .ctxt.console = con, -+ .ctxt.prio = NBCON_PRIO_NORMAL, -+ }; -+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt); -+ unsigned long flags; -+ short con_flags; -+ bool backlog; -+ int cookie; -+ int ret; -+ -+wait_for_event: -+ /* -+ * Guarantee this task is visible on the rcuwait before -+ * checking the wake condition. -+ * -+ * The full memory barrier within set_current_state() of -+ * ___rcuwait_wait_event() pairs with the full memory -+ * barrier within rcuwait_has_sleeper(). -+ * -+ * This pairs with rcuwait_has_sleeper:A and nbcon_kthread_wake:A. -+ */ -+ ret = rcuwait_wait_event(&con->rcuwait, -+ nbcon_kthread_should_wakeup(con, ctxt), -+ TASK_INTERRUPTIBLE); /* LMM(nbcon_kthread_func:A) */ -+ -+ if (kthread_should_stop()) -+ return 0; -+ -+ /* Wait was interrupted by a spurious signal, go back to sleep. */ -+ if (ret) -+ goto wait_for_event; -+ -+ do { -+ backlog = false; -+ -+ cookie = console_srcu_read_lock(); -+ -+ con_flags = console_srcu_read_flags(con); -+ -+ if (console_is_usable(con, con_flags)) { -+ con->device_lock(con, &flags); -+ -+ /* -+ * Ensure this stays on the CPU to make handover and -+ * takeover possible. -+ */ -+ cant_migrate(); -+ -+ if (nbcon_context_try_acquire(ctxt)) { -+ /* -+ * If the emit fails, this context is no -+ * longer the owner. -+ */ -+ if (nbcon_emit_next_record(&wctxt, false)) { -+ nbcon_context_release(ctxt); -+ backlog = ctxt->backlog; -+ } -+ } -+ -+ con->device_unlock(con, flags); -+ } -+ -+ console_srcu_read_unlock(cookie); -+ -+ } while (backlog); -+ -+ goto wait_for_event; -+} -+ - /* Track the nbcon emergency nesting per CPU. */ - static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting); - static unsigned int early_nbcon_pcpu_emergency_nesting __initdata; -@@ -982,7 +1102,7 @@ static bool nbcon_atomic_emit_one(struct - * handed over or taken over. In both cases the context is no - * longer valid. - */ -- if (!nbcon_emit_next_record(wctxt)) -+ if (!nbcon_emit_next_record(wctxt, true)) - return true; - - nbcon_context_release(ctxt); -@@ -1091,7 +1211,7 @@ static bool __nbcon_atomic_flush_pending - * handed over or taken over. In both cases the context is no - * longer valid. - */ -- if (!nbcon_emit_next_record(&wctxt)) -+ if (!nbcon_emit_next_record(&wctxt, true)) - return true; - - if (!ctxt->backlog) -@@ -1230,6 +1350,63 @@ void nbcon_cpu_emergency_exit(void) - } - - /** -+ * nbcon_kthread_stop - Stop a printer thread -+ * @con: Console to operate on -+ */ -+static void nbcon_kthread_stop(struct console *con) -+{ -+ lockdep_assert_console_list_lock_held(); -+ -+ if (!con->kthread) -+ return; -+ -+ kthread_stop(con->kthread); -+ con->kthread = NULL; -+} -+ -+/** -+ * nbcon_kthread_create - Create a printer thread -+ * @con: Console to operate on -+ * -+ * If it fails, let the console proceed. The atomic part might -+ * be usable and useful. -+ */ -+void nbcon_kthread_create(struct console *con) -+{ -+ struct task_struct *kt; -+ -+ lockdep_assert_console_list_lock_held(); -+ -+ if (!(con->flags & CON_NBCON) || !con->write_thread) -+ return; -+ -+ if (con->kthread) -+ return; -+ -+ /* -+ * Printer threads cannot be started as long as any boot console is -+ * registered because there is no way to synchronize the hardware -+ * registers between boot console code and regular console code. -+ */ -+ if (have_boot_console) -+ return; -+ -+ kt = kthread_run(nbcon_kthread_func, con, "pr/%s%d", con->name, con->index); -+ if (IS_ERR(kt)) { -+ con_printk(KERN_ERR, con, "failed to start printing thread\n"); -+ return; -+ } -+ -+ con->kthread = kt; -+ -+ /* -+ * It is important that console printing threads are scheduled -+ * shortly after a printk call and with generous runtime budgets. -+ */ -+ sched_set_normal(con->kthread, -20); -+} -+ -+/** - * nbcon_alloc - Allocate buffers needed by the nbcon console - * @con: Console to allocate buffers for - * -@@ -1273,6 +1450,7 @@ void nbcon_init(struct console *con) - /* nbcon_alloc() must have been called and successful! */ - BUG_ON(!con->pbufs); - -+ rcuwait_init(&con->rcuwait); - nbcon_seq_force(con, 0); - nbcon_state_set(con, &state); - } -@@ -1285,6 +1463,7 @@ void nbcon_free(struct console *con) - { - struct nbcon_state state = { }; - -+ nbcon_kthread_stop(con); - nbcon_state_set(con, &state); - - /* Boot consoles share global printk buffers. */ ---- a/kernel/printk/printk.c -+++ b/kernel/printk/printk.c -@@ -483,7 +483,7 @@ static bool have_nbcon_console; - * the console lock. This is because boot consoles and nbcon consoles may - * have mapped the same hardware. - */ --static bool have_boot_console; -+bool have_boot_console; - - /* - * Specifies if the console lock/unlock dance is needed for console -@@ -2698,6 +2698,8 @@ void suspend_console(void) - void resume_console(void) - { - struct console *con; -+ short flags; -+ int cookie; - - if (!console_suspend_enabled) - return; -@@ -2714,6 +2716,14 @@ void resume_console(void) - */ - synchronize_srcu(&console_srcu); - -+ cookie = console_srcu_read_lock(); -+ for_each_console_srcu(con) { -+ flags = console_srcu_read_flags(con); -+ if (flags & CON_NBCON) -+ nbcon_kthread_wake(con); -+ } -+ console_srcu_read_unlock(cookie); -+ - pr_flush(1000, true); - } - -@@ -3034,6 +3044,13 @@ static bool console_flush_all(bool do_co - u64 printk_seq; - bool progress; - -+ /* -+ * console_flush_all() is only for legacy consoles, -+ * unless the nbcon console has no kthread printer. -+ */ -+ if ((flags & CON_NBCON) && con->kthread) -+ continue; -+ - if (!console_is_usable(con, flags)) - continue; - any_usable = true; -@@ -3327,9 +3344,23 @@ EXPORT_SYMBOL(console_stop); - - void console_start(struct console *console) - { -+ short flags; -+ - console_list_lock(); - console_srcu_write_flags(console, console->flags | CON_ENABLED); -+ flags = console->flags; - console_list_unlock(); -+ -+ /* -+ * Ensure that all SRCU list walks have completed. The related -+ * printing context must be able to see it is enabled so that -+ * it is guaranteed to wake up and resume printing. -+ */ -+ synchronize_srcu(&console_srcu); -+ -+ if (flags & CON_NBCON) -+ nbcon_kthread_wake(console); -+ - __pr_flush(console, 1000, true); - } - EXPORT_SYMBOL(console_start); |