ibmvnic: Clean up tx pools when closing
authorNathan Fontenot <nfont@linux.vnet.ibm.com>
Wed, 3 May 2017 18:04:56 +0000 (14:04 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 3 May 2017 15:33:04 +0000 (11:33 -0400)
When closing the ibmvnic driver, most notably during the reset
path, the tx pools need to be cleaned to ensure there are no
hanging skbs that need to be free'ed.

The need for this was found during debugging a loss of network
traffic after handling a driver reset. The underlying cause was
some skbs in the tx pool that were never free'ed. As a
result the upper network layers never tried a re-send since it
believed the driver still had the skb.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ibm/ibmvnic.c

index bbbd57e272c4ca0df67c3eda966c8685efb18186..2297cf2390e18443cb12d1afa86c547c1e78d101 100644 (file)
@@ -760,6 +760,34 @@ static void disable_sub_crqs(struct ibmvnic_adapter *adapter)
        }
 }
 
+static void clean_tx_pools(struct ibmvnic_adapter *adapter)
+{
+       struct ibmvnic_tx_pool *tx_pool;
+       u64 tx_entries;
+       int tx_scrqs;
+       int i, j;
+
+       if (!adapter->tx_pool)
+               return;
+
+       tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+       tx_entries = adapter->req_tx_entries_per_subcrq;
+
+       /* Free any remaining skbs in the tx buffer pools */
+       for (i = 0; i < tx_scrqs; i++) {
+               tx_pool = &adapter->tx_pool[i];
+               if (!tx_pool)
+                       continue;
+
+               for (j = 0; j < tx_entries; j++) {
+                       if (tx_pool->tx_buff[j].skb) {
+                               dev_kfree_skb_any(tx_pool->tx_buff[j].skb);
+                               tx_pool->tx_buff[j].skb = NULL;
+                       }
+               }
+       }
+}
+
 static int __ibmvnic_close(struct net_device *netdev)
 {
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@@ -768,6 +796,8 @@ static int __ibmvnic_close(struct net_device *netdev)
 
        adapter->state = VNIC_CLOSING;
        netif_tx_stop_all_queues(netdev);
+
+       clean_tx_pools(adapter);
        disable_sub_crqs(adapter);
 
        if (adapter->napi) {