buf_ring: Use atomic operations with br_cons_tail

Use an atomic operation with a memory barrier loading br_cons_tail
from the producer thread and storing to it in the consumer thread.

On dequeue we need to read the pointer value from the buf_ring before
moving the consumer tail as that indicates the entry is available to be
used. The store release atomic operation guarantees this.

In the enqueueing thread we then need to use a load acquire atomic
operation to ensure writing to this entry can only happen after the
tail has been read and checked.

Reported by:	Ali Saidi <alisaidi@amazon.com>
Co-developed by: Ali Saidi <alisaidi@amazon.com>
Reviewed by:	markj
Sponsored by:	Arm Ltd
Differential Revision:	https://reviews.freebsd.org/D46152
This commit is contained in:
Andrew Turner
2024-08-19 10:06:52 +01:00
parent 3cc603909e
commit 44e1cfca41
+3 -3
View File
@@ -91,7 +91,7 @@ buf_ring_enqueue(struct buf_ring *br, void *buf)
do {
prod_head = br->br_prod_head;
prod_next = prod_head + 1;
cons_tail = br->br_cons_tail;
cons_tail = atomic_load_acq_32(&br->br_cons_tail);
if ((int32_t)(cons_tail + br->br_prod_size - prod_next) < 1) {
rmb();
@@ -229,7 +229,7 @@ buf_ring_dequeue_sc(struct buf_ring *br)
panic("inconsistent list cons_tail=%d cons_head=%d",
br->br_cons_tail, cons_head);
#endif
br->br_cons_tail = cons_next;
atomic_store_rel_32(&br->br_cons_tail, cons_next);
return (buf);
}
@@ -257,7 +257,7 @@ buf_ring_advance_sc(struct buf_ring *br)
#ifdef DEBUG_BUFRING
br->br_ring[cons_head & mask] = NULL;
#endif
br->br_cons_tail = cons_next;
atomic_store_rel_32(&br->br_cons_tail, cons_next);
}
/*