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:
committed by
David S. Miller
parent
f234ae2947
commit
baebdf48c3
@@ -4815,66 +4815,57 @@ static int netif_rx_internal(struct sk_buff *skb)
|
||||
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
|
||||
* @skb: buffer to post
|
||||
*
|
||||
* This function receives a packet from a device driver and queues it for
|
||||
* the upper (protocol) levels to process. It always succeeds. The buffer
|
||||
* may be dropped during processing for congestion control or by the
|
||||
* protocol layers.
|
||||
* the upper (protocol) levels to process via the backlog NAPI device. It
|
||||
* always succeeds. The buffer may be dropped during processing for
|
||||
* 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:
|
||||
* NET_RX_SUCCESS (no congestion)
|
||||
* NET_RX_DROP (packet was dropped)
|
||||
*
|
||||
*/
|
||||
|
||||
int netif_rx(struct sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
local_bh_disable();
|
||||
trace_netif_rx_entry(skb);
|
||||
|
||||
ret = netif_rx_internal(skb);
|
||||
trace_netif_rx_exit(ret);
|
||||
|
||||
local_bh_enable();
|
||||
return ret;
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct softnet_data *sd = this_cpu_ptr(&softnet_data);
|
||||
|
||||
Reference in New Issue
Block a user