7

I wrote a block driver program which creates a dummy block device (sbd0). I registered all device operations for that block device: (Refer to include/linux/blkdev.h in 2.6.32 kernel source)

static struct block_device_operations sbd_ops = {
    .owner           = THIS_MODULE,
    .open            = sbd_open,
    .release         = sbd_close,
    .ioctl           = sbd_ioctl,
    .getgeo          = sbd_getgeo,
    .locked_ioctl    = sbd_locked_ioctl,
    .compat_ioctl    = sbd_compat_ioctl,
    .direct_access   = sbd_direct_access,
    .media_changed   = sbd_media_changed,
    .revalidate_disk = sbd_revalidate_disk
};

I compiled the driver program. I inserted the module and /dev/sbd0 was created. Now I want to test my driver code. So I wrote an application as below.

fd = open("/dev/sbd0", O_RDONLY); 
retval = ioctl(fd, BLKBSZGET, &blksz); //trying to get logical block size

Output is :4096

I wondered: I didn't implement ioctl for BLKBSZGET. It didn't invoke my sbd_ioctl, instead it used the default driver and gave me the result. For open, close calls it executed sbd_open and sbd_close (that I implemented). And then I tried:

retval = ioctl(fd, HDIO_GETGEO, &geoinfo);

It invoked sbd_getgeo but I thought it would invoke sbd_ioctl.

Here are my questions:

  1. I implemented a driver and created a device. If I perform any operation on that device, it has to invoke my driver application. But how does it use a few of my driver functions and few default driver functions?
  2. ioctl(fd, HDIO_GETGEO, ..) didn't invoke .ioctl call, but it invoked .getgeo. How is this possible?
gangadhars
  • 2,584
  • 7
  • 41
  • 68

1 Answers1

6

The ioctl dispatching is handled by the blkdev_ioctl function, which will process some of the ioctls directly, without calling into your driver's specific routine.

For HDIO_GETGEO, it calls your driver's getgeo function directly (from kernel 3.13.6, doesn't appear to have changed much since 2.6.32):

[...]
/*
 * We need to set the startsect first, the driver may
 * want to override it.
 */
memset(&geo, 0, sizeof(geo));
geo.start = get_start_sect(bdev);
ret = disk->fops->getgeo(bdev, &geo); /* <- here */
[...]

For BLKBSZGET, it calls block_size(bdev)), which simply returns bdev->bd_block_size.

You'll find blkdev_ioctl in block/ioctl.c if you need to know what happens for other ioctls.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • you mean, first `ioctl` handled by `blkdev_ioctl`. So directly few `ioctl` operations handled by `blkdev_ioctl` and remaining will handled by my driver functions? – gangadhars Apr 24 '14 at 10:52
  • Yes, that's it exactly. – Mat Apr 24 '14 at 10:54
  • I saw the definition of `blkdev_ioctl`. really good and very clear. Now I want to see how `ioctl` calling `blkdev_ioctl`. I want to see source file. In which file I get this? – gangadhars Apr 24 '14 at 10:56
  • Sorry, that was a typo, there's no `block/ioctl.h` in 3.13 either. The route from userspace ioctl call down to that function is a bit complex. It starts from the syscall interface (`fs/ioctl.c`, `SYSCALL_DEFINE3(ioctl, ...`) then goes down chasing pointers in the VFS structures from the file down to the appropriate driver. – Mat Apr 24 '14 at 11:13