r8169: Fix rtl8169_rx_interrupt()
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>
This commit is contained in:
parent
6c9ae016a8
commit
6c3b9d3458
@ -1042,14 +1042,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;
|
||||
@ -1066,7 +1066,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;
|
||||
}
|
||||
@ -4445,12 +4445,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;
|
||||
@ -4512,8 +4520,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++;
|
||||
|
Loading…
Reference in New Issue
Block a user