|This article is part of the LWN Porting Drivers to 2.6 series.|
The first step in using RCU within a subsystem is to define a structure containing the data to be protected. Often that structure already exists; for example, RCU has been retrofitted into the dentry cache (using struct dentry), the network routing cache (struct rtable), and several other, similar contexts. The structures need to be allocated dynamically and accessed via a pointer - RCU cannot be used with static structures.
Code which reads data structures protected by RCU need only take a couple of simple precautions:
Thus, code which reads an RCU-protected data structure will look something like:
struct my_stuff *stuff; rcu_read_lock(); stuff = find_the_stuff(args...); do_something_with(stuff); /* Cannot sleep */ do_something_else_with(stuff); /* ditto */ rcu_read_unlock();
The write side of RCU is a little more complicated, but not that difficult. To update a data structure, the code starts by allocating a new copy of that structure, and filling in the new information. The code should then replace the pointer to the outdated structure with the new one, keeping a copy of the old pointer. After this operation, kernel code running on any other processor will find the new version of the structure. The old one cannot yet be freed, however, since it is possible that another processor is still using it.
The code should arrange to dispose of the old structure when it is known that it cannot be referenced anywhere else in the system. That is done through a call to call_rcu():
void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg);
The calling code must provide an rcu_head structure, but need not initialize it in any way. Usually, that structure is embedded within the larger structure protected by RCU. The function func will be called when the structure can be safely freed, with arg as its one argument. All that func need do, normally, is call something like kfree() to free up the structure.
The RCU algorithm works by waiting until every processor in the system has scheduled at least once. Since the rules require that references to RCU-protected structures cannot be held over sleeps, no processor can possibly hold a reference to an old structure after it has scheduled. When all processors have scheduled (after the pointer change), references to the old structure can not exist, and the structure can be freed.
For what it's worth, the RCU code exports the "wait for everybody to schedule" functionality, should it be useful elsewhere. To perform this wait, one need only make a call to synchronize_kernel().
Copyright © 2003, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds