summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/printk/printk.c90
-rw-r--r--kernel/printk/printk_ringbuffer.c17
-rw-r--r--lib/vsprintf.c11
3 files changed, 60 insertions, 58 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
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 1d95ab9314bf..90d0a724eadd 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -762,9 +762,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 +780,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);
/*