一,请求处理
块设备的处理函数里没有read write等函数,所有对块设备的请求如读取 写入等都是通过request函数处理的。request函数的原型是void request(request_queue_t *queue);
request函数的处理是异步的。每一个设备都有一个请求队列,当请求队列生成的时候,request函数就与该请求队列绑定在一起了,request函数总是与一个自旋锁一起使用,当request函数拥有自旋锁的时候,该锁防止内核为设备安排其它请求。构request代表了挂起的I/O请求,每个请求用一个结构request实例描述,存放在请求队列链表中
- <pre name="code" class="cpp">struct request {
- 02. //用于挂在请求队列链表的节点,使用函数blkdev_dequeue_request访问它,而不能直接访问
- 04. struct list_head queuelist;
- 05. struct list_head donelist; /*用于挂在已完成请求链表的节点*/
- 06. struct request_queue *q; /*指向请求队列*/
- 07. unsigned int cmd_flags; /*命令标识*/
- 08. enum rq_cmd_type_bits cmd_type; /*命令类型*/
- 09. /*各种各样的扇区计数,为提交i/o维护bio横断面的状态信息,hard_*成员是块层内部使用的,驱动程序不应该改变它们*/
- 12. sector_t sector; /*将提交的下一个扇区*/
- 13. sector_t hard_sector; /* 将完成的下一个扇区*/
- 14. unsigned long nr_sectors; /* 整个请求还需要传送的扇区数*/
- 15. unsigned long hard_nr_sectors; /* 将完成的扇区数*/
- 16. /*在当前bio中还需要传送的扇区数 */
- 17. unsigned int current_nr_sectors;
- 18. /*在当前段中将完成的扇区数*/
- 19. unsigned int hard_cur_sectors;
- 20. struct bio *bio; /*请求中第一个未完成操作的bio*、
- 21. struct bio *biotail; /*请求链表中末尾的bio*、
- 22. struct hlist_node hash; /*融合 hash */
- 23. /* rb_node仅用在I/O调度器中,当请求被移到分发队列中时,请求将被删除。因此,让completion_data与rb_node分享空间*/
- 25. union {
- 26. struct rb_node rb_node; /* 排序/查找*/
- 27. void *completion_data;
- 28. };
二,请求队列
每个块设备都有一个请求队列,每个请求队列单独执行I/O调度,请求队列是由请求结构实例链接成的双向链表,链表以及整个队列的信息用结构request_queue描述,称为请求队列对象结构或请求队列结构。它存放了关于挂起请求的信息以及管理请求队列(如:电梯算法)所需要的信息。结构成员request_fn是来自设备驱动程序的请求处理函数。
三,Bio结构
通常1个bio对应1个I/O请求,IO调度算法可将连续的bio合并成1个请求。所以,1个请求可以包含多个bio。bio为通用层的主要数据结构,既描述了磁盘的位置,又描述了内存的位置,是上层内核vfs与下层驱动的连接纽带
- struct bio {
- 02.sector_t bi_sector;//该bio结构所要传输的第一个(512字节)扇区:磁盘的位置
- 03.struct bio *bi_next; //请求链表
- 04.struct block_device *bi_bdev;//相关的块设备
- 05.unsigned long bi_flags//状态和命令标志
- 06.unsigned long bi_rw; //读写
- 07.unsigned short bi_vcnt;//bio_vesc偏移的个数
- 08.unsigned short bi_idx; //bi_io_vec的当前索引
- 09.unsigned short bi_phys_segments;//当DMA完成时候,它表示BIO中包含的物理段的数目
- 10.unsigned short bi_hw_segments;//当DMA完成时候,它表示BIO中包含的硬件所能操作的段数
- 11.unsigned int bi_size; //以字节为单位所需要传输数据的大小
- 12.unsigned int bi_hw_front_size;//第一个可合并的段大小;
- 13.unsigned int bi_hw_back_size;//最后一个可合并的段大小
- 14.unsigned int bi_max_vecs; //bio_vecs数目上限
- 15.struct bio_vec *bi_io_vec; //bio_vec链表:内存的位置
- 16.bio_end_io_t *bi_end_io;//I/O完成方法
- 17.atomic_t bi_cnt; //使用计数
- 18.void *bi_private; //拥有者的私有方法
- 19.bio_destructor_t *bi_destructor; //销毁方法
- 20.};
- 内存数据段结构bio_vec
- struct bio_vec {
- struct page *bv_page; /*数据段所在的页*/
- unsigned short bv_len; /*数据段的长度*/
- unsigned short bv_offset; /*数据段页内偏移*/
- };
四:
Linux中的队列请求处理函数为kernel/drivers/mmc/card/Block.c文件的mmc_blk_issue_rq()函数