diff options
| author | Kohei Enju <kohei@enjuk.jp> | 2026-02-20 11:09:17 +0000 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-03-03 17:15:20 -0800 |
| commit | 39feb171f361f887dad8504dc5822b852871ac21 (patch) | |
| tree | 2cb2bbe87e1c99024c52e4babbfa93b21cda251c /net | |
| parent | 8ce185c7e00dbddfdea026acd5dcf7b122af3db0 (diff) | |
net: core: allow netdev_upper_get_next_dev_rcu from bh context
Since XDP programs are called from a NAPI poll context, the RCU
reference liveness is ensured by local_bh_disable().
Commit aeea1b86f936 ("bpf, devmap: Exclude XDP broadcast to master
device") started to call netdev_upper_get_next_dev_rcu() from this
context, but missed adding rcu_read_lock_bh_held() as a condition to the
RCU checks.
While both bh_disabled and rcu_read_lock() provide RCU protection,
lockdep complains since the check condition is insufficient [1].
Add rcu_read_lock_bh_held() as condition to help lockdep to understand
the dereference is safe, in the same way as commit 694cea395fde ("bpf:
Allow RCU-protected lookups to happen from bh context").
[1]
WARNING: net/core/dev.c:8099 at netdev_upper_get_next_dev_rcu+0x96/0xd0, CPU#0: swapper/0/0
...
RIP: 0010:netdev_upper_get_next_dev_rcu+0x96/0xd0
...
<IRQ>
dev_map_enqueue_multi+0x411/0x970
xdp_do_redirect+0xdf2/0x1030
__igc_xdp_run_prog+0x6a0/0xc80
igc_poll+0x34b0/0x70b0
__napi_poll.constprop.0+0x98/0x490
net_rx_action+0x8f2/0xfa0
handle_softirqs+0x1c7/0x710
__irq_exit_rcu+0xb1/0xf0
irq_exit_rcu+0x9/0x20
common_interrupt+0x7f/0x90
</IRQ>
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20260220110922.94781-1-kohei@enjuk.jp
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/dev.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 1cf3ad840697..19b84eaa2643 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8113,7 +8113,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, { struct netdev_adjacent *upper; - WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); + WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held() && + !lockdep_rtnl_is_held()); upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); |
