Patchwork [2/4] forcedeth: xmit lock fix

login
register
mail settings
Submitter Ayaz Abdulla
Date Jan. 9, 2009, 9:03 p.m.
Message ID <4967BBB0.90809@nvidia.com>
Download mbox | patch
Permalink /patch/17690/
State Accepted
Delegated to: David Miller
Headers show

Comments

Ayaz Abdulla - Jan. 9, 2009, 9:03 p.m.
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>
David Miller - Jan. 10, 2009, 7:13 a.m.
From: Ayaz Abdulla <aabdulla@nvidia.com>
Date: Fri, 09 Jan 2009 16:03:44 -0500

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

Applied.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

--- old/drivers/net/forcedeth.c	2009-01-09 14:51:19.000000000 -0800
+++ new/drivers/net/forcedeth.c	2009-01-09 15:10:15.000000000 -0800
@@ -2096,14 +2096,15 @@ 
 			   ((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 @@ 
 			   ((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;