Skip to content

call_rcu()

Purpose

call_rcu() schedules deferred reclamation of an RCU-protected object.

Instead of blocking the writer until a grace period completes, call_rcu() registers a callback that will execute after the grace period.

This allows the writer to continue immediately.


Prototype

void call_rcu(struct rcu_head *head,
              rcu_callback_t func);

#include <linux/rcupdate.h>

Parameters

Pointer to an embedded struct rcu_head.

Example:

struct my_object {
    int value;
    struct rcu_head rcu;
};

func

Callback executed after the grace period completes.

Example:

static void my_free_callback(struct rcu_head *head)
{
    ...
}

Usage Pattern

old = rcu_dereference_protected(g_obj, 1);

rcu_assign_pointer(g_obj, new);

call_rcu(&old->rcu, my_free_callback);

The writer returns immediately.

Object reclamation occurs later.


Callback Example

static void my_free_callback(struct rcu_head *head)
{
    struct my_object *obj;

    obj = container_of(head,
                       struct my_object,
                       rcu);

    kfree(obj);
}

Concept

RCU updates consist of three phases:

Publication
Grace Period
Reclamation

With:

call_rcu()

the grace period and reclamation occur asynchronously.


Update Flow

Allocate New Object
Modify New Object
Publish New Object
call_rcu()
Writer Continues
Grace Period Completes
Callback Executes
Old Object Reclaimed

Why Use call_rcu()?

The writer does not need to wait.

Compared with:

synchronize_rcu();

which performs:

Publish
Wait
Free

call_rcu() performs:

Publish
Schedule Callback
Continue

Typical Use Case

struct my_object *old;
struct my_object *new;

new = kmalloc(sizeof(*new), GFP_KERNEL);

old = rcu_dereference_protected(g_obj, 1);

*new = *old;

new->value = 123;

rcu_assign_pointer(g_obj, new);

call_rcu(&old->rcu, my_free_callback);

Embedded rcu_head

RCU callbacks require an embedded:

struct rcu_head

inside the object.

Example:

struct my_object {
    int value;
    struct rcu_head rcu;
};

This allows the callback to recover the parent object:

container_of()

and reclaim memory.


Advantages

Non-Blocking Writers

The update path remains short:

Publish
Schedule Callback
Continue

Better Scalability

Frequent updates do not stall waiting for grace periods.


Natural Deferred Reclamation

Old objects are automatically reclaimed when safe.


Disadvantages

More Complex

A callback function is required.


Delayed Reclamation

Memory is not released immediately.

Objects remain alive until:

Grace Period Complete

Additional Memory Usage

Large numbers of pending callbacks may temporarily increase memory consumption.


call_rcu() vs synchronize_rcu()

synchronize_rcu()

Writer waits.

Example:

rcu_assign_pointer(g_obj, new);

synchronize_rcu();

kfree(old);

call_rcu()

Writer continues immediately.

Example:

rcu_assign_pointer(g_obj, new);

call_rcu(&old->rcu, my_free_callback);

Common Mistake

Incorrect:

rcu_assign_pointer(g_obj, new);

call_rcu(&new->rcu, my_free_callback);

The callback is scheduled for the wrong object.

The old object should be reclaimed:

call_rcu(&old->rcu, my_free_callback);

Common Mistake

Incorrect:

call_rcu(&old->rcu, my_free_callback);

kfree(old);

The object is freed twice.

The callback is responsible for reclamation.

Correct:

call_rcu(&old->rcu, my_free_callback);

and:

kfree(old);

must only occur inside the callback.