From: John Ogness <john.ogness@linutronix.de>
To: Petr Mladek <pmladek@suse.com>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>,
Sergey Senozhatsky <sergey.senozhatsky@gmail.com>,
Steven Rostedt <rostedt@goodmis.org>,
Thomas Gleixner <tglx@linutronix.de>,
linux-kernel@vger.kernel.org
Subject: [PATCH next v3 08/15] printk: use seqcount_latch for clear_seq
Date: Thu, 25 Feb 2021 21:24:31 +0100 [thread overview]
Message-ID: <20210225202438.28985-9-john.ogness@linutronix.de> (raw)
In-Reply-To: <20210225202438.28985-1-john.ogness@linutronix.de>
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>
---
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 a60f709896dd..b78b85947312 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -402,8 +402,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
@@ -457,6 +470,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)
{
@@ -801,7 +839,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 */
@@ -960,6 +998,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
@@ -1557,7 +1598,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);
@@ -1584,7 +1626,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);
@@ -1594,7 +1636,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();
}
@@ -3336,7 +3378,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);
@@ -3534,7 +3576,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.20.1
next prev parent reply other threads:[~2021-02-25 20:29 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-25 20:24 [PATCH next v3 00/15] printk: remove logbuf_lock John Ogness
2021-02-25 20:24 ` [PATCH next v3 01/15] um: synchronize kmsg_dumper John Ogness
2021-03-01 16:16 ` Petr Mladek
2021-03-01 16:57 ` Petr Mladek
2021-03-02 8:06 ` John Ogness
2021-03-02 10:12 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 02/15] mtd: mtdoops: " John Ogness
2021-03-01 12:13 ` Petr Mladek
2021-03-02 10:45 ` John Ogness
2021-03-02 12:48 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 03/15] printk: limit second loop of syslog_print_all John Ogness
2021-02-25 20:24 ` [PATCH next v3 04/15] printk: kmsg_dump: remove unused fields John Ogness
2021-02-25 20:24 ` [PATCH next v3 05/15] printk: refactor kmsg_dump_get_buffer() John Ogness
2021-02-25 20:24 ` [PATCH next v3 06/15] printk: consolidate kmsg_dump_get_buffer/syslog_print_all code John Ogness
2021-02-25 20:24 ` [PATCH next v3 07/15] printk: introduce CONSOLE_LOG_MAX for improved multi-line support John Ogness
2021-03-02 13:54 ` Geert Uytterhoeven
2021-03-02 13:58 ` Geert Uytterhoeven
2021-03-02 14:34 ` John Ogness
2021-02-25 20:24 ` John Ogness [this message]
2021-02-25 20:24 ` [PATCH next v3 09/15] printk: use atomic64_t for devkmsg_user.seq John Ogness
2021-02-25 20:24 ` [PATCH next v3 10/15] printk: add syslog_lock John Ogness
2021-03-01 17:07 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 11/15] printk: kmsg_dumper: remove @active field John Ogness
2021-03-01 17:09 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 12/15] printk: introduce a kmsg_dump iterator John Ogness
2021-02-25 21:59 ` Kees Cook
2021-02-26 7:59 ` John Ogness
2021-03-01 18:07 ` Petr Mladek
2021-03-02 13:20 ` John Ogness
2021-03-02 13:55 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 13/15] printk: remove logbuf_lock John Ogness
2021-03-02 12:15 ` Petr Mladek
2021-02-25 20:24 ` [PATCH next v3 14/15] printk: kmsg_dump: remove _nolock() variants John Ogness
2021-02-25 20:24 ` [PATCH next v3 15/15] printk: console: remove unnecessary safe buffer usage John Ogness
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210225202438.28985-9-john.ogness@linutronix.de \
--to=john.ogness@linutronix.de \
--cc=linux-kernel@vger.kernel.org \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=sergey.senozhatsky.work@gmail.com \
--cc=sergey.senozhatsky@gmail.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).