Re: [PATCH v2] ring-buffer: Handle a reader taking the new head in rb_handle_head_page()
From: Steven Rostedt
Date: Tue Nov 10 2026 - 03:35:34 EST
On Mon, 9 Nov 2026 09:21:32 +0000
Vincent Donnefort <vdonnefort@xxxxxxxxxx> wrote:
> > The issue I think you hit was that we have two HEAD pages, when interrupts
> > come in. That is, we can get a state of:
> >
> > --> subbuf --UPDATE--> subbuf --> subbuf --HEAD--> subbuf -->
>
> How we can end-up in this situation? The cmpxch will only swap HEAD for UPDATE.
The cpu_buffer->head_page is only updated by the reader, when it did its last read.
Let's look at it one at a time:
cpu_buffer->head_page
tail |
v v
+--> subbuf ----> subbuf --HEAD--> subbuf ----> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------+
Then the writer moves the HEAD page around the buffer while there are
no reads happening
cpu_buffer->head_page
tail |
v v
+--> subbuf ----> subbuf ----> subbuf --HEAD--> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------+
cpu_buffer->head_page
| tail
v v
+--> subbuf ----> subbuf ----> subbuf ----> subbuf --HEAD--> subbuf --+
| |
+---------------------------------------------------------------------+
cpu_buffer->head_page
| tail
v v
+-HEAD-> subbuf ----> subbuf ----> subbuf ----> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------+
cpu_buffer->head_page
tail |
v v
+--> subbuf --HEAD--> subbuf ----> subbuf ----> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------+
Now, I'll break up the update part:
cpu_buffer->head_page
tail |
v v
+--> subbuf --UPDATE--> subbuf ----> subbuf ----> subbuf ----> subbuf --+
| |
+-----------------------------------------------------------------------+
cpu_buffer->head_page
tail |
v v
+--> subbuf --UPDATE--> subbuf --HEAD--> subbuf ----> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------------+
An interrupt comes in and moves the head even more.
cpu_buffer->head_page
tail |
v v
+--> subbuf --UPDATE--> subbuf ----> subbuf --HEAD--> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------------+
Now the reader decides to read again and starts between the UPDATE and the HEAD
cpu_buffer->head_page
tail |
v v
+--> subbuf --UPDATE--> subbuf ----> subbuf --HEAD--> subbuf ----> subbuf --+
| |
+---------------------------------------------------------------------------+
It finds a page with the HEAD pointer set but not the UPDATE pointer and does a swap!
reader_page -----+
|
cpu_buffer->head_page |
tail | |
v v v
+--> subbuf --UPDATE--> subbuf ----> subbuf ----> subbuf --HEAD--> subbuf --+
| |
+---------------------------------------------------------------------------+
Now the commit finishes and moves forward and will even hit a blank
page but the last write is now on the reader page. This breaks the
entire integrity of the ring buffer.
Does this make sense?
-- Steve