qlcnic: limit skb frags for non tso packet
authorAmit Kumar Salecha <amit.salecha@qlogic.com>
Tue, 12 Apr 2011 17:05:55 +0000 (17:05 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Apr 2011 18:53:11 +0000 (11:53 -0700)
Machines are getting deadlock in four node cluster environment.
All nodes are accessing (find /gfs2 -depth -print|cpio -ocv > /dev/null)
200 GB storage on a GFS2 filesystem.
This result in memory fragmentation and driver receives 18 frags for
1448 byte packets.
For non tso packet, fw drops the tx request, if it has >14 frags.

Fixing it by pulling extra frags.

Cc: stable@kernel.org
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_main.c

index dc44564ef6f9984fdc9a214491d9bdced015eb80..b0dead00b2d1d6b7809bd2b01906b5bff5a786b5 100644 (file)
@@ -99,6 +99,7 @@
 #define TX_UDPV6_PKT   0x0c
 
 /* Tx defines */
+#define QLCNIC_MAX_FRAGS_PER_TX        14
 #define MAX_TSO_HEADER_DESC    2
 #define MGMT_CMD_DESC_RESV     4
 #define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
index cd88c7e1bfa9c76c3ae156da021a020f27346be5..cb1a1ef36c0ade56ddb5dfb98c2ef2ce8813b100 100644 (file)
@@ -2099,6 +2099,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct cmd_desc_type0 *hwdesc, *first_desc;
        struct pci_dev *pdev;
        struct ethhdr *phdr;
+       int delta = 0;
        int i, k;
 
        u32 producer;
@@ -2118,6 +2119,19 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        frag_count = skb_shinfo(skb)->nr_frags + 1;
+       /* 14 frags supported for normal packet and
+        * 32 frags supported for TSO packet
+        */
+       if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
+
+               for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
+                       delta += skb_shinfo(skb)->frags[i].size;
+
+               if (!__pskb_pull_tail(skb, delta))
+                       goto drop_packet;
+
+               frag_count = 1 + skb_shinfo(skb)->nr_frags;
+       }
 
        /* 4 fragments per cmd des */
        no_of_desc = (frag_count + 3) >> 2;