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:
ioctl(fd, HDIO_GETGEO, ..)
didn't invoke .ioctl
call, but it invoked .getgeo
. How is this possible?Instead, a kernel module is a collection of subroutines and data. A device driver is a kernel module that forms a software interface to an input/output (I/O) device. The subroutines in a device driver provide entry points to the device.
Devices that support a file system are known as block devices. Drivers written for these devices are known as block device drivers. Block device drivers take a file system request, in the form of a buf(9S) structure, and issue the I/O operations to the disk to transfer the specified block.
The Linux kernel supports two main types of USB drivers: drivers on a host system and drivers on a device.
A block driver provides access to devices that transfer randomly accessible data in fixed-size blocks—disk drives, primarily. The Linux kernel sees block devices as being fundamentally different from char devices; as a result, block drivers have a distinct interface and their own particular challenges.
Block device drivers manage devices with physically addressable storage media, such as disks. All other devices are considered character devices. Two types of character device drivers are standard character device drivers and STREAMS device drivers.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With