@@ -474,8 +474,10 @@ static enum desc_state desc_read(struct prb_desc_ring *desc_ring,
474
474
* state has been re-checked. A memcpy() for all of @desc
475
475
* cannot be used because of the atomic_t @state_var field.
476
476
*/
477
- memcpy (& desc_out -> text_blk_lpos , & desc -> text_blk_lpos ,
478
- sizeof (desc_out -> text_blk_lpos )); /* LMM(desc_read:C) */
477
+ if (desc_out ) {
478
+ memcpy (& desc_out -> text_blk_lpos , & desc -> text_blk_lpos ,
479
+ sizeof (desc_out -> text_blk_lpos )); /* LMM(desc_read:C) */
480
+ }
479
481
if (seq_out )
480
482
* seq_out = info -> seq ; /* also part of desc_read:C */
481
483
if (caller_id_out )
@@ -528,7 +530,8 @@ static enum desc_state desc_read(struct prb_desc_ring *desc_ring,
528
530
state_val = atomic_long_read (state_var ); /* LMM(desc_read:E) */
529
531
d_state = get_desc_state (id , state_val );
530
532
out :
531
- atomic_long_set (& desc_out -> state_var , state_val );
533
+ if (desc_out )
534
+ atomic_long_set (& desc_out -> state_var , state_val );
532
535
return d_state ;
533
536
}
534
537
@@ -1449,6 +1452,9 @@ static void desc_make_final(struct prb_desc_ring *desc_ring, unsigned long id)
1449
1452
1450
1453
atomic_long_cmpxchg_relaxed (& d -> state_var , prev_state_val ,
1451
1454
DESC_SV (id , desc_finalized )); /* LMM(desc_make_final:A) */
1455
+
1456
+ /* Best effort to remember the last finalized @id. */
1457
+ atomic_long_set (& desc_ring -> last_finalized_id , id );
1452
1458
}
1453
1459
1454
1460
/**
@@ -1657,7 +1663,12 @@ void prb_commit(struct prb_reserved_entry *e)
1657
1663
*/
1658
1664
void prb_final_commit (struct prb_reserved_entry * e )
1659
1665
{
1666
+ struct prb_desc_ring * desc_ring = & e -> rb -> desc_ring ;
1667
+
1660
1668
_prb_commit (e , desc_finalized );
1669
+
1670
+ /* Best effort to remember the last finalized @id. */
1671
+ atomic_long_set (& desc_ring -> last_finalized_id , e -> id );
1661
1672
}
1662
1673
1663
1674
/*
@@ -2005,9 +2016,39 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb)
2005
2016
*/
2006
2017
u64 prb_next_seq (struct printk_ringbuffer * rb )
2007
2018
{
2008
- u64 seq = 0 ;
2019
+ struct prb_desc_ring * desc_ring = & rb -> desc_ring ;
2020
+ enum desc_state d_state ;
2021
+ unsigned long id ;
2022
+ u64 seq ;
2023
+
2024
+ /* Check if the cached @id still points to a valid @seq. */
2025
+ id = atomic_long_read (& desc_ring -> last_finalized_id );
2026
+ d_state = desc_read (desc_ring , id , NULL , & seq , NULL );
2009
2027
2010
- /* Search forward from the oldest descriptor. */
2028
+ if (d_state == desc_finalized || d_state == desc_reusable ) {
2029
+ /*
2030
+ * Begin searching after the last finalized record.
2031
+ *
2032
+ * On 0, the search must begin at 0 because of hack#2
2033
+ * of the bootstrapping phase it is not known if a
2034
+ * record at index 0 exists.
2035
+ */
2036
+ if (seq != 0 )
2037
+ seq ++ ;
2038
+ } else {
2039
+ /*
2040
+ * The information about the last finalized sequence number
2041
+ * has gone. It should happen only when there is a flood of
2042
+ * new messages and the ringbuffer is rapidly recycled.
2043
+ * Give up and start from the beginning.
2044
+ */
2045
+ seq = 0 ;
2046
+ }
2047
+
2048
+ /*
2049
+ * The information about the last finalized @seq might be inaccurate.
2050
+ * Search forward to find the current one.
2051
+ */
2011
2052
while (_prb_read_valid (rb , & seq , NULL , NULL ))
2012
2053
seq ++ ;
2013
2054
@@ -2044,6 +2085,7 @@ void prb_init(struct printk_ringbuffer *rb,
2044
2085
rb -> desc_ring .infos = infos ;
2045
2086
atomic_long_set (& rb -> desc_ring .head_id , DESC0_ID (descbits ));
2046
2087
atomic_long_set (& rb -> desc_ring .tail_id , DESC0_ID (descbits ));
2088
+ atomic_long_set (& rb -> desc_ring .last_finalized_id , DESC0_ID (descbits ));
2047
2089
2048
2090
rb -> text_data_ring .size_bits = textbits ;
2049
2091
rb -> text_data_ring .data = text_buf ;
0 commit comments