From 3565071f226432336a54d0193d729fa4508a3394 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:28:00 +0200 Subject: Adding debian version 6.6.15-2. Signed-off-by: Daniel Baumann --- .../0080-printk-nbcon-Add-sequence-handling.patch | 311 +++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 debian/patches-rt/0080-printk-nbcon-Add-sequence-handling.patch (limited to 'debian/patches-rt/0080-printk-nbcon-Add-sequence-handling.patch') diff --git a/debian/patches-rt/0080-printk-nbcon-Add-sequence-handling.patch b/debian/patches-rt/0080-printk-nbcon-Add-sequence-handling.patch new file mode 100644 index 0000000000..3988d6124a --- /dev/null +++ b/debian/patches-rt/0080-printk-nbcon-Add-sequence-handling.patch @@ -0,0 +1,311 @@ +From: Thomas Gleixner +Date: Sat, 16 Sep 2023 21:26:05 +0206 +Subject: [PATCH 080/134] printk: nbcon: Add sequence handling +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patches-6.6.7-rt18.tar.xz + +Add an atomic_long_t field @nbcon_seq to the console struct to +store the sequence number for nbcon consoles. For nbcon consoles +this will be used instead of the non-atomic @seq field. The new +field allows for safe atomic sequence number updates without +requiring any locking. + +On 64bit systems the new field stores the full sequence number. +On 32bit systems the new field stores the lower 32 bits of the +sequence number, which are expanded to 64bit as needed by +folding the values based on the sequence numbers available in +the ringbuffer. + +For 32bit systems, having a 32bit representation in the console +is sufficient. If a console ever gets more than 2^31 records +behind the ringbuffer then this is the least of the problems. + +Co-developed-by: John Ogness +Signed-off-by: John Ogness +Signed-off-by: Thomas Gleixner (Intel) +Signed-off-by: Petr Mladek +Link: https://lore.kernel.org/r/20230916192007.608398-7-john.ogness@linutronix.de +Signed-off-by: Sebastian Andrzej Siewior +--- + include/linux/console.h | 4 + + kernel/printk/internal.h | 7 +++ + kernel/printk/nbcon.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 31 +++++++++++--- + 4 files changed, 136 insertions(+), 7 deletions(-) + +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -243,6 +243,7 @@ struct printk_buffers; + * might cause a system freeze when the console + * is used later. + * @pbufs: Pointer to the text buffer for this context ++ * @seq: The sequence number to print for this context + */ + struct nbcon_context { + /* members set by caller */ +@@ -253,6 +254,7 @@ struct nbcon_context { + + /* members set by acquire */ + struct printk_buffers *pbufs; ++ u64 seq; + }; + + /** +@@ -276,6 +278,7 @@ struct nbcon_context { + * @node: hlist node for the console list + * + * @nbcon_state: State for nbcon consoles ++ * @nbcon_seq: Sequence number of the next record for nbcon to print + * @pbufs: Pointer to nbcon private buffer + */ + struct console { +@@ -299,6 +302,7 @@ struct console { + + /* nbcon console specific members */ + atomic_t __private nbcon_state; ++ atomic_long_t __private nbcon_seq; + struct printk_buffers *pbufs; + }; + +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -4,6 +4,7 @@ + */ + #include + #include ++#include "printk_ringbuffer.h" + + #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL) + void __init printk_sysctl_init(void); +@@ -42,6 +43,8 @@ enum printk_info_flags { + LOG_CONT = 8, /* text is a fragment of a continuation line */ + }; + ++extern struct printk_ringbuffer *prb; ++ + __printf(4, 0) + int vprintk_store(int facility, int level, + const struct dev_printk_info *dev_info, +@@ -69,6 +72,8 @@ void defer_console_output(void); + u16 printk_parse_prefix(const char *text, int *level, + enum printk_info_flags *flags); + ++u64 nbcon_seq_read(struct console *con); ++void nbcon_seq_force(struct console *con, u64 seq); + bool nbcon_alloc(struct console *con); + void nbcon_init(struct console *con); + void nbcon_free(struct console *con); +@@ -88,6 +93,8 @@ void nbcon_free(struct console *con); + #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags) + + static inline bool printk_percpu_data_ready(void) { return false; } ++static inline u64 nbcon_seq_read(struct console *con) { return 0; } ++static inline void nbcon_seq_force(struct console *con, u64 seq) { } + static inline bool nbcon_alloc(struct console *con) { return false; } + static inline void nbcon_init(struct console *con) { } + static inline void nbcon_free(struct console *con) { } +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -140,6 +140,101 @@ static inline bool nbcon_state_try_cmpxc + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); + } + ++#ifdef CONFIG_64BIT ++ ++#define __seq_to_nbcon_seq(seq) (seq) ++#define __nbcon_seq_to_seq(seq) (seq) ++ ++#else /* CONFIG_64BIT */ ++ ++#define __seq_to_nbcon_seq(seq) ((u32)seq) ++ ++static inline u64 __nbcon_seq_to_seq(u32 nbcon_seq) ++{ ++ u64 seq; ++ u64 rb_next_seq; ++ ++ /* ++ * The provided sequence is only the lower 32 bits of the ringbuffer ++ * sequence. It needs to be expanded to 64bit. Get the next sequence ++ * number from the ringbuffer and fold it. ++ * ++ * Having a 32bit representation in the console is sufficient. ++ * If a console ever gets more than 2^31 records behind ++ * the ringbuffer then this is the least of the problems. ++ * ++ * Also the access to the ring buffer is always safe. ++ */ ++ rb_next_seq = prb_next_seq(prb); ++ seq = rb_next_seq - ((u32)rb_next_seq - nbcon_seq); ++ ++ return seq; ++} ++ ++#endif /* CONFIG_64BIT */ ++ ++/** ++ * nbcon_seq_read - Read the current console sequence ++ * @con: Console to read the sequence of ++ * ++ * Return: Sequence number of the next record to print on @con. ++ */ ++u64 nbcon_seq_read(struct console *con) ++{ ++ unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq)); ++ ++ return __nbcon_seq_to_seq(nbcon_seq); ++} ++ ++/** ++ * nbcon_seq_force - Force console sequence to a specific value ++ * @con: Console to work on ++ * @seq: Sequence number value to set ++ * ++ * Only to be used during init (before registration) or in extreme situations ++ * (such as panic with CONSOLE_REPLAY_ALL). ++ */ ++void nbcon_seq_force(struct console *con, u64 seq) ++{ ++ /* ++ * If the specified record no longer exists, the oldest available record ++ * is chosen. This is especially important on 32bit systems because only ++ * the lower 32 bits of the sequence number are stored. The upper 32 bits ++ * are derived from the sequence numbers available in the ringbuffer. ++ */ ++ u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb)); ++ ++ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(valid_seq)); ++ ++ /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */ ++ con->seq = 0; ++} ++ ++/** ++ * nbcon_seq_try_update - Try to update the console sequence number ++ * @ctxt: Pointer to an acquire context that contains ++ * all information about the acquire mode ++ * @new_seq: The new sequence number to set ++ * ++ * @ctxt->seq is updated to the new value of @con::nbcon_seq (expanded to ++ * the 64bit value). This could be a different value than @new_seq if ++ * nbcon_seq_force() was used or the current context no longer owns the ++ * console. In the later case, it will stop printing anyway. ++ */ ++__maybe_unused ++static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) ++{ ++ unsigned long nbcon_seq = __seq_to_nbcon_seq(ctxt->seq); ++ struct console *con = ctxt->console; ++ ++ if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq, ++ __seq_to_nbcon_seq(new_seq))) { ++ ctxt->seq = new_seq; ++ } else { ++ ctxt->seq = nbcon_seq_read(con); ++ } ++} ++ + /** + * nbcon_context_try_acquire_direct - Try to acquire directly + * @ctxt: The context of the caller +@@ -510,6 +605,9 @@ static bool nbcon_context_try_acquire(st + else + ctxt->pbufs = con->pbufs; + ++ /* Set the record sequence for this context to print. */ ++ ctxt->seq = nbcon_seq_read(ctxt->console); ++ + return true; + } + +@@ -722,6 +820,8 @@ bool nbcon_alloc(struct console *con) + * + * nbcon_alloc() *must* be called and succeed before this function + * is called. ++ * ++ * This function expects that the legacy @con->seq has been set. + */ + void nbcon_init(struct console *con) + { +@@ -730,6 +830,7 @@ void nbcon_init(struct console *con) + /* nbcon_alloc() must have been called and successful! */ + BUG_ON(!con->pbufs); + ++ nbcon_seq_force(con, con->seq); + nbcon_state_set(con, &state); + } + +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -494,7 +494,7 @@ static u32 log_buf_len = __LOG_BUF_LEN; + + static struct printk_ringbuffer printk_rb_dynamic; + +-static struct printk_ringbuffer *prb = &printk_rb_static; ++struct printk_ringbuffer *prb = &printk_rb_static; + + /* + * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before +@@ -3168,6 +3168,7 @@ void console_flush_on_panic(enum con_flu + + if (mode == CONSOLE_REPLAY_ALL) { + struct console *c; ++ short flags; + int cookie; + u64 seq; + +@@ -3175,11 +3176,17 @@ void console_flush_on_panic(enum con_flu + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +- /* +- * This is an unsynchronized assignment, but the +- * kernel is in "hope and pray" mode anyway. +- */ +- c->seq = seq; ++ flags = console_srcu_read_flags(c); ++ ++ if (flags & CON_NBCON) { ++ nbcon_seq_force(c, seq); ++ } else { ++ /* ++ * This is an unsynchronized assignment. On ++ * panic legacy consoles are only best effort. ++ */ ++ c->seq = seq; ++ } + } + console_srcu_read_unlock(cookie); + } +@@ -3750,6 +3757,7 @@ static bool __pr_flush(struct console *c + struct console *c; + u64 last_diff = 0; + u64 printk_seq; ++ short flags; + int cookie; + u64 diff; + u64 seq; +@@ -3777,6 +3785,9 @@ static bool __pr_flush(struct console *c + for_each_console_srcu(c) { + if (con && con != c) + continue; ++ ++ flags = console_srcu_read_flags(c); ++ + /* + * If consoles are not usable, it cannot be expected + * that they make forward progress, so only increment +@@ -3784,7 +3795,13 @@ static bool __pr_flush(struct console *c + */ + if (!console_is_usable(c)) + continue; +- printk_seq = c->seq; ++ ++ if (flags & CON_NBCON) { ++ printk_seq = nbcon_seq_read(c); ++ } else { ++ printk_seq = c->seq; ++ } ++ + if (printk_seq < seq) + diff += seq - printk_seq; + } -- cgit v1.2.3