Skip to content

Commit 7d66d3a

Browse files
committed
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
2 parents c3cda60 + 34767e5 commit 7d66d3a

File tree

7 files changed

+102
-23
lines changed

7 files changed

+102
-23
lines changed

drivers/tty/serial/earlycon.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,29 @@ static int __init param_setup_earlycon(char *buf)
248248
}
249249
early_param("earlycon", param_setup_earlycon);
250250

251+
/*
252+
* The `console` parameter is overloaded. It's handled here as an early param
253+
* and in `printk.c` as a late param. It's possible to specify an early
254+
* `bootconsole` using `earlycon=uartXXXX` (handled above), or via
255+
* the `console=uartXXX` alias. See the comment in `8250_early.c`.
256+
*/
257+
static int __init param_setup_earlycon_console_alias(char *buf)
258+
{
259+
/*
260+
* A plain `console` parameter must not enable the SPCR `bootconsole`
261+
* like a plain `earlycon` does.
262+
*
263+
* A `console=` parameter that specifies an empty value is used to
264+
* disable the `console`, not the `earlycon` `bootconsole`. The
265+
* disabling of the `console` is handled by `printk.c`.
266+
*/
267+
if (!buf || !buf[0])
268+
return 0;
269+
270+
return param_setup_earlycon(buf);
271+
}
272+
early_param("console", param_setup_earlycon_console_alias);
273+
251274
#ifdef CONFIG_OF_EARLY_FLATTREE
252275

253276
int __init of_setup_earlycon(const struct earlycon_id *match,

drivers/tty/sysrq.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,6 @@ static void __sysrq_put_key_op(u8 key, const struct sysrq_key_op *op_p)
583583
void __handle_sysrq(u8 key, bool check_mask)
584584
{
585585
const struct sysrq_key_op *op_p;
586-
int orig_log_level;
587586
int orig_suppress_printk;
588587
int i;
589588

@@ -593,13 +592,12 @@ void __handle_sysrq(u8 key, bool check_mask)
593592
rcu_sysrq_start();
594593
rcu_read_lock();
595594
/*
596-
* Raise the apparent loglevel to maximum so that the sysrq header
597-
* is shown to provide the user with positive feedback. We do not
598-
* simply emit this at KERN_EMERG as that would change message
599-
* routing in the consumers of /proc/kmsg.
595+
* Enter in the force_console context so that sysrq header is shown to
596+
* provide the user with positive feedback. We do not simply emit this
597+
* at KERN_EMERG as that would change message routing in the consumers
598+
* of /proc/kmsg.
600599
*/
601-
orig_log_level = console_loglevel;
602-
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
600+
printk_force_console_enter();
603601

604602
op_p = __sysrq_get_key_op(key);
605603
if (op_p) {
@@ -609,11 +607,11 @@ void __handle_sysrq(u8 key, bool check_mask)
609607
*/
610608
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
611609
pr_info("%s\n", op_p->action_msg);
612-
console_loglevel = orig_log_level;
610+
printk_force_console_exit();
613611
op_p->handler(key);
614612
} else {
615613
pr_info("This sysrq operation is disabled.\n");
616-
console_loglevel = orig_log_level;
614+
printk_force_console_exit();
617615
}
618616
} else {
619617
pr_info("HELP : ");
@@ -631,7 +629,7 @@ void __handle_sysrq(u8 key, bool check_mask)
631629
}
632630
}
633631
pr_cont("\n");
634-
console_loglevel = orig_log_level;
632+
printk_force_console_exit();
635633
}
636634
rcu_read_unlock();
637635
rcu_sysrq_end();

include/linux/printk.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ __printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
166166
extern void __printk_deferred_enter(void);
167167
extern void __printk_deferred_exit(void);
168168

169+
extern void printk_force_console_enter(void);
170+
extern void printk_force_console_exit(void);
171+
169172
/*
170173
* The printk_deferred_enter/exit macros are available only as a hack for
171174
* some code paths that need to defer all printk console printing. Interrupts
@@ -229,6 +232,14 @@ static inline void printk_deferred_exit(void)
229232
{
230233
}
231234

235+
static inline void printk_force_console_enter(void)
236+
{
237+
}
238+
239+
static inline void printk_force_console_exit(void)
240+
{
241+
}
242+
232243
static inline int printk_ratelimit(void)
233244
{
234245
return 0;

init/main.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -754,10 +754,7 @@ static int __init do_early_param(char *param, char *val,
754754
const struct obs_kernel_param *p;
755755

756756
for (p = __setup_start; p < __setup_end; p++) {
757-
if ((p->early && parameq(param, p->str)) ||
758-
(strcmp(param, "console") == 0 &&
759-
strcmp(p->str, "earlycon") == 0)
760-
) {
757+
if (p->early && parameq(param, p->str)) {
761758
if (p->setup_func(val) != 0)
762759
pr_warn("Malformed early option '%s'\n", param);
763760
}

kernel/printk/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
5353

5454
/* Flags for a single printk record. */
5555
enum printk_info_flags {
56+
/* always show on console, ignore console_loglevel */
57+
LOG_FORCE_CON = 1,
5658
LOG_NEWLINE = 2, /* text ended with a newline */
5759
LOG_CONT = 8, /* text is a fragment of a continuation line */
5860
};
@@ -90,6 +92,7 @@ bool printk_percpu_data_ready(void);
9092

9193
void defer_console_output(void);
9294
bool is_printk_legacy_deferred(void);
95+
bool is_printk_force_console(void);
9396

9497
u16 printk_parse_prefix(const char *text, int *level,
9598
enum printk_info_flags *flags);

kernel/printk/printk.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,17 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
11571157

