通用块层的核心数据结构称为bio描述符,它描述了块设备的io操作。每一个bio结构都包含一个磁盘存储区标识符(存储区中的起始扇区号和扇区数目)和一个或多个描述与IO操作相关的内存区段(bio_vec数组)
bio结构中的字段
struct bio {
sector_t bi_sector; //要传输的第一个扇区。
struct bio *bi_next; //链接到请求队列的下一个bio
struct block_device *bi_bdev;//指向块设备描述符的指针
unsigned long bi_flags; //bio的状态标志
unsigned long bi_rw;//IO操作标志 READ/WRITE
unsigned short bi_vcnt; //bio中的bio_vec数组中当前元素的个数
unsigned short bi_idx; //bio的bio_vec数组中段的当前索引值
unsigned int bi_phys_segments; //合并后bio中的物理段的数目
unsigned int bi_size; //所需传输的数据字节数
unsigned int bi_seg_front_size;
unsigned int bi_seg_back_size;
unsigned int bi_max_vecs; //bio的bio_vec数组中允许的最大段数
unsigned int bi_comp_cpu; /* completion CPU*/
atomic_t bi_cnt; //bio引用计数器
struct bio_vec *bi_io_vec; /* the actual vec list*/
bio_end_io_t *bi_end_io;//bio的IO操作结束时调用的方法
void *bi_private;//通用块层和块设备驱动程序的IO完成方法使用的指针
bio_destructor_t *bi_destructor; //释放bio时调用的析构方法
};
bio中的每个段是由一个bio_vec数据结构描述的,bio_vec数据结构如下
bio_vec{
struct page* bv_page //指向段在页框描述符的指针
unsigned int bv_len //段的字节长度
unsigned int bv_offset //页框中数据的偏移量
}
bio中的bi_io_vec字段指向bio_vec数组的第一个元素,bi_vcnt则说明了数组当前元素的个数,而bi_max_vecs则限定了数组的长度。
下面两幅图可以很好的说明bio与bio_vec的关系
下面两幅图可以很好的说明bio与bio_vec的关系
在通用块层启动一次新的IO操作时,会调用bio_alloc函数分配一个新的bio结构,bio是由slab分配器分配的。内核同时也为bio_vec结构分配内存池。