调用IOCTL时触发「Invalid argument」错误的排查求助
问题描述
用户态程序片段:
char path[SIZE]; printf( "Enter the path of the block device to add or remove: "); fgets(path, SIZE, stdin); path[strcspn(path, "\n")] = '\0'; int fd = open( path, O_RDWR ); if( fd < 0 ) { perror( "Failed to open device" ); exit( EXIT_FAILURE ); } while( 1 ) { int input; printf( "Enter a number [ 0 for add and 1 for remove ]: " ); scanf( "%d", &input ); switch( input ) { case 0: if( ioctl( fd, MY_BLOCK_DEVICE_ADD, &path ) < 0 ) { perror( "Failed to add device" ); exit( EXIT_FAILURE ); } break; case 1: if( ioctl( fd, MY_BLOCK_DEVICE_REMOVE, &path ) < 0 ) { perror( "Failed to remove device" ); exit( EXIT_FAILURE ); } break; case 2: close(fd); return 0; } }
头文件中IOCTL命令定义:
#define MY_BLOCK_DEVICE_ADD _IOWR('M', 1, char*) #define MY_BLOCK_DEVICE_REMOVE _IOWR('M', 2, char*)
驱动/模块代码片段:
static int device_ioctl( struct block_device *dev, fmode_t mode, unsigned int cmd, unsigned long arg ) { printk(KERN_INFO "in ioctl"); int ret; char path[SIZE]; switch( cmd ) { case MY_BLOCK_DEVICE_ADD: if( copy_from_user( path, (char *)arg, SIZE ) ) { return -EFAULT; } path[strcspn(path, "\n")] = '\0'; register_block_device(path); printk( KERN_INFO "Device added\n" ); break; case MY_BLOCK_DEVICE_REMOVE: if( copy_from_user( path, (char *)arg, SIZE ) ) { return -EFAULT; } unregister_block_device(); printk( KERN_INFO "Device removed\n" ); break; default: return -ENOTTY; } return 0; }
调用IOCTL时始终返回「invalid argument」错误,修改幻数后问题依旧,需排查原因。
排查与修复方案
参数传递类型不匹配:
IOCTL定义中用_IOWR('M', 1, char*)声明要传递char*类型,但用户态调用时传的是&path——这是char**二级指针,和定义类型完全不符,驱动端解析命令时会判定参数无效直接返回错误。
修复:用户态调用时直接传path即可,数组名本身就是指向首元素的指针,无需取地址:// 原代码 // if( ioctl( fd, MY_BLOCK_DEVICE_ADD, &path ) < 0 ) // 修改后 if( ioctl( fd, MY_BLOCK_DEVICE_ADD, path ) < 0 )同理,REMOVE命令的调用也要做相同修改。
SIZE宏一致性检查:
确保用户态和驱动代码中SIZE宏的定义完全一致,两边数值不同会导致copy_from_user拷贝长度不匹配,也可能触发参数错误。驱动IOCTL注册验证:
检查块设备操作结构体(struct block_device_operations)中的ioctl成员是否正确指向device_ioctl函数。如果注册错误,内核会默认处理IOCTL命令,导致返回「invalid argument」。额外逻辑问题(非直接报错原因,但需修正):
驱动中MY_BLOCK_DEVICE_REMOVE分支里,unregister_block_device()没有传入从用户态拷贝来的path参数,会导致卸载设备的逻辑大概率失效,建议补充参数传递。
内容的提问来源于stack exchange,提问作者Sumit Patil
相关产品推荐
相关产品推荐

