Question

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?
Était-ce utile?

La 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top