Commit e607a221 authored by Mike Marciniszyn's avatar Mike Marciniszyn Committed by Greg Kroah-Hartman

staging/rdma/hfi1: fix pio progress routine race with allocator

The allocation code assumes that the shadow ring cannot
be overrun because the credits will limit the allocation.

Unfortuately, the progress mechanism in sc_release_update() updates
the free count prior to processing the shadow ring, allowing the
shadow ring to be overrun by an allocation.
Reviewed-by: default avatarMark Debbage <mark.debbage@intel.com>
Signed-off-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6a5464f2
...@@ -1565,6 +1565,7 @@ void sc_release_update(struct send_context *sc) ...@@ -1565,6 +1565,7 @@ void sc_release_update(struct send_context *sc)
u64 hw_free; u64 hw_free;
u32 head, tail; u32 head, tail;
unsigned long old_free; unsigned long old_free;
unsigned long free;
unsigned long extra; unsigned long extra;
unsigned long flags; unsigned long flags;
int code; int code;
...@@ -1579,7 +1580,7 @@ void sc_release_update(struct send_context *sc) ...@@ -1579,7 +1580,7 @@ void sc_release_update(struct send_context *sc)
extra = (((hw_free & CR_COUNTER_SMASK) >> CR_COUNTER_SHIFT) extra = (((hw_free & CR_COUNTER_SMASK) >> CR_COUNTER_SHIFT)
- (old_free & CR_COUNTER_MASK)) - (old_free & CR_COUNTER_MASK))
& CR_COUNTER_MASK; & CR_COUNTER_MASK;
sc->free = old_free + extra; free = old_free + extra;
trace_hfi1_piofree(sc, extra); trace_hfi1_piofree(sc, extra);
/* call sent buffer callbacks */ /* call sent buffer callbacks */
...@@ -1589,7 +1590,7 @@ void sc_release_update(struct send_context *sc) ...@@ -1589,7 +1590,7 @@ void sc_release_update(struct send_context *sc)
while (head != tail) { while (head != tail) {
pbuf = &sc->sr[tail].pbuf; pbuf = &sc->sr[tail].pbuf;
if (sent_before(sc->free, pbuf->sent_at)) { if (sent_before(free, pbuf->sent_at)) {
/* not sent yet */ /* not sent yet */
break; break;
} }
...@@ -1603,8 +1604,10 @@ void sc_release_update(struct send_context *sc) ...@@ -1603,8 +1604,10 @@ void sc_release_update(struct send_context *sc)
if (tail >= sc->sr_size) if (tail >= sc->sr_size)
tail = 0; tail = 0;
} }
/* update tail, in case we moved it */
sc->sr_tail = tail; sc->sr_tail = tail;
/* make sure tail is updated before free */
smp_wmb();
sc->free = free;
spin_unlock_irqrestore(&sc->release_lock, flags); spin_unlock_irqrestore(&sc->release_lock, flags);
sc_piobufavail(sc); sc_piobufavail(sc);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment