* [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-19 14:49 ` [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy() Jonas Jensen
@ 2014-08-19 18:31 ` Eric Dumazet
2014-08-20 14:24 ` Jonas Jensen
2014-08-20 14:19 ` [PATCH v5 " Jonas Jensen
2014-08-21 21:43 ` [PATCH v4 2/2] " Michał Mirosław
2 siblings, 1 reply; 18+ messages in thread
From: Eric Dumazet @ 2014-08-19 18:31 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 2014-08-19 at 16:49 +0200, Jonas Jensen wrote:
> build_skb() is used to make skbs out of existing RX ring memory
> which is bad because the RX ring is allocated only once, on probe.
> Memory corruption occur because said memory is reclaimed, i.e.
> __kfree_skb() (and eventually put_page()).
>
> Replace build_skb() with netdev_alloc_skb_ip_align() and use memcpy().
> Also, synchronize DMA memory before passing skb to napi_gro_receive().
>
> Addresses https://bugzilla.kernel.org/show_bug.cgi?id=69041
Wow, this driver was really buggy.
Patch is not complete.
Instead of :
priv->rx_buf_size = RX_BUF_SIZE +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
I think rx_buf_size can now be RX_BUF_SIZE
Another point is that priv->stats seems not needed, as ndev->stats could
be used instead (and remove moxart_mac_get_stats())
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-19 18:31 ` Eric Dumazet
@ 2014-08-20 14:24 ` Jonas Jensen
0 siblings, 0 replies; 18+ messages in thread
From: Jonas Jensen @ 2014-08-20 14:24 UTC (permalink / raw)
To: linux-arm-kernel
On 19 August 2014 20:31, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Instead of :
>
> priv->rx_buf_size = RX_BUF_SIZE +
> SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
>
> I think rx_buf_size can now be RX_BUF_SIZE
You're right, that's now a remnant, see update in v5.
> Another point is that priv->stats seems not needed, as ndev->stats could
> be used instead (and remove moxart_mac_get_stats())
I will fix that. I can add it to patches adding support for ethtool /
stats and PHY.
I think I'm supposed to post those closer to the merge window, which
would keep this set about bug fixes only.
Regards,
Jonas
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v5 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-19 14:49 ` [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy() Jonas Jensen
2014-08-19 18:31 ` Eric Dumazet
@ 2014-08-20 14:19 ` Jonas Jensen
2014-08-25 14:22 ` [PATCH v6 2/4] " Jonas Jensen
2014-08-21 21:43 ` [PATCH v4 2/2] " Michał Mirosław
2 siblings, 1 reply; 18+ messages in thread
From: Jonas Jensen @ 2014-08-20 14:19 UTC (permalink / raw)
To: linux-arm-kernel
build_skb() is used to make skbs out of existing RX ring memory
which is bad because the RX ring is allocated only once, on probe.
Memory corruption occur because said memory is reclaimed, i.e.
__kfree_skb() (and eventually put_page()).
Replace build_skb() with netdev_alloc_skb_ip_align(), use memcpy(),
and synchronize DMA memory before passing skb to napi_gro_receive().
Remove SKB_DATA_ALIGN() from RX buffer size while we're at it.
Addresses https://bugzilla.kernel.org/show_bug.cgi?id=69041
Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
---
Notes:
Changes since v4:
1. remove SKB_DATA_ALIGN() from RX buffer size
Applies to next-20140820
drivers/net/ethernet/moxa/moxart_ether.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index aa45607..06a6fce 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -226,14 +226,21 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
if (len > RX_BUF_SIZE)
len = RX_BUF_SIZE;
- skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
+ dma_sync_single_for_cpu(&ndev->dev,
+ priv->rx_mapping[rx_head],
+ priv->rx_buf_size, DMA_FROM_DEVICE);
+ skb = netdev_alloc_skb_ip_align(ndev, len);
if (unlikely(!skb)) {
- net_dbg_ratelimited("build_skb failed\n");
+ net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
priv->stats.rx_dropped++;
priv->stats.rx_errors++;
}
-
+ memcpy(skb->data, priv->rx_buf[rx_head], len);
skb_put(skb, len);
+ dma_sync_single_for_device(&ndev->dev,
+ priv->rx_mapping[rx_head],
+ priv->rx_buf_size, DMA_FROM_DEVICE);
+
skb->protocol = eth_type_trans(skb, ndev);
napi_gro_receive(&priv->napi, skb);
rx++;
@@ -466,8 +473,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
spin_lock_init(&priv->txlock);
priv->tx_buf_size = TX_BUF_SIZE;
- priv->rx_buf_size = RX_BUF_SIZE +
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ priv->rx_buf_size = RX_BUF_SIZE;
priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE *
TX_DESC_NUM, &priv->tx_base,
--
1.8.2.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-20 14:19 ` [PATCH v5 " Jonas Jensen
@ 2014-08-25 14:22 ` Jonas Jensen
2014-08-26 0:26 ` David Miller
2014-08-26 9:04 ` Arnd Bergmann
0 siblings, 2 replies; 18+ messages in thread
From: Jonas Jensen @ 2014-08-25 14:22 UTC (permalink / raw)
To: linux-arm-kernel
build_skb() is used to make skbs out of existing RX ring memory
which is bad because the RX ring is allocated only once, on probe.
Memory corruption occur because said memory is reclaimed, i.e.
__kfree_skb() (and eventually put_page()).
Replace build_skb() with netdev_alloc_skb_ip_align() and use memcpy().
Remove SKB_DATA_ALIGN() from RX buffer size while we're at it.
Addresses https://bugzilla.kernel.org/show_bug.cgi?id=69041
Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
---
Notes:
Changes since v5:
1. broke out DMA synchronization to separate patch
Applies to next-20140825
drivers/net/ethernet/moxa/moxart_ether.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index eed70d9..d66058d 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -226,13 +226,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
if (len > RX_BUF_SIZE)
len = RX_BUF_SIZE;
- skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
+ skb = netdev_alloc_skb_ip_align(ndev, len);
+
if (unlikely(!skb)) {
- net_dbg_ratelimited("build_skb failed\n");
+ net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
priv->stats.rx_dropped++;
priv->stats.rx_errors++;
}
+ memcpy(skb->data, priv->rx_buf[rx_head], len);
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
napi_gro_receive(&priv->napi, skb);
@@ -464,8 +466,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
spin_lock_init(&priv->txlock);
priv->tx_buf_size = TX_BUF_SIZE;
- priv->rx_buf_size = RX_BUF_SIZE +
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ priv->rx_buf_size = RX_BUF_SIZE;
priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE *
TX_DESC_NUM, &priv->tx_base,
--
1.8.2.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-25 14:22 ` [PATCH v6 2/4] " Jonas Jensen
@ 2014-08-26 0:26 ` David Miller
2014-08-26 9:04 ` Arnd Bergmann
1 sibling, 0 replies; 18+ messages in thread
From: David Miller @ 2014-08-26 0:26 UTC (permalink / raw)
To: linux-arm-kernel
From: Jonas Jensen <jonas.jensen@gmail.com>
Date: Mon, 25 Aug 2014 16:22:22 +0200
> build_skb() is used to make skbs out of existing RX ring memory
> which is bad because the RX ring is allocated only once, on probe.
> Memory corruption occur because said memory is reclaimed, i.e.
> __kfree_skb() (and eventually put_page()).
>
> Replace build_skb() with netdev_alloc_skb_ip_align() and use memcpy().
>
> Remove SKB_DATA_ALIGN() from RX buffer size while we're at it.
>
> Addresses https://bugzilla.kernel.org/show_bug.cgi?id=69041
>
> Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
Applied.
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-25 14:22 ` [PATCH v6 2/4] " Jonas Jensen
2014-08-26 0:26 ` David Miller
@ 2014-08-26 9:04 ` Arnd Bergmann
2014-08-26 9:10 ` David Laight
1 sibling, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2014-08-26 9:04 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 25 August 2014 16:22:22 Jonas Jensen wrote:
> @@ -226,13 +226,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
> if (len > RX_BUF_SIZE)
> len = RX_BUF_SIZE;
>
> - skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
> + skb = netdev_alloc_skb_ip_align(ndev, len);
> +
> if (unlikely(!skb)) {
> - net_dbg_ratelimited("build_skb failed\n");
> + net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
> priv->stats.rx_dropped++;
> priv->stats.rx_errors++;
> }
>
> + memcpy(skb->data, priv->rx_buf[rx_head], len);
> skb_put(skb, len);
> skb->protocol = eth_type_trans(skb, ndev);
> napi_gro_receive(&priv->napi, skb);
While this seems correct, I wonder why you don't do the normal approach of
dequeuing the skb from the chain and adding a newly allocated skb to it to
save the memcpy.
Arnd
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-26 9:04 ` Arnd Bergmann
@ 2014-08-26 9:10 ` David Laight
2014-08-26 10:55 ` Eric Dumazet
0 siblings, 1 reply; 18+ messages in thread
From: David Laight @ 2014-08-26 9:10 UTC (permalink / raw)
To: linux-arm-kernel
From: Arnd Bergmann
> On Monday 25 August 2014 16:22:22 Jonas Jensen wrote:
> > @@ -226,13 +226,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
> > if (len > RX_BUF_SIZE)
> > len = RX_BUF_SIZE;
> >
> > - skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
> > + skb = netdev_alloc_skb_ip_align(ndev, len);
> > +
> > if (unlikely(!skb)) {
> > - net_dbg_ratelimited("build_skb failed\n");
> > + net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
> > priv->stats.rx_dropped++;
> > priv->stats.rx_errors++;
> > }
> >
> > + memcpy(skb->data, priv->rx_buf[rx_head], len);
Is this memcpy() aligned?
If the hardware can receive to a 4n+2 offset it is probably better to
copy the two bytes before the frame data and to round the length of to
a whole number of words.
> > skb_put(skb, len);
> > skb->protocol = eth_type_trans(skb, ndev);
> > napi_gro_receive(&priv->napi, skb);
>
> While this seems correct, I wonder why you don't do the normal approach of
> dequeuing the skb from the chain and adding a newly allocated skb to it to
> save the memcpy.
Because the receive buffer area isn't made of skbs.
Post-allocating the skb also reduces the 'true size' of the skb.
David
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-26 9:10 ` David Laight
@ 2014-08-26 10:55 ` Eric Dumazet
0 siblings, 0 replies; 18+ messages in thread
From: Eric Dumazet @ 2014-08-26 10:55 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 2014-08-26 at 09:10 +0000, David Laight wrote:
> From: Arnd Bergmann
> > While this seems correct, I wonder why you don't do the normal approach of
> > dequeuing the skb from the chain and adding a newly allocated skb to it to
> > save the memcpy.
>
> Because the receive buffer area isn't made of skbs.
> Post-allocating the skb also reduces the 'true size' of the skb.
This strategy assumes this is not a 10Gbe NIC.
We try to avoid copies because they are generally not needed.
Wifi devices are usually slow, and packet losses are more frequent, so
the copybreak gives better chance to not doing the collapses [1] later
in the TCP stack.
[1] collapses : reducing skb overhead (skb->len / skb->truesize ratio)
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-19 14:49 ` [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy() Jonas Jensen
2014-08-19 18:31 ` Eric Dumazet
2014-08-20 14:19 ` [PATCH v5 " Jonas Jensen
@ 2014-08-21 21:43 ` Michał Mirosław
2014-08-25 14:23 ` Jonas Jensen
2 siblings, 1 reply; 18+ messages in thread
From: Michał Mirosław @ 2014-08-21 21:43 UTC (permalink / raw)
To: linux-arm-kernel
2014-08-19 16:49 GMT+02:00 Jonas Jensen <jonas.jensen@gmail.com>:
[...]
> diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
> index aa45607..17c9f0e 100644
> --- a/drivers/net/ethernet/moxa/moxart_ether.c
> +++ b/drivers/net/ethernet/moxa/moxart_ether.c
> @@ -226,14 +226,21 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
> if (len > RX_BUF_SIZE)
> len = RX_BUF_SIZE;
>
> - skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
> + dma_sync_single_for_cpu(&ndev->dev,
> + priv->rx_mapping[rx_head],
> + priv->rx_buf_size, DMA_FROM_DEVICE);
> + skb = netdev_alloc_skb_ip_align(ndev, len);
> if (unlikely(!skb)) {
> - net_dbg_ratelimited("build_skb failed\n");
> + net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
> priv->stats.rx_dropped++;
> priv->stats.rx_errors++;
> }
> -
> + memcpy(skb->data, priv->rx_buf[rx_head], len);
This has implicit: if (!skb) BUG(); There should probably be a return
or continue inside the if (!skb).
> skb_put(skb, len);
> + dma_sync_single_for_device(&ndev->dev,
> + priv->rx_mapping[rx_head],
> + priv->rx_buf_size, DMA_FROM_DEVICE);
> +
dma_sync_single_for_device() is not needed here as CPU does not and
should not write to the DMA_FROM_DEVICE mapping.
> skb->protocol = eth_type_trans(skb, ndev);
> napi_gro_receive(&priv->napi, skb);
> rx++;
Best Regards,
Micha? Miros?aw
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 2/2] net: moxa: replace build_skb() with netdev_alloc_skb_ip_align() / memcpy()
2014-08-21 21:43 ` [PATCH v4 2/2] " Michał Mirosław
@ 2014-08-25 14:23 ` Jonas Jensen
0 siblings, 0 replies; 18+ messages in thread
From: Jonas Jensen @ 2014-08-25 14:23 UTC (permalink / raw)
To: linux-arm-kernel
Thanks for giving feedback.
On 21 August 2014 23:43, Micha? Miros?aw <mirqus@gmail.com> wrote:
> This has implicit: if (!skb) BUG(); There should probably be a return
> or continue inside the if (!skb).
Fixed, see v6 update (broken out to separate patch) which now includes
increment to RX head counter
> dma_sync_single_for_device() is not needed here as CPU does not and
> should not write to the DMA_FROM_DEVICE mapping.
Fixed, this was also broken out, dma_sync_single_for_device() moved to TX path.
Maybe someone can verify this is the correct thing to do.
Regards,
Jonas
^ permalink raw reply [flat|nested] 18+ messages in thread