Block Device Driver
Dr A Sahu
Dept of Comp Sc & Engg.
IIT Guwahati
Outline
File System & Block Devices
Block Devices Registration
File System & Block Devices
What is the VFS ?
Mounting a device
What will we learn ?
Common Block Device Operations
struct file_operations def_blk_fops = {
open: blkdev_open,
release: blkdev_close,
llseek: block_llseek,
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
fsync: block_fsync,
ioctl: blkdev_ioctl,
};
Block Device Specific Operations
struct block_device_operations {
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*ioctl) (struct inode *, struct file *, unsigned,
unsigned long);
int (*check_media_change) (kdev_t);
int (*revalidate) (kdev_t);
};
typedef void (request_fn_proc) (request_queue_t *q);
Bh= block header
Generic Block Device Layer
e.g. bread( ) block_prepare_write( )
block_read_full_page( ) ll_rw_block( )
Request Queue
Request Queue
Invoking the Lower Layer
Request Service Routine
Request submission
ll_rw_block()
submit_bh()
generic_make_request()
__make_request()
__make_request() (cont.)
{
register struct request *rq;
DECLARE_WAITQUEUE(wait, current);
generic_unplug_device(q);
add_wait_queue(&q->wait_for_request, &wait);
do {
set_current_state(TASK_UNINTERRUPTIBLE);
if (q->rq[rw].count < batch_requests)
schedule();
spin_lock_irq(&io_request_lock);
rq = get_request(q,rw);
spin_unlock_irq(&io_request_lock);
} while (rq == NULL);
remove_wait_queue(&q->wait_for_request, &wait);
current->state = TASK_RUNNING;
return rq;
}
Request processing
Block Device in 2.4 Kernel
request_queue_t request_q;
queue_proc *queue;
void *data;
}
struct blk_dev_struct blk_dev[MAX_BLKDEV];
#define BLK_DEFAULT_QUEUE(_MAJOR) &blk_dev[_MAJOR].request_q
Block Device in 2.4 Kernel (2)
include/linux/blk.h
Skeleton Block Device
{
open: xxx_open,
release: xxx_release,
ioctl: xxx_ioctl,
check_media_change, xxx_check_change,
revalidate, xxx_revalidate,
owner: THIS_MODULE,
};
Skeleton Block Device
Skeleton “ Init” Function
#define MAJOR_NR XXX_MAJOR
static int __init xxx_init(void){
/* probe the hardware, request irq, … */
devfs_dir = devfs_mk_dir(NULL, “xxx_dir”, NULL);
/* old way: register_blkdev(MAJOR_NR, “xxx”, &xxx_bdops); */
devfs_handle = devfs_register_blk(devfs_dir, “xxx", ......);
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), xxx_request);
read_ahead[MAJOR_NR] = 8; /* 8 sector (4K) read ahead */
/* you may also setup those:
blk_size[MAJOR_NR]
blksize_size[MAJOR_NR]
hardsect_size[MAJOR_NR]
*/
/* rest of the initial setup */
printk( … ); return 0;
}
Skeleton “ Exit” Function
static void __exit xxx_exit (void)
{
/* clean up */
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
/* old way: unregister_blkdev(MAJOR_NR, “xxx”); */
devfs_unregister(devfs_handle);
devfs_unregister(devfs_dir);
/* clean up */
}
module_init(xxx_init);
module_exit(xxx_exit);
Skeleton “ Request” Operation
static 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, i.e: memcpy(q->buffer, mem_block, size); */
case WRITE:
/* do write request, i.e: memcpy(mem_block, q->buffer, size); */
default: /* impossible */
return 0;
}
end_request(status);//when finishing a request, remove it
}
}
To Write a Block Device Driver (summarize)
Thanks�Ref: Chap 16, LDD 3e Rubini- Corbet���Wishing u happy diwali