forcedeth: xmit lock fix
authorAyaz Abdulla <aabdulla@nvidia.com>
Fri, 9 Jan 2009 11:03:44 +0000 (11:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 11 Jan 2009 08:07:32 +0000 (00:07 -0800)
This patch fixes a potential race condition between xmit thread and xmit
completion thread. The calculation of empty tx descriptors is not
performed under the lock. This could cause it to set the stop flag while
the completion thread finishes all tx's. This will result in the tx
queue in stopped state and no one to wake it up.

Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/forcedeth.c

index 5b68dc20168db466a867f63e44823e500568e837..6905ec9467dfaecb3c0e4f96a1f95a4c272c2854 100644 (file)
@@ -2096,14 +2096,15 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                           ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
        }
 
+       spin_lock_irqsave(&np->lock, flags);
        empty_slots = nv_get_empty_tx_slots(np);
        if (unlikely(empty_slots <= entries)) {
-               spin_lock_irqsave(&np->lock, flags);
                netif_stop_queue(dev);
                np->tx_stop = 1;
                spin_unlock_irqrestore(&np->lock, flags);
                return NETDEV_TX_BUSY;
        }
+       spin_unlock_irqrestore(&np->lock, flags);
 
        start_tx = put_tx = np->put_tx.orig;
 
@@ -2214,14 +2215,15 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
                           ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
        }
 
+       spin_lock_irqsave(&np->lock, flags);
        empty_slots = nv_get_empty_tx_slots(np);
        if (unlikely(empty_slots <= entries)) {
-               spin_lock_irqsave(&np->lock, flags);
                netif_stop_queue(dev);
                np->tx_stop = 1;
                spin_unlock_irqrestore(&np->lock, flags);
                return NETDEV_TX_BUSY;
        }
+       spin_unlock_irqrestore(&np->lock, flags);
 
        start_tx = put_tx = np->put_tx.ex;
        start_tx_ctx = np->put_tx_ctx;