Why is the kernel using the default block driver instead of my driver's code?
Asked Answered
T

1

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?
Tadashi answered 24/4, 2014 at 10:14 Comment(0)
W
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.

Weakly answered 24/4, 2014 at 10:37 Comment(4)
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?Tadashi
Yes, that's it exactly.Weakly
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?Tadashi
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.Weakly

© 2022 - 2024 — McMap. All rights reserved.