diff options
author | Dmitriy Vyukov <dvyukov@google.com> | 2015-09-08 11:52:44 +0300 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2015-12-13 10:09:48 +0300 |
commit | 9eab46b7cb8d0b0dcf014bf7b25e0e72b9e4d929 (patch) | |
tree | 33d44739cb702dddf3d371285c3ff4b24f134c7e /drivers/net/ethernet/intel/e1000/e1000.h | |
parent | 18f7ce5412027232890143ccfae23668d0872d27 (diff) | |
download | linux-9eab46b7cb8d0b0dcf014bf7b25e0e72b9e4d929.tar.xz |
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>
Diffstat (limited to 'drivers/net/ethernet/intel/e1000/e1000.h')
-rw-r--r-- | drivers/net/ethernet/intel/e1000/e1000.h | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h index 69707108d23c..98fe5a2cd6e3 100644 --- a/drivers/net/ethernet/intel/e1000/e1000.h +++ b/drivers/net/ethernet/intel/e1000/e1000.h @@ -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])) |