mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
printk changes for 6.13
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAmc7PG8ACgkQUqAMR0iA lPKJmg//VqbNkf+RW22U0LJ/BTkWLuV9af6WGRE2E7LFcZdzIhJz7YKkzEo2FkQW 9i/SajjbKOWJ7wsG6TgX4rbQbK27lTrmpctiJAg9NehuF0IjvJ3xb/no+MQnlqts OtD6icHs6WLeUhctz0njXMyn6W2zhNnIEIZy+ZLmg1hPdGugyoYkSxegY+7D1kse OKNMpC//2WwtKbcFxM/wust+WeWXRJ2Qby9WpM1ELYs8N+OWY3xX76h0H0rzN5J8 G+T9sHLnytETczZMcoB+2I2WJuXsREXjgRC0s2ZYn3AFpwpq/+ULaR8k0eGyLiCJ /MePtV70ArUfIzVCMShFfdaX5+V8fAXEQznuAXkLbO1t/7Vd8jIKCk00INvRhzyB kSRYC55QoRe43+Zxhe7vyqvj0o3ovZFjVIZ7lEJOSnoqB26N923j/eIPN1Aq4e1I mjWim6kJ+QvW+dfxA9iy115IKXKrf3qe2p16ayzcI9O/JyUw+Vseyqh+n2I0/gUQ Ui6fV8tgu5tBkvhXgLYQDPFQ9EynanLdjOGQxxIitlmZheOT2B+IHU/699VrOacN yOnU+vPIDkZHEgGyw29Qp0kO5msC4DB6zq7PQLCHMSnmvULENgYDvkUNfnE6N6fn csYYha2gVG4mdsL+WyZKDEhw80vsBKkIn0Fx9ntRZOBiHEDZ5UU= =89Bg -----END PGP SIGNATURE----- Merge tag 'printk-for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux Pull printk updates from Petr Mladek: - Print more precise information about the printk log buffer memory usage. - Make sure that the sysrq title is shown on the console even when deferred. - Do not enable earlycon by `console=` which is meant to disable the default console. * tag 'printk-for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: printk: add dummy printk_force_console_enter/exit helpers tty: sysrq: Use printk_force_console context on __handle_sysrq printk: Introduce FORCE_CON flag printk: Improve memory usage logging during boot init: Don't proxy `console=` to earlycon
This commit is contained in:
commit
7d66d3ab13
@ -248,6 +248,29 @@ static int __init param_setup_earlycon(char *buf)
|
|||||||
}
|
}
|
||||||
early_param("earlycon", param_setup_earlycon);
|
early_param("earlycon", param_setup_earlycon);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The `console` parameter is overloaded. It's handled here as an early param
|
||||||
|
* and in `printk.c` as a late param. It's possible to specify an early
|
||||||
|
* `bootconsole` using `earlycon=uartXXXX` (handled above), or via
|
||||||
|
* the `console=uartXXX` alias. See the comment in `8250_early.c`.
|
||||||
|
*/
|
||||||
|
static int __init param_setup_earlycon_console_alias(char *buf)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* A plain `console` parameter must not enable the SPCR `bootconsole`
|
||||||
|
* like a plain `earlycon` does.
|
||||||
|
*
|
||||||
|
* A `console=` parameter that specifies an empty value is used to
|
||||||
|
* disable the `console`, not the `earlycon` `bootconsole`. The
|
||||||
|
* disabling of the `console` is handled by `printk.c`.
|
||||||
|
*/
|
||||||
|
if (!buf || !buf[0])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return param_setup_earlycon(buf);
|
||||||
|
}
|
||||||
|
early_param("console", param_setup_earlycon_console_alias);
|
||||||
|
|
||||||
#ifdef CONFIG_OF_EARLY_FLATTREE
|
#ifdef CONFIG_OF_EARLY_FLATTREE
|
||||||
|
|
||||||
int __init of_setup_earlycon(const struct earlycon_id *match,
|
int __init of_setup_earlycon(const struct earlycon_id *match,
|
||||||
|
@ -583,7 +583,6 @@ static void __sysrq_put_key_op(u8 key, const struct sysrq_key_op *op_p)
|
|||||||
void __handle_sysrq(u8 key, bool check_mask)
|
void __handle_sysrq(u8 key, bool check_mask)
|
||||||
{
|
{
|
||||||
const struct sysrq_key_op *op_p;
|
const struct sysrq_key_op *op_p;
|
||||||
int orig_log_level;
|
|
||||||
int orig_suppress_printk;
|
int orig_suppress_printk;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -593,13 +592,12 @@ void __handle_sysrq(u8 key, bool check_mask)
|
|||||||
rcu_sysrq_start();
|
rcu_sysrq_start();
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
/*
|
/*
|
||||||
* Raise the apparent loglevel to maximum so that the sysrq header
|
* Enter in the force_console context so that sysrq header is shown to
|
||||||
* is shown to provide the user with positive feedback. We do not
|
* provide the user with positive feedback. We do not simply emit this
|
||||||
* simply emit this at KERN_EMERG as that would change message
|
* at KERN_EMERG as that would change message routing in the consumers
|
||||||
* routing in the consumers of /proc/kmsg.
|
* of /proc/kmsg.
|
||||||
*/
|
*/
|
||||||
orig_log_level = console_loglevel;
|
printk_force_console_enter();
|
||||||
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
|
|
||||||
|
|
||||||
op_p = __sysrq_get_key_op(key);
|
op_p = __sysrq_get_key_op(key);
|
||||||
if (op_p) {
|
if (op_p) {
|
||||||
@ -609,11 +607,11 @@ void __handle_sysrq(u8 key, bool check_mask)
|
|||||||
*/
|
*/
|
||||||
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
|
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
|
||||||
pr_info("%s\n", op_p->action_msg);
|
pr_info("%s\n", op_p->action_msg);
|
||||||
console_loglevel = orig_log_level;
|
printk_force_console_exit();
|
||||||
op_p->handler(key);
|
op_p->handler(key);
|
||||||
} else {
|
} else {
|
||||||
pr_info("This sysrq operation is disabled.\n");
|
pr_info("This sysrq operation is disabled.\n");
|
||||||
console_loglevel = orig_log_level;
|
printk_force_console_exit();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pr_info("HELP : ");
|
pr_info("HELP : ");
|
||||||
@ -631,7 +629,7 @@ void __handle_sysrq(u8 key, bool check_mask)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pr_cont("\n");
|
pr_cont("\n");
|
||||||
console_loglevel = orig_log_level;
|
printk_force_console_exit();
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
rcu_sysrq_end();
|
rcu_sysrq_end();
|
||||||
|
@ -166,6 +166,9 @@ __printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
|
|||||||
extern void __printk_deferred_enter(void);
|
extern void __printk_deferred_enter(void);
|
||||||
extern void __printk_deferred_exit(void);
|
extern void __printk_deferred_exit(void);
|
||||||
|
|
||||||
|
extern void printk_force_console_enter(void);
|
||||||
|
extern void printk_force_console_exit(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The printk_deferred_enter/exit macros are available only as a hack for
|
* The printk_deferred_enter/exit macros are available only as a hack for
|
||||||
* some code paths that need to defer all printk console printing. Interrupts
|
* some code paths that need to defer all printk console printing. Interrupts
|
||||||
@ -229,6 +232,14 @@ static inline void printk_deferred_exit(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void printk_force_console_enter(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void printk_force_console_exit(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline int printk_ratelimit(void)
|
static inline int printk_ratelimit(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -754,10 +754,7 @@ static int __init do_early_param(char *param, char *val,
|
|||||||
const struct obs_kernel_param *p;
|
const struct obs_kernel_param *p;
|
||||||
|
|
||||||
for (p = __setup_start; p < __setup_end; p++) {
|
for (p = __setup_start; p < __setup_end; p++) {
|
||||||
if ((p->early && parameq(param, p->str)) ||
|
if (p->early && parameq(param, p->str)) {
|
||||||
(strcmp(param, "console") == 0 &&
|
|
||||||
strcmp(p->str, "earlycon") == 0)
|
|
||||||
) {
|
|
||||||
if (p->setup_func(val) != 0)
|
if (p->setup_func(val) != 0)
|
||||||
pr_warn("Malformed early option '%s'\n", param);
|
pr_warn("Malformed early option '%s'\n", param);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
|
|||||||
|
|
||||||
/* Flags for a single printk record. */
|
/* Flags for a single printk record. */
|
||||||
enum printk_info_flags {
|
enum printk_info_flags {
|
||||||
|
/* always show on console, ignore console_loglevel */
|
||||||
|
LOG_FORCE_CON = 1,
|
||||||
LOG_NEWLINE = 2, /* text ended with a newline */
|
LOG_NEWLINE = 2, /* text ended with a newline */
|
||||||
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
||||||
};
|
};
|
||||||
@ -90,6 +92,7 @@ bool printk_percpu_data_ready(void);
|
|||||||
|
|
||||||
void defer_console_output(void);
|
void defer_console_output(void);
|
||||||
bool is_printk_legacy_deferred(void);
|
bool is_printk_legacy_deferred(void);
|
||||||
|
bool is_printk_force_console(void);
|
||||||
|
|
||||||
u16 printk_parse_prefix(const char *text, int *level,
|
u16 printk_parse_prefix(const char *text, int *level,
|
||||||
enum printk_info_flags *flags);
|
enum printk_info_flags *flags);
|
||||||
|
@ -1157,6 +1157,17 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
|
|||||||
|
|
||||||
static char setup_text_buf[PRINTKRB_RECORD_MAX] __initdata;
|
static char setup_text_buf[PRINTKRB_RECORD_MAX] __initdata;
|
||||||
|
|
||||||
|
static void print_log_buf_usage_stats(void)
|
||||||
|
{
|
||||||
|
unsigned int descs_count = log_buf_len >> PRB_AVGBITS;
|
||||||
|
size_t meta_data_size;
|
||||||
|
|
||||||
|
meta_data_size = descs_count * (sizeof(struct prb_desc) + sizeof(struct printk_info));
|
||||||
|
|
||||||
|
pr_info("log buffer data + meta data: %u + %zu = %zu bytes\n",
|
||||||
|
log_buf_len, meta_data_size, log_buf_len + meta_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
void __init setup_log_buf(int early)
|
void __init setup_log_buf(int early)
|
||||||
{
|
{
|
||||||
struct printk_info *new_infos;
|
struct printk_info *new_infos;
|
||||||
@ -1186,20 +1197,25 @@ void __init setup_log_buf(int early)
|
|||||||
if (!early && !new_log_buf_len)
|
if (!early && !new_log_buf_len)
|
||||||
log_buf_add_cpu();
|
log_buf_add_cpu();
|
||||||
|
|
||||||
if (!new_log_buf_len)
|
if (!new_log_buf_len) {
|
||||||
|
/* Show the memory stats only once. */
|
||||||
|
if (!early)
|
||||||
|
goto out;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
new_descs_count = new_log_buf_len >> PRB_AVGBITS;
|
new_descs_count = new_log_buf_len >> PRB_AVGBITS;
|
||||||
if (new_descs_count == 0) {
|
if (new_descs_count == 0) {
|
||||||
pr_err("new_log_buf_len: %lu too small\n", new_log_buf_len);
|
pr_err("new_log_buf_len: %lu too small\n", new_log_buf_len);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_log_buf = memblock_alloc(new_log_buf_len, LOG_ALIGN);
|
new_log_buf = memblock_alloc(new_log_buf_len, LOG_ALIGN);
|
||||||
if (unlikely(!new_log_buf)) {
|
if (unlikely(!new_log_buf)) {
|
||||||
pr_err("log_buf_len: %lu text bytes not available\n",
|
pr_err("log_buf_len: %lu text bytes not available\n",
|
||||||
new_log_buf_len);
|
new_log_buf_len);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_descs_size = new_descs_count * sizeof(struct prb_desc);
|
new_descs_size = new_descs_count * sizeof(struct prb_desc);
|
||||||
@ -1262,7 +1278,7 @@ void __init setup_log_buf(int early)
|
|||||||
prb_next_seq(&printk_rb_static) - seq);
|
prb_next_seq(&printk_rb_static) - seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("log_buf_len: %u bytes\n", log_buf_len);
|
print_log_buf_usage_stats();
|
||||||
pr_info("early log buf free: %u(%u%%)\n",
|
pr_info("early log buf free: %u(%u%%)\n",
|
||||||
free, (free * 100) / __LOG_BUF_LEN);
|
free, (free * 100) / __LOG_BUF_LEN);
|
||||||
return;
|
return;
|
||||||
@ -1271,6 +1287,8 @@ void __init setup_log_buf(int early)
|
|||||||
memblock_free(new_descs, new_descs_size);
|
memblock_free(new_descs, new_descs_size);
|
||||||
err_free_log_buf:
|
err_free_log_buf:
|
||||||
memblock_free(new_log_buf, new_log_buf_len);
|
memblock_free(new_log_buf, new_log_buf_len);
|
||||||
|
out:
|
||||||
|
print_log_buf_usage_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __read_mostly ignore_loglevel;
|
static bool __read_mostly ignore_loglevel;
|
||||||
@ -1320,11 +1338,11 @@ static void boot_delay_msec(int level)
|
|||||||
{
|
{
|
||||||
unsigned long long k;
|
unsigned long long k;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
bool suppress = !is_printk_force_console() &&
|
||||||
|
suppress_message_printing(level);
|
||||||
|
|
||||||
if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
|
if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING) || suppress)
|
||||||
|| suppress_message_printing(level)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
k = (unsigned long long)loops_per_msec * boot_delay;
|
k = (unsigned long long)loops_per_msec * boot_delay;
|
||||||
|
|
||||||
@ -2274,6 +2292,9 @@ int vprintk_store(int facility, int level,
|
|||||||
if (dev_info)
|
if (dev_info)
|
||||||
flags |= LOG_NEWLINE;
|
flags |= LOG_NEWLINE;
|
||||||
|
|
||||||
|
if (is_printk_force_console())
|
||||||
|
flags |= LOG_FORCE_CON;
|
||||||
|
|
||||||
if (flags & LOG_CONT) {
|
if (flags & LOG_CONT) {
|
||||||
prb_rec_init_wr(&r, reserve_size);
|
prb_rec_init_wr(&r, reserve_size);
|
||||||
if (prb_reserve_in_last(&e, prb, &r, caller_id, PRINTKRB_RECORD_MAX)) {
|
if (prb_reserve_in_last(&e, prb, &r, caller_id, PRINTKRB_RECORD_MAX)) {
|
||||||
@ -2281,6 +2302,9 @@ int vprintk_store(int facility, int level,
|
|||||||
facility, &flags, fmt, args);
|
facility, &flags, fmt, args);
|
||||||
r.info->text_len += text_len;
|
r.info->text_len += text_len;
|
||||||
|
|
||||||
|
if (flags & LOG_FORCE_CON)
|
||||||
|
r.info->flags |= LOG_FORCE_CON;
|
||||||
|
|
||||||
if (flags & LOG_NEWLINE) {
|
if (flags & LOG_NEWLINE) {
|
||||||
r.info->flags |= LOG_NEWLINE;
|
r.info->flags |= LOG_NEWLINE;
|
||||||
prb_final_commit(&e);
|
prb_final_commit(&e);
|
||||||
@ -2948,6 +2972,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|||||||
struct printk_info info;
|
struct printk_info info;
|
||||||
struct printk_record r;
|
struct printk_record r;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
bool force_con;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Formatting extended messages requires a separate buffer, so use the
|
* Formatting extended messages requires a separate buffer, so use the
|
||||||
@ -2966,9 +2991,13 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|||||||
|
|
||||||
pmsg->seq = r.info->seq;
|
pmsg->seq = r.info->seq;
|
||||||
pmsg->dropped = r.info->seq - seq;
|
pmsg->dropped = r.info->seq - seq;
|
||||||
|
force_con = r.info->flags & LOG_FORCE_CON;
|
||||||
|
|
||||||
/* Skip record that has level above the console loglevel. */
|
/*
|
||||||
if (may_suppress && suppress_message_printing(r.info->level))
|
* Skip records that are not forced to be printed on consoles and that
|
||||||
|
* has level above the console loglevel.
|
||||||
|
*/
|
||||||
|
if (!force_con && may_suppress && suppress_message_printing(r.info->level))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (is_extended) {
|
if (is_extended) {
|
||||||
|
@ -12,6 +12,24 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
/* Context where printk messages are never suppressed */
|
||||||
|
static atomic_t force_con;
|
||||||
|
|
||||||
|
void printk_force_console_enter(void)
|
||||||
|
{
|
||||||
|
atomic_inc(&force_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printk_force_console_exit(void)
|
||||||
|
{
|
||||||
|
atomic_dec(&force_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_printk_force_console(void)
|
||||||
|
{
|
||||||
|
return atomic_read(&force_con);
|
||||||
|
}
|
||||||
|
|
||||||
static DEFINE_PER_CPU(int, printk_context);
|
static DEFINE_PER_CPU(int, printk_context);
|
||||||
|
|
||||||
/* Can be preempted by NMI. */
|
/* Can be preempted by NMI. */
|
||||||
|
Loading…
Reference in New Issue
Block a user