e1000: Fix DMA mapping error handling on TX
Subsystems (2)
PATCH 1/2 e1000: Fix DMA mapping error handling on TX
There were a few issues in the DMA mapping error handling in e1000_tx_map which I found via fault injection.
If we fail to map the first descriptor count will end up as -1 but the check of (count >= 0) will still be true since count is unsigned. Instead of changing count to be signed, just simplify the logic.
Secondly, when we wrap the tx ring we rely on i to go negative, but it was unsigned.
---
drivers/net/e1000/e1000_main.c +3 -4
@@ -2693,8 +2693,9 @@ static int e1000_tx_map(struct e1000_adastruct pci_dev *pdev = adapter->pdev;struct e1000_buffer *buffer_info;unsigned int len =skb_headlen (skb); -unsigned int offset =0 , size, count =0 , i; +unsigned int offset =0 , size, count =0 ;unsigned int f; +int i; i = tx_ring->next_to_use;
@@ -2802,10 +2803,8 @@ static int e1000_tx_map(struct e1000_ada dma_error:dev_err (&pdev->dev,"TX DMA map failed\n" ); buffer_info->dma =0 ; - count--; -while (count >=0 ) { - count--; +while (count--) { i--;if (i <0 ) i += tx_ring->count;
PATCH 2/2 e1000: Fix DMA mapping error handling on RX
Check for error return from pci_map_single/pci_map_page and clean up.
With this and the previous patch the driver was able to handle a significant percentage of errors (I set the fault injection rate to 10% and could still download large files at a reasonable speed).
---
I wasn't able to stress the jumbo frame path, so that part could do with some more eyes.
drivers/net/e1000/e1000_main.c +18 -1
@@ -4014,11 +4014,21 @@ check_page: } } -if (!buffer_info->dma) +if (!buffer_info->dma) { buffer_info->dma =pci_map_page (pdev, buffer_info->page,0 , buffer_info->length,PCI_DMA_FROMDEVICE ); +if (pci_dma_mapping_error (pdev, buffer_info->dma)) { +put_page (buffer_info->page); +dev_kfree_skb (skb); + buffer_info->page =NULL ; + buffer_info->skb =NULL ; + buffer_info->dma =0 ; + adapter->alloc_rx_buff_failed++; +break ;/* while !buffer_info->skb */ + } + } rx_desc =E1000_RX_DESC (*rx_ring, i); rx_desc->buffer_addr =cpu_to_le64 (buffer_info->dma);
@@ -4109,6 +4119,13 @@ map_skb: skb->data, buffer_info->length, PCI_DMA_FROMDEVICE); +if (pci_dma_mapping_error (pdev, buffer_info->dma)) { +dev_kfree_skb (skb); + buffer_info->skb =NULL ; + buffer_info->dma =0 ; + adapter->alloc_rx_buff_failed++; +break ;/* while !buffer_info->skb */ + }/* * XXX if it was allocated cleanly it will never map to a
Re: [PATCH 2/2] e1000: Fix DMA mapping error handling on RX
Quoted 44 lines · Anton Blanchard
Check for error return from pci_map_single/pci_map_page and clean up.
With this and the previous patch the driver was able to handle a significant percentage of errors (I set the fault injection rate to 10% and could still download large files at a reasonable speed).
Signed-off-by Anton Blanchard <[email protected]>---
I wasn't able to stress the jumbo frame path, so that part could do with some more eyes.
Index:
linux.trees.git/drivers/net/e1000/e1000_main.c
===================================================================drivers/net/e1000/e1000_main.c 2010-01-21 11:15:54.000000000 +1100 renamed from drivers/net/e1000/e1000_main.c 2010-01-21 11:13:10.000000000 +1100 +11
-1@@ -4014,11 +4014,21 @@ check_page: } } - if (!buffer_info->dma) + if (!buffer_info->dma) { buffer_info->dma = pci_map_page(pdev, buffer_info->page, 0, buffer_info->length, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) { + put_page(buffer_info->page); + dev_kfree_skb(skb); + buffer_info->page = NULL; + buffer_info->skb = NULL; + buffer_info->dma = 0; + adapter->alloc_rx_buff_failed++; + break; /* while !buffer_info->skb */ + } + } rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);@@ -4109,6 +4119,13 @@ map_skb: skb->data, buffer_info->length, PCI_DMA_FROMDEVICE);
drivers/net/e1000/e1000_main.c 2010-01-21 11:15:54.000000000 +1100 map_skb: · line 4131
Quoted 10 lines
drivers/net/e1000/e1000_main.c 2010-01-21 11:15:54.000000000 +1100 renamed from drivers/net/e1000/e1000_main.c 2010-01-21 11:13:10.000000000 +1100 +7
-0+ if (pci_dma_mapping_error(pdev, buffer_info->dma)) { + dev_kfree_skb(skb); + buffer_info->skb = NULL; + buffer_info->dma = 0; + adapter->alloc_rx_buff_failed++; + break; /* while !buffer_info->skb */ + } /* * XXX if it was allocated cleanly it will never map to a
I have added this patch to my queue of patches for review and testing. Thanks.
Signature · 2 lines
Cheers, Jeff
Quoted 35 lines · Anton Blanchard
There were a few issues in the DMA mapping error handling in
e1000_tx_mapwhich I found via fault injection.If we fail to map the first descriptor count will end up as -1 but the check of (count >= 0) will still be true since count is unsigned. Instead of changing count to be signed, just simplify the logic.
Secondly, when we wrap the tx ring we rely on i to go negative, but it was unsigned.
Signed-off-by Anton Blanchard <[email protected]>---
Index:
linux.trees.git/drivers/net/e1000/e1000_main.c
===================================================================drivers/net/e1000/e1000_main.c 2010-01-21 11:12:52.000000000 +1100 renamed from drivers/net/e1000/e1000_main.c 2010-01-21 11:10:00.000000000 +1100 +2
-1@@ -2693,8 +2693,9 @@ static int e1000_tx_map(struct e1000_ada struct pci_dev *pdev = adapter->pdev; struct e1000_buffer *buffer_info; unsigned int len = skb_headlen(skb); - unsigned int offset = 0, size, count = 0, i; + unsigned int offset = 0, size, count = 0; unsigned int f; + int i; i = tx_ring->next_to_use;@@ -2802,10 +2803,8 @@ static int e1000_tx_map(struct e1000_adadma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");buffer_info->dma= 0;
- count--;
Quoted 6 lines
- while (count >= 0) {
- count--;
+ while (count--) {
i--;
if (i < 0)
i +=tx_ring->count;
This patch does not apply to the current e1000 driver in net-2.6, much of this patch has already been corrected (applied) by Roel Kluin recent patch.
Signature · 2 lines
Cheers, Jeff
Hi,
Quoted 3 lines
This patch does not apply to the current e1000 driver in net-2.6, much of this patch has already been corrected (applied) by Roel Kluin recent patch.
Sorry I was basing off net-next. I just compared it to my fix and looks like the patch in net-2.6 has an off by one error doesn't it?
Anton
--
Subject: [PATCH] e1000: Fix DMA mapping error handling on TX
e1000_tx_map has an off by one error in the dma mapping error cleanup path. We decrement count and never clean the first successfully mapped descriptor.
---
drivers/net/e1000/e1000_main.c +0 -2
@@ -2790,8 +2790,6 @@ static int e1000_tx_map(struct e1000_adapter *adapter, dma_error:dev_err (&pdev->dev,"TX DMA map failed\n" ); buffer_info->dma =0 ; -if (count) - count--;while (count--) {if (i==0 )
------------------------------------------------------------------------------
Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies.
http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
Quoted 7 lines · Anton Blanchard
Hi,
Quoted 3 lines
This patch does not apply to the current e1000 driver in net-2.6, much of this patch has already been corrected (applied) by Roel Kluin recent patch.
Quoted 7 lines
Sorry I was basing off net-next. I just compared it to my fix and looks like the patch in net-2.6 has an off by one error doesn't it?
Anton
--
This was discussed during our code review of Roel's patch, and it was found that there was not an issue. But I will review the code again to ensure that there is not "an off by one error". Thanks for looking at this.
Signature · 14 lines
Cheers, Jeff ------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev _______________________________________________ E1000-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/e1000-devel To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
This patch does not apply to the current e1000 driver in net-2.6, much of this patch has already been corrected (applied) by Roel Kluin recent patch.
Quoted 7 lines
Quoted 2 lines
Sorry I was basing off net-next. I just compared it to my fix and looks like the patch in net-2.6 has an off by one error doesn't it?
This was discussed during our code review of Roel's patch, and it was found that there was not an issue. But I will review the code again to ensure that there is not "an off by one error". Thanks for looking at this.
He is right, as also reported by Juha Leppanen:
Quoted 10 lines
Before your patch I suppose the logic disregarding the signed/unsigned error was :
1) if count==0, no unmapping/freeing inside while loop
2) if count>0, do 'count' loops unmapping/freeingAfter your patch the logic is :
1) if count==0, no unmapping/freeing inside while loop
1) if count==1, no unmapping/freeing inside while loop
2) if count>1, do 'count-1' loops unmapping/freeingCan
tx_ring->countbe zero? I hope not.
His suggested fix works:
Quoted 10 lines
dma_error:dev_err(&pdev->dev, "TX DMA map failed\n"); buffer_info->dma = 0;drivers/net/e1000/e1000_main.c +0
-2-if (count) - count--;while (count--) { if (i==0)(quoted diff) +1
-1- i += tx_ring->count; + i = tx_ring->count;
Quoted 7 lines
i--; buffer_info = &tx_ring->buffer_info[i]; e1000_unmap_and_free_tx_resource(adapter, buffer_info); } return 0; }
This affects the patches:
[PATCH] e1000: Fix tests of unsigned in e1000_tx_map() and the other patch in the same thread.
Do you want me to send a delta patch?
Roel
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
These functions have off by one errors in their dma mapping error cleanup paths. We decrement count and never clean the first successfully mapped descriptor.
--- drivers/net/e1000e/netdev.c | 4 +--- drivers/net/igbvf/netdev.c | 4 +--- drivers/net/ixgb/ixgb_main.c | 4 +--- drivers/net/ixgbe/ixgbe_main.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-)
My previous fix inadvertently introduced this change.
The e1000_tx_map() function in drivers/net/e1000/e1000_main.c is already fixed by the patch sent by Anton Blanchard that can be found here:
http://www.mail-archive.com/[email protected]/msg02313.html
drivers/net/e1000e/netdev.c +1 -3
@@ -3967,12 +3967,10 @@ static int e1000_tx_map(struct e1000_adapter *adapter, dma_error:dev_err (&pdev->dev,"TX DMA map failed\n" ); buffer_info->dma =0 ; -if (count) - count--;while (count--) {if (i==0 ) - i += tx_ring->count; + i = tx_ring->count; i--; buffer_info = &tx_ring->buffer_info[i];e1000_put_txbuf (adapter, buffer_info);;
drivers/net/igbvf/netdev.c +1 -3
@@ -2164,13 +2164,11 @@ dma_error: buffer_info->length =0 ; buffer_info->next_to_watch =0 ; buffer_info->mapped_as_page = false; -if (count) - count--;/* clear timestamp and dma mappings for remaining portion of packet */ while (count--) {if (i==0 ) - i += tx_ring->count; + i = tx_ring->count; i--; buffer_info = &tx_ring->buffer_info[i];igbvf_put_txbuf (adapter, buffer_info);
drivers/net/ixgb/ixgb_main.c +1 -3
@@ -1363,12 +1363,10 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, dma_error:dev_err (&pdev->dev,"TX DMA map failed\n" ); buffer_info->dma =0 ; -if (count) - count--;while (count--) {if (i==0 ) - i += tx_ring->count; + i = tx_ring->count; i--; buffer_info = &tx_ring->buffer_info[i];ixgb_unmap_and_free_tx_resource (adapter, buffer_info);
drivers/net/ixgbe/ixgbe_main.c +1 -3
@@ -5167,13 +5167,11 @@ dma_error: tx_buffer_info->dma =0 ; tx_buffer_info->time_stamp =0 ; tx_buffer_info->next_to_watch =0 ; -if (count) - count--;/* clear timestamp and dma mappings for remaining portion of packet */ while (count--) {if (i==0 ) - i += tx_ring->count; + i = tx_ring->count; i--; tx_buffer_info = &tx_ring->tx_buffer_info[i];ixgbe_unmap_and_free_tx_resource (adapter, tx_buffer_info);