Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does rcu_read_lock() actually do (Linux Kernel)

I'm trying to understand rcu_read_lock() synchronization mechanism. From what I understand, rcu_read_lock() is used, where there are several read threads and one write thread, that read/writes the same data, and reading is performed under rcu_read_lock(), and the data are copied for each thread. I wrote a simple driver to test this (read() and write() functions are core):

#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_INFO */
#include <linux/init.h>         /* Needed for the macros */
#include <linux/rcupdate.h>
#include <linux/preempt.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define MY_MAJOR 42
#define MY_MAX_MINORS 5

char buf[] = "0";

struct dev_data
{
    struct cdev cdev;
};

struct dev_data devs[MY_MAX_MINORS];

static ssize_t read(struct file *file, char __user *buffer, size_t size, loff_t *offset)
{
    rcu_read_lock();
    while (1)
    {
        printk(KERN_INFO "%s", buf);
    }
    rcu_read_unlock();

    return 0;
}

static ssize_t write(struct file *file, const char __user *buffer, size_t size, loff_t *offset)
{
    buf[0] = '1';

    return size;
}

const struct file_operations fops = {
    .read = &read,
    .write = &write,
};

static int __init foo_start(void)
{
    int i, err_code;

    err_code = register_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS, "Test char driver");
    if (err_code != 0)
        return err_code;

    for(i=0; i<MY_MAX_MINORS; ++i)
    {
        cdev_init(&devs[i].cdev, &fops);
        cdev_add(&devs[i].cdev, MKDEV(MY_MAJOR, i), 1);
    }

    return 0;
}

static void __exit foo_end(void)
{
    int i;

    for(i=0; i<MY_MAX_MINORS; ++i)
    {
        cdev_del(&devs[i].cdev);
    }

    unregister_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS);
}

module_init(foo_start);
module_exit(foo_end);

but when I call the write function during reading, the data is changing under rcu_read_lock() too. Where is my mistake?
P.S. The driver itself is crippy, but my goal was just to test rcu_read_lock().

like image 435
Андрій Немченко Avatar asked Sep 18 '19 08:09

Андрій Немченко


1 Answers

You can find the RCU documentation on kernel.org which describe it.

Its introduction is really interesting:

Although RCU is actually quite simple once you understand it, getting there can sometimes be a challenge. Part of the problem is that most of the past descriptions of RCU have been written with the mistaken assumption that there is "one true way" to describe RCU. Instead, the experience has been that different people must take different paths to arrive at an understanding of RCU.

As you can see, anyone who wants to really understand it must take the time to read the documentation.

To get a basic idea of it:

The basic idea behind RCU is to split updates into "removal" and "reclamation" phases. The removal phase removes references to data items within a data structure (possibly by replacing them with references to new versions of these data items), and can run concurrently with readers.

Read more from the documentation.

Coming now to your question, here is the description of the rcu_read_lock() and rcu_read_unlock() API functions:

rcu_read_lock()

void rcu_read_lock(void);

Used by a reader to inform the reclaimer that the reader is entering an RCU read-side critical section. It is illegal to block while in an RCU read-side critical section, though kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side critical sections. Any RCU-protected data structure accessed during an RCU read-side critical section is guaranteed to remain unreclaimed for the full duration of that critical section. Reference counts may be used in conjunction with RCU to maintain longer-term references to data structures.

rcu_read_unlock()

void rcu_read_unlock(void);

Used by a reader to inform the reclaimer that the reader is exiting an RCU read-side critical section. Note that RCU read-side critical sections may be nested and/or overlapping.

Have a look at the "WHAT ARE SOME EXAMPLE USES OF CORE RCU API?" section in order to have an example of code using them.

like image 149
ZedTuX Avatar answered Oct 08 '22 17:10

ZedTuX