07-26-2023, 09:09 PM
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().
#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().