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

block-device, kernel, linux

Solution

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.

Problem

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: - 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? - `ioctl(fd, HDIO_GETGEO, ..)` didn't invoke `.ioctl` call, but it invoked `.getgeo`. How is this possible?

Original source