Skip to contentSkip to conversation

v6.7-rc5-rt5

ANNOUNCE Sebastian Andrzej Siewior 1 participant 1 message Dec 15, 2023

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Dear RT folks!

I'm pleased to announce the v6.7-rc5-rt5 patch set.

Changes since v6.7-rc5-rt4:

- Update the printk code to the latest version which has been posted upstream for review.

Known issues
Pierre Gondois reported crashes on ARM64 together with "rtla timerlat hist" as trigger. It is not yet understood. The report is at
https://lore.kernel.org/[email protected]

The delta patch against v6.7-rc5-rt4 is appended below and can be found here:

     https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.7/incr/patch-6.7-rc5-rt4-rt5.patch.xz

You can get this release via the git tree at:

    https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v6.7-rc5-rt5

The RT patch against v6.7-rc5 can be found here:

    https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.7/older/patch-6.7-rc5-rt5.patch.xz

The split quilt queue is available at:

    https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.7/older/patches-6.7-rc5-rt5.tar.xz

Sebastian

drivers/tty/serial/8250/8250_core.c +13 -3
index ba6de401c458e..6b89e9c2374a5 100644
@@ -617,9 +617,18 @@ static bool univ8250_console_write_thread(struct console *co,
 	return serial8250_console_write_thread(up, wctxt);
 }
 
-static struct uart_port *univ8250_console_uart_port(struct console *con)
+static void univ8250_console_driver_enter(struct console *con, unsigned long *flags)
 {
-	return &serial8250_ports[con->index].port;
+	struct uart_port *up = &serial8250_ports[con->index].port;
+
+	__uart_port_lock_irqsave(up, flags);
+}
+
+static void univ8250_console_driver_exit(struct console *con, unsigned long flags)
+{
+	struct uart_port *up = &serial8250_ports[con->index].port;
+
+	__uart_port_unlock_irqrestore(up, flags);
 }
 #endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */
 
