Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1242841
  • 博文数量: 298
  • 博客积分: 10050
  • 博客等级: 上将
  • 技术积分: 3277
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-14 13:36
文章分类
文章存档

2015年(7)

2012年(1)

2010年(5)

2009年(55)

2008年(73)

2007年(160)

我的朋友

分类: LINUX

2007-07-02 11:16:19

/*

 *from为该页面起点,to为起点+写入长度

 *get_block针对具体的文件系统把文件逻辑块号-〉设备上记录块

 */

int block_prepare_write(struct page *page, unsigned from, unsigned to,

           get_block_t *get_block)

{

    struct inode *inode = page->mapping->host;

    int err = __block_prepare_write(inode, page, from, to, get_block);

    if (err) {

        ClearPageUptodate(page);

        kunmap(page);

    }

    return err;

}

 

 

 

/*

 *from为该页面起点,to为起点+写入长度

 */

static int __block_prepare_write(struct inode *inode, struct page *page,
       unsigned from, unsigned to, get_block_t *get_block)
{
    unsigned block_start, block_end;
    unsigned long block;
    int err = 0;
    unsigned blocksize, bbits;
    struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
    char *kaddr = kmap(page);

/*块大小*/
    blocksize = 1 << inode->i_blkbits;

 

/*

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

 *没有涉及bhstate标志

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

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

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

 * 详见create_empty_buffers解析一文

 */

    if (!page->buffers)
        create_empty_buffers(page, inode->i_dev, blocksize);
    head = page->buffers;
 

    /*块位数*/
    bbits = inode->i_blkbits;

 

    /*当前页所在的块号*/

 

    /*

     *假设块大小为1k,bbits = inode->i_blkbits, bbits10

     *则一页占2^(PAGE_CACHE_SHIFT-bbits)=2^(12-10)=2^2=4个块

     *因此该页的逻辑起始块号为: page->index*每页块数

     *page->index*2^(PAGE_CACHE_SHIFT-bbits)=

     * page->index<<(PAGE_CACHE_SHIFT-bbits)

     */
    block = page->index << (PAGE_CACHE_SHIFT - bbits);
 

 

 

    /*

     *对页中每个buffer对应的bh和受写影响的每个bh

     *block_start记录循环写入的总块大小

     */
    for(bh = head, block_start = 0; bh != head || !block_start;
        block++, block_start=block_end, bh = bh->b_this_page) {
        if (!bh)
            BUG();

 

        /*累计写入块大小*/
        block_end = block_start+blocksize;

        if (block_end <= from)
            continue;
        if (block_start >= to)
            break;

 

        /*BH_New标志(如果相应的文件块正好被分配但从未被访问)*/

            clear_bit(BH_New, &bh->b_state);

 

        /*

         *检查如果BH_Mapped标志未设置

         *调用get_block将文件逻辑块号-〉设备上记录块(相对磁盘分区的起始位置)

         *块号存放与b_blocknr字段且设置BH_Mapped标志(完成映射)

         */
        if (!buffer_mapped(bh)) {
            err = get_block(inode, block, bh, 1);
            if (err)
                goto out;

             /*

              *检查BH_New标志,如果被设置

              *调用unmap_underlying_metadata证实缓冲区高速缓存不包含引用磁盘同一块的

              *一个脏缓冲区(可能性不大)

              *如果不对整个缓冲区进行重写,则用0填充,跳过此buffer继续

              */
            if (buffer_new(bh)) {
                unmap_underlying_metadata(bh);
                if (Page_Uptodate(page)) {
                    set_bit(BH_Uptodate, &bh->b_state);
                    continue;
                }
                if (block_end > to)
                    memset(kaddr+to, 0, block_end-to);
                if (block_start < from)
                    memset(kaddr+block_start, 0, from-block_start);
                if (block_end > to || block_start < from)
                    flush_dcache_page(page);
                continue;
            }
        }//buffer_mapped(bh)
——if

 

 

        /*

         *如果page的读操作完成的PG_uptodate标志设置了,则将其缓冲区的BH_Uptodate也设置

         */

        if (Page_Uptodate(page)) {
            set_bit(BH_Uptodate, &bh->b_state);
            continue;
        }

 

 

         /*

          *检如果不对整个缓冲区进行重写,检查其BH_Uptodate标志,未被设置(不一致)

          *调用ll_rw_block来从磁盘读入块的内容

          *ll_rw_block函数中自定义了I/O完后调用了end_buffer_io_sync

          *详见end_buffer_io_sync解析一文

          */
        if (!buffer_uptodate(bh) &&
             (block_start < from || block_end > to)) {
            ll_rw_block(READ, 1, &bh);
            *wait_bh++=bh;
        }

        } // for循环

 

 

    /*
     * If we issued read requests - let them complete.
     */

    /*

     * 阻塞当前进程,直到for循环中的ll_rw_block读操作全部完成

     */
    while(wait_bh > wait) {
        wait_on_buffer(*--wait_bh);
        if (!buffer_uptodate(*wait_bh))
            return -EIO;
    }
    return 0;

 

 

 

/*检查未映射的时候调用get_block出错跳转的位置*/
out:
    /*
     * Zero out any newly allocated blocks to avoid exposing stale
     * data.  If BH_New is set, we know that the block was newly
     * allocated in the above loop.
     *
     * Details the buffer can be new and uptodate because:
     * 1) hole in uptodate page, get_block(create) allocate the block,
     *    so the buffer is new and additionally we also mark it uptodate
     * 2) The buffer is not mapped and uptodate due a previous partial read.
     *
     * We can always ignore uptodate buffers here, if you mark a buffer
     * uptodate you must make sure it contains the right data first.
     *
     * We must stop the "undo/clear" fixup pass not at the caller "to"
     * but at the last block that we successfully arrived in the main loop.
     */
    bh = head;
    to = block_start; /* stop at the last successfully handled block */
    block_start = 0;
    do {
        block_end = block_start+blocksize;
        if (block_end <= from)
            goto next_bh;
        if (block_start >= to)
            break;
        if (buffer_new(bh) && !buffer_uptodate(bh)) {
            memset(kaddr+block_start, 0, bh->b_size);
            flush_dcache_page(page);
            set_bit(BH_Uptodate, &bh->b_state);
            mark_buffer_dirty(bh);
        }
next_bh:
        block_start = block_end;
        bh = bh->b_this_page;
    } while (bh != head);
    return err;
}

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