[RFC] nvmet: clarify RCU-list traversal contract for PR registrants
From: Runyu Xiao
Date: Sat Jun 27 2026 - 09:02:56 EST
Hi NVMe target maintainers,
This question comes from a candidate found by our static analysis tool
and then manually reviewed against the current tree. The audit used
CONFIG_PROVE_RCU_LIST as target-matched triage evidence; I am asking
for maintainer guidance because the source-level review did not prove
a use-after-free.
A CONFIG_PROVE_RCU_LIST audit flags several persistent-reservation
writer-side scans of pr->registrant_list:
drivers/nvme/target/pr.c:299 nvmet_pr_unregister()
drivers/nvme/target/pr.c:362 nvmet_pr_replace()
drivers/nvme/target/pr.c:677 nvmet_execute_pr_acquire()
drivers/nvme/target/pr.c:788 nvmet_execute_pr_release()
These paths hold pr->pr_sem while walking the list with
list_for_each_entry_rcu(). Removals/replacements use list_del_rcu() or
list_replace_rcu() and release objects with kfree_rcu(), while true
read-side paths such as PR report/access checks use rcu_read_lock().
The audit did not prove a use-after-free. The question is about
expressing the intended API contract: pr->pr_sem is a struct semaphore,
so adding a naive lockdep_is_held() condition is not an obvious or
necessarily valid fix.
Would you prefer one of these directions?
1. split helper usage so PR writer paths under pr->pr_sem use ordinary
list_for_each_entry(), leaving list_for_each_entry_rcu() for true
RCU readers;
2. keep the current RCU iterator but add a small explicit RCU read-side
section around the writer-side scans;
3. document that the current semaphore-protected writer traversal is
intentional and leave it as-is despite CONFIG_PROVE_RCU_LIST noise;
4. use a different lock/annotation pattern that fits nvmet PR locking
better.
I am intentionally sending this as a maintainer question rather than a
patch because the current code appears lifetime-safe: registrants
removed from the RCU list are freed with kfree_rcu(), and the writer-side
operations are serialized by pr->pr_sem.
Thanks.