atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring (Closes: #718505)
svn path=/dists/sid/linux/; revision=20447
This commit is contained in:
parent
c02187d4c4
commit
acabcd80cc
|
@ -77,6 +77,8 @@ linux (3.10.5-1) UNRELEASED; urgency=low
|
||||||
* nl80211: fix another nl80211_fam.attrbuf race
|
* nl80211: fix another nl80211_fam.attrbuf race
|
||||||
* Bump ABI to 2
|
* Bump ABI to 2
|
||||||
* ext4: fix retry handling in ext4_ext_truncate()
|
* ext4: fix retry handling in ext4_ext_truncate()
|
||||||
|
* atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring
|
||||||
|
(Closes: #718505)
|
||||||
|
|
||||||
-- Ben Hutchings <ben@decadent.org.uk> Tue, 30 Jul 2013 18:09:20 +0200
|
-- Ben Hutchings <ben@decadent.org.uk> Tue, 30 Jul 2013 18:09:20 +0200
|
||||||
|
|
||||||
|
|
131
debian/patches/bugfix/all/atl1c-Fix-misuse-of-netdev_alloc_skb-in-refilling-rx.patch
vendored
Normal file
131
debian/patches/bugfix/all/atl1c-Fix-misuse-of-netdev_alloc_skb-in-refilling-rx.patch
vendored
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
From: Eric Dumazet <edumazet@google.com>
|
||||||
|
Date: Mon, 29 Jul 2013 10:24:04 -0700
|
||||||
|
Subject: atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring
|
||||||
|
Origin: https://git.kernel.org/linus/7b70176421993866e616f1cbc4d0dd4054f1bf78
|
||||||
|
|
||||||
|
On Mon, 2013-07-29 at 08:30 -0700, Eric Dumazet wrote:
|
||||||
|
> On Mon, 2013-07-29 at 13:09 +0100, Luis Henriques wrote:
|
||||||
|
>
|
||||||
|
> >
|
||||||
|
> > I confirm that I can't reproduce the issue using this patch.
|
||||||
|
> >
|
||||||
|
>
|
||||||
|
> Thanks, I'll send a polished patch, as this one had an error if
|
||||||
|
> build_skb() returns NULL (in case sk_buff allocation fails)
|
||||||
|
|
||||||
|
Please try the following patch : It should use 2K frags instead of 4K
|
||||||
|
for normal 1500 mtu
|
||||||
|
|
||||||
|
Thanks !
|
||||||
|
|
||||||
|
[PATCH] atl1c: use custom skb allocator
|
||||||
|
|
||||||
|
We had reports ( https://bugzilla.kernel.org/show_bug.cgi?id=54021 )
|
||||||
|
that using high order pages for skb allocations is problematic for atl1c
|
||||||
|
|
||||||
|
We do not know exactly what the problem is, but we suspect that crossing
|
||||||
|
4K pages is not well supported by this hardware.
|
||||||
|
|
||||||
|
Use a custom allocator, using page allocator and 2K fragments for
|
||||||
|
optimal stack behavior. We might make this allocator generic
|
||||||
|
in future kernels.
|
||||||
|
|
||||||
|
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||||
|
Cc: Luis Henriques <luis.henriques@canonical.com>
|
||||||
|
Cc: Neil Horman <nhorman@tuxdriver.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/ethernet/atheros/atl1c/atl1c.h | 3 ++
|
||||||
|
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 40 ++++++++++++++++++++++++-
|
||||||
|
2 files changed, 42 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
|
||||||
|
index b2bf324..0f05565 100644
|
||||||
|
--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h
|
||||||
|
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
|
||||||
|
@@ -520,6 +520,9 @@ struct atl1c_adapter {
|
||||||
|
struct net_device *netdev;
|
||||||
|
struct pci_dev *pdev;
|
||||||
|
struct napi_struct napi;
|
||||||
|
+ struct page *rx_page;
|
||||||
|
+ unsigned int rx_page_offset;
|
||||||
|
+ unsigned int rx_frag_size;
|
||||||
|
struct atl1c_hw hw;
|
||||||
|
struct atl1c_hw_stats hw_stats;
|
||||||
|
struct mii_if_info mii; /* MII interface info */
|
||||||
|
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
|
||||||
|
index 786a874..a36a760 100644
|
||||||
|
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
|
||||||
|
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
|
||||||
|
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
|
||||||
|
static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
|
||||||
|
struct net_device *dev)
|
||||||
|
{
|
||||||
|
+ unsigned int head_size;
|
||||||
|
int mtu = dev->mtu;
|
||||||
|
|
||||||
|
adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
|
||||||
|
roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
|
||||||
|
+
|
||||||
|
+ head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
|
||||||
|
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||||
|
+ adapter->rx_frag_size = roundup_pow_of_two(head_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
|
||||||
|
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
|
||||||
|
kfree(adapter->tpd_ring[0].buffer_info);
|
||||||
|
adapter->tpd_ring[0].buffer_info = NULL;
|
||||||
|
}
|
||||||
|
+ if (adapter->rx_page) {
|
||||||
|
+ put_page(adapter->rx_page);
|
||||||
|
+ adapter->rx_page = NULL;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
|
||||||
|
skb_checksum_none_assert(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
|
||||||
|
+{
|
||||||
|
+ struct sk_buff *skb;
|
||||||
|
+ struct page *page;
|
||||||
|
+
|
||||||
|
+ if (adapter->rx_frag_size > PAGE_SIZE)
|
||||||
|
+ return netdev_alloc_skb(adapter->netdev,
|
||||||
|
+ adapter->rx_buffer_len);
|
||||||
|
+
|
||||||
|
+ page = adapter->rx_page;
|
||||||
|
+ if (!page) {
|
||||||
|
+ adapter->rx_page = page = alloc_page(GFP_ATOMIC);
|
||||||
|
+ if (unlikely(!page))
|
||||||
|
+ return NULL;
|
||||||
|
+ adapter->rx_page_offset = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ skb = build_skb(page_address(page) + adapter->rx_page_offset,
|
||||||
|
+ adapter->rx_frag_size);
|
||||||
|
+ if (likely(skb)) {
|
||||||
|
+ adapter->rx_page_offset += adapter->rx_frag_size;
|
||||||
|
+ if (adapter->rx_page_offset >= PAGE_SIZE)
|
||||||
|
+ adapter->rx_page = NULL;
|
||||||
|
+ else
|
||||||
|
+ get_page(page);
|
||||||
|
+ }
|
||||||
|
+ return skb;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
|
||||||
|
{
|
||||||
|
struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
|
||||||
|
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
|
||||||
|
while (next_info->flags & ATL1C_BUFFER_FREE) {
|
||||||
|
rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
|
||||||
|
|
||||||
|
- skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
|
||||||
|
+ skb = atl1c_alloc_skb(adapter);
|
||||||
|
if (unlikely(!skb)) {
|
||||||
|
if (netif_msg_rx_err(adapter))
|
||||||
|
dev_warn(&pdev->dev, "alloc rx buffer failed\n");
|
|
@ -113,3 +113,4 @@ bugfix/m68k/ethernat-kconfig.patch
|
||||||
debian/sparc-cpufreq-convince-genksyms-that-the-abi-didnt-change.patch
|
debian/sparc-cpufreq-convince-genksyms-that-the-abi-didnt-change.patch
|
||||||
bugfix/all/nl80211-fix-another-nl80211_fam-attrbuf-race.patch
|
bugfix/all/nl80211-fix-another-nl80211_fam-attrbuf-race.patch
|
||||||
bugfix/all/ext4-fix-retry-handling-in-ext4_ext_truncate.patch
|
bugfix/all/ext4-fix-retry-handling-in-ext4_ext_truncate.patch
|
||||||
|
bugfix/all/atl1c-Fix-misuse-of-netdev_alloc_skb-in-refilling-rx.patch
|
||||||
|
|
Loading…
Reference in New Issue