十四、块I/O层-创新互联
字符设备按照字节流的方式有序访问,如键盘和串口。
目前成都创新互联公司已为近1000家的企业提供了网站建设、域名、雅安服务器托管、网站托管、企业网站设计、山丹网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。14.1 剖析一个块设备
块设备中最小的可寻址单元是扇区。扇区大小一般是2的整数倍,最常见的是512字节。扇区的大小是设备的物理属性,扇区是所有块设备的基本单元——块设备无法对比它还小的单元进行寻址和操作,尽管许多块设备能够一次对多个扇区进行操作。很多CD-ROM盘的扇区都是2kB大小。
虽然物理磁盘寻址按照扇区级别进行的,但是内核执行的所有磁盘操作都是按照块进行的。由于扇区是设备的最小可寻址单元,所以块不能比扇区小,只能数倍于扇区大小。内核要求块的大小是2的倍数且不能超过页的长度。所以通常块的大小是512字节、1KB或4KB。
14.2 缓冲区和缓冲区头
当一个块被调人内存时,它要存储在一个缓冲区中。每个缓冲区对应一个块它相当与磁盘块在内存中的表示。每个缓冲区都有一个对应的描述符。该描述符用buffer_head结构体表示,称作缓冲区头,它包含了内核操作缓冲区所需要的全部信息。
struct buffer_head{
usigned long b_state;//缓冲区状态
struct buffer_head *b_this_page; //页面中的缓冲区
struct page *b_page //缓冲区所在内存物理页
sector_t b_blocknr;//磁盘物理起始块号
size_t b_size ;// 映像大小
char *b_data ;//页面内数据指针,块在内存中的起始位置在b_data处,结束位置在b_data+b_size处
struct block_device *b_bdev; //管理的块设备
bh_end_io_t *b_end_io; //io完成方法
void* b_private; //io完成方法
struct list_head b_assoc_buffers; //相关的映射链表
struct address_space *b_assoc_map; //相关的地址空间
atomic_t b_count; //缓冲区使用计数
};
14.3 bio 结构体
目前内核中块I/O操作的基本容器有bio结构体表示,该结构体代表了正在现场的以片段链表形式组织的块I/O操作。一个片段是一小块连续的内存缓冲区。这样的话,就不需要保证单个缓冲区一定要连续。所以通过用片段来描述缓冲区,及时一个缓冲区分散在内存的多个位置上,bio结构体也能对内核保证IO操作的执行。像这样的向量IO就是所谓的聚合IO。
1 struct bio{
2 sector_t bi_sector //磁盘上相关的扇区 3 struct bio *bio_nex //请求链表 4 struct block_device *bi_dev;//相关的块设备 5 unsigned long bi_flags; //状态和命令标志 6 unsigned long bi_rw; //读还是写 7 unsigned short bi_vcnt; //bio_vecs偏移个数 8 unsigned short bi_idx; //bio_io_vec当前索引 9 unsigned short bi_phys_segments; //结合后的片段数目10 unsigned int bi_size; //IO计数11 unsigned int bi_seg_front_size; //第一个可合并段大小12 unsigned int bi_seg_back_size; //最后一个可合并段大小13 unsigned int bi_max_vecs; //bio_vecs数目上限14 unsigned int bi_comp_cpu; //结束cpu15 atomic_t bi_cnt ;//使用计数16 struct bio_vec *bi_io_vec; //bio_vecs链表17 bio_end_io_t *bi_end_io; //IO完成方法18 void *bi_private; //拥有者私有方法19 bio_destructor_r *bi_destructor;//撤销方法20 struct bio_vec bi_inline_vecs[0] //内嵌bio向量21 }
14.3.1 IO向量
bi_io_vec域指向一个bio_vec结构体链表,该链表包含了一个特定IO操作所需要使用到的所有片段。每个bio_vec结构都是一个形式为
在每个给定的块IO操作中,bi_vcnt域用来描述bi_io_vec所指向的vio_vec数组中向量数目。当块IO操作执行完毕后,bi_idx域指向数组的当前索引。
每一个块IO请求都通过一个bio结构体表示。每个请求包含一个或多个块。这些块存储在bio_vec结构体数组中。这些结构体描述了每个片段在物理页中的实际位置,并且像向量一样被组织在一起。IO操作的第一个片段有b_io_vec结构体所指向,其他片段在其后依次放置,公有bi_vcnt个片段。当块IO开始执行请求、需要使用各个片段时,bi_idx域会不断更新,从而总指向当前片段。
bi_cnt域用于记录bio结构体的使用计数,如果该域值减为0,就应该撤销该bio结构体,并释放它占用的内存。
void bio_get(struct bio *bio);
void bio_put(struct bio *bio);
14.3 新老方法比较
1、bio结构体很容易处理高端内存,因为它处理的是物理页而不是直接指针
2、bio亦可以代表普通页IO,同时也可以代表直接IO(不通过页高速缓存的操作)
3、bio结构体便于执行分散-集中块IO操作,操作中的数据可取自多个物理页面
4、bio相比缓冲区头属于轻量级结构体。因为它只需要包含块IO操作所需要的信息,不用包含于缓冲区本省相关的不必要信息。
14.4 请求队列
块设备将他们挂起的块IO请求保存在请求队列中,该队列由reques_queue结构表示。通过内核中像文件系统这样高层的代码将请求加入到队列中。请求队列只要不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去。
队列其中的请求由结构体request表示。因为一个请求可能要操作多个连续的磁盘块,所以每个请求可以由多个bio结构组成。
14.5 IO调度程序
当前文章:十四、块I/O层-创新互联
标题URL:http://scjbc.cn/article/csojps.html