[PATCH] pstore/zone: Order buffer contents before publishing datalen

From: Gui-Dong Han

Date: Fri Jul 10 2026 - 04:10:07 EST


buffer->datalen tells readers how many bytes in buffer->data are valid.
psz_zone_write() copies data first and then updates datalen. atomic_set()
and atomic_read() make datalen itself atomic, but do not order accesses to
buffer->data. A reader may therefore see the new length before it sees the
copied data.

Use release ordering when publishing a non-zero datalen and acquire
ordering when reading it through buffer_datalen(). This pair ensures that
a reader which sees the new length also sees the data written before it.
The full-buffer update in psz_record_write() publishes data in the same way
and therefore also needs release ordering.

The remaining datalen stores only clear or initialize buffers. Direct
relaxed loads either inspect writer state or buffers that are no longer
changing. start only tracks the write position and on_panic only selects
the write path; neither publishes buffer data, so leave them unchanged.

Fixes: d26c3321fe18 ("pstore/zone: Introduce common layer to manage storage zones")
Fixes: 0dc068265a1c ("pstore/zone,blk: Add support for pmsg frontend")
Signed-off-by: Gui-Dong Han <hanguidong02@xxxxxxxxx>
---
Found by auditing atomic operations used for synchronization.
A similar fix can be found in 6df8e84aa6b5.
---
fs/pstore/zone.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c
index a3b003f9a3a0..a4fe9d9ea965 100644
--- a/fs/pstore/zone.c
+++ b/fs/pstore/zone.c
@@ -159,7 +159,7 @@ enum psz_flush_mode {

static inline int buffer_datalen(struct pstore_zone *zone)
{
- return atomic_read(&zone->buffer->datalen);
+ return atomic_read_acquire(&zone->buffer->datalen);
}

static inline int buffer_start(struct pstore_zone *zone)
@@ -211,7 +211,7 @@ static int psz_zone_write(struct pstore_zone *zone,
wlen = min_t(size_t, len, zone->buffer_size - off);
if (buf && wlen) {
memcpy(zone->buffer->data + off, buf, wlen);
- atomic_set(&zone->buffer->datalen, wlen + off);
+ atomic_set_release(&zone->buffer->datalen, wlen + off);
}

/* avoid damaging old records */
@@ -863,7 +863,7 @@ static int notrace psz_record_write(struct pstore_zone *zone,
* is greater than buffer size.
*/
if (is_full_data) {
- atomic_set(&zone->buffer->datalen, zone->buffer_size);
+ atomic_set_release(&zone->buffer->datalen, zone->buffer_size);
psz_zone_write(zone, FLUSH_META, NULL, 0, 0);
}
return 0;
--
2.34.1