* [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean
@ 2015-09-07 18:12 Dmitry Vyukov
2015-09-07 18:15 ` Dmitry Vyukov
0 siblings, 1 reply; 4+ messages in thread
From: Dmitry Vyukov @ 2015-09-07 18:12 UTC (permalink / raw)
To: intel-wired-lan
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>
---
drivers/net/ethernet/intel/e1000/e1000.h | 7 +++++--
drivers/net/ethernet/intel/e1000/e1000_main.c | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 6970710..244c0e7 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]))
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 74dc150..97e38ce 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -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);
--
2.5.0.457.gab17608
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean
2015-09-07 18:12 [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean Dmitry Vyukov
@ 2015-09-07 18:15 ` Dmitry Vyukov
2015-09-08 8:52 ` Dmitry Vyukov
2015-09-08 8:53 ` Dmitry Vyukov
0 siblings, 2 replies; 4+ messages in thread
From: Dmitry Vyukov @ 2015-09-07 18:15 UTC (permalink / raw)
To: intel-wired-lan
On Mon, Sep 7, 2015 at 8:12 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
> 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>
> ---
> drivers/net/ethernet/intel/e1000/e1000.h | 7 +++++--
> drivers/net/ethernet/intel/e1000/e1000_main.c | 5 ++++-
> 2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
> index 6970710..244c0e7 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; \
I did not grasp why it just returns 0 when clean > use, and not
something along the lines of "count + use - clean". So I left it
as-is.
What's the reason to return 0?
> +})
>
> #define E1000_RX_DESC_EXT(R, i) \
> (&(((union e1000_rx_desc_extended *)((R).desc))[i]))
> diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
> index 74dc150..97e38ce 100644
> --- a/drivers/net/ethernet/intel/e1000/e1000_main.c
> +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
> @@ -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);
>
> --
> 2.5.0.457.gab17608
>
--
Dmitry Vyukov, Software Engineer, dvyukov at google.com
Google Germany GmbH, Dienerstra?e 12, 80331, M?nchen
Gesch?ftsf?hrer: Graham Law, Christine Elizabeth Flores
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Diese E-Mail ist vertraulich. Wenn Sie nicht der richtige Adressat
sind, leiten Sie diese bitte nicht weiter, informieren Sie den
Absender und l?schen Sie die E-Mail und alle Anh?nge. Vielen Dank.
This e-mail is confidential. If you are not the right addressee please
do not forward it, please inform the sender, and please erase this
e-mail including any attachments. Thanks.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean
2015-09-07 18:15 ` Dmitry Vyukov
@ 2015-09-08 8:52 ` Dmitry Vyukov
2015-09-08 8:53 ` Dmitry Vyukov
1 sibling, 0 replies; 4+ messages in thread
From: Dmitry Vyukov @ 2015-09-08 8:52 UTC (permalink / raw)
To: intel-wired-lan
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>
---
drivers/net/ethernet/intel/e1000/e1000.h | 7 +++++--
drivers/net/ethernet/intel/e1000/e1000_main.c | 5 ++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 6970710..98fe5a2 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]))
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 74dc150..97e38ce 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -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);
--
2.5.0.457.gab17608
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean
2015-09-07 18:15 ` Dmitry Vyukov
2015-09-08 8:52 ` Dmitry Vyukov
@ 2015-09-08 8:53 ` Dmitry Vyukov
1 sibling, 0 replies; 4+ messages in thread
From: Dmitry Vyukov @ 2015-09-08 8:53 UTC (permalink / raw)
To: intel-wired-lan
On Mon, Sep 7, 2015 at 8:15 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
> On Mon, Sep 7, 2015 at 8:12 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
>> 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>
>> ---
>> drivers/net/ethernet/intel/e1000/e1000.h | 7 +++++--
>> drivers/net/ethernet/intel/e1000/e1000_main.c | 5 ++++-
>> 2 files changed, 9 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
>> index 6970710..244c0e7 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; \
>
> I did not grasp why it just returns 0 when clean > use, and not
> something along the lines of "count + use - clean". So I left it
> as-is.
> What's the reason to return 0?
OK, I see, I missed brackets in the macro.
>> +})
>>
>> #define E1000_RX_DESC_EXT(R, i) \
>> (&(((union e1000_rx_desc_extended *)((R).desc))[i]))
>> diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
>> index 74dc150..97e38ce 100644
>> --- a/drivers/net/ethernet/intel/e1000/e1000_main.c
>> +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
>> @@ -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);
>>
>> --
>> 2.5.0.457.gab17608
--
Dmitry Vyukov, Software Engineer, dvyukov at google.com
Google Germany GmbH, Dienerstra?e 12, 80331, M?nchen
Gesch?ftsf?hrer: Graham Law, Christine Elizabeth Flores
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
Diese E-Mail ist vertraulich. Wenn Sie nicht der richtige Adressat
sind, leiten Sie diese bitte nicht weiter, informieren Sie den
Absender und l?schen Sie die E-Mail und alle Anh?nge. Vielen Dank.
This e-mail is confidential. If you are not the right addressee please
do not forward it, please inform the sender, and please erase this
e-mail including any attachments. Thanks.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-09-08 8:53 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-07 18:12 [Intel-wired-lan] [PATCH] e1000: fix data race between tx_ring->next_to_clean Dmitry Vyukov
2015-09-07 18:15 ` Dmitry Vyukov
2015-09-08 8:52 ` Dmitry Vyukov
2015-09-08 8:53 ` Dmitry Vyukov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox