8/8/2019 Block Driver
1/22
` From a userland programmer's point of view the block
and character devices look similar because both use the
VFS
` layer to initiate access. Hence, to use either, oneemploys similar library calls to do such things as
` open the device
` read or write from it
` close the device
8/8/2019 Block Driver
2/22
` Typical block devices are the various kinds of
disk drives. From the CPU's viewpoint, these are
relatively slow electromechanical devices.
` If a user program makes read/write library calls
to access a character device, the VFS passes
these requests on to the low level read/write
functions in the driver` If a user program makes read/write library calls
to access a block device, the VFS does not pass
these requests on to low level read/write
functions in the driver. Instead, the block_read()
8/8/2019 Block Driver
3/22
` Clearly, if a block device driver does not have adirect
read/write interaction with the user program because
of the intervening buffer, then it must provide
functions to keep the buffer appropriately up to date. Inshort, the device driver must provide low level
read/write functionality to interact with the buffer as
needed.
` These low levelfunctions arenot entry points triggered
directly by user programs and hence donot belong in
theblock_device_operations struct. Nevertheless, the
kernel must know about the block driver's low levelread/write functionalit .
8/8/2019 Block Driver
4/22
8/8/2019 Block Driver
5/22
Generic Block Device LayerGeneric Block Device Layer
` Provides common functionality for all blockdevices in Linux
Uniform interface (to file system)e.g. bread( ) block_prepare_write( )
block_read_full_page( )ll_rw_block( )
buffer management and disk caching
Block I/O requests scheduling` Generates and queues actual I/O requests in
a request queue (per device)
Individual device driver services this
8/8/2019 Block Driver
6/22
Request QueueRequest Queue
` Data structure: in include/linux/blkdev.h` Queue header: type request_queue_t
typedef structure request_queue request_queue_t
queue_head: double linked list ofpending
requests request_fn: pointer to request service routine
` Queue element: struct request
cmd: read or write
Number of request sectors, segments bh, bhtail: a list of buffer header
Memory area (for I/O transfer)
8/8/2019 Block Driver
7/22
8/8/2019 Block Driver
8/22
8/8/2019 Block Driver
9/22
8/8/2019 Block Driver
10/22
8/8/2019 Block Driver
11/22
8/8/2019 Block Driver
12/22
8/8/2019 Block Driver
13/22
8/8/2019 Block Driver
14/22
SkeletonSkeleton InitInit FunctionFunction
res = register_blkdev(RADIMO_MAJOR, "radimo", &radimo_fops))
static char *my_dev;
my_dev = vmalloc (disk_size)
my_request_queue = blk_init_queue (my_request, &lock)
blk_queue_logical_block_size (my_request_queue, sector_size);
my_gd = alloc_disk (16)
static struct gendisk *my_gd;
8/8/2019 Block Driver
15/22
my_gd->major = mybdrv_ma_no;
my_gd->first_minor = 0;
my_gd->fops = &mybdrv_fops;
strcpy (my_gd->disk_name, MY_DEVICE_NAME);
my_gd->queue = my_request_queue;
set_capacity (my_gd, disk_size / sector_size);
add_disk (my_gd);
8/8/2019 Block Driver
16/22
static void __exit my_exit (void)
{
del_gendisk (my_gd);
put_disk (my_gd);
unregister_blkdev (mybdrv_ma_no, MY_DEVICE_NAME);
printk (KERN_INFO "module successfully unloaded, Major No. = %d\n",mybdrv_ma_no);
blk_cleanup_queue (my_request_queue);
vfree (my_dev);
}
8/8/2019 Block Driver
17/22
SkeletonSkeleton ExitExit FunctionFunction
static void __exit xxx_exit (void){
/* clean up */
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));devfs_unregister(devfs_handle);devfs_unregister(devfs_dir);
/* clean up */}
module_init(xxx_init);module_exit(xxx_exit);
8/8/2019 Block Driver
18/22
SkeletonSkeleton RequestRequest
OperationOperationstatic void xxx_request(request_queue_t *q)
{
while (1) {
INIT_REQUEST;//a macro,quit while loop when request queue is empty
switch (CURRENT->cmd) {case READ:
/* do read request */
case WRITE:
/* do write request */
}
end_request(status);//when finishing a request,remove the request}
}
8/8/2019 Block Driver
19/22
` Recall that for character drivers, ioctl() was a catchall for any hardwarecommands the specific driver might need.
` This is also true for the block drivers, but there is also a set ofcommonly used commands which usually suffice (see
` ); for example:` BLKROSET - set device read-only
` BLKGETSIZE - return device size` BLKFLSBUF - flush buffer cache` BLKRASET - set the read ahead value
` BLKRAGET - get the read ahead value` There are on the order of a dozen of these ioctl commands. The ioctl()
function in the driver could handle these, as` well as any custom commands, in a switch structure as usual.
8/8/2019 Block Driver
20/22
` These are intended for use with removable media. Theirfunctionality is:
` check_media_change - returns 1 if the media has been changedsince last access, but otherwise returns 0
` revalidate - typically updates internal status information to reflect
new media; called after media change is detected` The kernel automatically checks for media change on mounting a
device. If the driver keeps status information` concerning a removable device, it should check for media
change (and revalidate on change) in the open command` as well.
8/8/2019 Block Driver
21/22
` These are triggered by user programs which use the library callsopen and close, as usual. Typically when a file is
` opened the open command passes a pointer to a file struct andthat structure is then bound to the process which
` performed the open. Mounting also uses the open command, but
the file structure passed is quite different and does not becomebound to the mount process. This 'quite different' file struct hasonly one field that is relevant i.e. the
` f_mode field. The other fields should not be used. The f_modetells the driver to open in one of two modes:
`
read-only via f_mode = FMODE_READ` read-write via f_mode = FMODE_READ | FMODE_WRITE
8/8/2019 Block Driver
22/22