list_for_each_entry_rcu(9)
π list_for_each_entry_rcu β the Kernel API Manual page, bestie edition
okay so you found list_for_each_entry_rcu(9) and you're like "what is this, why is it everywhere in the kernel" β don't panic, I got you. this is the RCU list-walker. it's iconic, it's everywhere, and it's literally just a for-loop with vibes. let's go π¦
β¨ SYNOPSIS β¨
list_for_each_entry_rcu (pos , head , member , cond... );
yes bestie, the spacing is exactly like that, don't come for me, that's how the manpage wrote it π
π ARGUMENTS π
posβ thetype *you use as your loop cursor. this is your main character pointer, the one that walks the list. every iteration it's pointing at something new. she's booked and busy.headβ the head for your list. the anchor. the starting point. the group chat that everyone's in πΈmemberβ the name of thelist_headinside the struct. so like, if your struct has astruct list_head fooinside it, you passfoohere. it's how the macro finds the list node hiding inside your struct, iykyk.condβ optional lockdep expression, for when you're calling this from a non-RCU-protection situation. it's the...in the synopsis, so it's optional-optional π
π DESCRIPTION π
so here's the tea: this list-traversal primitive may safely run concurrently with the _rcu list-mutation primitives β think list_add_rcu and friends β as long as the traversal is guarded by rcu_read_lock. that's the whole deal. that's the contract. π₯
no cap, the "as long as it's guarded by rcu_read_lock" part is not optional. skip it and you're in undefined-behaviour territory. she will not be nice about it π
other walkers can be adding and removing stuff while you iterate, and you're fine β because RCU. slay. periodt.
π SEE ALSO π
fr fr go read the source, it's right here in the kernel file:
./include/linux/rculist.h
and then the whole friend group, alphabetically-ish, all of them:
list_for_each_rcu(9)list_tail_rcu(9)list_add_rcu(9)list_add_tail_rcu(9)list_del_rcu(9)list_bidir_del_rcu(9)hlist_del_init_rcu(9)list_replace_rcu(9)list_splice_rcu(9)__list_splice_init_rcu(9)list_splice_init_rcu(9)list_splice_tail_init_rcu(9)list_entry_rcu(9)list_first_or_null_rcu(9)list_next_or_null_rcu(9)list_for_each_entry_srcu(9)list_entry_lockless(9)list_for_each_entry_lockless(9)list_for_each_entry_continue_rcu(9)list_for_each_entry_from_rcu(9)hlist_del_rcu(9)hlist_replace_rcu(9)hlists_swap_heads_rcu(9)hlist_add_head_rcu(9)hlist_add_tail_rcu(9)hlist_add_before_rcu(9)hlist_add_behind_rcu(9)hlist_for_each_entry_rcu(9)hlist_for_each_entry_srcu(9)hlist_for_each_entry_rcu_notrace(9)hlist_for_each_entry_rcu_bh(9)hlist_for_each_entry_continue_rcu(9)hlist_for_each_entry_continue_rcu_bh(9)hlist_for_each_entry_from_rcu(9)
like, the whole roster. read them all. or at least the ones you need. no pressure π«Ά
π the sign-off π
this page lives in ./include/linux, and it's stamped October 2026. so go forth, iterate your RCU lists, hold that read lock, and remember: main character energy only. mwah π β¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms