缓冲,I/O调度,请求队列等都是与块设备驱动相关的概念。
1.块设备I/O特点。字符设备和块设备I/O上的诧异。
2.Linux块设备驱动结构。数据结构,函数,关系。
3.块设备驱动模块的加载与卸载,打开/释放/ioctl
4.块设备I/O操作所依赖的请求,bio处理方法。
5.Linux下的块设备例子。
-------------------------
块设备与字符设备区别:
1.字符设备以字符串为单位读写,块设备以固定块大小进行操作。
2.块设备对于I/O请求有缓冲区,读写顺序可以调整。读写连续的扇区,存储速度更快。
3.字符设备顺序读写,块设备随机访问。
---------------
块设备驱动结构:
file_operation ---> block_device_operations块设备操作的集合。
//打开和释放
int(*open)(struct block_device*, fmode_t);
void(*release)(struct gendisk*, fmode_t);
// I/O控制
int(*ioctl)(struct block_device*, fmode_t, unsigned, unsigned long);
int(*compat_ioctl)(struct block_device*, fmode_t, unsigned, unsigned, unsigned long);
//介质改变
int (*media_changed)(struct gendisk *gd);
unsigned int (*check_events)(struct gendisk *disk, unsigned int clearing);
//使介质有效
int (*revalidate_disk)(struct gendisk *gd);
//5.获得驱动器信息,hd_geometry结构体包含磁头,扇区,柱面等信息
int (*getgeo)(struct block_device *, struct hd_geometry *);
-------------------
块设备注册和初始化阶段
register_blkdev() 注册到内核,申请设备号, 返回主设备号。
unregister_blkdev()
int register_blkdev(unsigned int major, const char* name);
int unregister_blkdev(unsigned int major, const char *name);
--------------
static int xxx_init(void)
{
if(register_blkdev(XXX_MAJOR, "xxx"))
{
err = -EIO;
goto out;
}
xxx_queue = blk_init_queue(xxx_request, xxx_lock);
if(!xxx_queue)
goto out_queue;
blk_queue_max_hw_sectors(xxx_queue, 255);
blk_queue_logcal_block_size(xxx_queue, 512);
xxx_disks->major = XXX_MAJOR;
xxx_disks->first_minor = 0;
xxx_disks->fops = &xxx_op;
xxx_disks->queue = xxx_queue;
sprintf(xxx_disks->disk_name, "xxx%d", i);
set_capacity(xxx_disks, xxx_size * 2);
add_disk(xxx_disks);
return 0;
out_queue:unregister_blkdev(XXX_MAJOR, "xxx");
out:put_disk(xxx_disks);
blk_cleanup_queue(xxx_queue);
return -ENOMEME;
}
清除请求队列,使用blk_cleanup();
删除对gendisk的引用,使用put_disk()
删除对块设备的引用,注销块设备驱动,使用unregister_blkdev();
static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigne int cmd, unsigned long arg)
{
int ret = -EINVAL;
if(cmd == MMC_IOC_CMD)
ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user*)arg);
return ret;
}