内核探针到字符设备文件操作的数据传递方法问询
内核探针到字符设备文件操作传递数据的推荐方式
核心方案是利用内核提供的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
相关产品推荐
相关产品推荐