11581158
static char setup_text_buf[PRINTKRB_RECORD_MAX] __initdata;
11591159

1160+
static void print_log_buf_usage_stats(void)
1161+
{
1162+
unsigned int descs_count = log_buf_len >> PRB_AVGBITS;
1163+
size_t meta_data_size;
1164+
1165+
meta_data_size = descs_count * (sizeof(struct prb_desc) + sizeof(struct printk_info));
1166+
1167+
pr_info("log buffer data + meta data: %u + %zu = %zu bytes\n",
1168+
log_buf_len, meta_data_size, log_buf_len + meta_data_size);
1169+
}
1170+
11601171
void __init setup_log_buf(int early)
11611172
{
11621173
struct printk_info *new_infos;
@@ -1186,20 +1197,25 @@ void __init setup_log_buf(int early)
11861197
if (!early && !new_log_buf_len)
11871198
log_buf_add_cpu();
11881199

1189-
if (!new_log_buf_len)
1200+
if (!new_log_buf_len) {
1201+
/* Show the memory stats only once. */
1202+
if (!early)
1203+
goto out;
1204+
11901205
return;
1206+
}
11911207

11921208
new_descs_count = new_log_buf_len >> PRB_AVGBITS;
11931209
if (new_descs_count == 0) {
11941210
pr_err("new_log_buf_len: %lu too small\n", new_log_buf_len);
1195-
return;
1211+
goto out;
11961212
}
11971213

11981214
new_log_buf = memblock_alloc(new_log_buf_len, LOG_ALIGN);
11991215
if (unlikely(!new_log_buf)) {
12001216
pr_err("log_buf_len: %lu text bytes not available\n",
12011217
new_log_buf_len);
1202-
return;
1218+
goto out;
12031219
}
12041220

12051221
new_descs_size = new_descs_count * sizeof(struct prb_desc);
@@ -1262,7 +1278,7 @@ void __init setup_log_buf(int early)
12621278
prb_next_seq(&printk_rb_static) - seq);
12631279
}
12641280

1265-
pr_info("log_buf_len: %u bytes\n", log_buf_len);
1281+
print_log_buf_usage_stats();
12661282
pr_info("early log buf free: %u(%u%%)\n",
12671283
free, (free * 100) / __LOG_BUF_LEN);
12681284
return;
@@ -1271,6 +1287,8 @@ void __init setup_log_buf(int early)
12711287
memblock_free(new_descs, new_descs_size);
12721288
err_free_log_buf:
12731289
memblock_free(new_log_buf, new_log_buf_len);
1290+
out:
1291+
print_log_buf_usage_stats();
12741292
}
12751293

12761294
static bool __read_mostly ignore_loglevel;
@@ -1320,11 +1338,11 @@ static void boot_delay_msec(int level)
13201338
{
13211339
unsigned long long k;
13221340
unsigned long timeout;
1341+
bool suppress = !is_printk_force_console() &&
1342+
suppress_message_printing(level);
13231343

1324-
if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
1325-
|| suppress_message_printing(level)) {
1344+
if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING) || suppress)
13261345
return;
1327-
}
13281346

13291347
k = (unsigned long long)loops_per_msec * boot_delay;
13301348

@@ -2274,13 +2292,19 @@ int vprintk_store(int facility, int level,
22742292
if (dev_info)
22752293
flags |= LOG_NEWLINE;
22762294

2295+
if (is_printk_force_console())
2296+
flags |= LOG_FORCE_CON;
2297+
22772298
if (flags & LOG_CONT) {
22782299
prb_rec_init_wr(&r, reserve_size);
22792300
if (prb_reserve_in_last(&e, prb, &r, caller_id, PRINTKRB_RECORD_MAX)) {
22802301
text_len = printk_sprint(&r.text_buf[r.info->text_len], reserve_size,
22812302
facility, &flags, fmt, args);
22822303
r.info->text_len += text_len;
22832304

2305+
if (flags & LOG_FORCE_CON)
2306+
r.info->flags |= LOG_FORCE_CON;
2307+
22842308
if (flags & LOG_NEWLINE) {
22852309
r.info->flags |= LOG_NEWLINE;
22862310
prb_final_commit(&e);
@@ -2948,6 +2972,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
29482972
struct printk_info info;
29492973
struct printk_record r;
29502974
size_t len = 0;
2975+
bool force_con;
29512976

29522977
/*
29532978
* 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,
29662991

29672992
pmsg->seq = r.info->seq;
29682993
pmsg->dropped = r.info->seq - seq;
2994+
force_con = r.info->flags & LOG_FORCE_CON;
29692995

2970-
/* Skip record that has level above the console loglevel. */
2971-
if (may_suppress && suppress_message_printing(r.info->level))
2996+
/*
2997+
* Skip records that are not forced to be printed on consoles and that
2998+
* has level above the console loglevel.
2999+
*/
3000+
if (!force_con && may_suppress && suppress_message_printing(r.info->level))
29723001
goto out;
29733002

29743003
if (is_extended) {

kernel/printk/printk_safe.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@
1212

1313
#include "internal.h"
1414

15+
/* Context where printk messages are never suppressed */
16+
static atomic_t force_con;
17+
18+
void printk_force_console_enter(void)
19+
{
20+
atomic_inc(&force_con);
21+
}
22+
23+
void printk_force_console_exit(void)
24+
{
25+
atomic_dec(&force_con);
26+
}
27+
28+
bool is_printk_force_console(void)
29+
{
30+
return atomic_read(&force_con);
31+
}
32+
1533
static DEFINE_PER_CPU(int, printk_context);
1634

1735
/* Can be preempted by NMI. */

0 commit comments

Comments
 (0)