Reference for the Linux kernel RCU (Read-Copy Update) API, covering read-side locking, pointer publication and dereference, grace period management, SRCU, and when to use RCU versus traditional locks.
Read-Copy Update (RCU) is a synchronization mechanism optimized for read-mostly data. The key insight is that readers need not acquire any lock, perform atomic instructions, or execute memory barriers (on most architectures). Updates proceed by:
Copying the data to be changed.
Modifying the copy.
Publishing the new version atomically.
Waiting for a grace period — until all pre-existing readers have finished.
Freeing the old version.
#include <linux/rcupdate.h>#include <linux/rculist.h> /* for list_for_each_entry_rcu */
Zero-cost readers
rcu_read_lock / rcu_read_unlock are typically no-ops on non-preemptible kernels.
Safe pointer publication
rcu_assign_pointer inserts the necessary memory barriers to safely publish a new pointer.
Safe pointer dereference
rcu_dereference enforces dependency ordering so the compiler cannot speculate loads.
Deferred free
call_rcu and kfree_rcu free memory after a grace period — no explicit waiting.
Delimit an RCU read-side critical section. On non-preemptible kernels these are typically no-ops (preemption is already disabled by other means). On CONFIG_PREEMPT_RCU kernels they manipulate a per-task nesting counter.Rules for read-side critical sections:
Must not block or sleep (GFP_ATOMIC allocations are acceptable).
RCU read-side critical sections do not provide mutual exclusion between readers and updaters. They only guarantee that the memory backing p is not freed while you hold the rcu_read_lock. If you need to modify data, use a separate lock (e.g., a spinlock or mutex) that protects the write side.
Fetch an RCU-protected pointer. Inserts a data-dependency barrier (on architectures that need it, such as Alpha) to prevent the compiler or CPU from speculating loads that depend on the pointer value. Must be called from within an RCU read-side critical section.
Publish a new pointer value. Inserts a store-release barrier so that all prior writes to the pointed-to structure are visible to any reader that loads the pointer. Must be called with whatever lock protects the write side.
A grace period is a time interval after a pointer update during which every CPU must have passed through at least one quiescent state (context switch, user-mode execution, or idle loop). After a grace period, no reader can hold a reference to the old version.
Block the calling thread until a full RCU grace period has elapsed. After this returns, all pre-existing RCU read-side critical sections have completed. May sleep; cannot be called from interrupt context.
/* After publishing new_ptr, wait for old readers to finish */synchronize_rcu();kfree(old_ptr);
The rculist.h API wraps list_head operations with the correct barriers for RCU traversal.
#include <linux/rculist.h>/* Adding to a list (must hold update-side lock) */list_add_rcu(&node->list, &my_list);list_add_tail_rcu(&node->list, &my_list);/* Removing from a list (must hold update-side lock) */list_del_rcu(&node->list);/* Traversal (inside rcu_read_lock) */list_for_each_entry_rcu(pos, head, member) { /* pos is valid for the duration of this iteration */}
/* Full traversal example */rcu_read_lock();list_for_each_entry_rcu(node, &my_list, list) { if (node->key == target_key) { do_work(node); break; }}rcu_read_unlock();
Use list_del_rcu (not list_del) when removing a node that may still be visible to RCU readers. list_del_rcu sets the prev pointer to LIST_POISON2 rather than modifying it in a way that could confuse concurrent list_for_each_entry_rcu traversals.
Standard RCU read-side critical sections may not sleep. SRCU (Sleepable RCU) lifts this restriction at the cost of a small per-subsystem overhead and slower grace periods.
The SRCU domain. Each subsystem that needs SRCU must have its own srcu_struct.
int idx = srcu_read_lock(&my_srcu);/* may sleep here — blocking is allowed */struct data *p = srcu_dereference(my_ptr, &my_srcu);process(p); /* may block */srcu_read_unlock(&my_srcu, idx);
SRCU grace periods are slower than regular RCU grace periods because the kernel must wait for all SRCU read-side critical sections to complete rather than simply waiting for all CPUs to pass through a quiescent state. Use SRCU only when blocking inside the read-side critical section is genuinely required.
The data structure requires complex multi-step updates that cannot be made atomic with pointer replacement.
You need to read and then conditionally modify data atomically.
The read-side critical section must be able to sleep (consider SRCU).
RCU is strictly superior to rwlock_t for read-mostly data: RCU read-side is cheaper, scales better, and can be used from interrupt context. The kernel is actively replacing rwlock_t with RCU in many subsystems. Prefer RCU over rwlock_t for any new read-mostly data structure.
All fields of the new object must be fully initialized and visible to other CPUs before calling rcu_assign_pointer. The macro provides the necessary store-release barrier.
new->field = value; /* initialize first */rcu_assign_pointer(ptr, new); /* then publish */
Wait for a grace period before freeing
Never free an RCU-protected object immediately after removing it from a data structure. Always use synchronize_rcu(), call_rcu(), or kfree_rcu() first.
Protect writers with a separate lock
RCU does not serialize concurrent writers. If multiple threads may update the same RCU-protected data structure, they must hold a conventional lock (e.g., a spinlock or mutex) with respect to each other.