Linux下驱动间IOCTL调用实现方法及内核模块中ioctl使用咨询
问题1:Linux系统中如何从一个驱动向另一个驱动发起IOCTL调用
驱动之间发起IOCTL调用,本质是通过内核态的文件系统接口访问目标驱动的设备节点,具体步骤如下:
- 确定目标驱动的设备文件路径(例如
/dev/target_device) - 在内核空间使用
filp_open()打开该设备文件,需传入正确的访问权限(如O_RDWR),获取struct file指针 - 调用
vfs_ioctl()(或内核版本对应的vfs_unlocked_ioctl())发起IOCTL请求,传入文件指针、约定好的命令码和数据参数 - 操作完成后调用
filp_close()关闭文件指针,释放资源 - 全程严格处理错误:检查
filp_open的返回值是否为有效指针,判断vfs_ioctl的返回值是否成功
示例代码片段:
#include <linux/fs.h> #include <linux/uaccess.h> struct file *fp; long ret; int cmd_data = 0x1234; // 打开目标设备 fp = filp_open("/dev/target_device", O_RDWR, 0); if (IS_ERR(fp)) { return PTR_ERR(fp); } // 发起IOCTL调用 ret = vfs_ioctl(fp, TARGET_IOCTL_CUSTOM_CMD, (unsigned long)&cmd_data); if (ret < 0) { // 处理调用失败逻辑 } // 关闭文件 filp_close(fp, NULL);
注意事项:
- 确保目标设备文件存在且内核态具备访问权限
- 禁止在原子上下文(如中断处理函数)中执行上述操作,因为
filp_open和vfs_ioctl可能触发睡眠 - IOCTL命令码需与目标驱动提前约定,使用内核提供的
_IO/_IOR/_IOW/_IOWR宏定义,避免冲突
问题2:内核模块中是否可以使用ioctl?若可行,是否有较好的实现方案?
完全可以在内核模块中使用IOCTL,既可以调用其他驱动的IOCTL接口,也可以自身实现IOCTL供外部调用,以下是两种场景的优化方案:
场景1:自身实现IOCTL接口供其他模块调用
- 规范定义命令码:用内核宏
_IO/_IOR/_IOW/_IOWR定义命令码,避免与其他驱动冲突 - 封装内核态直接调用函数:无需通过文件系统层,直接导出核心处理函数(用
EXPORT_SYMBOL_GPL),供其他模块直接调用,效率更高 - 权限与参数校验:敏感操作需用
capable()检查调用者权限(如CAP_SYS_ADMIN),同时严格校验传入的数据指针、长度合法性
示例代码:
// 定义IOCTL命令码 #define MY_DRIVER_SET_DATA _IOW('D', 1, int) // 驱动私有数据结构 struct my_drv_data { int core_data; }; // 内核态可直接调用的IOCTL处理函数 long my_drv_ioctl(struct my_drv_data *dev, unsigned int cmd, unsigned long arg) { int input_data; switch (cmd) { case MY_DRIVER_SET_DATA: if (!capable(CAP_SYS_ADMIN)) { return -EPERM; } if (copy_from_user(&input_data, (int __user *)arg, sizeof(input_data))) { return -EFAULT; } dev->core_data = input_data; return 0; default: return -ENOTTY; } } EXPORT_SYMBOL_GPL(my_drv_ioctl);
场景2:调用其他模块的IOCTL
- 优先直接函数调用:若两个驱动协同开发,直接调用对方导出的核心函数,比通过设备文件的IOCTL更高效安全
- 必须用IOCTL时的优化:可缓存打开的
struct file指针,避免重复打开关闭,但需处理目标设备卸载的场景;全程完善错误处理,避免内核panic或资源泄漏
内容的提问来源于stack exchange,提问作者Hoang Do
相关产品推荐
相关产品推荐

