forked from mirrors/linux
		
	net: dev: Makes sure netif_rx() can be invoked in any context.
Dave suggested a while ago (eleven years by now) "Let's make netif_rx() work in all contexts and get rid of netif_rx_ni()". Eric agreed and pointed out that modern devices should use netif_receive_skb() to avoid the overhead. In the meantime someone added another variant, netif_rx_any_context(), which behaves as suggested. netif_rx() must be invoked with disabled bottom halves to ensure that pending softirqs, which were raised within the function, are handled. netif_rx_ni() can be invoked only from process context (bottom halves must be enabled) because the function handles pending softirqs without checking if bottom halves were disabled or not. netif_rx_any_context() invokes on the former functions by checking in_interrupts(). netif_rx() could be taught to handle both cases (disabled and enabled bottom halves) by simply disabling bottom halves while invoking netif_rx_internal(). The local_bh_enable() invocation will then invoke pending softirqs only if the BH-disable counter drops to zero. Eric is concerned about the overhead of BH-disable+enable especially in regard to the loopback driver. As critical as this driver is, it will receive a shortcut to avoid the additional overhead which is not needed. Add a local_bh_disable() section in netif_rx() to ensure softirqs are handled if needed. Provide __netif_rx() which does not disable BH and has a lockdep assert to ensure that interrupts are disabled. Use this shortcut in the loopback driver and in drivers/net/*.c. Make netif_rx_ni() and netif_rx_any_context() invoke netif_rx() so they can be removed once they are no more users left. Link: https://lkml.kernel.org/r/20100415.020246.218622820.davem@davemloft.net Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									f234ae2947
								
							
						
					
					
						commit
						baebdf48c3
					
				
					 16 changed files with 60 additions and 73 deletions
				
			
		|  | @ -2373,7 +2373,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt, | ||||||
| 	skb->pkt_type = PACKET_MULTICAST; | 	skb->pkt_type = PACKET_MULTICAST; | ||||||
| 	skb->ip_summed = CHECKSUM_NONE; | 	skb->ip_summed = CHECKSUM_NONE; | ||||||
| 	len = skb->len; | 	len = skb->len; | ||||||
| 	if (netif_rx(skb) == NET_RX_SUCCESS) { | 	if (__netif_rx(skb) == NET_RX_SUCCESS) { | ||||||
| 		amt_update_gw_status(amt, AMT_STATUS_RECEIVED_QUERY, true); | 		amt_update_gw_status(amt, AMT_STATUS_RECEIVED_QUERY, true); | ||||||
| 		dev_sw_netstats_rx_add(amt->dev, len); | 		dev_sw_netstats_rx_add(amt->dev, len); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -2470,7 +2470,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb) | ||||||
| 	skb->pkt_type = PACKET_MULTICAST; | 	skb->pkt_type = PACKET_MULTICAST; | ||||||
| 	skb->ip_summed = CHECKSUM_NONE; | 	skb->ip_summed = CHECKSUM_NONE; | ||||||
| 	len = skb->len; | 	len = skb->len; | ||||||
| 	if (netif_rx(skb) == NET_RX_SUCCESS) { | 	if (__netif_rx(skb) == NET_RX_SUCCESS) { | ||||||
| 		amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_UPDATE, | 		amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_UPDATE, | ||||||
| 					true); | 					true); | ||||||
| 		dev_sw_netstats_rx_add(amt->dev, len); | 		dev_sw_netstats_rx_add(amt->dev, len); | ||||||
|  |  | ||||||
|  | @ -925,7 +925,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		skb->protocol = eth_type_trans(skb, geneve->dev); | 		skb->protocol = eth_type_trans(skb, geneve->dev); | ||||||
| 		netif_rx(skb); | 		__netif_rx(skb); | ||||||
| 		dst_release(&rt->dst); | 		dst_release(&rt->dst); | ||||||
| 		return -EMSGSIZE; | 		return -EMSGSIZE; | ||||||
| 	} | 	} | ||||||
|  | @ -1021,7 +1021,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		skb->protocol = eth_type_trans(skb, geneve->dev); | 		skb->protocol = eth_type_trans(skb, geneve->dev); | ||||||
| 		netif_rx(skb); | 		__netif_rx(skb); | ||||||
| 		dst_release(dst); | 		dst_release(dst); | ||||||
| 		return -EMSGSIZE; | 		return -EMSGSIZE; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -207,7 +207,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 	dev_sw_netstats_rx_add(pctx->dev, skb->len); | 	dev_sw_netstats_rx_add(pctx->dev, skb->len); | ||||||
| 
 | 
 | ||||||
| 	netif_rx(skb); | 	__netif_rx(skb); | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err: | err: | ||||||
|  |  | ||||||
|  | @ -78,7 +78,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 	skb_orphan(skb); | 	skb_orphan(skb); | ||||||
| 
 | 
 | ||||||
| 	/* Before queueing this packet to netif_rx(),
 | 	/* Before queueing this packet to __netif_rx(),
 | ||||||
| 	 * make sure dst is refcounted. | 	 * make sure dst is refcounted. | ||||||
| 	 */ | 	 */ | ||||||
| 	skb_dst_force(skb); | 	skb_dst_force(skb); | ||||||
|  | @ -86,7 +86,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, | ||||||
| 	skb->protocol = eth_type_trans(skb, dev); | 	skb->protocol = eth_type_trans(skb, dev); | ||||||
| 
 | 
 | ||||||
