2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

printk changes for 6.17

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAmiQpykACgkQUqAMR0iA
 lPJcrg/9Hez6+zO7LECCn5VkuK5oJWR5CyCfwx14ki8UF38djQGU2frckI5837rE
 MnVoEBexZunK5SXy4MAy7bTCitzR+lMqNtP5uq9J2ovlSPtNlfuJRDr7uGQLDtSS
 M5KZ1qsZnhgwLYeNhfVVToHgp+OwIQb2GcgYmYc8k03fUI1NQpdxIM46DzoTj+06
 x6qgrNsmmJbm8E73VWBByJAEFoq9ugjny8Rt+tYMi/CmhgZpp0ZyF1r5dYfYX/KS
 VS8UQY//aZOFhNsQUAXwP7Ym00CYRgTg7Na+MHivYLXmYGH2gF6tWQhX/eEgHKcJ
 RTmUbLFx70fdBbjJMxv2k8vyMk2sy6sTfJHPqM/NS/Fb0tSPBXQJG/EexzfoqiBc
 wcjgOPkeALIosVdFdTqXxjoIGOP8rqsU4t6Y6WFjJlWK04SBVjxBUofytRdQSxkG
 5Sb0rFVGKrKIkXaVkt4byPa1/BDpfNhfKMYPtQ56pv2VNUgzfye4prUAZHE5pLnK
 8nixeeMtKDFFCBpn6rG5wZW7k2mK5FrWGZUfdfxdK1gWQ1y0kqGy5wa3lNZLcxlH
 l3AtOYoDeWM2DjDVO6WCj8ambEWkbjbGg7tC9TI3F0NvRJSYytTb6npMqb3Gwhcb
 U4NgT+Ho0GJ/5BLUye8HMfhvrGoCfRCeptHtEFXAK7pzKyjc0+c=
 =Mocd
 -----END PGP SIGNATURE-----

Merge tag 'printk-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux

Pull printk updates from Petr Mladek:

 - Add new "hash_pointers=[auto|always|never]" boot parameter to force
   the hashing even with "slab_debug" enabled

 - Allow to stop CPU, after losing nbcon console ownership during
   panic(), even without proper NMI

 - Allow to use the printk kthread immediately even for the 1st
   registered nbcon

 - Compiler warning removal

* tag 'printk-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux:
  printk: nbcon: Allow reacquire during panic
  printk: Allow to use the printk kthread immediately even for 1st nbcon
  slab: Decouple slab_debug and no_hash_pointers
  vsprintf: Use __diag macros to disable '-Wsuggest-attribute=format'
  compiler-gcc.h: Introduce __diag_GCC_all
This commit is contained in:
Linus Torvalds 2025-08-04 10:54:36 -07:00
commit 35a813e010
8 changed files with 170 additions and 58 deletions

View File

@ -1828,6 +1828,27 @@
backtraces on all cpus.
Format: 0 | 1
hash_pointers=
[KNL,EARLY]
By default, when pointers are printed to the console
or buffers via the %p format string, that pointer is
"hashed", i.e. obscured by hashing the pointer value.
This is a security feature that hides actual kernel
addresses from unprivileged users, but it also makes
debugging the kernel more difficult since unequal
pointers can no longer be compared. The choices are:
Format: { auto | always | never }
Default: auto
auto - Hash pointers unless slab_debug is enabled.
always - Always hash pointers (even if slab_debug is
enabled).
never - Never hash pointers. This option should only
be specified when debugging the kernel. Do
not use on production kernels. The boot
param "no_hash_pointers" is an alias for
this mode.
hashdist= [KNL,NUMA] Large hashes allocated during boot
are distributed across NUMA nodes. Defaults on
for 64-bit NUMA, off otherwise.
@ -4216,18 +4237,7 @@
no_hash_pointers
[KNL,EARLY]
Force pointers printed to the console or buffers to be
unhashed. By default, when a pointer is printed via %p
format string, that pointer is "hashed", i.e. obscured
by hashing the pointer value. This is a security feature
that hides actual kernel addresses from unprivileged
users, but it also makes debugging the kernel more
difficult since unequal pointers can no longer be
compared. However, if this command-line option is
specified, then all normal pointers will have their true
value printed. This option should only be specified when
debugging the kernel. Please do not use on production
kernels.
Alias for "hash_pointers=never".
nohibernate [HIBERNATION] Disable hibernation and resume.
@ -6644,6 +6654,10 @@
Documentation/admin-guide/mm/slab.rst.
(slub_debug legacy name also accepted for now)
Using this option implies the "no_hash_pointers"
option which can be undone by adding the
"hash_pointers=always" option.
slab_max_order= [MM]
Determines the maximum allowed order for slabs.
A high setting may cause OOMs due to memory

