Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Sebastian Andrzej Siewior and committed by
Jakub Kicinski
b22800f9 a8760d0d

+12 -1
+1
include/linux/netdevice.h
··· 3202 3202 struct softnet_data { 3203 3203 struct list_head poll_list; 3204 3204 struct sk_buff_head process_queue; 3205 + local_lock_t process_queue_bh_lock; 3205 3206 3206 3207 /* stats */ 3207 3208 unsigned int processed;
+11 -1
net/core/dev.c
··· 449 449 * queue in the local softnet handler. 450 450 */ 451 451 452 - DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data); 452 + DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data) = { 453 + .process_queue_bh_lock = INIT_LOCAL_LOCK(process_queue_bh_lock), 454 + }; 453 455 EXPORT_PER_CPU_SYMBOL(softnet_data); 454 456 455 457 /* Page_pool has a lockless array/stack to alloc/recycle pages. ··· 5951 5949 } 5952 5950 backlog_unlock_irq_enable(sd); 5953 5951 5952 + local_lock_nested_bh(&softnet_data.process_queue_bh_lock); 5954 5953 skb_queue_walk_safe(&sd->process_queue, skb, tmp) { 5955 5954 if (skb->dev->reg_state == NETREG_UNREGISTERING) { 5956 5955 __skb_unlink(skb, &sd->process_queue); ··· 5959 5956 rps_input_queue_head_incr(sd); 5960 5957 } 5961 5958 } 5959 + local_unlock_nested_bh(&softnet_data.process_queue_bh_lock); 5962 5960 local_bh_enable(); 5963 5961 } 5964 5962 ··· 6081 6077 while (again) { 6082 6078 struct sk_buff *skb; 6083 6079 6080 + local_lock_nested_bh(&softnet_data.process_queue_bh_lock); 6084 6081 while ((skb = __skb_dequeue(&sd->process_queue))) { 6082 + local_unlock_nested_bh(&softnet_data.process_queue_bh_lock); 6085 6083 rcu_read_lock(); 6086 6084 __netif_receive_skb(skb); 6087 6085 rcu_read_unlock(); ··· 6092 6086 return work; 6093 6087 } 6094 6088 6089 + local_lock_nested_bh(&softnet_data.process_queue_bh_lock); 6095 6090 } 6091 + local_unlock_nested_bh(&softnet_data.process_queue_bh_lock); 6096 6092 6097 6093 backlog_lock_irq_disable(sd); 6098 6094 if (skb_queue_empty(&sd->input_pkt_queue)) { ··· 6109 6101 napi->state &= NAPIF_STATE_THREADED; 6110 6102 again = false; 6111 6103 } else { 6104 + local_lock_nested_bh(&softnet_data.process_queue_bh_lock); 6112 6105 skb_queue_splice_tail_init(&sd->input_pkt_queue, 6113 6106 &sd->process_queue); 6107 + local_unlock_nested_bh(&softnet_data.process_queue_bh_lock); 6114 6108 } 6115 6109 backlog_unlock_irq_enable(sd); 6116 6110 }