[PATCH ath-next] wifi: ath9k: use rcu_dereference_bh() for sta->rates in ath_merge_ratetbl()

Jeff Johnson <[email protected]>
Newsgroups org.kernel.vger.linux-wireless,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Commit c4f518736472 ("wifi: ath9k: Remove redundant rcu_read_lock/unlock()
in spin_lock") removed the explicit rcu_read_lock()/rcu_read_unlock() pair
from ath_txq_schedule(), relying on spin_lock_bh() to provide an implicit
RCU read-side critical section.

That is correct on kernels without CONFIG_DEBUG_LOCK_ALLOC, where
rcu_read_lock_any_held() falls back to !preemptible() as a proxy, and
spin_lock_bh() disables preemption.

However, rcu_dereference() in ath_merge_ratetbl() checks
rcu_read_lock_held(), which under CONFIG_DEBUG_LOCK_ALLOC only returns
true when lock_is_held(&rcu_lock_map) — set exclusively by an explicit
rcu_read_lock().  A spin_lock_bh() does not set rcu_lock_map, so on a
CONFIG_DEBUG_LOCK_ALLOC + CONFIG_PROVE_RCU kernel, any call path that
reaches ath_merge_ratetbl() with a non-NULL sta will produce a lockdep
splat.

The correct fix is to use rcu_dereference_bh(), whose validity check
calls rcu_read_lock_bh_held(), which returns true whenever BH is disabled
(in_softirq() || irqs_disabled()).  This matches the actual protection
at all callers of ath_set_rates() that pass a non-NULL sta: they all hold
a spin_lock_bh() (either sc->chan_lock or txq->axq_lock).

Fixes: c4f518736472 ("wifi: ath9k: Remove redundant rcu_read_lock/unlock() in spin_lock")
Assisted-by: Claude:claude-sonnet-4-6
Signed-off-by: Jeff Johnson <[email protected]>
---
 drivers/net/wireless/ath/ath9k/xmit.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 89d8b3178784..3413bb4906d4 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -168,7 +168,7 @@ static bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf,
 	if (!sta)
 		return false;
 
-	ratetbl = rcu_dereference(sta->rates);
+	ratetbl = rcu_dereference_bh(sta->rates);
 	if (!ratetbl)
 		return false;
 

---
base-commit: e07447e654476262558bee570f4cf456e2b32565
change-id: 20260813-ath9k-rcu-fix-5469a4603fd5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.