e1000: fix data race between tx_ring->next_to_clean
e1000_clean_tx_irq cleans buffers and sets tx_ring->next_to_clean, then e1000_xmit_frame reuses the cleaned buffers. But there are no memory barriers when buffers gets recycled, so the recycled buffers can be corrupted. Use smp_store_release to update tx_ring->next_to_clean and smp_load_acquire to read tx_ring->next_to_clean to properly hand off buffers from e1000_clean_tx_irq to e1000_xmit_frame. The data race was found with KernelThreadSanitizer (KTSAN). Signed-off-by: Dmitry Vyukov <dvyukov@google.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
18f7ce5412
commit
9eab46b7cb
|
@ -213,8 +213,11 @@ struct e1000_rx_ring {
|
|||
};
|
||||
|
||||
#define E1000_DESC_UNUSED(R) \
|
||||
((((R)->next_to_clean > (R)->next_to_use) \
|
||||
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
|
||||
({ \
|
||||
unsigned int clean = smp_load_acquire(&(R)->next_to_clean); \
|
||||
unsigned int use = READ_ONCE((R)->next_to_use); \
|
||||
(clean > use ? 0 : (R)->count) + clean - use - 1; \
|
||||
})
|
||||
|
||||
#define E1000_RX_DESC_EXT(R, i) \
|
||||
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
|
||||
|
|
|
@ -3876,7 +3876,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
|
|||
eop_desc = E1000_TX_DESC(*tx_ring, eop);
|
||||
}
|
||||
|
||||
tx_ring->next_to_clean = i;
|
||||
/* Synchronize with E1000_DESC_UNUSED called from e1000_xmit_frame,
|
||||
* which will reuse the cleaned buffers.
|
||||
*/
|
||||
smp_store_release(&tx_ring->next_to_clean, i);
|
||||
|
||||
netdev_completed_queue(netdev, pkts_compl, bytes_compl);
|
||||
|
||||
|
|
Loading…
Reference in New Issue