diff options
Diffstat (limited to '')
-rw-r--r-- | debian/patches-rt/0087-printk-use-seqcount_latch-for-clear_seq.patch | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/debian/patches-rt/0087-printk-use-seqcount_latch-for-clear_seq.patch b/debian/patches-rt/0087-printk-use-seqcount_latch-for-clear_seq.patch new file mode 100644 index 000000000..f34000021 --- /dev/null +++ b/debian/patches-rt/0087-printk-use-seqcount_latch-for-clear_seq.patch @@ -0,0 +1,147 @@ +From 0b877c3f36fc909dc2aec9f70e2e80ad0c69a60b Mon Sep 17 00:00:00 2001 +From: John Ogness <john.ogness@linutronix.de> +Date: Mon, 30 Nov 2020 01:41:58 +0106 +Subject: [PATCH 087/323] printk: use seqcount_latch for clear_seq +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.204-rt100.tar.xz + +kmsg_dump_rewind_nolock() locklessly reads @clear_seq. However, +this is not done atomically. Since @clear_seq is 64-bit, this +cannot be an atomic operation for all platforms. Therefore, use +a seqcount_latch to allow readers to always read a consistent +value. + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +Reviewed-by: Petr Mladek <pmladek@suse.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + kernel/printk/printk.c | 58 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 50 insertions(+), 8 deletions(-) + +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index 1bc4ff19c0d2..4444b3e292d5 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -404,8 +404,21 @@ static u64 console_seq; + static u64 exclusive_console_stop_seq; + static unsigned long console_dropped; + +-/* the next printk record to read after the last 'clear' command */ +-static u64 clear_seq; ++struct latched_seq { ++ seqcount_latch_t latch; ++ u64 val[2]; ++}; ++ ++/* ++ * The next printk record to read after the last 'clear' command. There are ++ * two copies (updated with seqcount_latch) so that reads can locklessly ++ * access a valid value. Writers are synchronized by @logbuf_lock. ++ */ ++static struct latched_seq clear_seq = { ++ .latch = SEQCNT_LATCH_ZERO(clear_seq.latch), ++ .val[0] = 0, ++ .val[1] = 0, ++}; + + #ifdef CONFIG_PRINTK_CALLER + #define PREFIX_MAX 48 +@@ -459,6 +472,31 @@ bool printk_percpu_data_ready(void) + return __printk_percpu_data_ready; + } + ++/* Must be called under logbuf_lock. */ ++static void latched_seq_write(struct latched_seq *ls, u64 val) ++{ ++ raw_write_seqcount_latch(&ls->latch); ++ ls->val[0] = val; ++ raw_write_seqcount_latch(&ls->latch); ++ ls->val[1] = val; ++} ++ ++/* Can be called from any context. */ ++static u64 latched_seq_read_nolock(struct latched_seq *ls) ++{ ++ unsigned int seq; ++ unsigned int idx; ++ u64 val; ++ ++ do { ++ seq = raw_read_seqcount_latch(&ls->latch); ++ idx = seq & 0x1; ++ val = ls->val[idx]; ++ } while (read_seqcount_latch_retry(&ls->latch, seq)); ++ ++ return val; ++} ++ + /* Return log buffer address */ + char *log_buf_addr_get(void) + { +@@ -804,7 +842,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) + * like issued by 'dmesg -c'. Reading /dev/kmsg itself + * changes no global state, and does not clear anything. + */ +- user->seq = clear_seq; ++ user->seq = latched_seq_read_nolock(&clear_seq); + break; + case SEEK_END: + /* after the last record */ +@@ -963,6 +1001,9 @@ void log_buf_vmcoreinfo_setup(void) + + VMCOREINFO_SIZE(atomic_long_t); + VMCOREINFO_TYPE_OFFSET(atomic_long_t, counter); ++ ++ VMCOREINFO_STRUCT_SIZE(latched_seq); ++ VMCOREINFO_OFFSET(latched_seq, val); + } + #endif + +@@ -1560,7 +1601,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear) + * Find first record that fits, including all following records, + * into the user-provided buffer for this dump. + */ +- seq = find_first_fitting_seq(clear_seq, -1, size, true, time); ++ seq = find_first_fitting_seq(latched_seq_read_nolock(&clear_seq), -1, ++ size, true, time); + + prb_rec_init_rd(&r, &info, text, CONSOLE_LOG_MAX); + +@@ -1587,7 +1629,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) + } + + if (clear) +- clear_seq = seq; ++ latched_seq_write(&clear_seq, seq); + logbuf_unlock_irq(); + + kfree(text); +@@ -1597,7 +1639,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) + static void syslog_clear(void) + { + logbuf_lock_irq(); +- clear_seq = prb_next_seq(prb); ++ latched_seq_write(&clear_seq, prb_next_seq(prb)); + logbuf_unlock_irq(); + } + +@@ -3341,7 +3383,7 @@ void kmsg_dump(enum kmsg_dump_reason reason) + dumper->active = true; + + logbuf_lock_irqsave(flags); +- dumper->cur_seq = clear_seq; ++ dumper->cur_seq = latched_seq_read_nolock(&clear_seq); + dumper->next_seq = prb_next_seq(prb); + logbuf_unlock_irqrestore(flags); + +@@ -3539,7 +3581,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); + */ + void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) + { +- dumper->cur_seq = clear_seq; ++ dumper->cur_seq = latched_seq_read_nolock(&clear_seq); + dumper->next_seq = prb_next_seq(prb); + } + +-- +2.43.0 + |