Linux驱动框架中关于私有数据private_data的一些理解

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>

struct device_test {
    struct cdev cdev_test;
    dev_t dev_num;
    struct class *class;
    struct device *device;
    int major;
    int minor;
    char kbuf[32];
};

struct device_test dev1;

static int cdev_test_open(struct inode *inode, struct file *file)
{
    file->private_data = &dev1;
    printk("This is cdev_test_open\n");
    return 0;
}

static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
    struct device_test *test_dev = (struct device_test *)file->private_data;
    
    if (size > sizeof(test_dev->kbuf) - 1) {
        size = sizeof(test_dev->kbuf) - 1;
    }
    
    if (copy_from_user(test_dev->kbuf, buf, size) != 0) {
        printk("copy_from_user error\n");
        return -EFAULT;
    }
    test_dev->kbuf[size] = '\0'; // Ensure null termination
    printk("copy_from_user test_dev->kbuf %s\n", test_dev->kbuf);
    return size;
}

static ssize_t cdev_test_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
    struct device_test *test_dev = (struct device_test *)file->private_data;
    ssize_t len = strlen(test_dev->kbuf);
    
    if (len > size) {
        len = size;
    }
    
    if (copy_to_user(buf, test_dev->kbuf, len) != 0) {
        printk("copy_to_user error\n");
        return -EFAULT;
    }
    printk("This is cdev_test_read\n");
    return len;
}

static int cdev_test_release(struct inode *inode, struct file *file)
{
    printk("This is cdev_test_release\n");
    return 0;
}

static struct file_operations cdev_test_ops = {
    .owner = THIS_MODULE,
    .open = cdev_test_open,
    .read = cdev_test_read,
    .write = cdev_test_write,
    .release = cdev_test_release,
};

static int __init modulecdev_init(void)
{
    int ret;
    
    ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name");
    if (ret < 0) {
        printk("alloc_chrdev_region error\n");
        return ret;
    }
    printk("alloc_chrdev_region ok\n");
    
    dev1.major = MAJOR(dev1.dev_num);
    dev1.minor = MINOR(dev1.dev_num);
    printk("major is %d\n", dev1.major);
    printk("minor is %d\n", dev1.minor);
    
    cdev_init(&dev1.cdev_test, &cdev_test_ops);
    dev1.cdev_test.owner = THIS_MODULE;
    
    ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
    if (ret < 0) {
        printk("cdev_add error\n");
        unregister_chrdev_region(dev1.dev_num, 1);
        return ret;
    }
    
    dev1.class = class_create(THIS_MODULE, "test_class");
    if (IS_ERR(dev1.class)) {
        printk("class_create error\n");
        cdev_del(&dev1.cdev_test);
        unregister_chrdev_region(dev1.dev_num, 1);
        return PTR_ERR(dev1.class);
    }
    
    dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test_device");
    if (IS_ERR(dev1.device)) {
        printk("device_create error\n");
        class_destroy(dev1.class);
        cdev_del(&dev1.cdev_test);
        unregister_chrdev_region(dev1.dev_num, 1);
        return PTR_ERR(dev1.device);
    }
    
    return 0;
}

static void __exit modulecdev_exit(void)
{
    device_destroy(dev1.class, dev1.dev_num);
    class_destroy(dev1.class);
    cdev_del(&dev1.cdev_test);
    unregister_chrdev_region(dev1.dev_num, 1);
    printk("Goodbye, world\n");
}

module_init(modulecdev_init);
module_exit(modulecdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhangsan");
MODULE_DESCRIPTION("A simple character device module");
MODULE_VERSION("V1.0");

关于为什么在Linux驱动模块中,test_dev在cdev_test_read和cdev_test_write函数中都可以使用,是否是一个全局变量。需要结合代码来解释这个问题。

首先,在代码中,有一个结构体struct device_test的实例dev1被定义为全局变量。不过,在读写函数中,test_dev实际上是从file->private_data获取的,这应该是在open函数中设置的。用户可能混淆了全局变量和通过private_data传递的指针。

然后,示例代码使用了全局变量data,这可能让我们认为test_dev也是全局的。但实际上,代码中,test_dev是通过file->private_data来传递的,而不是全局变量。需要解释清楚这个机制,以及为什么不同的函数可以访问同一个结构体实例。

需要指出,在open函数中,file->private_data被设置为&dev1,这样在read和write函数中,可以通过file->private_data获取到同一个结构体指针。而dev1本身是全局变量,但test_dev在读写函数中是局部指针变量,指向这个全局变量。

可能误解test_dev的作用域,认为它在不同函数中重复定义,但实际上它是通过private_data传递的指针。需要分点说明:1. private_data的作用;2. dev1作为全局变量的角色;3. 读写函数如何通过private_data访问同一实例。同时,引用搜索结果中的例子,说明其他驱动也可能使用类似方法,比如通过全局缓冲区data,但实现方式不同。


在Linux驱动开发中,`test_dev`在`cdev_test_read`和`cdev_test_write`中的可访问性并非因为全局变量,而是通过**文件操作上下文传递机制**实现的。以下是具体原理分点说明:

---

### 1. **`private_data`字段的桥梁作用**
在`cdev_test_open`函数中,通过`file->private_data = &dev1`将全局变量`dev1`的地址绑定到文件指针的私有数据字段。  
• 所有后续的文件操作函数(如`read`/`write`)都可以通过`file->private_data`获取到同一实例的指针。
• 这种设计避免了全局变量的直接暴露,同时实现了跨函数的数据共享。

---

### 2. **全局变量`dev1`的定位**
代码中定义的`struct device_test dev1`确实是一个全局变量:  
• 全局变量的作用域覆盖整个驱动模块,但直接操作全局变量会增加并发风险(如竞态条件)。
• 通过`private_data`间接访问,实际上是驱动开发中推荐的**数据封装**方式,既能共享设备实例,又通过文件指针隔离了不同进程的访问。

---

### 3. **读写函数中的`test_dev`本质**
在`cdev_test_read`和`cdev_test_write`中:  
```c
struct device_test *test_dev = (struct device_test *)file->private_data;
```
• 此处的`test_dev`是**局部指针变量**,仅指向全局变量`dev1`的内存地址。  
• 所有读写操作最终都作用于`dev1`这一全局实例,但通过指针间接操作提高了安全性。

---

### 对比搜索结果的实现
搜索结果中的示例驱动通过全局变量`data`直接操作缓冲区,而当前代码则通过`private_data`传递设备实例:  
• **相同点**:均需共享设备状态或缓冲区。  
• **差异点**:当前代码通过`private_data`实现了更规范的上下文传递,避免了全局变量的滥用。

---

### 总结
`test_dev`在读写函数中的可访问性依赖于:  
1. 全局变量`dev1`作为设备实例的存储载体;  
2. `file->private_data`实现跨函数指针传递;  
3. 局部指针变量`test_dev`的解引用操作。  
这种设计既符合Linux驱动开发规范,又兼顾了数据共享的安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值