Intel-Wired-Lan Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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