mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
Merge tag 'printk-for-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: - John Ogness became PRINTK co-maintainer - Unregister boot consoles when any proper console is registered at the end of the boot phase. Before they were removed only when the so-called preferred console, usually set via the last 'console=' parameter, got registered - Fix computation for increasing the printk ringbuffer on systems with many CPUs and possibly long backtraces from all CPUs - Cleaned up irq_works handling for deferred printk operations - Use acquire/release semantic for filled_random_ptr_key - Allow to use ':' in console options - More code clean up * tag 'printk-for-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: MAINTAINERS: Make John PRINTK co-maintainer lib/vsprintf: Use EXPORT_SYMBOL_IF_KUNIT() to export symbols printk: Remove console options before decoding the name printk: increase the ring buffer for more than 16 CPUs by default printk_ringbuffer: Avoid needless read of prb_desc printk: Use two irq_works instead per-CPU lib/vsprintf: Use acquire/release for ptr_key publication printk: Remove remaining boot consoles when a real console exists
This commit is contained in:
commit
5b212610d0
5 files changed
+88
-81
No files matched your search
+1
-1
@@ -21961,8 +21961,8 @@ F: scripts/Makefile.propeller
|
||||
|
||||
PRINTK
|
||||
M: Petr Mladek <pmladek@suse.com>
|
||||
M: John Ogness <john.ogness@linutronix.de>
|
||||
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
|
||||
|
||||
+70
-60
@@ -1085,9 +1085,9 @@ static void __init log_buf_add_cpu(void)
|
||||
if (num_possible_cpus() == 1)
|
||||
return;
|
||||
|
||||
cpu_extra = (num_possible_cpus() - 1) * __LOG_CPU_MAX_BUF_LEN;
|
||||
cpu_extra = num_possible_cpus() * __LOG_CPU_MAX_BUF_LEN;
|
||||
|
||||
/* by default this will only continue through for large > 64 CPUs */
|
||||
/* by default this will only continue through for more than 16 CPUs */
|
||||
if (cpu_extra <= __LOG_BUF_LEN / 2)
|
||||
return;
|
||||
|
||||
@@ -2646,24 +2646,25 @@ static int __init console_setup(char *str)
|
||||
if (_braille_console_setup(&str, &brl_options))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Decode str into name, index and options. Start with options, since
|
||||
* it might also contain a ':' used for DEVNAME.
|
||||
*/
|
||||
options = strchr(str, ',');
|
||||
if (options)
|
||||
*(options++) = 0;
|
||||
|
||||
/* For a DEVNAME:0.0 style console the character device is unknown early */
|
||||
if (strchr(str, ':'))
|
||||
devname = buf;
|
||||
else
|
||||
ttyname = buf;
|
||||
|
||||
/*
|
||||
* Decode str into name, index, options.
|
||||
*/
|
||||
if (ttyname && isdigit(str[0]))
|
||||
scnprintf(buf, sizeof(buf), "ttyS%s", str);
|
||||
else
|
||||
strscpy(buf, str);
|
||||
|
||||
options = strchr(str, ',');
|
||||
if (options)
|
||||
*(options++) = 0;
|
||||
|
||||
#ifdef __sparc__
|
||||
if (!strcmp(str, "ttya"))
|
||||
strscpy(buf, "ttyS0");
|
||||
@@ -2671,17 +2672,18 @@ static int __init console_setup(char *str)
|
||||
strscpy(buf, "ttyS1");
|
||||
#endif
|
||||
|
||||
for (s = buf; *s; s++)
|
||||
if ((ttyname && isdigit(*s)) || *s == ',')
|
||||
break;
|
||||
|
||||
/* @idx will get defined when devname matches. */
|
||||
if (devname)
|
||||
idx = -1;
|
||||
else
|
||||
if (ttyname) {
|
||||
/* Detect @idx in ttyname and remove it. */
|
||||
for (s = ttyname; *s; s++) {
|
||||
if (isdigit(*s))
|
||||
break;
|
||||
}
|
||||
idx = simple_strtoul(s, NULL, 10);
|
||||
|
||||
*s = 0;
|
||||
*s = 0;
|
||||
} else {
|
||||
/* @idx will get defined when devname matches. */
|
||||
idx = -1;
|
||||
}
|
||||
|
||||
__add_preferred_console(ttyname, idx, devname, options, brl_options, true);
|
||||
return 1;
|
||||
@@ -4424,36 +4426,51 @@ void __init console_init(void)
|
||||
* be a brief interval in which no messages are logged to the console, which
|
||||
* makes it difficult to diagnose problems that occur during this time.
|
||||
*
|
||||
* To mitigate this problem somewhat, only unregister consoles whose memory
|
||||
* intersects with the init section. Note that all other boot consoles will
|
||||
* get unregistered when the real preferred console is registered.
|
||||
* If a real console has already registered, remove all remaining boot consoles.
|
||||
* Otherwise, mitigate the no-console interval by removing only boot consoles
|
||||
* whose memory intersects with the init section.
|
||||
*/
|
||||
static int __init printk_late_init(void)
|
||||
{
|
||||
bool have_real_console = false;
|
||||
struct hlist_node *tmp;
|
||||
struct console *con;
|
||||
int ret;
|
||||
|
||||
console_list_lock();
|
||||
for_each_console(con) {
|
||||
if (!(con->flags & CON_BOOT)) {
|
||||
have_real_console = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hlist_for_each_entry_safe(con, tmp, &console_list, node) {
|
||||
if (!(con->flags & CON_BOOT))
|
||||
continue;
|
||||
|
||||
/* Check addresses that might be used for enabled consoles. */
|
||||
if (init_section_intersects(con, sizeof(*con)) ||
|
||||
init_section_contains(con->write, 0) ||
|
||||
init_section_contains(con->read, 0) ||
|
||||
init_section_contains(con->device, 0) ||
|
||||
init_section_contains(con->unblank, 0) ||
|
||||
init_section_contains(con->data, 0)) {
|
||||
/*
|
||||
* Keep the boot console when requested or as a fallback
|
||||
* unless it is using an init section.
|
||||
*/
|
||||
if (keep_bootcon || !have_real_console) {
|
||||
if (!init_section_intersects(con, sizeof(*con)) &&
|
||||
!init_section_contains(con->write, 0) &&
|
||||
!init_section_contains(con->read, 0) &&
|
||||
!init_section_contains(con->device, 0) &&
|
||||
!init_section_contains(con->unblank, 0) &&
|
||||
!init_section_contains(con->data, 0))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Please, consider moving the reported consoles out
|
||||
* of the init section.
|
||||
*/
|
||||
pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n",
|
||||
con->name, con->index);
|
||||
unregister_console_locked(con);
|
||||
}
|
||||
|
||||
unregister_console_locked(con);
|
||||
}
|
||||
console_list_unlock();
|
||||
|
||||
@@ -4593,31 +4610,26 @@ bool pr_flush(int timeout_ms, bool reset_on_progress)
|
||||
/*
|
||||
* Delayed printk version, for scheduler-internal messages:
|
||||
*/
|
||||
#define PRINTK_PENDING_WAKEUP 0x01
|
||||
#define PRINTK_PENDING_OUTPUT 0x02
|
||||
#define PRINTK_PENDING_OUTPUT 0x01
|
||||
|
||||
static DEFINE_PER_CPU(int, printk_pending);
|
||||
|
||||
static void wake_up_klogd_work_func(struct irq_work *irq_work)
|
||||
static void pending_wake_fn(struct irq_work *irq_work)
|
||||
{
|
||||
int pending = this_cpu_xchg(printk_pending, 0);
|
||||
|
||||
if (pending & PRINTK_PENDING_OUTPUT) {
|
||||
if (force_legacy_kthread()) {
|
||||
if (printk_legacy_kthread)
|
||||
wake_up_interruptible(&legacy_wait);
|
||||
} else {
|
||||
if (console_trylock())
|
||||
console_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (pending & PRINTK_PENDING_WAKEUP)
|
||||
wake_up_interruptible(&log_wait);
|
||||
wake_up_interruptible(&log_wait);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) =
|
||||
IRQ_WORK_INIT_LAZY(wake_up_klogd_work_func);
|
||||
static void pending_output_fn(struct irq_work *irq_work)
|
||||
{
|
||||
if (force_legacy_kthread()) {
|
||||
if (printk_legacy_kthread)
|
||||
wake_up_interruptible(&legacy_wait);
|
||||
} else {
|
||||
if (console_trylock())
|
||||
console_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static struct irq_work pending_wakeup_work = IRQ_WORK_INIT_LAZY(pending_wake_fn);
|
||||
static struct irq_work pending_output_work = IRQ_WORK_INIT_LAZY(pending_output_fn);
|
||||
|
||||
static void __wake_up_klogd(int val)
|
||||
{
|
||||
@@ -4631,7 +4643,6 @@ static void __wake_up_klogd(int val)
|
||||
if (WARN_ON_ONCE(console_irqwork_blocked))
|
||||
return;
|
||||
|
||||
preempt_disable();
|
||||
/*
|
||||
* Guarantee any new records can be seen by tasks preparing to wait
|
||||
* before this context checks if the wait queue is empty.
|
||||
@@ -4643,12 +4654,11 @@ static void __wake_up_klogd(int val)
|
||||
*
|
||||
* This pairs with devkmsg_read:A and syslog_print:A.
|
||||
*/
|
||||
if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */
|
||||
(val & PRINTK_PENDING_OUTPUT)) {
|
||||
this_cpu_or(printk_pending, val);
|
||||
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
|
||||
}
|
||||
preempt_enable();
|
||||
if (wq_has_sleeper(&log_wait)) /* LMM(__wake_up_klogd:A) */
|
||||
irq_work_queue(&pending_wakeup_work);
|
||||
|
||||
if (val & PRINTK_PENDING_OUTPUT)
|
||||
irq_work_queue(&pending_output_work);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4663,7 +4673,7 @@ static void __wake_up_klogd(int val)
|
||||
*/
|
||||
void wake_up_klogd(void)
|
||||
{
|
||||
__wake_up_klogd(PRINTK_PENDING_WAKEUP);
|
||||
__wake_up_klogd(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4684,7 +4694,7 @@ void defer_console_output(void)
|
||||
* New messages may have been added directly to the ringbuffer
|
||||
* using vprintk_store(), so wake any waiters as well.
|
||||
*/
|
||||
__wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
|
||||
__wake_up_klogd(PRINTK_PENDING_OUTPUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -439,13 +439,12 @@ static enum desc_state get_desc_state(unsigned long id,
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a copy of a specified descriptor and return its queried state. If the
|
||||
* descriptor is in an inconsistent state (miss or reserved), the caller can
|
||||
* only expect the descriptor's @state_var field to be valid.
|
||||
* Get the state of a specified descriptor.
|
||||
*
|
||||
* The sequence number and caller_id can be optionally retrieved. Like all
|
||||
* non-state_var data, they are only valid if the descriptor is in a
|
||||
* consistent state.
|
||||
* Optionally, a copy of the descriptor, sequence number and/or caller ID can
|
||||
* be retrieved. However, (with the exception of @desc_out->state_var) all
|
||||
* retrieved values are invalid if the descriptor is in an inconsistent state
|
||||
* (miss or reserved).
|
||||
*/
|
||||
static enum desc_state desc_read(struct prb_desc_ring *desc_ring,
|
||||
unsigned long id, struct prb_desc *desc_out,
|
||||
@@ -1335,7 +1334,6 @@ static struct prb_desc *desc_reopen_last(struct prb_desc_ring *desc_ring,
|
||||
{
|
||||
unsigned long prev_state_val;
|
||||
enum desc_state d_state;
|
||||
struct prb_desc desc;
|
||||
struct prb_desc *d;
|
||||
unsigned long id;
|
||||
u32 cid;
|
||||
@@ -1346,7 +1344,7 @@ static struct prb_desc *desc_reopen_last(struct prb_desc_ring *desc_ring,
|
||||
* To reduce unnecessarily reopening, first check if the descriptor
|
||||
* state and caller ID are correct.
|
||||
*/
|
||||
d_state = desc_read(desc_ring, id, &desc, NULL, &cid);
|
||||
d_state = desc_read(desc_ring, id, NULL, NULL, &cid);
|
||||
if (d_state != desc_committed || cid != caller_id)
|
||||
return NULL;
|
||||
|
||||
@@ -2007,14 +2005,13 @@ u64 prb_first_seq(struct printk_ringbuffer *rb)
|
||||
{
|
||||
struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
||||
enum desc_state d_state;
|
||||
struct prb_desc desc;
|
||||
unsigned long id;
|
||||
u64 seq;
|
||||
|
||||
for (;;) {
|
||||
id = atomic_long_read(&rb->desc_ring.tail_id); /* LMM(prb_first_seq:A) */
|
||||
|
||||
d_state = desc_read(desc_ring, id, &desc, &seq, NULL); /* LMM(prb_first_seq:B) */
|
||||
d_state = desc_read(desc_ring, id, NULL, &seq, NULL); /* LMM(prb_first_seq:B) */
|
||||
|
||||
/*
|
||||
* This loop will not be infinite because the tail is
|
||||
|
||||
@@ -876,3 +876,4 @@ kunit_test_suite(printf_test_suite);
|
||||
MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>");
|
||||
MODULE_DESCRIPTION("Test cases for printf facility");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
|
||||
+9
-10
@@ -25,6 +25,7 @@
|
||||
#include <linux/module.h> /* for KSYM_SYMBOL_LEN */
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/hex.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -54,12 +55,13 @@
|
||||
#include <asm/byteorder.h> /* cpu_to_le16 */
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include <linux/string_helpers.h>
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
#include "kstrtox.h"
|
||||
|
||||
/* Disable pointer hashing if requested */
|
||||
bool no_hash_pointers __ro_after_init;
|
||||
EXPORT_SYMBOL_FOR_MODULES(no_hash_pointers, "printf_kunit");
|
||||
EXPORT_SYMBOL_IF_KUNIT(no_hash_pointers);
|
||||
|
||||
/*
|
||||
* Hashed pointers policy selected by "hash_pointers=..." boot param
|
||||
@@ -762,9 +764,8 @@ static int fill_ptr_key(struct notifier_block *nb, unsigned long action, void *d
|
||||
{
|
||||
get_random_bytes(&ptr_key, sizeof(ptr_key));
|
||||
|
||||
/* Pairs with smp_rmb() before reading ptr_key. */
|
||||
smp_wmb();
|
||||
WRITE_ONCE(filled_random_ptr_key, true);
|
||||
/* Pairs with smp_load_acquire() before reading ptr_key. */
|
||||
smp_store_release(&filled_random_ptr_key, true);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@@ -781,12 +782,10 @@ static inline int __ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
|
||||
{
|
||||
unsigned long hashval;
|
||||
|
||||
if (!READ_ONCE(filled_random_ptr_key))
|
||||
/* Pairs with smp_store_release() after writing ptr_key. */
|
||||
if (!smp_load_acquire(&filled_random_ptr_key))
|
||||
return -EBUSY;
|
||||
|
||||
/* Pairs with smp_wmb() after writing ptr_key. */
|
||||
smp_rmb();
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
|
||||
/*
|
||||
@@ -850,7 +849,7 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
|
||||
}
|
||||
|
||||
int kptr_restrict __read_mostly;
|
||||
EXPORT_SYMBOL_FOR_MODULES(kptr_restrict, "printf_kunit");
|
||||
EXPORT_SYMBOL_IF_KUNIT(kptr_restrict);
|
||||
|
||||
static noinline_for_stack
|
||||
char *restricted_pointer(char *buf, char *end, const void *ptr,
|
||||
|
||||
Reference in new issue
Block a user