@@ -727,8 +736,9 @@ static struct console univ8250_console = {
 #else
 	.write_atomic	= univ8250_console_write_atomic,
 	.write_thread	= univ8250_console_write_thread,
+	.driver_enter	= univ8250_console_driver_enter,
+	.driver_exit	= univ8250_console_driver_exit,
 	.flags		= CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
-	.uart_port	= univ8250_console_uart_port,
 #endif
 	.device		= uart_console_device,
 	.setup		= univ8250_console_setup,
drivers/tty/serial/8250/8250_port.c +14 -22
index c8d15f659de98..3b26105f01570 100644
@@ -3509,13 +3509,11 @@ bool serial8250_console_write_thread(struct uart_8250_port *up,
 	if (!nbcon_enter_unsafe(wctxt))
 		return false;
 
-	/*
-	 *	First save the IER then disable the interrupts
-	 */
+	/* First save IER then disable the interrupts. */
 	ier = serial_port_in(port, UART_IER);
 	serial8250_clear_IER(up);
 
-	/* check scratch reg to see if port powered off during system sleep */
+	/* Check scratch reg if port powered off during system sleep. */
 	if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
 		serial8250_console_restore(up);
 		up->canary = 0;
@@ -3563,30 +3561,25 @@ bool serial8250_console_write_thread(struct uart_8250_port *up,
 	while (!nbcon_enter_unsafe(wctxt))
 		nbcon_reacquire(wctxt);
 
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore the IER
-	 */
+	/* Finally, wait for transmitter to become empty and restore IER. */
 	wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
-
 	if (em485) {
 		mdelay(port->rs485.delay_rts_after_send);
 		if (em485->tx_stopped)
 			up->rs485_stop_tx(up);
 	}
-
 	serial_port_out(port, UART_IER, ier);
 
 	/*
-	 *	The receive handling will happen properly because the
-	 *	receive ready bit will still be set; it is not cleared
-	 *	on read.  However, modem control will not, we must
-	 *	call it if we have saved something in the saved flags
-	 *	while processing with interrupts off.
+	 * The receive handling will happen properly because the receive ready
+	 * bit will still be set; it is not cleared on read.  However, modem
+	 * control will not, we must call it if we have saved something in the
+	 * saved flags while processing with interrupts off.
 	 */
 	if (up->msr_saved_flags)
 		serial8250_modem_status(up);
 
+	/* Success if no handover/takeover and message fully printed. */
 	return (nbcon_exit_unsafe(wctxt) && done);
 }
 
@@ -3606,12 +3599,14 @@ bool serial8250_console_write_atomic(struct uart_8250_port *up,
 		return false;
 
 	/*
-	 *	First save the IER then disable the interrupts
+	 * First save IER then disable the interrupts. The special variant to
+	 * clear IER is used because atomic printing may occur without holding
+	 * the port lock.
 	 */
 	ier = serial_port_in(port, UART_IER);
 	__serial8250_clear_IER(up);
 
-	/* check scratch reg to see if port powered off during system sleep */
+	/* Check scratch reg if port powered off during system sleep. */
 	if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
 		serial8250_console_restore(up);
 		up->canary = 0;
@@ -3621,14 +3616,11 @@ bool serial8250_console_write_atomic(struct uart_8250_port *up,
 		uart_console_write(port, "\n", 1, serial8250_console_putchar);
 	uart_console_write(port, wctxt->outbuf, wctxt->len, serial8250_console_putchar);
 
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore the IER
-	 */
+	/* Finally, wait for transmitter to become empty and restore IER. */
 	wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
-
 	serial_port_out(port, UART_IER, ier);
 
+	/* Success if no handover/takeover. */
 	return nbcon_exit_unsafe(wctxt);
 }
 #endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */
include/linux/console.h +4 -2
index ac14ff49e86bb..79ef2fd2bd155 100644
@@ -306,7 +306,8 @@ struct nbcon_write_context {
  *
  * @write_atomic:	Write callback for atomic context
  * @write_thread:	Write callback for non-atomic context
- * @uart_port:		Callback to provide the associated uart port
+ * @driver_enter:	Callback to begin synchronization with driver code
+ * @driver_exit:	Callback to finish synchronization with driver code
  * @nbcon_state:	State for nbcon consoles
  * @nbcon_seq:		Sequence number of the next record for nbcon to print
  * @pbufs:		Pointer to nbcon private buffer
@@ -339,7 +340,8 @@ struct console {
 						struct nbcon_write_context *wctxt);
 	bool			(*write_thread)(struct console *con,
 						struct nbcon_write_context *wctxt);
-	struct uart_port *	(*uart_port)(struct console *con);
+	void			(*driver_enter)(struct console *con, unsigned long *flags);
+	void			(*driver_exit)(struct console *con, unsigned long flags);
 	atomic_t		__private nbcon_state;
 	atomic_long_t		__private nbcon_seq;
 	struct printk_buffers	*pbufs;
include/linux/printk.h +9 -4
index 196a4cf3ccb76..7a942e987b165 100644
@@ -197,8 +197,9 @@ void show_regs_print_info(const char *log_lvl);
 extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
 extern asmlinkage void dump_stack(void) __cold;
 void printk_trigger_flush(void);
-extern void nbcon_handle_port_lock(struct uart_port *up);
-extern void nbcon_handle_port_unlock(struct uart_port *up);
+void printk_legacy_allow_panic_sync(void);
+extern void nbcon_acquire(struct uart_port *up);
+extern void nbcon_release(struct uart_port *up);
 void nbcon_atomic_flush_unsafe(void);
 #else
 static inline __printf(1, 0)
@@ -280,11 +281,15 @@ static inline void printk_trigger_flush(void)
 {
 }
 
-static inline void nbcon_handle_port_lock(struct uart_port *up)
+static inline void printk_legacy_allow_panic_sync(void)
 {
 }
 
-static inline void nbcon_handle_port_unlock(struct uart_port *up)
+static inline void nbcon_acquire(struct uart_port *up)
+{
+}
+
+static inline void nbcon_release(struct uart_port *up)
 {
 }
 
include/linux/serial_core.h +20 -8
index 198d8088a9984..a49ce4bf7fae8 100644
@@ -595,7 +595,7 @@ struct uart_port {
 static inline void uart_port_lock(struct uart_port *up)
 {
 	spin_lock(&up->lock);
-	nbcon_handle_port_lock(up);
+	nbcon_acquire(up);
 }
 
 /**
@@ -605,7 +605,7 @@ static inline void uart_port_lock(struct uart_port *up)
 static inline void uart_port_lock_irq(struct uart_port *up)
 {
 	spin_lock_irq(&up->lock);
-	nbcon_handle_port_lock(up);
+	nbcon_acquire(up);
 }
 
 /**
@@ -616,7 +616,7 @@ static inline void uart_port_lock_irq(struct uart_port *up)
 static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
 {
 	spin_lock_irqsave(&up->lock, *flags);
-	nbcon_handle_port_lock(up);
+	nbcon_acquire(up);
 }
 
 /**
@@ -630,7 +630,7 @@ static inline bool uart_port_trylock(struct uart_port *up)
 	if (!spin_trylock(&up->lock))
 		return false;
 
-	nbcon_handle_port_lock(up);
+	nbcon_acquire(up);
 	return true;
 }
 
@@ -646,7 +646,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
 	if (!spin_trylock_irqsave(&up->lock, *flags))
 		return false;
 
-	nbcon_handle_port_lock(up);
+	nbcon_acquire(up);
 	return true;
 }
 
@@ -656,7 +656,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
  */
 static inline void uart_port_unlock(struct uart_port *up)
 {
-	nbcon_handle_port_unlock(up);
+	nbcon_release(up);
 	spin_unlock(&up->lock);
 }
 
@@ -666,7 +666,7 @@ static inline void uart_port_unlock(struct uart_port *up)
  */
 static inline void uart_port_unlock_irq(struct uart_port *up)
 {
-	nbcon_handle_port_unlock(up);
+	nbcon_release(up);
 	spin_unlock_irq(&up->lock);
 }
 
@@ -677,7 +677,19 @@ static inline void uart_port_unlock_irq(struct uart_port *up)
  */
 static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
 {
-	nbcon_handle_port_unlock(up);
+	nbcon_release(up);
+	spin_unlock_irqrestore(&up->lock, flags);
+}
+
+/* Only for use in the console->driver_enter() callback. */
+static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
+{
+	spin_lock_irqsave(&up->lock, *flags);
+}
+
+/* Only for use in the console->driver_exit() callback. */
+static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
+{
 	spin_unlock_irqrestore(&up->lock, flags);
 }
 
kernel/panic.c +8 -0
index 88902355600f5..9fa44bc38f466 100644
@@ -370,6 +370,8 @@ void panic(const char *fmt, ...)
 	 */
 	atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
+	printk_legacy_allow_panic_sync();
+
 	panic_print_sys_info(false);
 
 	kmsg_dump(KMSG_DUMP_PANIC);
@@ -447,6 +449,12 @@ void panic(const char *fmt, ...)
 	/* Do not scroll important messages printed above */
 	suppress_printk = 1;
 
+	/*
+	 * The final messages may not have been printed if in a context that
+	 * defers printing (such as NMI) and irq_work is not available.
+	 * Explicitly flush the kernel log buffer one last time.
+	 */
+	console_flush_on_panic(CONSOLE_FLUSH_PENDING);
 	nbcon_atomic_flush_unsafe();
 
 	local_irq_enable();
kernel/printk/internal.h +8 -4
index a3ae0710346cd..7db6992c54f38 100644
@@ -82,6 +82,8 @@ void defer_console_output(void);
 
 u16 printk_parse_prefix(const char *text, int *level,
 			enum printk_info_flags *flags);
+void console_lock_spinning_enable(void);
+int console_lock_spinning_disable_and_check(int cookie);
 
 u64 nbcon_seq_read(struct console *con);
 void nbcon_seq_force(struct console *con, u64 seq);
@@ -90,7 +92,7 @@ void nbcon_init(struct console *con);
 void nbcon_free(struct console *con);
 enum nbcon_prio nbcon_get_default_prio(void);
 void nbcon_atomic_flush_all(void);
-bool nbcon_atomic_emit_next_record(struct console *con);
+bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie);
 void nbcon_kthread_create(struct console *con);
 void nbcon_wake_threads(void);
 void nbcon_legacy_kthread_create(void);
@@ -143,7 +145,7 @@ 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
+	 * 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.
@@ -180,9 +182,11 @@ static inline void nbcon_init(struct console *con) { }
 static inline void nbcon_free(struct console *con) { }
 static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
 static inline void nbcon_atomic_flush_all(void) { }
-static bool nbcon_atomic_emit_next_record(struct console *con) { return false; }
+static inline bool nbcon_atomic_emit_next_record(struct console *con, bool *handover,
+						 int cookie) { return false; }
 
-static inline bool console_is_usable(struct console *con, short flags, bool use_atomic) { return false; }
+static inline bool console_is_usable(struct console *con, short flags,
+				     bool use_atomic) { return false; }
 
 #endif /* CONFIG_PRINTK */
 
kernel/printk/nbcon.c +103 -128

458 lines not on this page · raw message

kernel/printk/printk.c +148 -116

453 lines not on this page · raw message

kernel/printk/printk_ringbuffer.c +47 -40

183 lines not on this page · raw message

kernel/printk/printk_ringbuffer.h +33 -0
index b48b44ecbe6da..52626d0f1fa37 100644
@@ -392,8 +392,41 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq,
 bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq,
 			 struct printk_info *info, unsigned int *line_count);
 
+u64 prb_first_seq(struct printk_ringbuffer *rb);
 u64 prb_first_valid_seq(struct printk_ringbuffer *rb);
 u64 prb_next_seq(struct printk_ringbuffer *rb);
 u64 prb_next_reserve_seq(struct printk_ringbuffer *rb);
 
+#ifdef CONFIG_64BIT
+
+#define __u64seq_to_ulseq(u64seq) (u64seq)
+#define __ulseq_to_u64seq(rb, ulseq) (ulseq)
+
+#else /* CONFIG_64BIT */
+
+#define __u64seq_to_ulseq(u64seq) ((u32)u64seq)
+
+static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq)
+{
+	u64 rb_first_seq = prb_first_seq(rb);
+	u64 seq;
+
+	/*
+	 * The provided sequence is only the lower 32 bits of the ringbuffer
+	 * sequence. It needs to be expanded to 64bit. Get the first 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.
+	 */
+	seq = rb_first_seq - (s32)((u32)rb_first_seq - ulseq);
+
+	return seq;
+}
+
+#endif /* CONFIG_64BIT */
+
 #endif /* _KERNEL_PRINTK_RINGBUFFER_H */
localversion-rt +1 -1
index ad3da1bcab7e8..0efe7ba1930e1 100644
@@ -1 +1 @@
--rt4
+-rt5