| 	len = skb->len; | 	len = skb->len; | ||||||
| 	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) | 	if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) | ||||||
| 		dev_lstats_add(dev, len); | 		dev_lstats_add(dev, len); | ||||||
| 
 | 
 | ||||||
| 	return NETDEV_TX_OK; | 	return NETDEV_TX_OK; | ||||||
|  |  | ||||||
|  | @ -1033,7 +1033,7 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb) | ||||||
| 				else | 				else | ||||||
| 					nskb->pkt_type = PACKET_MULTICAST; | 					nskb->pkt_type = PACKET_MULTICAST; | ||||||
| 
 | 
 | ||||||
| 				netif_rx(nskb); | 				__netif_rx(nskb); | ||||||
| 			} | 			} | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | @ -1056,7 +1056,7 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb) | ||||||
| 
 | 
 | ||||||
| 		nskb->dev = ndev; | 		nskb->dev = ndev; | ||||||
| 
 | 
 | ||||||
| 		if (netif_rx(nskb) == NET_RX_SUCCESS) { | 		if (__netif_rx(nskb) == NET_RX_SUCCESS) { | ||||||
| 			u64_stats_update_begin(&secy_stats->syncp); | 			u64_stats_update_begin(&secy_stats->syncp); | ||||||
| 			secy_stats->stats.InPktsUntagged++; | 			secy_stats->stats.InPktsUntagged++; | ||||||
| 			u64_stats_update_end(&secy_stats->syncp); | 			u64_stats_update_end(&secy_stats->syncp); | ||||||
|  | @ -1288,7 +1288,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) | ||||||
| 
 | 
 | ||||||
| 		macsec_reset_skb(nskb, macsec->secy.netdev); | 		macsec_reset_skb(nskb, macsec->secy.netdev); | ||||||
| 
 | 
 | ||||||
| 		ret = netif_rx(nskb); | 		ret = __netif_rx(nskb); | ||||||
| 		if (ret == NET_RX_SUCCESS) { | 		if (ret == NET_RX_SUCCESS) { | ||||||
| 			u64_stats_update_begin(&secy_stats->syncp); | 			u64_stats_update_begin(&secy_stats->syncp); | ||||||
| 			secy_stats->stats.InPktsUnknownSCI++; | 			secy_stats->stats.InPktsUnknownSCI++; | ||||||
|  |  | ||||||
|  | @ -410,7 +410,7 @@ static void macvlan_forward_source_one(struct sk_buff *skb, | ||||||
| 	if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, dev->dev_addr)) | 	if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, dev->dev_addr)) | ||||||
| 		nskb->pkt_type = PACKET_HOST; | 		nskb->pkt_type = PACKET_HOST; | ||||||
| 
 | 
 | ||||||
