Skip to content

Commit 5102981

Browse files
jognesspmladek
authored andcommitted
printk: nbcon: Show replay message on takeover
An emergency or panic context can takeover console ownership while the current owner was printing a printk message. The atomic printer will re-print the message that the previous owner was printing. However, this can look confusing to the user and may even seem as though a message was lost. [3430014.1 [3430014.181123] usb 1-2: Product: USB Audio Add a new field @nbcon_prev_seq to struct console to track the sequence number to print that was assigned to the previous console owner. If this matches the sequence number to print that the current owner is assigned, then a takeover must have occurred. In this case, print an additional message to inform the user that the previous message is being printed again. [3430014.1 ** replaying previous printk message ** [3430014.181123] usb 1-2: Product: USB Audio Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Petr Mladek <[email protected]>
1 parent 75d4303 commit 5102981

File tree

4 files changed

+40
-0
lines changed

4 files changed

+40
-0
lines changed

include/linux/console.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ struct nbcon_write_context {
325325
* @nbcon_state: State for nbcon consoles
326326
* @nbcon_seq: Sequence number of the next record for nbcon to print
327327
* @nbcon_device_ctxt: Context available for non-printing operations
328+
* @nbcon_prev_seq: Seq num the previous nbcon owner was assigned to print
328329
* @pbufs: Pointer to nbcon private buffer
329330
* @kthread: Printer kthread for this console
330331
* @rcuwait: RCU-safe wait object for @kthread waking
@@ -459,6 +460,7 @@ struct console {
459460
atomic_t __private nbcon_state;
460461
atomic_long_t __private nbcon_seq;
461462
struct nbcon_context __private nbcon_device_ctxt;
463+
atomic_long_t __private nbcon_prev_seq;
462464

463465
struct printk_buffers *pbufs;
464466
struct task_struct *kthread;

kernel/printk/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,4 +319,5 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
319319

320320
#ifdef CONFIG_PRINTK
321321
void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped);
322+
void console_prepend_replay(struct printk_message *pmsg);
322323
#endif

kernel/printk/nbcon.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,9 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
946946
.pbufs = ctxt->pbufs,
947947
};
948948
unsigned long con_dropped;
949+
struct nbcon_state cur;
949950
unsigned long dropped;
951+
unsigned long ulseq;
950952

951953
/*
952954
* This function should never be called for consoles that have not
@@ -987,6 +989,29 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
987989
if (dropped && !is_extended)
988990
console_prepend_dropped(&pmsg, dropped);
989991

992+
/*
993+
* If the previous owner was assigned the same record, this context
994+
* has taken over ownership and is replaying the record. Prepend a
995+
* message to let the user know the record is replayed.
996+
*/
997+
ulseq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_prev_seq));
998+
if (__ulseq_to_u64seq(prb, ulseq) == pmsg.seq) {
999+
console_prepend_replay(&pmsg);
1000+
} else {
1001+
/*
1002+
* Ensure this context is still the owner before trying to
1003+
* update @nbcon_prev_seq. Otherwise the value in @ulseq may
1004+
* not be from the previous owner and instead be some later
1005+
* value from the context that took over ownership.
1006+
*/
1007+
nbcon_state_read(con, &cur);
1008+
if (!nbcon_context_can_proceed(ctxt, &cur))
1009+
return false;
1010+
1011+
atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_prev_seq), &ulseq,
1012+
__u64seq_to_ulseq(pmsg.seq));
1013+
}
1014+
9901015
if (!nbcon_context_exit_unsafe(ctxt))
9911016
return false;
9921017

@@ -1646,6 +1671,7 @@ bool nbcon_alloc(struct console *con)
16461671

16471672
rcuwait_init(&con->rcuwait);
16481673
init_irq_work(&con->irq_work, nbcon_irq_work);
1674+
atomic_long_set(&ACCESS_PRIVATE(con, nbcon_prev_seq), -1UL);
16491675
nbcon_state_set(con, &state);
16501676

16511677
/*

kernel/printk/printk.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2902,6 +2902,17 @@ void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
29022902
console_prepend_message(pmsg, "** %lu printk messages dropped **\n", dropped);
29032903
}
29042904

2905+
/*
2906+
* Prepend the message in @pmsg->pbufs->outbuf with a "replay message".
2907+
* @pmsg->outbuf_len is updated appropriately.
2908+
*
2909+
* @pmsg is the printk message to prepend.
2910+
*/
2911+
void console_prepend_replay(struct printk_message *pmsg)
2912+
{
2913+
console_prepend_message(pmsg, "** replaying previous printk message **\n");
2914+
}
2915+
29052916
/*
29062917
* Read and format the specified record (or a later record if the specified
29072918
* record is not available).

0 commit comments

Comments
 (0)