Commit baebdf48 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by David S. Miller
Browse files

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: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f234ae29
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2373,7 +2373,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
	skb->pkt_type = PACKET_MULTICAST;
	skb->ip_summed = CHECKSUM_NONE;
	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);
		dev_sw_netstats_rx_add(amt->dev, len);
	} else {
@@ -2470,7 +2470,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
	skb->pkt_type = PACKET_MULTICAST;
	skb->ip_summed = CHECKSUM_NONE;
	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,
					true);
		dev_sw_netstats_rx_add(amt->dev, len);
+2 −2
Original line number Diff line number Diff line
@@ -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);
		netif_rx(skb);
		__netif_rx(skb);
		dst_release(&rt->dst);
		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);
		netif_rx(skb);
		__netif_rx(skb);
		dst_release(dst);
		return -EMSGSIZE;
	}
+1 −1
Original line number Diff line number Diff line
@@ -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);

	netif_rx(skb);
	__netif_rx(skb);
	return 0;

err:
+2 −2
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,

	skb_orphan(skb);

	/* Before queueing this packet to netif_rx(),
	/* Before queueing this packet to __netif_rx(),
	 * make sure dst is refcounted.
	 */
	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);

	len = skb->len;
	if (likely(netif_rx(skb) == NET_RX_SUCCESS))
	if (likely(__netif_rx(skb) == NET_RX_SUCCESS))
		dev_lstats_add(dev, len);

	return NETDEV_TX_OK;
+3 −3
Original line number Diff line number Diff line
@@ -1033,7 +1033,7 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
				else
					nskb->pkt_type = PACKET_MULTICAST;

				netif_rx(nskb);
				__netif_rx(nskb);
			}
			continue;
		}
@@ -1056,7 +1056,7 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)

		nskb->dev = ndev;

		if (netif_rx(nskb) == NET_RX_SUCCESS) {
		if (__netif_rx(nskb) == NET_RX_SUCCESS) {
			u64_stats_update_begin(&secy_stats->syncp);
			secy_stats->stats.InPktsUntagged++;
			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);

		ret = netif_rx(nskb);
		ret = __netif_rx(nskb);
		if (ret == NET_RX_SUCCESS) {
			u64_stats_update_begin(&secy_stats->syncp);
			secy_stats->stats.InPktsUnknownSCI++;
Loading