| 	ret = netif_rx(nskb); | 	ret = __netif_rx(nskb); | ||||||
| 	macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false); | 	macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -468,7 +468,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) | ||||||
| 			/* forward to original port. */ | 			/* forward to original port. */ | ||||||
| 			vlan = src; | 			vlan = src; | ||||||
| 			ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?: | 			ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?: | ||||||
| 			      netif_rx(skb); | 			      __netif_rx(skb); | ||||||
| 			handle_res = RX_HANDLER_CONSUMED; | 			handle_res = RX_HANDLER_CONSUMED; | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -225,7 +225,7 @@ static void mhi_net_dl_callback(struct mhi_device *mhi_dev, | ||||||
| 		u64_stats_inc(&mhi_netdev->stats.rx_packets); | 		u64_stats_inc(&mhi_netdev->stats.rx_packets); | ||||||
| 		u64_stats_add(&mhi_netdev->stats.rx_bytes, skb->len); | 		u64_stats_add(&mhi_netdev->stats.rx_bytes, skb->len); | ||||||
| 		u64_stats_update_end(&mhi_netdev->stats.rx_syncp); | 		u64_stats_update_end(&mhi_netdev->stats.rx_syncp); | ||||||
| 		netif_rx(skb); | 		__netif_rx(skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Refill if RX buffers queue becomes low */ | 	/* Refill if RX buffers queue becomes low */ | ||||||
|  |  | ||||||
|  | @ -119,7 +119,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data, | ||||||
| 	skb->protocol = eth_type_trans(skb, ndev); | 	skb->protocol = eth_type_trans(skb, ndev); | ||||||
| 	skb->ip_summed = CHECKSUM_NONE; | 	skb->ip_summed = CHECKSUM_NONE; | ||||||
| 
 | 
 | ||||||
| 	if (netif_rx(skb) == NET_RX_DROP) { | 	if (__netif_rx(skb) == NET_RX_DROP) { | ||||||
| 		ndev->stats.rx_errors++; | 		ndev->stats.rx_errors++; | ||||||
| 		ndev->stats.rx_dropped++; | 		ndev->stats.rx_dropped++; | ||||||
| 	} else { | 	} else { | ||||||
|  |  | ||||||
|  | @ -109,7 +109,7 @@ static int rionet_rx_clean(struct net_device *ndev) | ||||||
| 		skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); | 		skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); | ||||||
| 		rnet->rx_skb[i]->protocol = | 		rnet->rx_skb[i]->protocol = | ||||||
| 		    eth_type_trans(rnet->rx_skb[i], ndev); | 		    eth_type_trans(rnet->rx_skb[i], ndev); | ||||||
| 		error = netif_rx(rnet->rx_skb[i]); | 		error = __netif_rx(rnet->rx_skb[i]); | ||||||
| 
 | 
 | ||||||
| 		if (error == NET_RX_DROP) { | 		if (error == NET_RX_DROP) { | ||||||
| 			ndev->stats.rx_dropped++; | 			ndev->stats.rx_dropped++; | ||||||
|  |  | ||||||
|  | @ -872,7 +872,7 @@ printk("cm0: IP identification: %02x%02x  fragment offset: %02x%02x\n", buffer[3 | ||||||
| 
 | 
 | ||||||
| 	/* datagram completed: send to upper level */ | 	/* datagram completed: send to upper level */ | ||||||
| 	skb_trim(skb, dlen); | 	skb_trim(skb, dlen); | ||||||
| 	netif_rx(skb); | 	__netif_rx(skb); | ||||||
| 	stats->rx_bytes+=dlen; | 	stats->rx_bytes+=dlen; | ||||||
| 	stats->rx_packets++; | 	stats->rx_packets++; | ||||||
| 	lp->rx_skb[ns] = NULL; | 	lp->rx_skb[ns] = NULL; | ||||||
|  |  | ||||||
|  | @ -287,7 +287,7 @@ static int veth_forward_skb(struct net_device *dev, struct sk_buff *skb, | ||||||
| { | { | ||||||
| 	return __dev_forward_skb(dev, skb) ?: xdp ? | 	return __dev_forward_skb(dev, skb) ?: xdp ? | ||||||
| 		veth_xdp_rx(rq, skb) : | 		veth_xdp_rx(rq, skb) : | ||||||
| 		netif_rx(skb); | 		__netif_rx(skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* return true if the specified skb has chances of GRO aggregation
 | /* return true if the specified skb has chances of GRO aggregation
 | ||||||
|  |  | ||||||
|  | @ -418,7 +418,7 @@ static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	skb->protocol = eth_type_trans(skb, dev); | 	skb->protocol = eth_type_trans(skb, dev); | ||||||
| 
 | 
 | ||||||
| 	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) | 	if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) | ||||||
| 		vrf_rx_stats(dev, len); | 		vrf_rx_stats(dev, len); | ||||||
| 	else | 	else | ||||||
| 		this_cpu_inc(dev->dstats->rx_drps); | 		this_cpu_inc(dev->dstats->rx_drps); | ||||||
|  |  | ||||||
|  | @ -2541,7 +2541,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, | ||||||
| 	tx_stats->tx_bytes += len; | 	tx_stats->tx_bytes += len; | ||||||
| 	u64_stats_update_end(&tx_stats->syncp); | 	u64_stats_update_end(&tx_stats->syncp); | ||||||
| 
 | 
 | ||||||
| 	if (netif_rx(skb) == NET_RX_SUCCESS) { | 	if (__netif_rx(skb) == NET_RX_SUCCESS) { | ||||||
| 		u64_stats_update_begin(&rx_stats->syncp); | 		u64_stats_update_begin(&rx_stats->syncp); | ||||||
| 		rx_stats->rx_packets++; | 		rx_stats->rx_packets++; | ||||||
| 		rx_stats->rx_bytes += len; | 		rx_stats->rx_bytes += len; | ||||||
|  |  | ||||||
|  | @ -3672,8 +3672,18 @@ u32 bpf_prog_run_generic_xdp(struct sk_buff *skb, struct xdp_buff *xdp, | ||||||
| void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog); | void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog); | ||||||
| int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb); | int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb); | ||||||
| int netif_rx(struct sk_buff *skb); | int netif_rx(struct sk_buff *skb); | ||||||
| int netif_rx_ni(struct sk_buff *skb); | int __netif_rx(struct sk_buff *skb); | ||||||
| int netif_rx_any_context(struct sk_buff *skb); | 
 | ||||||
|  | static inline int netif_rx_ni(struct sk_buff *skb) | ||||||
|  | { | ||||||
|  | 	return netif_rx(skb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline int netif_rx_any_context(struct sk_buff *skb) | ||||||
|  | { | ||||||
|  | 	return netif_rx(skb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int netif_receive_skb(struct sk_buff *skb); | int netif_receive_skb(struct sk_buff *skb); | ||||||
| int netif_receive_skb_core(struct sk_buff *skb); | int netif_receive_skb_core(struct sk_buff *skb); | ||||||
| void netif_receive_skb_list_internal(struct list_head *head); | void netif_receive_skb_list_internal(struct list_head *head); | ||||||
|  |  | ||||||
|  | @ -260,13 +260,6 @@ DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_entry, | ||||||
| 	TP_ARGS(skb) | 	TP_ARGS(skb) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_ni_entry, |  | ||||||
| 
 |  | ||||||
| 	TP_PROTO(const struct sk_buff *skb), |  | ||||||
| 
 |  | ||||||
| 	TP_ARGS(skb) |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| DECLARE_EVENT_CLASS(net_dev_rx_exit_template, | DECLARE_EVENT_CLASS(net_dev_rx_exit_template, | ||||||
| 
 | 
 | ||||||
| 	TP_PROTO(int ret), | 	TP_PROTO(int ret), | ||||||
|  | @ -312,13 +305,6 @@ DEFINE_EVENT(net_dev_rx_exit_template, netif_rx_exit, | ||||||
| 	TP_ARGS(ret) | 	TP_ARGS(ret) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| DEFINE_EVENT(net_dev_rx_exit_template, netif_rx_ni_exit, |  | ||||||
| 
 |  | ||||||
| 	TP_PROTO(int ret), |  | ||||||
| 
 |  | ||||||
| 	TP_ARGS(ret) |  | ||||||
| ); |  | ||||||
| 
 |  | ||||||
| DEFINE_EVENT(net_dev_rx_exit_template, netif_receive_skb_list_exit, | DEFINE_EVENT(net_dev_rx_exit_template, netif_receive_skb_list_exit, | ||||||
| 
 | 
 | ||||||
| 	TP_PROTO(int ret), | 	TP_PROTO(int ret), | ||||||
|  |  | ||||||
|  | @ -4815,66 +4815,57 @@ static int netif_rx_internal(struct sk_buff *skb) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  *	__netif_rx	-	Slightly optimized version of netif_rx | ||||||
|  |  *	@skb: buffer to post | ||||||
|  |  * | ||||||
|  |  *	This behaves as netif_rx except that it does not disable bottom halves. | ||||||
|  |  *	As a result this function may only be invoked from the interrupt context | ||||||
|  |  *	(either hard or soft interrupt). | ||||||
|  |  */ | ||||||
|  | int __netif_rx(struct sk_buff *skb) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	lockdep_assert_once(hardirq_count() | softirq_count()); | ||||||
|  | 
 | ||||||
|  | 	trace_netif_rx_entry(skb); | ||||||
|  | 	ret = netif_rx_internal(skb); | ||||||
|  | 	trace_netif_rx_exit(ret); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(__netif_rx); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  *	netif_rx	-	post buffer to the network code |  *	netif_rx	-	post buffer to the network code | ||||||
|  *	@skb: buffer to post |  *	@skb: buffer to post | ||||||
|  * |  * | ||||||
|  *	This function receives a packet from a device driver and queues it for |  *	This function receives a packet from a device driver and queues it for | ||||||
|  *	the upper (protocol) levels to process.  It always succeeds. The buffer |  *	the upper (protocol) levels to process via the backlog NAPI device. It | ||||||
|  *	may be dropped during processing for congestion control or by the |  *	always succeeds. The buffer may be dropped during processing for | ||||||
|  *	protocol layers. |  *	congestion control or by the protocol layers. | ||||||
|  |  *	The network buffer is passed via the backlog NAPI device. Modern NIC | ||||||
|  |  *	driver should use NAPI and GRO. | ||||||
|  |  *	This function can used from any context. | ||||||
|  * |  * | ||||||
|  *	return values: |  *	return values: | ||||||
|  *	NET_RX_SUCCESS	(no congestion) |  *	NET_RX_SUCCESS	(no congestion) | ||||||
|  *	NET_RX_DROP     (packet was dropped) |  *	NET_RX_DROP     (packet was dropped) | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 |  | ||||||
| int netif_rx(struct sk_buff *skb) | int netif_rx(struct sk_buff *skb) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | 	local_bh_disable(); | ||||||
| 	trace_netif_rx_entry(skb); | 	trace_netif_rx_entry(skb); | ||||||
| 
 |  | ||||||
| 	ret = netif_rx_internal(skb); | 	ret = netif_rx_internal(skb); | ||||||
| 	trace_netif_rx_exit(ret); | 	trace_netif_rx_exit(ret); | ||||||
| 
 | 	local_bh_enable(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(netif_rx); | EXPORT_SYMBOL(netif_rx); | ||||||
| 
 | 
 | ||||||
| int netif_rx_ni(struct sk_buff *skb) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	trace_netif_rx_ni_entry(skb); |  | ||||||
| 
 |  | ||||||
| 	preempt_disable(); |  | ||||||
| 	err = netif_rx_internal(skb); |  | ||||||
| 	if (local_softirq_pending()) |  | ||||||
| 		do_softirq(); |  | ||||||
| 	preempt_enable(); |  | ||||||
| 	trace_netif_rx_ni_exit(err); |  | ||||||
| 
 |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(netif_rx_ni); |  | ||||||
| 
 |  | ||||||
| int netif_rx_any_context(struct sk_buff *skb) |  | ||||||
| { |  | ||||||
| 	/*
 |  | ||||||
| 	 * If invoked from contexts which do not invoke bottom half |  | ||||||
| 	 * processing either at return from interrupt or when softrqs are |  | ||||||
| 	 * reenabled, use netif_rx_ni() which invokes bottomhalf processing |  | ||||||
| 	 * directly. |  | ||||||
| 	 */ |  | ||||||
| 	if (in_interrupt()) |  | ||||||
| 		return netif_rx(skb); |  | ||||||
| 	else |  | ||||||
| 		return netif_rx_ni(skb); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(netif_rx_any_context); |  | ||||||
| 
 |  | ||||||
| static __latent_entropy void net_tx_action(struct softirq_action *h) | static __latent_entropy void net_tx_action(struct softirq_action *h) | ||||||
| { | { | ||||||
| 	struct softnet_data *sd = this_cpu_ptr(&softnet_data); | 	struct softnet_data *sd = this_cpu_ptr(&softnet_data); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Sebastian Andrzej Siewior
						Sebastian Andrzej Siewior