forcedeth: xmit lock fix

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>
This commit is contained in:
Ayaz Abdulla 2009-01-09 11:03:44 +00:00 committed by David S. Miller
parent 52255bbe35
commit 001eb84bbf
1 changed files with 4 additions and 2 deletions

View 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;