drivers/net: using spin_lock_irqsave() in net_send_packet()
Dongdong Deng [Sun, 12 Jul 2009 20:27:06 +0000 (20:27 +0000)]
spin_unlock_irq() will enable interrupt in net_send_packet(),
this patch changes it to spin_lock_irqsave/spin_lock_irqrestore,
so that it doesn't enable interrupts when already disabled,
and netconsole would work properly over cs89x0/isa-skeleton.

Call trace:
netconsole write_msg()
{
 ...
 -> spin_lock_irqsave();
        -> netpoll_send_udp()
          -> netpoll_send_skb()
            -> net_send_packet()
              ->...

 -> spin_unlock_irqrestore();
 ...
}

Signed-off-by: Dongdong Deng <dongdong.deng@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/cs89x0.c
drivers/net/isa-skeleton.c

index 3eee666..55445f9 100644 (file)
@@ -1524,6 +1524,7 @@ static void net_timeout(struct net_device *dev)
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_local *lp = netdev_priv(dev);
+       unsigned long flags;
 
        if (net_debug > 3) {
                printk("%s: sent %d byte packet of type %x\n",
@@ -1535,7 +1536,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                   ask the chip to start transmitting before the
                   whole packet has been completely uploaded. */
 
-       spin_lock_irq(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        netif_stop_queue(dev);
 
        /* initiate a transmit sequence */
@@ -1549,13 +1550,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
                 * we're waiting for TxOk, so return 1 and requeue this packet.
                 */
 
-               spin_unlock_irq(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                if (net_debug) printk("cs89x0: Tx buffer not free!\n");
                return NETDEV_TX_BUSY;
        }
        /* Write the contents of the packet */
        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
-       spin_unlock_irq(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
index 73585fd..d12377b 100644 (file)
@@ -430,7 +430,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * hardware interrupt handler.  Queue flow control is
         * thus managed under this lock as well.
         */
-       spin_lock_irq(&np->lock);
+       unsigned long flags;
+       spin_lock_irqsave(&np->lock, flags);
 
        add_to_tx_ring(np, skb, length);
        dev->trans_start = jiffies;
@@ -446,7 +447,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * is when the transmit statistics are updated.
         */
 
-       spin_unlock_irq(&np->lock);
+       spin_unlock_irqrestore(&np->lock, flags);
 #else
        /* This is the case for older hardware which takes
         * a single transmit buffer at a time, and it is