# Understanding RCU in the Linux Kernel: A Beginner’s Guide

## 1️⃣ Introduction

Traversing kernel data structures safely is one of the most common challenges for Linux kernel developers.  
For example, iterating over all running processes seems straightforward, but **the task list may change while you are reading it**.  

If a process exits while your code is traversing the list, it could cause a **use-after-free** error, leading to a kernel crash.  

Traditional locks like **mutexes or spinlocks** can prevent crashes but **block readers**, slowing down read-heavy workloads.  

The Linux kernel solves this problem with **RCU (Read-Copy-Update)** — a mechanism that allows **lockless reads** while writers safely update data.  

In this post, we’ll cover:

- What RCU is and why it exists  
- How to use `rcu_read_lock()` and `rcu_read_unlock()`  
- A small **kernel module demo** to safely log processes and memory info  
- Step-by-step walkthrough and exercises for practice  

---

## 2️⃣ Why RCU Exists

### The problem

Imagine iterating over the task list while another part of the kernel modifies it:

- **Reader**: prints PID and name of each process  
- **Writer**: adds or removes processes  

Without protection:

- Readers may see invalid or freed memory  
- Kernel could crash  

Traditional locks solve safety issues, but **every reader blocks the writer**, which can reduce performance in **read-heavy workloads** (like process monitoring, networking, or filesystem operations).  

### The solution: RCU

RCU provides:

- **Read-side protection**: `rcu_read_lock()` / `rcu_read_unlock()`  
- **Grace periods**: writers defer freeing memory until all readers are done  
- High performance for **read-dominated workloads**  

**Text-based diagram (conceptual):**


- Readers never block writers  
- Writers wait only for **grace period**, not for each reader individually  

---

## 3️⃣ Minimal RCU Example

Here’s how you safely iterate over processes with RCU:

```c
struct task_struct *task;

rcu_read_lock();
for_each_process(task) {
    printk(KERN_INFO "PID=%d, Name=%s\n", task->pid, task->comm);
}
rcu_read_unlock();```

Timer triggers every 5 sec
         │
         ▼
   log_proc_mem() function
         │
         ├── Read memory info
         │
         ├── rcu_read_lock()
         │    └── for_each_process() → printk PID+Name
         │
         └── rcu_read_unlock()

Key Takeaways

RCU allows lockless reads, making the kernel efficient for read-heavy workloads

Always use rcu_read_lock() / rcu_read_unlock() for RCU-protected data
