Commit abe2792f authored by Dmitriy Vyukov's avatar Dmitriy Vyukov Committed by Greg Kroah-Hartman

e1000: fix data race between tx_ring->next_to_clean

[ Upstream commit 9eab46b7 ]

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: default avatarDmitry Vyukov <dvyukov@google.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5c5989e0
...@@ -213,8 +213,11 @@ struct e1000_rx_ring { ...@@ -213,8 +213,11 @@ struct e1000_rx_ring {
}; };
#define E1000_DESC_UNUSED(R) \ #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) \ #define E1000_RX_DESC_EXT(R, i) \
(&(((union e1000_rx_desc_extended *)((R).desc))[i])) (&(((union e1000_rx_desc_extended *)((R).desc))[i]))
......
...@@ -3876,7 +3876,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter, ...@@ -3876,7 +3876,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
eop_desc = E1000_TX_DESC(*tx_ring, eop); 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); netdev_completed_queue(netdev, pkts_compl, bytes_compl);
......
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