Search code examples
clinux-kernellinux-device-driverioctlblock-device

Getting 'Invalid argument' error when using IOCTL


My userspace program is like this(this is only part of code):

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;
    }

in '.h' file I have defined custom IOCTL commands -

#define MY_BLOCK_DEVICE_ADD    _IOWR('M', 1, char*)
#define MY_BLOCK_DEVICE_REMOVE _IOWR('M', 2, char*)

in driver/module code -

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;
}

But every time when I call IOCTL from userspace, I am getting invalid argument error. I verified changing magic numbers but didn't succeed. Can you plz help me with this?

EDIT Note that these aren't full code snippets.


Solution

  • The problem is that you try to do your own device-IOCTL calls on a totally different device.

    If, as you claim in a comment, that you open the /dev/sdb device, then you can't do the IOCTL calls on it. You must open your own device, then call the IOCTL on that device:

    // Error checking omitted
    int mydevice = open("/dev/myowndevicefile", O_RDWR);
    
    ioctl(mydevice, MY_BLOCK_DEVICE_ADD, path);