十四、块I/O层-创新互联

系统中能够随机访问固定大小数据片的硬件设备称作块设备,这些固定大小的数据片称为块。最常见的块设备是硬盘、还有软盘驱动器、光驱盒闪存等。他们都是以安装文件系统的方式使用的。十四、块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层-创新互联
网页链接:http://myzitong.com/article/csojps.html