Linux驱动中filp_open()返回EFAULT错误的原因及修复方案
filp_open()返回EFAULT错误的原因及代码修复
错误原因
- 路径指向无效对象:
/sys/class/leds/dell::kbd_backlight是sysfs下的设备目录,不是可读写的文件节点。真正控制键盘背光亮度的是目录下的brightness文件,直接打开目录会让内核无法找到有效文件对象,触发EFAULT错误(该错误表示内核无法访问指定的地址/资源)。 - 非法使用文件打开标志:sysfs是虚拟文件系统,不支持创建新文件,原代码中
O_WRONLY|O_CREAT|O_TRUNC里的O_CREAT属于无效参数,会干扰文件打开流程。 - 错误处理不完整:原代码未打印具体错误码,无法直观定位问题类型。
代码修复方案
针对上述问题,修改后的代码如下:
int keyboard_event_handler(struct notifier_block *nblock, unsigned long code, void *_param) { char keybuf[12] = {0}; struct keyboard_notifier_param *param = _param; struct file* filp = NULL; char buf[] = "2"; int bytes_written; int err; if (!(param->down)) return NOTIFY_OK; keycode_to_string(param->value, param->shift, keybuf, 12); if (strlen(keybuf) < 1) return NOTIFY_OK; printk(KERN_INFO "Keylog: %s", keybuf); // 修正路径为实际控制文件,移除无效的O_CREAT标志 filp = filp_open("/sys/class/leds/dell::kbd_backlight/brightness", O_WRONLY|O_TRUNC, 0644); if (IS_ERR(filp)) { // 打印具体错误码,便于排查问题 printk(KERN_ALERT "Error opening file: %ld", PTR_ERR(filp)); return NOTIFY_OK; // 返回NOTIFY_OK,避免中断其他通知链处理 } if(strcmp(keybuf,"z") == 0) { // 仅写入有效字符(避免写入字符串终止符) bytes_written = kernel_write(filp, buf, 1, &filp->f_pos); if (bytes_written < 0) { printk(KERN_ALERT "Error writing to file: %d\n", bytes_written); } else { printk(KERN_INFO "%d bytes written to file\n", bytes_written); } } err = filp_close(filp, NULL); if (err){ printk(KERN_ALERT "Error closing file: %d\n", err); } return NOTIFY_OK; }
额外优化建议
- 减少频繁IO操作:每次按键都打开/关闭文件效率较低,可以在模块初始化阶段打开
brightness文件,模块退出时再关闭,避免重复IO开销。 - 针对性错误处理:针对不同错误码(如EACCES权限不足、ENOENT文件不存在)做分支处理,提升代码健壮性。
- 权限适配:部分系统可能需要调整sysfs节点的udev规则或文件权限,确保驱动进程拥有读写权限。
内容的提问来源于stack exchange,提问作者AAKK
相关产品推荐
相关产品推荐

