page,bio,与buffer_head的关系

一、pagebuffer_head的关系

 

1页中的块在磁盘上连续

如果page中的块在磁盘上连续,那么pagePG_private不会被置位,private字段也不会指向buffer_head的链表。

 

但是page还是得用到buffer_head结构,因为它需要通过get_block()函数来获得磁盘上的逻辑块号。

虽然ext2_getblock()函数的代码我暂时还没有看,但是通过do_mpage_readpage()函数代码的阅读,可以对get_block()系列函数的功能进行如下猜想:

typedef int (get_block_t)(struct inode *inode, sector_t iblock,

struct buffer_head *bh_result, int create);

这类函数会得到在文件中块号iblock在磁盘上的逻辑块号,然后赋给bh中的b_blocknr字段。在调用get_block()函数前,bh中的b_size被赋为期望的连续的块数的总大小,返回前,get_block()函数被设置为以iblock块为第一块(什么意思?),且在磁盘上连续的实际的块数(如果实际连续的比期望的小)。

 

do_mpage_readpage()函数中,得到了块在磁盘上的逻辑块号后,buffer_head结构就没有什么用了,将其中的b_blocknr赋给了blocks数组后,生成bio的函数mapge_alloc()使用blocks[0]就行了。

Blocks[0]是否表示磁盘上连续的实际的块数的总的大小(以位为单位)?

 

2页中的块在磁盘上不连续

页一开始和buffer_head是没有关系的,但是通过get_block()发现页中的块在磁盘上不连续等现象后,就需要调用create_empty_buffers()函数来为page创建buffer_head链表了。create_empty_buffers的结构很简单,它先调用alloc_page_buffers()来为page创建一个buffer_head的链表,之后为链表中每个buffer_headb_state赋值,并顺便将该链表构造成循环链表,然后看情况设置buffer_headBH_dirtyBH_uptodate标志,最后调用attach_page_buffers()来将pagePG_private置位。

链表建成后,pagebuffer_head的关系就如下图所示了:

Struct buffer_head *b_this_page 是否指向下一个Buffer head?确定

 

二、buffer_headbio的关系

个人认为,buffer_headbio关系在submit_bh()函数中可以充分体现:(也就是说只有在page中的块不连续时,buffer_headbio才建立关系?)

 

       bio = bio_alloc(GFP_NOIO, 1);

 

       bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);//表示磁盘上相关的扇区号

       bio->bi_bdev = bh->b_bdev;

       bio->bi_io_vec[0].bv_page = bh->b_page;

       bio->bi_io_vec[0].bv_len = bh->b_size; //应该不一定对应一个block的大小

       bio->bi_io_vec[0].bv_offset = bh_offset(bh);

 

       bio->bi_vcnt = 1;

       bio->bi_idx = 0;

       bio->bi_size = bh->b_size;

 

上述代码已经把buffer_headbio关系说的差不多了就不多说了。

稍微注意一点的话,可以发现io_vec中的bv_page指向了buffer_head中的b_page,即bv_page指向了也描述符,而bv_offset则是在页中的偏移,为len则为要传输的数据的(在这里就是块的大小)长度。

 

 

三、pagebio的关系

pagebio的关系在上面一段中稍微说了一下,即io_vec中的bv_page字段会指向page

将一个整页加到bio中,可以看看_add_page函数中的如下几行(do_mpage_readpage()函数调用bio_add_page()时,offset参数是0):

 

       bvec = &bio->bi_io_vec[bio->bi_vcnt];

       bvec->bv_page = page;

       bvec->bv_len = len;

       bvec->bv_offset = offset;

……

       bio->bi_vcnt++;

 

 

 

 

这几行代码将pagelen等赋给一个新的io_vec,然后增加bi_vcnt的值。

 

 

 

 

当页中的块连续时:  一个bio包含许多blocks             

    Mpage_allock                  

   Bio_add_page                                                                               

   Mpage_bio_submit                

         Submit_bio

 

当页中的块不连续时:一个bio只包含一个block,然后在IO层可能进行重组

(这里每个bio应该只对应一个block,所以不需要类似Bio_add_page的函数)

b lock_read_full_page

submit_bh(bhbio建立联系)

     submit_bio

你可能感兴趣的:(struct,IO,ext,BI,buffer,磁盘)