Skip to content

Commit

Permalink
ptr_ring: add barriers
Browse files Browse the repository at this point in the history
Users of ptr_ring expect that it's safe to give the
data structure a pointer and have it be available
to consumers, but that actually requires an smb_wmb
or a stronger barrier.

In absence of such barriers and on architectures that reorder writes,
consumer might read an un=initialized value from an skb pointer stored
in the skb array.  This was observed causing crashes.

To fix, add memory barriers.  The barrier we use is a wmb, the
assumption being that producers do not need to read the value so we do
not need to order these reads.

Reported-by: George Cherian <george.cherian@cavium.com>
Suggested-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael S. Tsirkin authored and David S. Miller committed Dec 11, 2017
1 parent f0f1d01 commit a8ceb5d
Showing 1 changed file with 9 additions and 0 deletions.
9 changes: 9 additions & 0 deletions include/linux/ptr_ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,18 @@ static inline bool ptr_ring_full_bh(struct ptr_ring *r)

/* Note: callers invoking this in a loop must use a compiler barrier,
* for example cpu_relax(). Callers must hold producer_lock.
* Callers are responsible for making sure pointer that is being queued
* points to a valid data.
*/
static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr)
{
if (unlikely(!r->size) || r->queue[r->producer])
return -ENOSPC;

/* Make sure the pointer we are storing points to a valid data. */
/* Pairs with smp_read_barrier_depends in __ptr_ring_consume. */
smp_wmb();

r->queue[r->producer++] = ptr;
if (unlikely(r->producer >= r->size))
r->producer = 0;
Expand Down Expand Up @@ -275,6 +281,9 @@ static inline void *__ptr_ring_consume(struct ptr_ring *r)
if (ptr)
__ptr_ring_discard_one(r);

/* Make sure anyone accessing data through the pointer is up to date. */
/* Pairs with smp_wmb in __ptr_ring_produce. */
smp_read_barrier_depends();
return ptr;
}

Expand Down

0 comments on commit a8ceb5d

Please sign in to comment.