You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核探针到字符设备文件操作的数据传递方法问询

内核探针到字符设备文件操作传递数据的推荐方式

核心方案是利用内核提供的dev_set_drvdata()/dev_get_drvdata()绑定设备私有数据,同时通过字符设备(cdev)与inode/file结构的关联,在文件操作函数中安全获取数据,彻底替代全局变量。

1. 探针阶段绑定私有数据

在platform驱动的probe函数中,先分配并初始化私有数据结构体,再将其绑定到平台设备的struct device对象上:

#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>

struct my_dev_data {
    int device_state;
    struct cdev cdev;
    // 其他业务相关成员
};

static int my_probe(struct platform_device *pdev) {
    struct my_dev_data *priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
    if (!priv_data)
        return -ENOMEM;

    // 初始化私有数据的业务字段
    priv_data->device_state = 0;

    // 将私有数据绑定到设备对象
    dev_set_drvdata(&pdev->dev, priv_data);

    // 后续完成字符设备注册(见下一步)
    return 0;
}

2. 注册字符设备并关联inode

在probe函数中完成cdev的初始化与添加,确保cdev与私有数据结构体绑定:

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .read = my_read,
    .write = my_write,
};

static int my_probe(struct platform_device *pdev) {
    // ...前面的私有数据分配与绑定...

    dev_t devno;
    int ret;

    // 分配设备号(静态/动态分配均可)
    ret = alloc_chrdev_region(&devno, 0, 1, "my_device");
    if (ret) {
        dev_err(&pdev->dev, "alloc chrdev region failed\n");
        return ret;
    }

    // 初始化cdev并关联文件操作集合
    cdev_init(&priv_data->cdev, &my_fops);
    priv_data->cdev.owner = THIS_MODULE;

    // 将cdev添加到内核
    ret = cdev_add(&priv_data->cdev, devno, 1);
    if (ret) {
        dev_err(&pdev->dev, "cdev add failed\n");
        unregister_chrdev_region(devno, 1);
        return ret;
    }

    return 0;
}

3. 在文件操作函数中获取私有数据

在open函数中,通过两种方式拿到私有数据,还可以将其存入struct file的private_data字段,供后续read/write等函数直接使用:

static int my_open(struct inode *inode, struct file *filp) {
    // 方式1:通过container_of从cdev反向获取私有数据
    struct my_dev_data *priv_data = container_of(inode->i_cdev, struct my_dev_data, cdev);

    // 方式2:从inode关联的device对象中取出绑定的私有数据
    // struct my_dev_data *priv_data = dev_get_drvdata(inode->i_dev);

    // 将私有数据存入file结构,后续函数直接取用
    filp->private_data = priv_data;
    return 0;
}

static ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
    struct my_dev_data *priv_data = filp->private_data;

    // 这里直接使用priv_data中的业务数据,比如读取device_state
    // ...业务逻辑实现...

    return count;
}

4. 卸载阶段清理

在remove函数中,只需清理字符设备,devm分配的内存会随设备对象销毁自动释放:

static int my_remove(struct platform_device *pdev) {
    struct my_dev_data *priv_data = dev_get_drvdata(&pdev->dev);
    dev_t devno = priv_data->cdev.dev;

    cdev_del(&priv_data->cdev);
    unregister_chrdev_region(devno, 1);

    return 0;
}

关键注意事项

  • 优先使用devm_kzalloc()等devm系列函数分配内存,避免手动管理内存导致泄漏。
  • container_of的三个参数必须对应:目标结构体类型、源指针、源指针在目标结构体中的成员名。
  • 确保设备号的分配与释放成对出现,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Nick Skywalker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 07:38:37