mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
printk changes for 6.6
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAmT1pbAACgkQUqAMR0iA lPLoxBAAl18gKo6C8zIBNBoYNl7FxvChrJORjK7RQONs5RYKt8drHjSrJGazhjiV TIdbZt9juqs+UT/f6DnkJznrqQ0W70fQsgUpw+q7n7+cnkIoXAiAs+plexdQXigB 6nx67b2oub41jTwzn/uV7R/eTwq2VnoZqudS/o9iAI/Ia9JzkqmGx08hQedvOoqX 2SWs140iY/zXsFUyEfe8UTXwJUnC/n9pwtpe5sLpmtyupGc/KumUimTQ+LFJbV9o n8QhcQn10CE93M5fH/R2JXjZO7wuSmCHt/V8oSnoOwdCBBe7Tc6aBx5wUwc4XCuC 450h5hlYBKq97lA1PnWGC01uAkeDTRw8963LVRRqWvohoFuHXR0cisF9FTM9LXfs bg90XjzYAK7Ns9fJ0dZHOSbUtRaa06hiExUnO3ctyv2G6h8qKfv86LCuP0CMFmQU rflfk1dPiMW20HT3ZJNtMCy3Vu6kVQSdSaGKTnwzTcUWop5tCQxhmWYBXH6q/1LH aD7xT1xJnBGqLUqq5C8twoOea+w47x/vtjTLi7mJarP5Wfh8xv6axdkwE8N4NrYp cc2RR83a1BZ7At3YkAjfjHmhaZ97gSSe6+Yqk9UzvUEQY/WILEGnb0DKO1jCSB34 D2NPh1MHF5MFQjazdt/dSyMJVxDlTeY/S5wqfLLhNZts48LJ8n0= =D7ZU -----END PGP SIGNATURE----- Merge tag 'printk-for-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux Pull printk updates from Petr Mladek: - Do not try to get the console lock when it is not need or useful in panic() - Replace the global console_suspended state by a per-console flag - Export symbols needed for dumping the raw printk buffer in panic() - Fix documentation of printf formats for integer types - Moved Sergey Senozhatsky to the reviewer role - Misc cleanups * tag 'printk-for-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: printk: export symbols for debug modules lib: test_scanf: Add explicit type cast to result initialization in test_number_prefix() printk: ringbuffer: Fix truncating buffer size min_t cast printk: Rename abandon_console_lock_in_panic() to other_cpu_in_panic() printk: Add per-console suspended state printk: Consolidate console deferred printing printk: Do not take console lock for console_flush_on_panic() printk: Keep non-panic-CPUs out of console lock printk: Reduce console_unblank() usage in unsafe scenarios kdb: Do not assume write() callback available docs: printk-formats: Treat char as always unsigned docs: printk-formats: Fix hex printing of signed values MAINTAINERS: adjust printk/vsprintf entries
This commit is contained in:
commit
3c31041e37
@ -15,9 +15,10 @@ Integer types
|
||||
|
||||
If variable is of Type, use printk format specifier:
|
||||
------------------------------------------------------------
|
||||
char %d or %x
|
||||
signed char %d or %hhx
|
||||
unsigned char %u or %x
|
||||
short int %d or %x
|
||||
char %u or %x
|
||||
short int %d or %hx
|
||||
unsigned short int %u or %x
|
||||
int %d or %x
|
||||
unsigned int %u or %x
|
||||
@ -27,9 +28,9 @@ Integer types
|
||||
unsigned long long %llu or %llx
|
||||
size_t %zu or %zx
|
||||
ssize_t %zd or %zx
|
||||
s8 %d or %x
|
||||
s8 %d or %hhx
|
||||
u8 %u or %x
|
||||
s16 %d or %x
|
||||
s16 %d or %hx
|
||||
u16 %u or %x
|
||||
s32 %d or %x
|
||||
u32 %u or %x
|
||||
|
@ -17176,9 +17176,9 @@ F: kernel/sched/psi.c
|
||||
|
||||
PRINTK
|
||||
M: Petr Mladek <pmladek@suse.com>
|
||||
M: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
R: Steven Rostedt <rostedt@goodmis.org>
|
||||
R: John Ogness <john.ogness@linutronix.de>
|
||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
||||
F: include/linux/printk.h
|
||||
@ -23072,9 +23072,9 @@ F: drivers/net/vrf.c
|
||||
VSPRINTF
|
||||
M: Petr Mladek <pmladek@suse.com>
|
||||
M: Steven Rostedt <rostedt@goodmis.org>
|
||||
M: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
|
||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
|
||||
F: Documentation/core-api/printk-formats.rst
|
||||
|
@ -154,6 +154,8 @@ static inline int con_debug_leave(void)
|
||||
* receiving the printk spam for obvious reasons.
|
||||
* @CON_EXTENDED: The console supports the extended output format of
|
||||
* /dev/kmesg which requires a larger output buffer.
|
||||
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the
|
||||
* printing callbacks must not be called.
|
||||
*/
|
||||
enum cons_flags {
|
||||
CON_PRINTBUFFER = BIT(0),
|
||||
@ -163,6 +165,7 @@ enum cons_flags {
|
||||
CON_ANYTIME = BIT(4),
|
||||
CON_BRL = BIT(5),
|
||||
CON_EXTENDED = BIT(6),
|
||||
CON_SUSPENDED = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -590,6 +590,8 @@ static void kdb_msg_write(const char *msg, int msg_len)
|
||||
continue;
|
||||
if (c == dbg_io_ops->cons)
|
||||
continue;
|
||||
if (!c->write)
|
||||
continue;
|
||||
/*
|
||||
* Set oops_in_progress to encourage the console drivers to
|
||||
* disregard their internal spin locks: in the current calling
|
||||
|
@ -103,3 +103,5 @@ struct printk_message {
|
||||
u64 seq;
|
||||
unsigned long dropped;
|
||||
};
|
||||
|
||||
bool other_cpu_in_panic(void);
|
||||
|
@ -88,7 +88,7 @@ EXPORT_SYMBOL(oops_in_progress);
|
||||
static DEFINE_MUTEX(console_mutex);
|
||||
|
||||
/*
|
||||
* console_sem protects updates to console->seq and console_suspended,
|
||||
* console_sem protects updates to console->seq
|
||||
* and also provides serialization for console printing.
|
||||
*/
|
||||
static DEFINE_SEMAPHORE(console_sem, 1);
|
||||
@ -361,7 +361,7 @@ static bool panic_in_progress(void)
|
||||
* paths in the console code where we end up in places I want
|
||||
* locked without the console semaphore held).
|
||||
*/
|
||||
static int console_locked, console_suspended;
|
||||
static int console_locked;
|
||||
|
||||
/*
|
||||
* Array of consoles built from command line options (console=)
|
||||
@ -538,12 +538,14 @@ char *log_buf_addr_get(void)
|
||||
{
|
||||
return log_buf;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(log_buf_addr_get);
|
||||
|
||||
/* Return log buffer size */
|
||||
u32 log_buf_len_get(void)
|
||||
{
|
||||
return log_buf_len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(log_buf_len_get);
|
||||
|
||||
/*
|
||||
* Define how much of the log buffer we could take at maximum. The value
|
||||
@ -2308,7 +2310,11 @@ asmlinkage int vprintk_emit(int facility, int level,
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
wake_up_klogd();
|
||||
if (in_sched)
|
||||
defer_console_output();
|
||||
else
|
||||
wake_up_klogd();
|
||||
|
||||
return printed_len;
|
||||
}
|
||||
EXPORT_SYMBOL(vprintk_emit);
|
||||
@ -2547,22 +2553,46 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig
|
||||
*/
|
||||
void suspend_console(void)
|
||||
{
|
||||
struct console *con;
|
||||
|
||||
if (!console_suspend_enabled)
|
||||
return;
|
||||
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
|
||||
pr_flush(1000, true);
|
||||
console_lock();
|
||||
console_suspended = 1;
|
||||
up_console_sem();
|
||||
|
||||
console_list_lock();
|
||||
for_each_console(con)
|
||||
console_srcu_write_flags(con, con->flags | CON_SUSPENDED);
|
||||
console_list_unlock();
|
||||
|
||||
/*
|
||||
* Ensure that all SRCU list walks have completed. All printing
|
||||
* contexts must be able to see that they are suspended so that it
|
||||
* is guaranteed that all printing has stopped when this function
|
||||
* completes.
|
||||
*/
|
||||
synchronize_srcu(&console_srcu);
|
||||
}
|
||||
|
||||
void resume_console(void)
|
||||
{
|
||||
struct console *con;
|
||||
|
||||
if (!console_suspend_enabled)
|
||||
return;
|
||||
down_console_sem();
|
||||
console_suspended = 0;
|
||||
console_unlock();
|
||||
|
||||
console_list_lock();
|
||||
for_each_console(con)
|
||||
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
|
||||
console_list_unlock();
|
||||
|
||||
/*
|
||||
* Ensure that all SRCU list walks have completed. All printing
|
||||
* contexts must be able to see they are no longer suspended so
|
||||
* that they are guaranteed to wake up and resume printing.
|
||||
*/
|
||||
synchronize_srcu(&console_srcu);
|
||||
|
||||
pr_flush(1000, true);
|
||||
}
|
||||
|
||||
@ -2585,6 +2615,26 @@ static int console_cpu_notify(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if a panic is in progress on a remote CPU.
|
||||
*
|
||||
* On true, the local CPU should immediately release any printing resources
|
||||
* that may be needed by the panic CPU.
|
||||
*/
|
||||
bool other_cpu_in_panic(void)
|
||||
{
|
||||
if (!panic_in_progress())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We can use raw_smp_processor_id() here because it is impossible for
|
||||
* the task to be migrated to the panic_cpu, or away from it. If
|
||||
* panic_cpu has already been set, and we're not currently executing on
|
||||
* that CPU, then we never will be.
|
||||
*/
|
||||
return atomic_read(&panic_cpu) != raw_smp_processor_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* console_lock - block the console subsystem from printing
|
||||
*
|
||||
@ -2597,9 +2647,11 @@ void console_lock(void)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
/* On panic, the console_lock must be left to the panic cpu. */
|
||||
while (other_cpu_in_panic())
|
||||
msleep(1000);
|
||||
|
||||
down_console_sem();
|
||||
if (console_suspended)
|
||||
return;
|
||||
console_locked = 1;
|
||||
console_may_schedule = 1;
|
||||
}
|
||||
@ -2615,12 +2667,11 @@ EXPORT_SYMBOL(console_lock);
|
||||
*/
|
||||
int console_trylock(void)
|
||||
{
|
||||
/* On panic, the console_lock must be left to the panic cpu. */
|
||||
if (other_cpu_in_panic())
|
||||
return 0;
|
||||
if (down_trylock_console_sem())
|
||||
return 0;
|
||||
if (console_suspended) {
|
||||
up_console_sem();
|
||||
return 0;
|
||||
}
|
||||
console_locked = 1;
|
||||
console_may_schedule = 0;
|
||||
return 1;
|
||||
@ -2633,25 +2684,6 @@ int is_console_locked(void)
|
||||
}
|
||||
EXPORT_SYMBOL(is_console_locked);
|
||||
|
||||
/*
|
||||
* Return true when this CPU should unlock console_sem without pushing all
|
||||
* messages to the console. This reduces the chance that the console is
|
||||
* locked when the panic CPU tries to use it.
|
||||
*/
|
||||
static bool abandon_console_lock_in_panic(void)
|
||||
{
|
||||
if (!panic_in_progress())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We can use raw_smp_processor_id() here because it is impossible for
|
||||
* the task to be migrated to the panic_cpu, or away from it. If
|
||||
* panic_cpu has already been set, and we're not currently executing on
|
||||
* that CPU, then we never will be.
|
||||
*/
|
||||
return atomic_read(&panic_cpu) != raw_smp_processor_id();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the given console is currently capable and allowed to print
|
||||
* records.
|
||||
@ -2665,6 +2697,9 @@ static inline bool console_is_usable(struct console *con)
|
||||
if (!(flags & CON_ENABLED))
|
||||
return false;
|
||||
|
||||
if ((flags & CON_SUSPENDED))
|
||||
return false;
|
||||
|
||||
if (!con->write)
|
||||
return false;
|
||||
|
||||
@ -2948,7 +2983,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
|
||||
any_progress = true;
|
||||
|
||||
/* Allow panic_cpu to take over the consoles safely. */
|
||||
if (abandon_console_lock_in_panic())
|
||||
if (other_cpu_in_panic())
|
||||
goto abandon;
|
||||
|
||||
if (do_cond_resched)
|
||||
@ -2983,11 +3018,6 @@ void console_unlock(void)
|
||||
bool flushed;
|
||||
u64 next_seq;
|
||||
|
||||
if (console_suspended) {
|
||||
up_console_sem();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Console drivers are called with interrupts disabled, so
|
||||
* @console_may_schedule should be cleared before; however, we may
|
||||
@ -3045,9 +3075,27 @@ EXPORT_SYMBOL(console_conditional_schedule);
|
||||
|
||||
void console_unblank(void)
|
||||
{
|
||||
bool found_unblank = false;
|
||||
struct console *c;
|
||||
int cookie;
|
||||
|
||||
/*
|
||||
* First check if there are any consoles implementing the unblank()
|
||||
* callback. If not, there is no reason to continue and take the
|
||||
* console lock, which in particular can be dangerous if
|
||||
* @oops_in_progress is set.
|
||||
*/
|
||||
cookie = console_srcu_read_lock();
|
||||
for_each_console_srcu(c) {
|
||||
if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) {
|
||||
found_unblank = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
console_srcu_read_unlock(cookie);
|
||||
if (!found_unblank)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Stop console printing because the unblank() callback may
|
||||
* assume the console is not within its write() callback.
|
||||
@ -3056,6 +3104,16 @@ void console_unblank(void)
|
||||
* In that case, attempt a trylock as best-effort.
|
||||
*/
|
||||
if (oops_in_progress) {
|
||||
/* Semaphores are not NMI-safe. */
|
||||
if (in_nmi())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Attempting to trylock the console lock can deadlock
|
||||
* if another CPU was stopped while modifying the
|
||||
* semaphore. "Hope and pray" that this is not the
|
||||
* current situation.
|
||||
*/
|
||||
if (down_trylock_console_sem() != 0)
|
||||
return;
|
||||
} else
|
||||
@ -3085,14 +3143,24 @@ void console_unblank(void)
|
||||
*/
|
||||
void console_flush_on_panic(enum con_flush_mode mode)
|
||||
{
|
||||
bool handover;
|
||||
u64 next_seq;
|
||||
|
||||
/*
|
||||
* If someone else is holding the console lock, trylock will fail
|
||||
* and may_schedule may be set. Ignore and proceed to unlock so
|
||||
* that messages are flushed out. As this can be called from any
|
||||
* context and we don't want to get preempted while flushing,
|
||||
* ensure may_schedule is cleared.
|
||||
* Ignore the console lock and flush out the messages. Attempting a
|
||||
* trylock would not be useful because:
|
||||
*
|
||||
* - if it is contended, it must be ignored anyway
|
||||
* - console_lock() and console_trylock() block and fail
|
||||
* respectively in panic for non-panic CPUs
|
||||
* - semaphores are not NMI-safe
|
||||
*/
|
||||
|
||||
/*
|
||||
* If another context is holding the console lock,
|
||||
* @console_may_schedule might be set. Clear it so that
|
||||
* this context does not call cond_resched() while flushing.
|
||||
*/
|
||||
console_trylock();
|
||||
console_may_schedule = 0;
|
||||
|
||||
if (mode == CONSOLE_REPLAY_ALL) {
|
||||
@ -3105,15 +3173,15 @@ void console_flush_on_panic(enum con_flush_mode mode)
|
||||
cookie = console_srcu_read_lock();
|
||||
for_each_console_srcu(c) {
|
||||
/*
|
||||
* If the above console_trylock() failed, this is an
|
||||
* unsynchronized assignment. But in that case, the
|
||||
* This is an unsynchronized assignment, but the
|
||||
* kernel is in "hope and pray" mode anyway.
|
||||
*/
|
||||
c->seq = seq;
|
||||
}
|
||||
console_srcu_read_unlock(cookie);
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
console_flush_all(false, &next_seq, &handover);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3679,8 +3747,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
||||
|
||||
/*
|
||||
* Hold the console_lock to guarantee safe access to
|
||||
* console->seq and to prevent changes to @console_suspended
|
||||
* until all consoles have been processed.
|
||||
* console->seq.
|
||||
*/
|
||||
console_lock();
|
||||
|
||||
@ -3688,6 +3755,11 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
||||
for_each_console_srcu(c) {
|
||||
if (con && con != c)
|
||||
continue;
|
||||
/*
|
||||
* If consoles are not usable, it cannot be expected
|
||||
* that they make forward progress, so only increment
|
||||
* @diff for usable consoles.
|
||||
*/
|
||||
if (!console_is_usable(c))
|
||||
continue;
|
||||
printk_seq = c->seq;
|
||||
@ -3696,18 +3768,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
||||
}
|
||||
console_srcu_read_unlock(cookie);
|
||||
|
||||
/*
|
||||
* If consoles are suspended, it cannot be expected that they
|
||||
* make forward progress, so timeout immediately. @diff is
|
||||
* still used to return a valid flush status.
|
||||
*/
|
||||
if (console_suspended)
|
||||
remaining = 0;
|
||||
else if (diff != last_diff && reset_on_progress)
|
||||
if (diff != last_diff && reset_on_progress)
|
||||
remaining = timeout_ms;
|
||||
|
||||
console_unlock();
|
||||
|
||||
/* Note: @diff is 0 if there are no usable consoles. */
|
||||
if (diff == 0 || remaining == 0)
|
||||
break;
|
||||
|
||||
@ -3741,7 +3807,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
||||
* printer has been seen to make some forward progress.
|
||||
*
|
||||
* Context: Process context. May sleep while acquiring console lock.
|
||||
* Return: true if all enabled printers are caught up.
|
||||
* Return: true if all usable printers are caught up.
|
||||
*/
|
||||
static bool pr_flush(int timeout_ms, bool reset_on_progress)
|
||||
{
|
||||
@ -3798,11 +3864,33 @@ static void __wake_up_klogd(int val)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* wake_up_klogd - Wake kernel logging daemon
|
||||
*
|
||||
* Use this function when new records have been added to the ringbuffer
|
||||
* and the console printing of those records has already occurred or is
|
||||
* known to be handled by some other context. This function will only
|
||||
* wake the logging daemon.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void wake_up_klogd(void)
|
||||
{
|
||||
__wake_up_klogd(PRINTK_PENDING_WAKEUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* defer_console_output - Wake kernel logging daemon and trigger
|
||||
* console printing in a deferred context
|
||||
*
|
||||
* Use this function when new records have been added to the ringbuffer,
|
||||
* this context is responsible for console printing those records, but
|
||||
* the current context is not allowed to perform the console printing.
|
||||
* Trigger an irq_work context to perform the console printing. This
|
||||
* function also wakes the logging daemon.
|
||||
*
|
||||
* Context: Any context.
|
||||
*/
|
||||
void defer_console_output(void)
|
||||
{
|
||||
/*
|
||||
@ -3819,12 +3907,7 @@ void printk_trigger_flush(void)
|
||||
|
||||
int vprintk_deferred(const char *fmt, va_list args)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, fmt, args);
|
||||
defer_console_output();
|
||||
|
||||
return r;
|
||||
return vprintk_emit(0, LOGLEVEL_SCHED, NULL, fmt, args);
|
||||
}
|
||||
|
||||
int _printk_deferred(const char *fmt, ...)
|
||||
|
@ -1735,7 +1735,7 @@ static bool copy_data(struct prb_data_ring *data_ring,
|
||||
if (!buf || !buf_size)
|
||||
return true;
|
||||
|
||||
data_size = min_t(u16, buf_size, len);
|
||||
data_size = min_t(unsigned int, buf_size, len);
|
||||
|
||||
memcpy(&buf[0], data, data_size); /* LMM(copy_data:A) */
|
||||
return true;
|
||||
|
@ -38,13 +38,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
|
||||
* Use the main logbuf even in NMI. But avoid calling console
|
||||
* drivers that might have their own locks.
|
||||
*/
|
||||
if (this_cpu_read(printk_context) || in_nmi()) {
|
||||
int len;
|
||||
|
||||
len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, fmt, args);
|
||||
defer_console_output();
|
||||
return len;
|
||||
}
|
||||
if (this_cpu_read(printk_context) || in_nmi())
|
||||
return vprintk_deferred(fmt, args);
|
||||
|
||||
/* No obstacles. */
|
||||
return vprintk_default(fmt, args);
|
||||
|
@ -606,7 +606,7 @@ static void __init numbers_slice(void)
|
||||
#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \
|
||||
do { \
|
||||
const T expect[2] = { expect0, expect1 }; \
|
||||
T result[2] = {~expect[0], ~expect[1]}; \
|
||||
T result[2] = { (T)~expect[0], (T)~expect[1] }; \
|
||||
\
|
||||
_test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \
|
||||
} while (0)
|
||||
|
Loading…
Reference in New Issue
Block a user