@@ -402,8 +402,21 @@ static u64 console_seq;
402402static u64 exclusive_console_stop_seq ;
403403static unsigned long console_dropped ;
404404
405- /* the next printk record to read after the last 'clear' command */
406- static u64 clear_seq ;
405+ struct latched_seq {
406+ seqcount_latch_t latch ;
407+ u64 val [2 ];
408+ };
409+
410+ /*
411+ * The next printk record to read after the last 'clear' command. There are
412+ * two copies (updated with seqcount_latch) so that reads can locklessly
413+ * access a valid value. Writers are synchronized by @logbuf_lock.
414+ */
415+ static struct latched_seq clear_seq = {
416+ .latch = SEQCNT_LATCH_ZERO (clear_seq .latch ),
417+ .val [0 ] = 0 ,
418+ .val [1 ] = 0 ,
419+ };
407420
408421#ifdef CONFIG_PRINTK_CALLER
409422#define PREFIX_MAX 48
@@ -457,6 +470,31 @@ bool printk_percpu_data_ready(void)
457470 return __printk_percpu_data_ready ;
458471}
459472
473+ /* Must be called under logbuf_lock. */
474+ static void latched_seq_write (struct latched_seq * ls , u64 val )
475+ {
476+ raw_write_seqcount_latch (& ls -> latch );
477+ ls -> val [0 ] = val ;
478+ raw_write_seqcount_latch (& ls -> latch );
479+ ls -> val [1 ] = val ;
480+ }
481+
482+ /* Can be called from any context. */
483+ static u64 latched_seq_read_nolock (struct latched_seq * ls )
484+ {
485+ unsigned int seq ;
486+ unsigned int idx ;
487+ u64 val ;
488+
489+ do {
490+ seq = raw_read_seqcount_latch (& ls -> latch );
491+ idx = seq & 0x1 ;
492+ val = ls -> val [idx ];
493+ } while (read_seqcount_latch_retry (& ls -> latch , seq ));
494+
495+ return val ;
496+ }
497+
460498/* Return log buffer address */
461499char * log_buf_addr_get (void )
462500{
@@ -801,7 +839,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
801839 * like issued by 'dmesg -c'. Reading /dev/kmsg itself
802840 * changes no global state, and does not clear anything.
803841 */
804- user -> seq = clear_seq ;
842+ user -> seq = latched_seq_read_nolock ( & clear_seq ) ;
805843 break ;
806844 case SEEK_END :
807845 /* after the last record */
@@ -960,6 +998,9 @@ void log_buf_vmcoreinfo_setup(void)
960998
961999 VMCOREINFO_SIZE (atomic_long_t );
9621000 VMCOREINFO_TYPE_OFFSET (atomic_long_t , counter );
1001+
1002+ VMCOREINFO_STRUCT_SIZE (latched_seq );
1003+ VMCOREINFO_OFFSET (latched_seq , val );
9631004}
9641005#endif
9651006
@@ -1557,7 +1598,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
15571598 * Find first record that fits, including all following records,
15581599 * into the user-provided buffer for this dump.
15591600 */
1560- seq = find_first_fitting_seq (clear_seq , -1 , size , true, time );
1601+ seq = find_first_fitting_seq (latched_seq_read_nolock (& clear_seq ), -1 ,
1602+ size , true, time );
15611603
15621604 prb_rec_init_rd (& r , & info , text , CONSOLE_LOG_MAX );
15631605
@@ -1584,7 +1626,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
15841626 }
15851627
15861628 if (clear )
1587- clear_seq = seq ;
1629+ latched_seq_write ( & clear_seq , seq ) ;
15881630 logbuf_unlock_irq ();
15891631
15901632 kfree (text );
@@ -1594,7 +1636,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
15941636static void syslog_clear (void )
15951637{
15961638 logbuf_lock_irq ();
1597- clear_seq = prb_next_seq (prb );
1639+ latched_seq_write ( & clear_seq , prb_next_seq (prb ) );
15981640 logbuf_unlock_irq ();
15991641}
16001642
@@ -3336,7 +3378,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
33363378 dumper -> active = true;
33373379
33383380 logbuf_lock_irqsave (flags );
3339- dumper -> cur_seq = clear_seq ;
3381+ dumper -> cur_seq = latched_seq_read_nolock ( & clear_seq ) ;
33403382 dumper -> next_seq = prb_next_seq (prb );
33413383 logbuf_unlock_irqrestore (flags );
33423384
@@ -3534,7 +3576,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
35343576 */
35353577void kmsg_dump_rewind_nolock (struct kmsg_dumper * dumper )
35363578{
3537- dumper -> cur_seq = clear_seq ;
3579+ dumper -> cur_seq = latched_seq_read_nolock ( & clear_seq ) ;
35383580 dumper -> next_seq = prb_next_seq (prb );
35393581}
35403582
0 commit comments