View File

@ -127,6 +127,8 @@
#define __diag_GCC_8(s)
#endif
#define __diag_GCC_all(s) __diag(s)
#define __diag_ignore_all(option, comment) \
__diag(__diag_GCC_ignore option)

View File

@ -23,7 +23,7 @@ __scanf(2, 0) int vsscanf(const char *, const char *, va_list);
/* These are for specific cases, do not use without real need */
extern bool no_hash_pointers;
int no_hash_pointers_enable(char *str);
void hash_pointers_finalize(bool slub_debug);
/* Used for Rust formatting ('%pA') */
char *rust_fmt_argument(char *buf, char *end, const void *ptr);

View File

@ -64,6 +64,7 @@ struct dev_printk_info;
extern struct printk_ringbuffer *prb;
extern bool printk_kthreads_running;
extern bool printk_kthreads_ready;
extern bool debug_non_panic_cpus;
__printf(4, 0)
@ -179,6 +180,7 @@ static inline void nbcon_kthread_wake(struct console *con)
#define PRINTKRB_RECORD_MAX 0
#define printk_kthreads_running (false)
#define printk_kthreads_ready (false)
/*
* In !PRINTK builds we still export console_sem

View File

@ -214,8 +214,9 @@ static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq)
/**
* nbcon_context_try_acquire_direct - Try to acquire directly
* @ctxt: The context of the caller
* @cur: The current console state
* @ctxt: The context of the caller
* @cur: The current console state
* @is_reacquire: This acquire is a reacquire
*
* Acquire the console when it is released. Also acquire the console when
* the current owner has a lower priority and the console is in a safe state.
@ -225,17 +226,17 @@ static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq)
*
* Errors:
*
* -EPERM: A panic is in progress and this is not the panic CPU.
* Or the current owner or waiter has the same or higher
* priority. No acquire method can be successful in
* this case.
* -EPERM: A panic is in progress and this is neither the panic
* CPU nor is this a reacquire. Or the current owner or
* waiter has the same or higher priority. No acquire
* method can be successful in these cases.
*
* -EBUSY: The current owner has a lower priority but the console
* in an unsafe state. The caller should try using
* the handover acquire method.
*/
static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
struct nbcon_state *cur)
struct nbcon_state *cur, bool is_reacquire)
{
unsigned int cpu = smp_processor_id();
struct console *con = ctxt->console;
@ -243,14 +244,20 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
do {
/*
* Panic does not imply that the console is owned. However, it
* is critical that non-panic CPUs during panic are unable to
* acquire ownership in order to satisfy the assumptions of
* nbcon_waiter_matches(). In particular, the assumption that
* lower priorities are ignored during panic.
* Panic does not imply that the console is owned. However,
* since all non-panic CPUs are stopped during panic(), it
* is safer to have them avoid gaining console ownership.
*
* If this acquire is a reacquire (and an unsafe takeover
* has not previously occurred) then it is allowed to attempt
* a direct acquire in panic. This gives console drivers an
* opportunity to perform any necessary cleanup if they were
* interrupted by the panic CPU while printing.
*/
if (other_cpu_in_panic())
if (other_cpu_in_panic() &&
(!is_reacquire || cur->unsafe_takeover)) {
return -EPERM;
}
if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio)
return -EPERM;
@ -301,8 +308,9 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
* Event #1 implies this context is EMERGENCY.
* Event #2 implies the new context is PANIC.
* Event #3 occurs when panic() has flushed the console.
* Events #4 and #5 are not possible due to the other_cpu_in_panic()
* check in nbcon_context_try_acquire_direct().
* Event #4 occurs when a non-panic CPU reacquires.
* Event #5 is not possible due to the other_cpu_in_panic() check
* in nbcon_context_try_acquire_handover().
*/
return (cur->req_prio == expected_prio);
@ -431,6 +439,16 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
WARN_ON_ONCE(!cur->unsafe);
/*
* Panic does not imply that the console is owned. However, it
* is critical that non-panic CPUs during panic are unable to
* wait for a handover in order to satisfy the assumptions of
* nbcon_waiter_matches(). In particular, the assumption that
* lower priorities are ignored during panic.
*/
if (other_cpu_in_panic())
return -EPERM;
/* Handover is not possible on the same CPU. */
if (cur->cpu == cpu)
return -EBUSY;
@ -558,7 +576,8 @@ static struct printk_buffers panic_nbcon_pbufs;
/**
* nbcon_context_try_acquire - Try to acquire nbcon console
* @ctxt: The context of the caller
* @ctxt: The context of the caller
* @is_reacquire: This acquire is a reacquire
*
* Context: Under @ctxt->con->device_lock() or local_irq_save().
* Return: True if the console was acquired. False otherwise.
@ -568,7 +587,7 @@ static struct printk_buffers panic_nbcon_pbufs;
* in an unsafe state. Otherwise, on success the caller may assume
* the console is not in an unsafe state.
*/
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire)
{
unsigned int cpu = smp_processor_id();
struct console *con = ctxt->console;
@ -577,7 +596,7 @@ static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
nbcon_state_read(con, &cur);
try_again:
err = nbcon_context_try_acquire_direct(ctxt, &cur);
err = nbcon_context_try_acquire_direct(ctxt, &cur, is_reacquire);
if (err != -EBUSY)
goto out;
@ -913,7 +932,7 @@ void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
while (!nbcon_context_try_acquire(ctxt))
while (!nbcon_context_try_acquire(ctxt, true))
cpu_relax();
nbcon_write_context_set_buf(wctxt, NULL, 0);
@ -1101,7 +1120,7 @@ static bool nbcon_emit_one(struct nbcon_write_context *wctxt, bool use_atomic)
cant_migrate();
}
if (!nbcon_context_try_acquire(ctxt))
if (!nbcon_context_try_acquire(ctxt, false))
goto out;
/*
@ -1486,7 +1505,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
ctxt->prio = nbcon_get_default_prio();
ctxt->allow_unsafe_takeover = allow_unsafe_takeover;
if (!nbcon_context_try_acquire(ctxt))
if (!nbcon_context_try_acquire(ctxt, false))
return -EPERM;
while (nbcon_seq_read(con) < stop_seq) {
@ -1671,6 +1690,9 @@ bool nbcon_alloc(struct console *con)
{
struct nbcon_state state = { };
/* Synchronize the kthread start. */
lockdep_assert_console_list_lock_held();
/* The write_thread() callback is mandatory. */
if (WARN_ON(!con->write_thread))
return false;
@ -1701,12 +1723,15 @@ bool nbcon_alloc(struct console *con)
return false;
}
if (printk_kthreads_running) {
if (printk_kthreads_ready && !have_boot_console) {
if (!nbcon_kthread_create(con)) {
kfree(con->pbufs);
con->pbufs = NULL;
return false;
}
/* Might be the first kthread. */
printk_kthreads_running = true;
}
}
@ -1716,14 +1741,30 @@ bool nbcon_alloc(struct console *con)
/**
* nbcon_free - Free and cleanup the nbcon console specific data
* @con: Console to free/cleanup nbcon data
*
* Important: @have_nbcon_console must be updated before calling
* this function. In particular, it can be set only when there
* is still another nbcon console registered.
*/
void nbcon_free(struct console *con)
{
struct nbcon_state state = { };
if (printk_kthreads_running)
/* Synchronize the kthread stop. */
lockdep_assert_console_list_lock_held();
if (printk_kthreads_running) {
nbcon_kthread_stop(con);
/* Might be the last nbcon console.
*
* Do not rely on printk_kthreads_check_locked(). It is not
* called in some code paths, see nbcon_free() callers.
*/
if (!have_nbcon_console)
printk_kthreads_running = false;
}
nbcon_state_set(con, &state);
/* Boot consoles share global printk buffers. */
@ -1762,7 +1803,7 @@ bool nbcon_device_try_acquire(struct console *con)
ctxt->console = con;
ctxt->prio = NBCON_PRIO_NORMAL;
if (!nbcon_context_try_acquire(ctxt))
if (!nbcon_context_try_acquire(ctxt, false))
return false;
if (!nbcon_context_enter_unsafe(ctxt))

View File

@ -3574,7 +3574,7 @@ EXPORT_SYMBOL(console_resume);
static int unregister_console_locked(struct console *console);
/* True when system boot is far enough to create printer threads. */
static bool printk_kthreads_ready __ro_after_init;
bool printk_kthreads_ready __ro_after_init;
static struct task_struct *printk_legacy_kthread;
@ -3713,6 +3713,7 @@ static void printk_kthreads_check_locked(void)
if (!printk_kthreads_ready)
return;
/* Start or stop the legacy kthread when needed. */
if (have_legacy_console || have_boot_console) {
if (!printk_legacy_kthread &&
force_legacy_kthread() &&
@ -4204,14 +4205,6 @@ static int unregister_console_locked(struct console *console)
*/
synchronize_srcu(&console_srcu);
if (console->flags & CON_NBCON)
nbcon_free(console);
console_sysfs_notify();
if (console->exit)
res = console->exit(console);
/*
* With this console gone, the global flags tracking registered
* console types may have changed. Update them.
@ -4232,6 +4225,15 @@ static int unregister_console_locked(struct console *console)
if (!found_nbcon_con)
have_nbcon_console = found_nbcon_con;
/* @have_nbcon_console must be updated before calling nbcon_free(). */
if (console->flags & CON_NBCON)
nbcon_free(console);
console_sysfs_notify();
if (console->exit)
res = console->exit(console);
/* Changed console list, may require printer threads to start/stop. */
printk_kthreads_check_locked();

View File

@ -60,6 +60,20 @@
bool no_hash_pointers __ro_after_init;
EXPORT_SYMBOL_GPL(no_hash_pointers);
/*
* Hashed pointers policy selected by "hash_pointers=..." boot param
*
* `auto` - Hashed pointers enabled unless disabled by slub_debug_enabled=true
* `always` - Hashed pointers enabled unconditionally
* `never` - Hashed pointers disabled unconditionally
*/
enum hash_pointers_policy {
HASH_PTR_AUTO = 0,
HASH_PTR_ALWAYS,
HASH_PTR_NEVER
};
static enum hash_pointers_policy hash_pointers_mode __initdata;
noinline
static unsigned long long simple_strntoull(const char *startp, char **endp, unsigned int base, size_t max_chars)
{
@ -1699,10 +1713,9 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
return buf;
}
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
#endif
__diag_push();
__diag_ignore(GCC, all, "-Wsuggest-attribute=format",
"Not a valid __printf() conversion candidate.");
static char *va_format(char *buf, char *end, struct va_format *va_fmt,
struct printf_spec spec)
{
@ -1717,7 +1730,7 @@ static char *va_format(char *buf, char *end, struct va_format *va_fmt,
return buf;
}
#pragma GCC diagnostic pop
__diag_pop();
static noinline_for_stack
char *uuid_string(char *buf, char *end, const u8 *addr,
@ -2289,12 +2302,23 @@ char *resource_or_range(const char *fmt, char *buf, char *end, void *ptr,
return resource_string(buf, end, ptr, spec, fmt);
}
int __init no_hash_pointers_enable(char *str)
void __init hash_pointers_finalize(bool slub_debug)
{
if (no_hash_pointers)
return 0;
switch (hash_pointers_mode) {
case HASH_PTR_ALWAYS:
no_hash_pointers = false;
break;
case HASH_PTR_NEVER:
no_hash_pointers = true;
break;
case HASH_PTR_AUTO:
default:
no_hash_pointers = slub_debug;
break;
}
no_hash_pointers = true;
if (!no_hash_pointers)
return;
pr_warn("**********************************************************\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
@ -2307,11 +2331,39 @@ int __init no_hash_pointers_enable(char *str)
pr_warn("** the kernel, report this immediately to your system **\n");
pr_warn("** administrator! **\n");
pr_warn("** **\n");
pr_warn("** Use hash_pointers=always to force this mode off **\n");
pr_warn("** **\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("**********************************************************\n");
}
static int __init hash_pointers_mode_parse(char *str)
{
if (!str) {
pr_warn("Hash pointers mode empty; falling back to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
} else if (strncmp(str, "auto", 4) == 0) {
pr_info("Hash pointers mode set to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
} else if (strncmp(str, "never", 5) == 0) {
pr_info("Hash pointers mode set to never.\n");
hash_pointers_mode = HASH_PTR_NEVER;
} else if (strncmp(str, "always", 6) == 0) {
pr_info("Hash pointers mode set to always.\n");
hash_pointers_mode = HASH_PTR_ALWAYS;
} else {
pr_warn("Unknown hash_pointers mode '%s' specified; assuming auto.\n", str);
hash_pointers_mode = HASH_PTR_AUTO;
}
return 0;
}
early_param("hash_pointers", hash_pointers_mode_parse);
static int __init no_hash_pointers_enable(char *str)
{
return hash_pointers_mode_parse("never");
}
early_param("no_hash_pointers", no_hash_pointers_enable);
/*

View File

@ -6312,9 +6312,8 @@ void __init kmem_cache_init(void)
if (debug_guardpage_minorder())
slub_max_order = 0;
/* Print slub debugging pointers without hashing */
if (__slub_debug_enabled())
no_hash_pointers_enable(NULL);
/* Inform pointer hashing choice about slub debugging state. */
hash_pointers_finalize(__slub_debug_enabled());
kmem_cache_node = &boot_kmem_cache_node;
kmem_cache = &boot_kmem_cache;