diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
| -rw-r--r-- | net/8021q/vlan_dev.c | 52 | 
1 files changed, 31 insertions, 21 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 73a2a83ee2d..402442402af 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -137,9 +137,21 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,  	return rc;  } +static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb) +{ +#ifdef CONFIG_NET_POLL_CONTROLLER +	if (vlan->netpoll) +		netpoll_send_skb(vlan->netpoll, skb); +#else +	BUG(); +#endif +	return NETDEV_TX_OK; +} +  static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,  					    struct net_device *dev)  { +	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);  	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);  	unsigned int len;  	int ret; @@ -150,29 +162,30 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,  	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...  	 */  	if (veth->h_vlan_proto != htons(ETH_P_8021Q) || -	    vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR) { +	    vlan->flags & VLAN_FLAG_REORDER_HDR) {  		u16 vlan_tci; -		vlan_tci = vlan_dev_priv(dev)->vlan_id; +		vlan_tci = vlan->vlan_id;  		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);  		skb = __vlan_hwaccel_put_tag(skb, vlan_tci);  	} -	skb->dev = vlan_dev_priv(dev)->real_dev; +	skb->dev = vlan->real_dev;  	len = skb->len; -	if (netpoll_tx_running(dev)) -		return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev); +	if (unlikely(netpoll_tx_running(dev))) +		return vlan_netpoll_send_skb(vlan, skb); +  	ret = dev_queue_xmit(skb);  	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {  		struct vlan_pcpu_stats *stats; -		stats = this_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats); +		stats = this_cpu_ptr(vlan->vlan_pcpu_stats);  		u64_stats_update_begin(&stats->syncp);  		stats->tx_packets++;  		stats->tx_bytes += len;  		u64_stats_update_end(&stats->syncp);  	} else { -		this_cpu_inc(vlan_dev_priv(dev)->vlan_pcpu_stats->tx_dropped); +		this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);  	}  	return ret; @@ -669,25 +682,26 @@ static void vlan_dev_poll_controller(struct net_device *dev)  	return;  } -static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo) +static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo, +				  gfp_t gfp)  { -	struct vlan_dev_priv *info = vlan_dev_priv(dev); -	struct net_device *real_dev = info->real_dev; +	struct vlan_dev_priv *vlan = vlan_dev_priv(dev); +	struct net_device *real_dev = vlan->real_dev;  	struct netpoll *netpoll;  	int err = 0; -	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); +	netpoll = kzalloc(sizeof(*netpoll), gfp);  	err = -ENOMEM;  	if (!netpoll)  		goto out; -	err = __netpoll_setup(netpoll, real_dev); +	err = __netpoll_setup(netpoll, real_dev, gfp);  	if (err) {  		kfree(netpoll);  		goto out;  	} -	info->netpoll = netpoll; +	vlan->netpoll = netpoll;  out:  	return err; @@ -695,19 +709,15 @@ out:  static void vlan_dev_netpoll_cleanup(struct net_device *dev)  { -	struct vlan_dev_priv *info = vlan_dev_priv(dev); -	struct netpoll *netpoll = info->netpoll; +	struct vlan_dev_priv *vlan= vlan_dev_priv(dev); +	struct netpoll *netpoll = vlan->netpoll;  	if (!netpoll)  		return; -	info->netpoll = NULL; - -        /* Wait for transmitting packets to finish before freeing. */ -        synchronize_rcu_bh(); +	vlan->netpoll = NULL; -        __netpoll_cleanup(netpoll); -        kfree(netpoll); +	__netpoll_free_rcu(netpoll);  }  #endif /* CONFIG_NET_POLL_CONTROLLER */  |