与请求处理相关的几个数据结构:
struct request_queue
struct request
struct bio
一个bio对应上层传递的I/O请求,I/O调度算法会把多个bio合并为一个request,多个request又构成了request_queue,request_queue是上节提到的gendisk结构中的成员。
bio的定义:
struct bio {
struct bio *bi_next; /* request queue link */
struct block_device *bi_bdev;
unsigned long bi_flags; /* status, command, etc */
unsigned long bi_rw; /* bottom bits READ/WRITE,
* top bits priority
*/
struct bvec_iter bi_iter;
/* Number of segments in this BIO after
* physical address coalescing is performed.
*/
unsigned int bi_phys_segments;
...
struct bio_vec *bi_io_vec; /* the actual vec list */
struct bio_set *bi_pool;
...
}
其中bio_vec用来描述与bio对应的内存,这些bio_vec可能不在同一数据页中,所以要用向量(bi_io_vec)来表示,bio_vec的定义为:
struct bio_vec {
struct page *bv_page;
unsigned int bv_len;
unsigned int bv_offset;
};
bvec_iter是用来遍历bio的迭代器,记录了当前bi_io_vec的处理情况
struct bvec_iter {
sector_t bi_sector; /* device address in 512 byte sectors */
unsigned int bi_size; /* residual I/O count */
unsigned int bi_idx; /* current index into bvl_vec */
unsigned int bi_bvec_done; /* number of bytes completed in current bvec */
};
宏定义__rq_for_each_bio()用来遍历一个请求的所有bio
#define __rq_for_each_bio(_bio, rq)
宏定义bio_for_each_segment()遍历一个bio所有的bio_vec。
#define bio_for_each_segment(bvl, bio, iter)
简单来说,请求处理就是在请求对应的内存和磁盘之间进行数据传输,传输数据需要知道请求的内存数据页,磁盘的扇区地址和传输的数据量这三个要素。
通过宏定义__bio_kmap_atomic()将bio_vec的页映射为内核的虚拟地址
__bio_kmap_atomic(bio, iter)
例如:char *buf = __bio_kmap_atomic(bio, iter);
对应的,用宏定义__bio_kunmap_atomic(addr)来解除映射
#define __bio_kunmap_atomic(addr)
例如:__bio_kunmap_atomic(buf)
磁盘的扇区地址由bvec_iter的bi_sector成员获得
传输的数据量可以由函数bio_cur_bytes()获得
static inline unsigned int bio_cur_bytes(struct bio *bio);
综上所述,我们可以得出请求处理的方法:
遍历一个请求的所有bio,再遍历一个bio的所有bio_vec,得到数据传输的三个主要参数,再根据实际情况完成数据的读写。