r8169: Fix rtl8169_rx_interrupt()
Eric Dumazet [Wed, 31 Mar 2010 02:08:31 +0000 (02:08 +0000)]
In case a reset is performed, rtl8169_rx_interrupt() is called from
process context instead of softirq context. Special care must be taken
to call appropriate network core services (netif_rx() instead of
netif_receive_skb()). VLAN handling also corrected.

Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Tested-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Diagnosed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/r8169.c

index 964305c..f7ffa5d 100644 (file)
@@ -1054,14 +1054,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
 }
 
 static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
-                              struct sk_buff *skb)
+                              struct sk_buff *skb, int polling)
 {
        u32 opts2 = le32_to_cpu(desc->opts2);
        struct vlan_group *vlgrp = tp->vlgrp;
        int ret;
 
        if (vlgrp && (opts2 & RxVlanTag)) {
-               vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
+               __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
                ret = 0;
        } else
                ret = -1;
@@ -1078,7 +1078,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
 }
 
 static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
-                              struct sk_buff *skb)
+                              struct sk_buff *skb, int polling)
 {
        return -1;
 }
@@ -4467,12 +4467,20 @@ out:
        return done;
 }
 
+/*
+ * Warning : rtl8169_rx_interrupt() might be called :
+ * 1) from NAPI (softirq) context
+ *     (polling = 1 : we should call netif_receive_skb())
+ * 2) from process context (rtl8169_reset_task())
+ *     (polling = 0 : we must call netif_rx() instead)
+ */
 static int rtl8169_rx_interrupt(struct net_device *dev,
                                struct rtl8169_private *tp,
                                void __iomem *ioaddr, u32 budget)
 {
        unsigned int cur_rx, rx_left;
        unsigned int delta, count;
+       int polling = (budget != ~(u32)0) ? 1 : 0;
 
        cur_rx = tp->cur_rx;
        rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
@@ -4534,8 +4542,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                        skb_put(skb, pkt_size);
                        skb->protocol = eth_type_trans(skb, dev);
 
-                       if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
-                               netif_receive_skb(skb);
+                       if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
+                               if (likely(polling))
+                                       netif_receive_skb(skb);
+                               else
+                                       netif_rx(skb);
+                       }
 
                        dev->stats.rx_bytes += pkt_size;
                        dev->stats.rx_packets++;