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

调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:45:34