Skip to content

Commit 741ea7a

Browse files
amurray-thegoodpenguinpmladek
authored andcommitted
printk: Introduce console_flush_one_record
console_flush_all prints all remaining records to all usable consoles whilst its caller holds console_lock. This can result in large waiting times for those waiting for console_lock especially where there is a large volume of records or where the console is slow (e.g. serial). Let's extract the parts of this function which print a single record into a new function named console_flush_one_record. This can later be used for functions that will release and reacquire console_lock between records. This commit should not change existing functionality. Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk> Reviewed-by: John Ogness <john.ogness@linutronix.de> Link: https://patch.msgid.link/20251020-printk_legacy_thread_console_lock-v3-1-00f1f0ac055a@thegoodpenguin.co.uk Signed-off-by: Petr Mladek <pmladek@suse.com>
1 parent 48e3694 commit 741ea7a

1 file changed

Lines changed: 99 additions & 59 deletions

File tree

kernel/printk/printk.c

Lines changed: 99 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,99 @@ static inline void printk_kthreads_check_locked(void) { }
31343134

31353135
#endif /* CONFIG_PRINTK */
31363136

3137+
3138+
/*
3139+
* Print out one record for each console.
3140+
*
3141+
* @do_cond_resched is set by the caller. It can be true only in schedulable
3142+
* context.
3143+
*
3144+
* @next_seq is set to the sequence number after the last available record.
3145+
* The value is valid only when there is at least one usable console and all
3146+
* usable consoles were flushed.
3147+
*
3148+
* @handover will be set to true if a printk waiter has taken over the
3149+
* console_lock, in which case the caller is no longer holding the
3150+
* console_lock. Otherwise it is set to false.
3151+
*
3152+
* @any_usable will be set to true if there are any usable consoles.
3153+
*
3154+
* Returns true when there was at least one usable console and a record was
3155+
* flushed. A returned false indicates there were no records to flush for any
3156+
* of the consoles. It may also indicate that there were no usable consoles,
3157+
* the context has been lost or there is a panic suitation. Regardless the
3158+
* reason, the caller should assume it is not useful to immediately try again.
3159+
*
3160+
* Requires the console_lock.
3161+
*/
3162+
static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *handover,
3163+
bool *any_usable)
3164+
{
3165+
struct console_flush_type ft;
3166+
bool any_progress = false;
3167+
struct console *con;
3168+
int cookie;
3169+
3170+
printk_get_console_flush_type(&ft);
3171+
3172+
cookie = console_srcu_read_lock();
3173+
for_each_console_srcu(con) {
3174+
short flags = console_srcu_read_flags(con);
3175+
u64 printk_seq;
3176+
bool progress;
3177+
3178+
/*
3179+
* console_flush_one_record() is only responsible for
3180+
* nbcon consoles when the nbcon consoles cannot print via
3181+
* their atomic or threaded flushing.
3182+
*/
3183+
if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
3184+
continue;
3185+
3186+
if (!console_is_usable(con, flags, !do_cond_resched))
3187+
continue;
3188+
*any_usable = true;
3189+
3190+
if (flags & CON_NBCON) {
3191+
progress = nbcon_legacy_emit_next_record(con, handover, cookie,
3192+
!do_cond_resched);
3193+
printk_seq = nbcon_seq_read(con);
3194+
} else {
3195+
progress = console_emit_next_record(con, handover, cookie);
3196+
printk_seq = con->seq;
3197+
}
3198+
3199+
/*
3200+
* If a handover has occurred, the SRCU read lock
3201+
* is already released.
3202+
*/
3203+
if (*handover)
3204+
return false;
3205+
3206+
/* Track the next of the highest seq flushed. */
3207+
if (printk_seq > *next_seq)
3208+
*next_seq = printk_seq;
3209+
3210+
if (!progress)
3211+
continue;
3212+
any_progress = true;
3213+
3214+
/* Allow panic_cpu to take over the consoles safely. */
3215+
if (panic_on_other_cpu())
3216+
goto abandon;
3217+
3218+
if (do_cond_resched)
3219+
cond_resched();
3220+
}
3221+
console_srcu_read_unlock(cookie);
3222+
3223+
return any_progress;
3224+
3225+
abandon:
3226+
console_srcu_read_unlock(cookie);
3227+
return false;
3228+
}
3229+
31373230
/*
31383231
* Print out all remaining records to all consoles.
31393232
*
@@ -3159,77 +3252,24 @@ static inline void printk_kthreads_check_locked(void) { }
31593252
*/
31603253
static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handover)
31613254
{
3162-
struct console_flush_type ft;
31633255
bool any_usable = false;
3164-
struct console *con;
31653256
bool any_progress;
3166-
int cookie;
31673257

31683258
*next_seq = 0;
31693259
*handover = false;
31703260

31713261
do {
3172-
any_progress = false;
3262+
any_progress = console_flush_one_record(do_cond_resched, next_seq, handover,
3263+
&any_usable);
31733264

3174-
printk_get_console_flush_type(&ft);
3175-
3176-
cookie = console_srcu_read_lock();
3177-
for_each_console_srcu(con) {
3178-
short flags = console_srcu_read_flags(con);
3179-
u64 printk_seq;
3180-
bool progress;
3265+
if (*handover)
3266+
return false;
31813267

3182-
/*
3183-
* console_flush_all() is only responsible for nbcon
3184-
* consoles when the nbcon consoles cannot print via
3185-
* their atomic or threaded flushing.
3186-
*/
3187-
if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload))
3188-
continue;
3189-
3190-
if (!console_is_usable(con, flags, !do_cond_resched))
3191-
continue;
3192-
any_usable = true;
3193-
3194-
if (flags & CON_NBCON) {
3195-
progress = nbcon_legacy_emit_next_record(con, handover, cookie,
3196-
!do_cond_resched);
3197-
printk_seq = nbcon_seq_read(con);
3198-
} else {
3199-
progress = console_emit_next_record(con, handover, cookie);
3200-
printk_seq = con->seq;
3201-
}
3202-
3203-
/*
3204-
* If a handover has occurred, the SRCU read lock
3205-
* is already released.
3206-
*/
3207-
if (*handover)
3208-
return false;
3209-
3210-
/* Track the next of the highest seq flushed. */
3211-
if (printk_seq > *next_seq)
3212-
*next_seq = printk_seq;
3213-
3214-
if (!progress)
3215-
continue;
3216-
any_progress = true;
3217-
3218-
/* Allow panic_cpu to take over the consoles safely. */
3219-
if (panic_on_other_cpu())
3220-
goto abandon;
3221-
3222-
if (do_cond_resched)
3223-
cond_resched();
3224-
}
3225-
console_srcu_read_unlock(cookie);
3268+
if (panic_on_other_cpu())
3269+
return false;
32263270
} while (any_progress);
32273271

32283272
return any_usable;
3229-
3230-
abandon:
3231-
console_srcu_read_unlock(cookie);
3232-
return false;
32333273
}
32343274

32353275
static void __console_flush_and_unlock(void)

0 commit comments

Comments
 (0)