diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2009-05-25 03:42:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-25 03:42:34 -0400 |
commit | 4e2fd555199977c5994d1a4d2d3b8761b20ca4c7 (patch) | |
tree | 474454cd8fbe7f643d5ae5136bf43ec8a8513359 /drivers/net | |
parent | 0975ecba3b670df7c488a5e0e6fe9f1f370a8ad8 (diff) |
gianfar: fix BUG under load after introduction of skb recycling
Since commit 0fd56bb5be6455d0d42241e65aed057244665e5e ("gianfar:
Add support for skb recycling"), gianfar puts skbuffs that are in
the rx ring back onto the recycle list as-is in case there was a
receive error, but this breaks the following invariant: that all
skbuffs on the recycle list have skb->data = skb->head + NET_SKB_PAD.
The RXBUF_ALIGNMENT realignment done in gfar_new_skb() will be done
twice on skbuffs recycled in this way, causing there not to be enough
room in the skb anymore to receive a full packet, eventually leading
to an skb_over_panic from gfar_clean_rx_ring() -> skb_put().
Resetting the skb->data pointer to skb->head + NET_SKB_PAD before
putting the skb back onto the recycle list restores the mentioned
invariant, and should fix this issue.
Reported-by: Michael Guntsche <mike@it-loops.com>
Tested-by: Michael Guntsche <mike@it-loops.com>
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/gianfar.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b2c49679bba..a0519184e54 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -1885,8 +1885,17 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1885 | 1885 | ||
1886 | if (unlikely(!newskb)) | 1886 | if (unlikely(!newskb)) |
1887 | newskb = skb; | 1887 | newskb = skb; |
1888 | else if (skb) | 1888 | else if (skb) { |
1889 | /* | ||
1890 | * We need to reset ->data to what it | ||
1891 | * was before gfar_new_skb() re-aligned | ||
1892 | * it to an RXBUF_ALIGNMENT boundary | ||
1893 | * before we put the skb back on the | ||
1894 | * recycle list. | ||
1895 | */ | ||
1896 | skb->data = skb->head + NET_SKB_PAD; | ||
1889 | __skb_queue_head(&priv->rx_recycle, skb); | 1897 | __skb_queue_head(&priv->rx_recycle, skb); |
1898 | } | ||
1890 | } else { | 1899 | } else { |
1891 | /* Increment the number of packets */ | 1900 | /* Increment the number of packets */ |
1892 | dev->stats.rx_packets++; | 1901 | dev->stats.rx_packets++; |