Chinaunix首页 | 论坛 | 博客
  • 博客访问: 96171
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-09-01 19:43
文章分类
文章存档

2017年(4)

2015年(24)

2014年(1)

我的朋友

分类: LINUX

2015-07-11 13:56:47

原文地址:create_empty_buffers解析 作者:zixin

readpage方法里面包装了block_read_full_page函数,prepare_write里面包装了block_prepare_write函数,其中均调用了create_empty_buffers调用create_buffers为该页建立缓冲区队列,然后对队列进行初始化。

 

/*

 *调用create_buffers为该页建立缓冲区队列,然后对队列进行初始化。

 *没有涉及bhstate标志

 *调用的create_buffers中设置bh->state = 0

 *且把新分配的buffer放入BUF_CLEAN链表(BH_dirty标志为0

 * 缓冲队列头赋给page->buffer

*/

void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)

{

    struct buffer_head *bh, *head, *tail;

 

    /* FIXME: create_buffers should fail if there's no enough memory */

 

//为该页建立缓冲区队列

    head = create_buffers(page, blocksize, 1);

    if (page->buffers)

           BUG();

 

//对缓冲队列进行初始化

    bh = head;

    do {

           bh->b_dev = dev; //设备标识符

           bh->b_blocknr = 0; //逻辑块号

           bh->b_end_io = NULL;

           tail = bh;

           bh = bh->b_this_page;

    } while (bh);

 

    tail->b_this_page = head;   //双向链表

    page->buffers = head;     //链表头赋给page->buffers

    page_cache_get(page);

}

EXPORT_SYMBOL(create_empty_buffers);

 

/*

 * Create the appropriate buffers when given a page for data area and

 * the size of each buffer.. Use the bh->b_this_page linked list to

 * follow the buffers created.  Return NULL if unable to create more

 * buffers.

 * The async flag is used to differentiate async IO (paging, swapping)

 * from ordinary buffer allocations, and only async requests are allowed

 * to sleep waiting for buffer heads.

 */

/*

*为页面pageasync形式(是否异步),分配大小为size的缓冲区

*不能分配更多的buffers时返回NULL

*/

static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)

{

    struct buffer_head *bh, *head;

    long offset;

 

try_again:

    head = NULL;

    offset = PAGE_SIZE; //页面大小

 

//分配一个buffersoffset-size

    while ((offset - = size) >= 0) {  

 

//get_unused_buffer_head来获得一个新的缓冲区首部

//I/O操作对bh请求,如果未用缓冲区首部链表不为空,则获取unused_list_lock自旋锁,删除其中一个元素并返回它的地址 

           bh = get_unused_buffer_head(async);

           if (!bh)

                  goto no_grow;

 

           bh->b_dev = NODEV; //虚拟设备标识符

           bh->b_this_page = head;

           head = bh;

 

           bh->b_state = 0;    //state状态标志均为0

           bh->b_next_free = NULL;  //链接针对缓冲区首部链表的字段

           bh->b_pprev = NULL;

           atomic_set(&bh->b_count, 0);

           bh->b_size = size;  //块大小

 

           set_bh_page(bh, page, offset); //设置bh对象的b_page指针和b_date指针

 

           bh->b_list = BUF_CLEAN;  //放入BUF_CLEAN链表(BH_dirty标志为0

           bh->b_end_io = NULL;

    }

    return head;

/*

 * In case anything failed, we just free everything we got.

 */

//如果没有分配成功

no_grow:

    if (head) {

           spin_lock(&unused_list_lock);

           do {

                  bh = head;

                  head = head->b_this_page;

                  __put_unused_buffer_head(bh);

           } while (head);

           spin_unlock(&unused_list_lock);

 

           /* Wake up any waiters ... */

           wake_up(&buffer_wait);

    }

 

    /*

     * Return failure for non-async IO requests.  Async IO requests

     * are not allowed to fail, so we have to wait until buffer heads

     * become available.  But we don't want tasks sleeping with

     * partially complete buffers, so all were released above.

     */

    if (!async)

           return NULL;

 

    /* We're _really_ low on memory. Now we just

     * wait for old buffer heads to become free due to

     * finishing IO.  Since this is an async request and

     * the reserve list is empty, we're sure there are

     * async buffer heads in use.

     */

    run_task_queue(&tq_disk);

 

    free_more_memory();

    goto try_again;

}

 

              create_empty_buffers(page,dev,blocksize)

                     +                                    +

               create_buffers                bh队列初始化 b_dev = dev逻辑设备标识符

           为该页建立buffer队列        bh队列第一个bh地址给page->buffers

                             +

    +++++++++++++++++++++++++++++++++++++++

    +                                                                                      +

get_unsued_buf_head                               bh->b_dev=NODEV 虚拟设备标识符

获得新bh                                                      set_bh_page(bh,page,offset)设置了bh对象b_page指针

                                                                                                                                                     b_data指针

                                                                       bh->state = 0

                                                                       bh->b_list = BUF_CLEAN 这里表示放入BUF_CLEAN链表

 

问题1:

 

    在create_buffers()中 对该bh对象进行初始化时
         bh->b_dev = NODEV; 给了虚拟逻辑标识符 
       //这里的NODEV是哪里来的?
       include/linux/kdev中初始定义了#define   0
 
问题2:
          bh->b_list = BUF_CLEAN;   
        //那这里是否表示将其链入BUF_CLEAN链表,还是只是 记录这个缓冲区应该出现在哪个链表上
         因为一旦是lru_list[BUF_CLEAN],该bh就是处于正在使用状态了吧
 
my idea:
如果是已用状态,b_dev,b_date字段,BH_Mapped标志都需要
前面两个在以上程序中都已经赋值了
 
而在__block_prepare_write调用create_empty_buffers后也设置了BH_Mapped标志,看来这里更偏向与是记录这个缓冲区应该出现在哪个链表上

        

问题3:create_empty_buffers中调用了create_buffers将bh对象的b_dev赋值为NODEV,调用完后,又将b_dev赋值为传参进来的dev,即inode->i_dev,为什么呢?

阅读(1691) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~