unsigned short bi_vcnt; /* how many bio_vec's (bio_vec的数量)*/
unsigned short bi_idx; /* current index into bvl_vec(当前bio_vec的索引) */
/*不相邻的物理段的数目*/
unsigned short bi_phys_segments;
/*物理合并和DMA remap合并后不相邻的物理扇区*/
unsigned short bi_hw_segments;
/*被传送的数据大小(byte),用bio_sector(bio)获取扇区为单位的大小*/
unsigned int bi_size; /* residual I/O count */
/*被传送的数据大小(byte),用bio_sector(bio)获取扇区为单位的大小*/
/*为了明了最大的hw尺寸,考虑bio中第一个和最后一个虚拟的可合并的段的尺寸*/
unsigned int bi_hw_front_size;
unsigned int bi_hw_back_size;
unsigned int bi_max_vecs; /*能持有的最大bvl_vecs数*/
struct bio_vec *bi_io_vec; /*能持有的最大bvl_vecs数*/
...................
}
struct bio_vec {
struct page *bv_page; /*要操作的页指针*/
unsigned int bv_len; /*要传输的字节数*/
unsigned int bv_offset;/*偏移位置*/
};
/*一般不直接访问bio的bio_vec成员,而使用bio_for_each_segment()宏进行操作.
*该宏循环遍历整个bio中的每个段.
*/
#define __bio_for_each_segment(bvl, bio, i, start_idx)\
for(
bvl = bio_iovec_idx((bio),(start_idx)),i = (start_idx);\
i <(bio)->bi_vcnt;\
bvl++, i++\
)
#define bio_for_each_segment(bvl, bio, i)\
__bio_for_each_segment(bvl, bio, i, (bio)->bi_idx)
在内核中,提供了一组函数(宏)用于操作bio:
int bio_data_dir(struct bio* bio);
该函数用于获得数据传送方向.
struct page* bio_page(struct bio* bio);
该函数用于获得目前的页指针.
int bio_offset(struct bio* bio);
该函数返回操作对应的当前页的页内偏移,通常块IO操作本身就是页对齐的.
int bio_cur_sectors(struct bio* bio);
该函数返回当前bio_vec要传输的扇区数.
char* bio_data(struct bio* bio);
该函数返回数据缓冲区的内核虚拟地址.
char* bvec_kmap_irq(struct bio_vec* bvec, unsigned long* offset);
该函数也返回一个内核虚拟地址此地址可用于存取被给定的bio_vec入口指向的数据缓冲区.同时会屏蔽中断并返回一个原子kmap,因此,在此函数调用之前,驱动不应该是睡眠状态.
void bvec_kunmap_irq(char* buffer, unsigned long flags);
该函数撤销函数bvec_kmap_irq()创建的内存映射.
char* bio_kmap_irq(struct bio* bio, unsigned long* flags);
该函数是对bvec_kmap_irq函数的封装,它返回给定的比偶的当前bio_vec入口的映射.
char* __bio_kmap_atomic(struct bio* bio, int i, enum km_type type);
该函数是通过kmap_atomic()获得返回给定bio的第i个缓冲区的虚拟地址.
void __bio_kunmap_atomic(char* addr, enum km_type type);
该函数返还由函数__bio_kmap_atomic()获得的内核虚拟地址给系统.
void bio_get(struct bio* bio);
void bio_put(struct bio* bio);
7、块设备注册与取消