Skip to content

Commit bd07d86

Browse files
jognesspmladek
authored andcommitted
printk: nbcon: Add function for printers to reacquire ownership
Since ownership can be lost at any time due to handover or takeover, a printing context _must_ be prepared to back out immediately and carefully. However, there are scenarios where the printing context must reacquire ownership in order to finalize or revert hardware changes. One such example is when interrupts are disabled during printing. No other context will automagically re-enable the interrupts. For this case, the disabling context _must_ reacquire nbcon ownership so that it can re-enable the interrupts. Provide nbcon_reacquire_nobuf() for exactly this purpose. It allows a printing context to reacquire ownership using the same priority as its previous ownership. Note that after a successful reacquire the printing context will have no output buffer because that has been lost. This function cannot be used to resume printing. 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 d33d5e6 commit bd07d86

File tree

2 files changed

+73
-7
lines changed

2 files changed

+73
-7
lines changed

include/linux/console.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ struct console {
366366
*
367367
* The callback should allow the takeover whenever it is safe. It
368368
* increases the chance to see messages when the system is in trouble.
369+
* If the driver must reacquire ownership in order to finalize or
370+
* revert hardware changes, nbcon_reacquire_nobuf() can be used.
371+
* However, on reacquire the buffer content is no longer available. A
372+
* reacquire cannot be used to resume printing.
369373
*
370374
* The callback can be called from any context (including NMI).
371375
* Therefore it must avoid usage of any locking and instead rely
@@ -558,12 +562,14 @@ extern void nbcon_cpu_emergency_exit(void);
558562
extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
559563
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
560564
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
565+
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
561566
#else
562567
static inline void nbcon_cpu_emergency_enter(void) { }
563568
static inline void nbcon_cpu_emergency_exit(void) { }
564569
static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
565570
static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
566571
static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
572+
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
567573
#endif
568574

569575
extern int console_set_on_cmdline;

kernel/printk/nbcon.c

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,19 @@ static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsaf
830830
return nbcon_context_can_proceed(ctxt, &cur);
831831
}
832832

833+
static void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
834+
char *buf, unsigned int len)
835+
{
836+
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
837+
struct console *con = ctxt->console;
838+
struct nbcon_state cur;
839+
840+
wctxt->outbuf = buf;
841+
wctxt->len = len;
842+
nbcon_state_read(con, &cur);
843+
wctxt->unsafe_takeover = cur.unsafe_takeover;
844+
}
845+
833846
/**
834847
* nbcon_enter_unsafe - Enter an unsafe region in the driver
835848
* @wctxt: The write context that was handed to the write function
@@ -845,8 +858,12 @@ static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsaf
845858
bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt)
846859
{
847860
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
861+
bool is_owner;
848862

849-
return nbcon_context_enter_unsafe(ctxt);
863+
is_owner = nbcon_context_enter_unsafe(ctxt);
864+
if (!is_owner)
865+
nbcon_write_context_set_buf(wctxt, NULL, 0);
866+
return is_owner;
850867
}
851868
EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
852869

@@ -865,11 +882,43 @@ EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
865882
bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt)
866883
{
867884
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
885+
bool ret;
868886

869-
return nbcon_context_exit_unsafe(ctxt);
887+
ret = nbcon_context_exit_unsafe(ctxt);
888+
if (!ret)
889+
nbcon_write_context_set_buf(wctxt, NULL, 0);
890+
return ret;
870891
}
871892
EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
872893

894+
/**
895+
* nbcon_reacquire_nobuf - Reacquire a console after losing ownership
896+
* while printing
897+
* @wctxt: The write context that was handed to the write callback
898+
*
899+
* Since ownership can be lost at any time due to handover or takeover, a
900+
* printing context _must_ be prepared to back out immediately and
901+
* carefully. However, there are scenarios where the printing context must
902+
* reacquire ownership in order to finalize or revert hardware changes.
903+
*
904+
* This function allows a printing context to reacquire ownership using the
905+
* same priority as its previous ownership.
906+
*
907+
* Note that after a successful reacquire the printing context will have no
908+
* output buffer because that has been lost. This function cannot be used to
909+
* resume printing.
910+
*/
911+
void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
912+
{
913+
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
914+
915+
while (!nbcon_context_try_acquire(ctxt))
916+
cpu_relax();
917+
918+
nbcon_write_context_set_buf(wctxt, NULL, 0);
919+
}
920+
EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf);
921+
873922
/**
874923
* nbcon_emit_next_record - Emit a record in the acquired context
875924
* @wctxt: The write context that will be handed to the write function
@@ -895,7 +944,6 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
895944
.pbufs = ctxt->pbufs,
896945
};
897946
unsigned long con_dropped;
898-
struct nbcon_state cur;
899947
unsigned long dropped;
900948

901949
/*
@@ -930,10 +978,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
930978
goto update_con;
931979

932980
/* Initialize the write context for driver callbacks. */
933-
wctxt->outbuf = &pmsg.pbufs->outbuf[0];
934-
wctxt->len = pmsg.outbuf_len;
935-
nbcon_state_read(con, &cur);
936-
wctxt->unsafe_takeover = cur.unsafe_takeover;
981+
nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len);
937982

938983
if (con->write_atomic) {
939984
con->write_atomic(con, wctxt);
@@ -947,6 +992,21 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
947992
return false;
948993
}
949994

995+
if (!wctxt->outbuf) {
996+
/*
997+
* Ownership was lost and reacquired by the driver. Handle it
998+
* as if ownership was lost.
999+
*/
1000+
nbcon_context_release(ctxt);
1001+
return false;
1002+
}
1003+
1004+
/*
1005+
* Ownership may have been lost but _not_ reacquired by the driver.
1006+
* This case is detected and handled when entering unsafe to update
1007+
* dropped/seq values.
1008+
*/
1009+
9501010
/*
9511011
* Since any dropped message was successfully output, reset the
9521012
* dropped count for the console.

0 commit comments

Comments
 (0)