Skip to content

Commit 93d17c1

Browse files
committed
Merge tag 'printk-for-5.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk fixes from Petr Mladek: "Make the global console_sem available for CPU that is handling panic() or shutdown. This is an old problem when an existing console lock owner might block console output, but it became more visible with the kthreads" * tag 'printk-for-5.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: printk: Wait for the global console lock when the system is going down printk: Block console kthreads when direct printing will be required
2 parents ef06e68 + 38335cc commit 93d17c1

File tree

6 files changed

+50
-1
lines changed

6 files changed

+50
-1
lines changed

include/linux/printk.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ extern void printk_prefer_direct_enter(void);
173173
extern void printk_prefer_direct_exit(void);
174174

175175
extern bool pr_flush(int timeout_ms, bool reset_on_progress);
176+
extern void try_block_console_kthreads(int timeout_ms);
176177

177178
/*
178179
* Please don't use printk_ratelimit(), because it shares ratelimiting state
@@ -237,6 +238,10 @@ static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
237238
return true;
238239
}
239240

241+
static inline void try_block_console_kthreads(int timeout_ms)
242+
{
243+
}
244+
240245
static inline int printk_ratelimit(void)
241246
{
242247
return 0;

kernel/panic.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,15 @@ void panic(const char *fmt, ...)
297297
* unfortunately means it may not be hardened to work in a
298298
* panic situation.
299299
*/
300+
try_block_console_kthreads(10000);
300301
smp_send_stop();
301302
} else {
302303
/*
303304
* If we want to do crash dump after notifier calls and
304305
* kmsg_dump, we will need architecture dependent extra
305306
* works in addition to stopping other CPUs.
306307
*/
308+
try_block_console_kthreads(10000);
307309
crash_smp_send_stop();
308310
}
309311

kernel/printk/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ enum printk_info_flags {
2020
LOG_CONT = 8, /* text is a fragment of a continuation line */
2121
};
2222

23+
extern bool block_console_kthreads;
24+
2325
__printf(4, 0)
2426
int vprintk_store(int facility, int level,
2527
const struct dev_printk_info *dev_info,

kernel/printk/printk.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ static atomic_t console_kthreads_active = ATOMIC_INIT(0);
250250
#define console_kthread_printing_exit() \
251251
atomic_dec(&console_kthreads_active)
252252

253+
/* Block console kthreads to avoid processing new messages. */
254+
bool block_console_kthreads;
255+
253256
/*
254257
* Helper macros to handle lockdep when locking/unlocking console_sem. We use
255258
* macros instead of functions so that _RET_IP_ contains useful information.
@@ -3729,7 +3732,10 @@ static bool printer_should_wake(struct console *con, u64 seq)
37293732
return true;
37303733

37313734
if (con->blocked ||
3732-
console_kthreads_atomically_blocked()) {
3735+
console_kthreads_atomically_blocked() ||
3736+
block_console_kthreads ||
3737+
system_state > SYSTEM_RUNNING ||
3738+
oops_in_progress) {
37333739
return false;
37343740
}
37353741

kernel/printk/printk_safe.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#include <linux/smp.h>
99
#include <linux/cpumask.h>
1010
#include <linux/printk.h>
11+
#include <linux/console.h>
1112
#include <linux/kprobes.h>
13+
#include <linux/delay.h>
1214

1315
#include "internal.h"
1416

@@ -50,3 +52,33 @@ asmlinkage int vprintk(const char *fmt, va_list args)
5052
return vprintk_default(fmt, args);
5153
}
5254
EXPORT_SYMBOL(vprintk);
55+
56+
/**
57+
* try_block_console_kthreads() - Try to block console kthreads and
58+
* make the global console_lock() avaialble
59+
*
60+
* @timeout_ms: The maximum time (in ms) to wait.
61+
*
62+
* Prevent console kthreads from starting processing new messages. Wait
63+
* until the global console_lock() become available.
64+
*
65+
* Context: Can be called in any context.
66+
*/
67+
void try_block_console_kthreads(int timeout_ms)
68+
{
69+
block_console_kthreads = true;
70+
71+
/* Do not wait when the console lock could not be safely taken. */
72+
if (this_cpu_read(printk_context) || in_nmi())
73+
return;
74+
75+
while (timeout_ms > 0) {
76+
if (console_trylock()) {
77+
console_unlock();
78+
return;
79+
}
80+
81+
udelay(1000);
82+
timeout_ms -= 1;
83+
}
84+
}

kernel/reboot.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ void kernel_restart_prepare(char *cmd)
8282
{
8383
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
8484
system_state = SYSTEM_RESTART;
85+
try_block_console_kthreads(10000);
8586
usermodehelper_disable();
8687
device_shutdown();
8788
}
@@ -270,6 +271,7 @@ static void kernel_shutdown_prepare(enum system_states state)
270271
blocking_notifier_call_chain(&reboot_notifier_list,
271272
(state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);
272273
system_state = state;
274+
try_block_console_kthreads(10000);
273275
usermodehelper_disable();
274276
device_shutdown();
275277
}

0 commit comments

Comments
 (0)