块设备是通过generic_make_request提交请求给I/O调度层,然后驱动层通过调用blk_init_queue来准备请求,这节来看看怎么样写一个块设备驱动程序。一个块设备的是由一个gendisk结构体来描述,每一个gendisk可以支持多个分区,内核对于块设备的访问,都是基于这个结构体展开
struct gendisk { int major; //主设备号 int first_minor; //第一个次设备号 int minors; //次设备个数,每个分区都需要一个次设备号 char disk_name[DISK_NAME_LEN]; //块设备名字,可以通过/proc/partions获取 char *(*devnode)(struct gendisk *gd, umode_t *mode); unsigned int events; //supported events unsigned int async_events; // async events, subset of all struct disk_part_tbl __rcu *part_tbl; struct hd_struct part0; //分区表 const struct block_device_operations *fops; //块设备操作集 struct request_queue *queue; //请求队列 void *private_data; //私有成员变量 int flags; struct device *driverfs_dev; // FIXME: remove struct kobject *slave_dir; struct timer_rand_state *random; atomic_t sync_io; /* RAID */ struct disk_events *ev; #ifdef CONFIG_BLK_DEV_INTEGRITY struct blk_integrity *integrity; #endif int node_id; }
其实驱动就是构造这个结构体,并且提供一个驱动程序的访问队列即可。由通用层,如果驱动程序没有提供处理等待队列的处理函数,就会使用内核提供的默认的等待队列的处理函数,那么就分为两种情况,来看看怎么写一个块设备的驱动程序。
1. 对于没有提供等待队列的处理函数情况
1. 分配一个请求队列:blk_alloc_queue
2. 分配一个 gendisk 结构:alloc_disk
3. 设置 gendisk 主要结构成员:置主次设备号,设置操作函数集,设置容量等
4. 向内核注册块设备驱动:add_disk
2. 对于提供等待队列的处理函数的情况
1. 分配一个请求队列:blk_alloc_queue
2. 为请求队列绑定 make_request_fn 方法:blk_queue_make_request
3. 分配一个 gendisk 结构:alloc_disk
4. 设置 gendisk 主要结构成员:置主次设备号,设置操作函数集,设置容量等
5. 向内核注册块设备驱动:add_disk
时间: 2024-10-24 22:20:32