dev: Use nested-BH locking for softnet_data.process_queue.
softnet_data::process_queue is a per-CPU variable and relies on disabled BH for its locking. Without per-CPU locking in local_bh_disable() on PREEMPT_RT this data structure requires explicit locking. softnet_data::input_queue_head can be updated lockless. This is fine because this value is only update CPU local by the local backlog_napi thread. Add a local_lock_t to softnet_data and use local_lock_nested_bh() for locking of process_queue. This change adds only lockdep coverage and does not alter the functional behaviour for !PREEMPT_RT. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: https://patch.msgid.link/20240620132727.660738-11-bigeasy@linutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
a8760d0d14
commit
b22800f9d3
@@ -3202,6 +3202,7 @@ static inline bool dev_has_header(const struct net_device *dev)
|
||||
struct softnet_data {
|
||||
struct list_head poll_list;
|
||||
struct sk_buff_head process_queue;
|
||||
local_lock_t process_queue_bh_lock;
|
||||
|
||||
/* stats */
|
||||
unsigned int processed;
|
||||
|
||||
+11
-1
@@ -449,7 +449,9 @@ static RAW_NOTIFIER_HEAD(netdev_chain);
|
||||
* queue in the local softnet handler.
|
||||
*/
|
||||
|
||||
DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
|
||||
DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data) = {
|
||||
.process_queue_bh_lock = INIT_LOCAL_LOCK(process_queue_bh_lock),
|
||||
};
|
||||
EXPORT_PER_CPU_SYMBOL(softnet_data);
|
||||
|
||||
/* Page_pool has a lockless array/stack to alloc/recycle pages.
|
||||
@@ -5949,6 +5951,7 @@ static void flush_backlog(struct work_struct *work)
|
||||
}
|
||||
backlog_unlock_irq_enable(sd);
|
||||
|
||||
local_lock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
skb_queue_walk_safe(&sd->process_queue, skb, tmp) {
|
||||
if (skb->dev->reg_state == NETREG_UNREGISTERING) {
|
||||
__skb_unlink(skb, &sd->process_queue);
|
||||
@@ -5956,6 +5959,7 @@ static void flush_backlog(struct work_struct *work)
|
||||
rps_input_queue_head_incr(sd);
|
||||
}
|
||||
}
|
||||
local_unlock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
@@ -6077,7 +6081,9 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
while (again) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
local_lock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
while ((skb = __skb_dequeue(&sd->process_queue))) {
|
||||
local_unlock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
rcu_read_lock();
|
||||
__netif_receive_skb(skb);
|
||||
rcu_read_unlock();
|
||||
@@ -6086,7 +6092,9 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
return work;
|
||||
}
|
||||
|
||||
local_lock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
}
|
||||
local_unlock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
|
||||
backlog_lock_irq_disable(sd);
|
||||
if (skb_queue_empty(&sd->input_pkt_queue)) {
|
||||
@@ -6101,8 +6109,10 @@ static int process_backlog(struct napi_struct *napi, int quota)
|
||||
napi->state &= NAPIF_STATE_THREADED;
|
||||
again = false;
|
||||
} else {
|
||||
local_lock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
skb_queue_splice_tail_init(&sd->input_pkt_queue,
|
||||
&sd->process_queue);
|
||||
local_unlock_nested_bh(&softnet_data.process_queue_bh_lock);
|
||||
}
|
||||
backlog_unlock_irq_enable(sd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user