@@ -402,8 +402,21 @@ static u64 console_seq;
402
402
static u64 exclusive_console_stop_seq ;
403
403
static unsigned long console_dropped ;
404
404
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
+ };
407
420
408
421
#ifdef CONFIG_PRINTK_CALLER
409
422
#define PREFIX_MAX 48
@@ -457,6 +470,31 @@ bool printk_percpu_data_ready(void)
457
470
return __printk_percpu_data_ready ;
458
471
}
459
472
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
+
460
498
/* Return log buffer address */
461
499
char * log_buf_addr_get (void )
462
500
{
@@ -801,7 +839,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
801
839
* like issued by 'dmesg -c'. Reading /dev/kmsg itself
802
840
* changes no global state, and does not clear anything.
803
841
*/
804
- user -> seq = clear_seq ;
842
+ user -> seq = latched_seq_read_nolock ( & clear_seq ) ;
805
843
break ;
806
844
case SEEK_END :
807
845
/* after the last record */
@@ -960,6 +998,9 @@ void log_buf_vmcoreinfo_setup(void)
960
998
961
999
VMCOREINFO_SIZE (atomic_long_t );
962
1000
VMCOREINFO_TYPE_OFFSET (atomic_long_t , counter );
1001
+
1002
+ VMCOREINFO_STRUCT_SIZE (latched_seq );
1003
+ VMCOREINFO_OFFSET (latched_seq , val );
963
1004
}
964
1005
#endif
965
1006
@@ -1557,7 +1598,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
1557
1598
* Find first record that fits, including all following records,
1558
1599
* into the user-provided buffer for this dump.
1559
1600
*/
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 );
1561
1603
1562
1604
prb_rec_init_rd (& r , & info , text , CONSOLE_LOG_MAX );
1563
1605
@@ -1584,7 +1626,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
1584
1626
}
1585
1627
1586
1628
if (clear )
1587
- clear_seq = seq ;
1629
+ latched_seq_write ( & clear_seq , seq ) ;
1588
1630
logbuf_unlock_irq ();
1589
1631
1590
1632
kfree (text );
@@ -1594,7 +1636,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
1594
1636
static void syslog_clear (void )
1595
1637
{
1596
1638
logbuf_lock_irq ();
1597
- clear_seq = prb_next_seq (prb );
1639
+ latched_seq_write ( & clear_seq , prb_next_seq (prb ) );
1598
1640
logbuf_unlock_irq ();
1599
1641
}
1600
1642
@@ -3336,7 +3378,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
3336
3378
dumper -> active = true;
3337
3379
3338
3380
logbuf_lock_irqsave (flags );
3339
- dumper -> cur_seq = clear_seq ;
3381
+ dumper -> cur_seq = latched_seq_read_nolock ( & clear_seq ) ;
3340
3382
dumper -> next_seq = prb_next_seq (prb );
3341
3383
logbuf_unlock_irqrestore (flags );
3342
3384
@@ -3534,7 +3576,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
3534
3576
*/
3535
3577
void kmsg_dump_rewind_nolock (struct kmsg_dumper * dumper )
3536
3578
{
3537
- dumper -> cur_seq = clear_seq ;
3579
+ dumper -> cur_seq = latched_seq_read_nolock ( & clear_seq ) ;
3538
3580
dumper -> next_seq = prb_next_seq (prb );
3539
3581
}
3540
3582
0 commit comments