首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

块装置的读流程分析

2013-02-24 
块设备的读流程分析关于VFS的通用读,我们不做考虑,本文以如下函数为根,往下分析:block_in_file page-in

块设备的读流程分析

关于VFS的通用读,我们不做考虑,本文以如下函数为根,往下分析:

block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);

好,现在分别来看两个场景。


场景1)  初次访问文件。


   很明显,这个时候刚刚在mapping的address_space里分配了一块纯净的page。
   page的private字段为0,因此代码姑且认为此page里的块缓冲都是磁盘连续的。
   于是,依次对页内的所有块进行处理(一般一个页有4个块)
将这些页内块号,传递给文件系统相关的get_block函数,即ext2_get_block,
计算出每个块在磁盘上的块号。假设得到第n个块的磁盘编号s(n),那么还要与前一个
块比较,是否编号连续,即s(n)是否等于s(n-1)+1
如果不等,则说明此page内的块缓冲在磁盘上不连续,需要额外处理。


 1.1) 假如块在磁盘上连续存放

则把这些块号依次保存到局部blocks数组。接着就分配新bio。

关键是把bio->bi_sector设置成这些块的第一个扇区号(因为磁盘连续),
并分配一个bio_vec,将此bio_vec的page设置为此page,并且offset设置为0(页内偏移),
长度则设置为PAGE_SIZE(不考虑文件洞)
最后就submit_bio把数据提交给块设备层。


可以看出,对于磁盘连续的情况,该page并没有为其分配块缓冲首部,同时也没有给page->private
置位。


1.2) 假如块在磁盘上非连续存放

则需要给页内的每个块都单独提交bio。

   这是靠block_read_full_page来完成的。
   先检查此page的private标志,如果没有设置,则说明需要分配新缓冲区首部来指示这个page。
   这个是通过create_empty_buffers来完成的。
 
  同样的,根据page在mapping里的index,算出页的第一个块的序号index,接着对从index到
  index+3的4个块,分别调用ext2_get_block,算出各自在磁盘上的序号b_blocknr,从而生成最重要的
  bh结构(dev,b_blocknr),接着对这4个bh提交bio,即submit_bh(READ, bh);
  submit_bh新生成一个bio,
  bio的内存缓冲数据(读文件目的地址):
  bio_vec[0]的page设置为新page,bio_vec[0]的bv_len为块默认大小,
  bio_vec[0]的bv_offset(页内偏移)为相应的块在页内偏移。


  bio的磁盘地址(读文件源地址):
  bio->bi_sector根据之前get_block的结果bh->b_blocknr计算
  bio->bi_bdev设置为文件所在块设备dev,这样有了dev和设备块逻辑号,即可定位块设备磁盘的扇区位置。
  


场景2)  之前已经访问过文件


  根据场景1我们知道,如果文件的这个页page里的块数据,在磁盘中是分散存放的,那么这个page就会对应一个
缓冲区首部链表;如果连续,那么page的private是空。


对于连续存放的情况,每次走到do_mpage_readpage,都会对4个块执行ext2_get_block,
检查相邻的块在磁盘是否连续。也就是说,对于连续存放的情况,代码并没有做优化,而是
仍然每个块都要深入驱动的代码,查找对应的磁盘扇区。


对于非连续存放的情况,由于page的private保存了上次访问时设置的块缓冲区首部
(即bh带BH_Mapped标志,表示缓冲区首部的b_bdev和b_blocknr是有效的),因此可以
直接根据上次的结果,即保存的bh链表,去查找每个块在磁盘的扇区位置。


如果要优化连续存放的场景,笔者认为,可以给page->flag添加字段,来区分此page对应
的块在磁盘上是否连续,这样可以借助第一次访问得到的块磁盘扇区信息,直接操作磁盘,
这样就少了深入驱动查找磁盘扇区号的操作,也许可以提高性能。

热点排行