免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1688 | 回复: 1
打印 上一主题 下一主题

Linux缓存机制之块缓存 2.。。。。。。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-03 11:32 |只看该作者 |倒序浏览
    Linux缓存机制之块缓存 2.。。。。。。










   除了读操作之外,页面的写操作也可以划分为更小的单位。只有页中实际修改的内容需要回写,而不用回写整页的内容。遗憾的是,从缓冲区的角度来看,写操作的实现比上述的读操作复杂的多。

__block_wirte_full_page函数中回写脏页面设计的缓冲区相关操作。
  1. [cpp] view plaincopyprint?
  2. /*
  3. * NOTE! All mapped/uptodate combinations are valid:
  4. *
  5. *  Mapped  Uptodate    Meaning
  6. *
  7. *  No  No      "unknown" - must do get_block()
  8. *  No  Yes     "hole" - zero-filled
  9. *  Yes No      "allocated" - allocated on disk, not read in
  10. *  Yes Yes     "valid" - allocated and up-to-date in memory.
  11. *
  12. * "Dirty" is valid only with the last case (mapped+uptodate).
  13. */  
  14.   
  15. /*
  16. * While block_write_full_page is writing back the dirty buffers under
  17. * the page lock, whoever dirtied the buffers may decide to clean them
  18. * again at any time.  We handle that by only looking at the buffer
  19. * state inside lock_buffer().
  20. *
  21. * If block_write_full_page() is called for regular writeback
  22. * (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a page which has a
  23. * locked buffer.   This only can happen if someone has written the buffer
  24. * directly, with submit_bh().  At the address_space level PageWriteback
  25. * prevents this contention from occurring.
  26. *
  27. * If block_write_full_page() is called with wbc->sync_mode ==
  28. * WB_SYNC_ALL, the writes are posted using WRITE_SYNC_PLUG; this
  29. * causes the writes to be flagged as synchronous writes, but the
  30. * block device queue will NOT be unplugged, since usually many pages
  31. * will be pushed to the out before the higher-level caller actually
  32. * waits for the writes to be completed.  The various wait functions,
  33. * such as wait_on_writeback_range() will ultimately call sync_page()
  34. * which will ultimately call blk_run_backing_dev(), which will end up
  35. * unplugging the device queue.
  36. */  
  37. static int __block_write_full_page(struct inode *inode, struct page *page,  
  38.             get_block_t *get_block, struct writeback_control *wbc,  
  39.             bh_end_io_t *handler)  
  40. {  
  41.     int err;  
  42.     sector_t block;  
  43.     sector_t last_block;  
  44.     struct buffer_head *bh, *head;  
  45.     const unsigned blocksize = 1 << inode->i_blkbits;  
  46.     int nr_underway = 0;  
  47.     int write_op = (wbc->sync_mode == WB_SYNC_ALL ?  
  48.             WRITE_SYNC_PLUG : WRITE);  
  49.   
  50.     BUG_ON(!PageLocked(page));  
  51.   
  52.     last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;  
  53.     /*页面是否有关联缓冲区,如果没有创建他*/  
  54.     if (!page_has_buffers(page)) {  
  55.         create_empty_buffers(page, blocksize,  
  56.                     (1 << BH_Dirty)|(1 << BH_Uptodate));  
  57.     }  
  58.   
  59.     /*
  60.      * Be very careful.  We have no exclusion from __set_page_dirty_buffers
  61.      * here, and the (potentially unmapped) buffers may become dirty at
  62.      * any time.  If a buffer becomes dirty here after we've inspected it
  63.      * then we just miss that fact, and the page stays dirty.
  64.      *
  65.      * Buffers outside i_size may be dirtied by __set_page_dirty_buffers;
  66.      * handle that here by just cleaning them.
  67.      */  
  68.   
  69.     block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);  
  70.     head = page_buffers(page);  
  71.     bh = head;  
  72.   
  73.     /*
  74.      * Get all the dirty buffers mapped to disk addresses and
  75.      * handle any aliases from the underlying blockdev's mapping.
  76.      */  
  77.      /*对所有未映射的脏缓冲区,在缓冲区和块设备
  78.     之间建立映射*/  
  79.     do {  
  80.         if (block > last_block) {  
  81.             /*
  82.              * mapped buffers outside i_size will occur, because
  83.              * this page can be outside i_size when there is a
  84.              * truncate in progress.
  85.              */  
  86.             /*
  87.              * The buffer was zeroed by block_write_full_page()
  88.              */  
  89.             clear_buffer_dirty(bh);  
  90.             set_buffer_uptodate(bh);  
  91.         } else if ((!buffer_mapped(bh) || buffer_delay(bh)) &&  
  92.                buffer_dirty(bh)) {  
  93.             WARN_ON(bh->b_size != blocksize);  
  94.             /*查找块设备上与缓冲区项匹配的块*/  
  95.             err = get_block(inode, block, bh, 1);  
  96.             if (err)  
  97.                 goto recover;  
  98.             clear_buffer_delay(bh);  
  99.             if (buffer_new(bh)) {  
  100.                 /* blockdev mappings never come here */  
  101.                 clear_buffer_new(bh);  
  102.                 unmap_underlying_metadata(bh->b_bdev,  
  103.                             bh->b_blocknr);  
  104.             }  
  105.         }  
  106.         bh = bh->b_this_page;  
  107.         block++;  
  108.     } while (bh != head);  
  109.     /*第二遍遍历,将滤出所有的脏缓冲区*/  
  110.     do {  
  111.         if (!buffer_mapped(bh))  
  112.             continue;  
  113.         /*
  114.          * If it's a fully non-blocking write attempt and we cannot
  115.          * lock the buffer then redirty the page.  Note that this can
  116.          * potentially cause a busy-wait loop from writeback threads
  117.          * and kswapd activity, but those code paths have their own
  118.          * higher-level throttling.
  119.          */  
  120.         if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {  
  121.             lock_buffer(bh);  
  122.         } else if (!trylock_buffer(bh)) {  
  123.             redirty_page_for_writepage(wbc, page);  
  124.             continue;  
  125.         }  
  126.         /*如果设置了脏页标志,则会在调用该函数时清除
  127.         因为缓冲区的内容将立即回写*/  
  128.         if (test_clear_buffer_dirty(bh)) {  
  129.             /*设置BH_Async_Write状态位,并将end_buffer_async_write
  130.             指定为BIO完成处理程序即b_end_io*/  
  131.             mark_buffer_async_write_endio(bh, handler);  
  132.         } else {  
  133.             unlock_buffer(bh);  
  134.         }  
  135.     } while ((bh = bh->b_this_page) != head);  
  136.   
  137.     /*
  138.      * The page and its buffers are protected by PageWriteback(), so we can
  139.      * drop the bh refcounts early.
  140.      */  
  141.     BUG_ON(PageWriteback(page));  
  142.     set_page_writeback(page);  
  143.     /*最后一次遍历*/  
  144.     do {  
  145.         struct buffer_head *next = bh->b_this_page;  
  146.         if (buffer_async_write(bh)) {  
  147.             /*将前一次遍历中标记为BH_Async_Write的所有缓冲区
  148.             转交给块层执行实际的写操作,该函数向块层提交
  149.             了对应的请求*/  
  150.             submit_bh(write_op, bh);  
  151.             nr_underway++;  
  152.         }  
  153.         bh = next;  
  154.     } while (bh != head);  
  155.     unlock_page(page);  
  156.   
  157.     err = 0;  
  158. done:  
  159.     if (nr_underway == 0) {  
  160.         /*
  161.          * The page was marked dirty, but the buffers were
  162.          * clean.  Someone wrote them back by hand with
  163.          * ll_rw_block/submit_bh.  A rare case.
  164.          */  
  165.         end_page_writeback(page);  
  166.   
  167.         /*
  168.          * The page and buffer_heads can be released at any time from
  169.          * here on.
  170.          */  
  171.     }  
  172.     return err;  
  173.   
  174. recover:  
  175.     /*
  176.      * ENOSPC, or some other error.  We may already have added some
  177.      * blocks to the file, so we need to write these out to avoid
  178.      * exposing stale data.
  179.      * The page is currently locked and not marked for writeback
  180.      */  
  181.     bh = head;  
  182.     /* Recovery: lock and submit the mapped buffers */  
  183.     do {  
  184.         if (buffer_mapped(bh) && buffer_dirty(bh) &&  
  185.             !buffer_delay(bh)) {  
  186.             lock_buffer(bh);  
  187.             mark_buffer_async_write_endio(bh, handler);  
  188.         } else {  
  189.             /*
  190.              * The buffer may have been set dirty during
  191.              * attachment to a dirty page.
  192.              */  
  193.             clear_buffer_dirty(bh);  
  194.         }  
  195.     } while ((bh = bh->b_this_page) != head);  
  196.     SetPageError(page);  
  197.     BUG_ON(PageWriteback(page));  
  198.     mapping_set_error(page->mapping, err);  
  199.     set_page_writeback(page);  
  200.     do {  
  201.         struct buffer_head *next = bh->b_this_page;  
  202.         if (buffer_async_write(bh)) {  
  203.             clear_buffer_dirty(bh);  
  204.             submit_bh(write_op, bh);  
  205.             nr_underway++;  
  206.         }  
  207.         bh = next;  
  208.     } while (bh != head);  
  209.     unlock_page(page);  
  210.     goto done;  
  211. }  
复制代码

论坛徽章:
0
2 [报告]
发表于 2012-03-03 11:32 |只看该作者
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP