How Linux Kernel Uses Read-Copy-Update (RCU)
The Read-Copy-Update (RCU) mechanism in the Linux kernel is a synchronization pattern optimized for read-heavy workloads, allowing concurrent reads to occur without locks while updates happen safely in the background. This article explores the core architecture of RCU, how the Linux kernel executes reads and updates simultaneously without data corruption, and the primary subsystems—such as networking and the Virtual File System—that rely on RCU to achieve massive scalability on multi-core systems.
Core Mechanics of RCU
RCU splits the synchronization problem into three distinct phases: read-side execution, update-side execution, and deferred reclamation.
- Read-Side Operations: Readers mark the entry and
exit of their critical sections using
rcu_read_lock()andrcu_read_unlock(). In non-preemptible kernels, these primitives have zero CPU overhead; in preemptible kernels, they merely track nesting levels without taking locks, disabling interrupts, or modifying shared cache lines. Reads proceed completely unobstructed. - Update Operations (Read-Copy): When a writer needs
to modify a data structure, it does not alter the shared data directly.
Instead, it creates a new copy of the object, applies changes to the
copy, and then atomically swaps the global pointer to point to the new
structure using primitives like
rcu_assign_pointer(). New readers immediately observe the new version, while concurrent existing readers continue accessing the old version undisturbed. - Grace Period and Reclamation (Update): The old
memory cannot be freed immediately because in-flight readers may still
be traversing it. The kernel enforces a "grace period"—an interval
during which every CPU passes through at least one quiescent state (such
as a context switch, executing in user mode, or entering an idle state).
Once the grace period completes, no readers hold references to the old
data. The writer can then safely reclaim the old memory using
kfree_rcu()or asynchronous callbacks scheduled viacall_rcu().
Major Subsystems Utilizing RCU
The Linux kernel deploys RCU across several core components where read operations exponentially outnumber modifications:
- Virtual File System (VFS): The Directory Entry
Cache (dcache) relies heavily on RCU-path walk. When processes resolve
file paths (e.g.,
/usr/bin/python), the kernel traverses the dentry tree lock-free. Millions of path lookups per second occur across multiple cores without cache-line bouncing or lock contention. - Networking Subsystem: Network routing tables, firewall rules (Netfilter/nftables), and socket lookup tables utilize RCU. Ingress packet processing reads forwarding tables without acquiring spinlocks. When routes update, the kernel modifies the routing tree and defers memory reclamation, preventing packet drops and latency spikes during high-throughput networking.
- Process and Security Credentials: Task structures,
process IDs, and security attributes (such as POSIX credentials and
SELinux contexts) are accessed frequently during permission checks.
Updating a process credential generates a new credential structure,
swaps the pointer on the
task_struct, and retires the old credentials via RCU.
RCU Flavors in the Kernel
To accommodate diverse hardware profiles and latency requirements, the Linux kernel provides specialized implementations of RCU:
- Tree RCU: The default implementation designed for medium-to-large symmetric multiprocessing (SMP) systems. It organizes CPUs into a hierarchical tree structure to aggregate quiescent states without creating a global bottleneck.
- Tiny RCU: A lightweight alternative designed for single-CPU and resource-constrained embedded systems, drastically reducing kernel footprint by eliminating multi-core coordination overhead.
- Sleepable RCU (SRCU): Standard RCU prohibits readers from blocking or sleeping inside read-side critical sections. SRCU provides distinct domains where readers are permitted to sleep, useful for tracing mechanisms, filesystem notifications, and device driver subsystems that require blocking calls during traversal.