summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-30 12:48:40 +0100
committerMark Brown <broonie@kernel.org>2026-09-30 12:48:40 +0100
commit3b3fc5d9f44cafc0b9d6536f73691e3abfc9dd59 (patch)
tree8c65ea685fce2b959f21b28b53a460cb9e3ebce4 /kernel
parentc0c20ac78811bbb321b9f1b1b7ee3c00c847e95d (diff)
parent3fa6f22c1dc835fe1757b06e7d51d8c424ac978a (diff)
downloadlinux-next-3b3fc5d9f44cafc0b9d6536f73691e3abfc9dd59.tar.gz
linux-next-3b3fc5d9f44cafc0b9d6536f73691e3abfc9dd59.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk/printk.c90
-rw-r--r--kernel/printk/printk_ringbuffer.c17
2 files changed, 56 insertions, 51 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 6d3d18a50da7..6c8bacb173b7 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -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;
@@ -4424,36 +4424,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 +4608,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
-
-static DEFINE_PER_CPU(int, printk_pending);
+#define PRINTK_PENDING_OUTPUT 0x01
-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);
+ wake_up_interruptible(&log_wait);
+}
- if (pending & PRINTK_PENDING_OUTPUT) {
- if (force_legacy_kthread()) {
- if (printk_legacy_kthread)
- wake_up_interruptible(&legacy_wait);
- } else {
- if (console_trylock())
- console_unlock();
- }
+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();
}
-
- if (pending & PRINTK_PENDING_WAKEUP)
- 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 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 +4641,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 +4652,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 +4671,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 +4692,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);
}
/**
diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c
index 85c0c854b3ce..d38e7c2f6887 100644
--- a/kernel/printk/printk_ringbuffer.c
+++ b/kernel/printk/printk_ringbuffer.c
@@ -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