//根据驱动器的几何信息填充hd_geometry,包含磁头,柱面,扇区等信息. int (* getgeo)(struct block_device*, struct hd_geometry*); 3.gendisk结构体 使用gendisk结果提来描述一个独立的磁盘设备或分区. //gendisk structure struct gendisk{ /*前三个元素共同表征了一个磁盘的主,次设备号,同一个磁盘的各个分区共享一个主设备号*/ int major;/*主设备号*/ int first_minor;/*第一个次设备号*/ int minors;/*最大的次设备数,如果不能分区,则为1*/ char disk_name[32]; struct hd_struct** part;/*磁盘上的分区信息*/ struct block_device_operations* fops;/*块设备操作,block_device_operations*/ struct request_queue* queue;/*请求队列,用于管理该设备IO请求队列的指针*/ void* private_data;/*私有数据*/ sector_t capacity;/*扇区数,512字节为1个扇区,描述设备容量*/ //...... }; 关于gendisk的操作: /*分配一个gendisk结构体,此结构体是由内核动态分配的*/ struct gendisk* alloc_disk(int minors); /*增加gendisk,来注册该设备,此动作应该在设备驱动初始化完毕,并能响应磁盘请求之后*/ void add_disk(struct gendisk* gd); /*释放一个不再需要的磁盘*/ void del_gendisk(struct gendisk* gd); /*gendisk引用计数*/ /** ***gendisk引用计数器:gendisk包含一个kobject成员.通过get_disk()&put_disk()函数来操作引用 ***计数,此操作不需要驱动亲自完成.通常调用del_gendisk()会去掉gendisk的最终引用计数,但不是必 ***须的,因此在del_gendisk()后gendisk结构体可能继续存在. **/ /*设置gendisk容量*/ void set_capacity(struct gendisk* disk, sector_t size); 块设备中,最小的可寻址单元就扇区,常见扇区大小是512字节.扇区的大小是设备的物理属性,是所有块设备的基本单元,块设备无法对比扇区小的单元进行寻址和操作.不过许多块设备能够一次传输多个扇区.不管物理设备的真实扇区是多少,内核与块设备交互的扇区均以512字节为单位.所以set_capcity()函数以512字节为单位. 4.request和bio结构体 1)请求request request和request_queue结构体:Linux块设备驱动中,使用request结构体来表征等待进行的IO请求;并用request_queue来表征一个块IO请求队列.两个结构体的定义如下: request结构体 struct request{ struct list_head queuelist; unsigned long flags;
sector_t sector;/*要传输的下一个扇区*/ unsigned long nr_sectors;/*要传送的扇区数目*/ unsigned int current_nr_sector;/*当前要传送的扇区*/
sector_t hard_sector;/*要完成的下一个扇区*/ unsigned long hard_nr_sectors;/*要被完成的扇区数目*/ unsigned int hard_cur_sectors;/*当前要被完成的扇区数目*/
struct bio* bio;/*请求的bio结构体的链表*/ struct bio* biotail;/*请求的bio结构体的链表尾*/
/*请求在屋里内存中占据的不连续的段的数目*/ unsigned short nr_phys_segments; unsigned short nr_hw_segments;
int tag; char* buffer;/*传送的缓冲区,内核的虚拟地址*/ int ref_count;/*引用计数*/ ... }; 说明: request结构体的主要成员包括: sector_t hard_sector;/*要完成的下一个扇区*/ unsigned long hard_nr_sectors;/*要被完成的扇区数目*/ unsigned int hard_cur_sectors;/*当前要被完成的扇区数目*/ /* * 上述三个成员依次是第一个尚未传输的扇区,尚待完成的扇区数,当前IO操作中待完成的扇区数 * 但驱动中一般不会用到他们.而是下面的一组成员. */ sector_t sector;/*要传输的下一个扇区*/ unsigned long nr_sectors;/*要传送的扇区数目*/ unsigned int current_nr_sector;/*当前要传送的扇区*/ /* * 这三个成员,以字节为单位.如果硬件的扇区大小不是512字节.如字节,则在开始对硬件进行操作之 * 前,应先用4来除起始扇区号.前三个成员,与后三个成员的关系可以理解为"副本". */ 关于unsigned short nr_phys_segments:该成员表示相邻的页被合并后,这个请求在物理内存中的段的数目.如果该设备支持SG(分散/聚合,scatter/gather),可根据该字段申请sizeof(scatterlist*) nr_phys_segments的内存,并使用下面的函数进行DMA映射: int blk_rq_map_sg(request_queue_t* q, struct request* rq, struct scatterlist *sg); 该函数与dma_map_sg()类似,返回scatterlist列表入口的数量. 关于struct list_head queuelist:该成员用于链接这个请求到请求队列的链表结构,函数blkdev_ dequeue_request()可用于从队列中移除请求.宏rq_data_dir(struct request* req)可获得数据传送方向.返回0表示从设备读取,否则表示写向设备. |
|