@@ -474,8 +474,10 @@ static enum desc_state desc_read(struct prb_desc_ring *desc_ring,
474474 * state has been re-checked. A memcpy() for all of @desc
475475 * cannot be used because of the atomic_t @state_var field.
476476 */
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+ }
479481 if (seq_out )
480482 * seq_out = info -> seq ; /* also part of desc_read:C */
481483 if (caller_id_out )
@@ -528,7 +530,8 @@ static enum desc_state desc_read(struct prb_desc_ring *desc_ring,
528530 state_val = atomic_long_read (state_var ); /* LMM(desc_read:E) */
529531 d_state = get_desc_state (id , state_val );
530532out :
531- atomic_long_set (& desc_out -> state_var , state_val );
533+ if (desc_out )
534+ atomic_long_set (& desc_out -> state_var , state_val );
532535 return d_state ;
533536}
534537
@@ -1449,6 +1452,9 @@ static void desc_make_final(struct prb_desc_ring *desc_ring, unsigned long id)
14491452
14501453 atomic_long_cmpxchg_relaxed (& d -> state_var , prev_state_val ,
14511454 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 );
14521458}
14531459
14541460/**
@@ -1657,7 +1663,12 @@ void prb_commit(struct prb_reserved_entry *e)
16571663 */
16581664void prb_final_commit (struct prb_reserved_entry * e )
16591665{
1666+ struct prb_desc_ring * desc_ring = & e -> rb -> desc_ring ;
1667+
16601668 _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 );
16611672}
16621673
16631674/*
@@ -2005,9 +2016,39 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb)
20052016 */
20062017u64 prb_next_seq (struct printk_ringbuffer * rb )
20072018{
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 );
20092027
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+ */
20112052 while (_prb_read_valid (rb , & seq , NULL , NULL ))
20122053 seq ++ ;
20132054
@@ -2044,6 +2085,7 @@ void prb_init(struct printk_ringbuffer *rb,
20442085 rb -> desc_ring .infos = infos ;
20452086 atomic_long_set (& rb -> desc_ring .head_id , DESC0_ID (descbits ));
20462087 atomic_long_set (& rb -> desc_ring .tail_id , DESC0_ID (descbits ));
2088+ atomic_long_set (& rb -> desc_ring .last_finalized_id , DESC0_ID (descbits ));
20472089
20482090 rb -> text_data_ring .size_bits = textbits ;
20492091 rb -> text_data_ring .data = text_buf ;
0 commit comments