- 论坛徽章:
- 2
|
本帖最后由 镇水铁牛 于 2014-11-23 03:30 编辑
回复 11# yangPSO - static int __block_write_full_page(struct inode *inode, struct page *page,
- get_block_t *get_block, struct writeback_control *wbc,
- bh_end_io_t *handler)
- {
- .......................第一个大循环.......................
- do {
- if (block > last_block) {
- /*
- * mapped buffers outside i_size will occur, because
- * this page can be outside i_size when there is a
- * truncate in progress.
- */
- /*
- * The buffer was zeroed by block_write_full_page()
- */
- clear_buffer_dirty(bh);
- set_buffer_uptodate(bh);
- } else if ((!buffer_mapped(bh) || buffer_delay(bh)) &&
- buffer_dirty(bh)) {
- WARN_ON(bh->b_size != blocksize);
- err = get_block(inode, block, bh, 1);/////////////////////////////核心:建立未映射且脏bh和block设备的映射关系
- if (err)
- goto recover;
- clear_buffer_delay(bh);
- if (buffer_new(bh)) {
- /* blockdev mappings never come here */
- clear_buffer_new(bh);
- unmap_underlying_metadata(bh->b_bdev,
- bh->b_blocknr);
- }
- }
- bh = bh->b_this_page;
- block++;
- } while (bh != head);
- .......................第二个大循环.......................过滤所有脏的bh
- do {
- if (!buffer_mapped(bh))
- continue;
- /*
- * If it's a fully non-blocking write attempt and we cannot
- * lock the buffer then redirty the page. Note that this can
- * potentially cause a busy-wait loop from writeback threads
- * and kswapd activity, but those code paths have their own
- * higher-level throttling.
- */
- if (wbc->sync_mode != WB_SYNC_NONE) {
- lock_buffer(bh);
- } else if (!trylock_buffer(bh)) {//////////////////////////////////////////////////这里会lock,如果失败,redirty page
- redirty_page_for_writepage(wbc, page);
- continue;
- }
- if (test_clear_buffer_dirty(bh)) {
- mark_buffer_async_write_endio(bh, handler); /////lock成功的话,设置bh的回调
- } else {
- unlock_buffer(bh);
- }
- } while ((bh = bh->b_this_page) != head);
- /*
- * The page and its buffers are protected by PageWriteback(), so we can
- * drop the bh refcounts early.
- */
- BUG_ON(PageWriteback(page));
- set_page_writeback(page);
- .......................第三个大循环.......................
- do {
- struct buffer_head *next = bh->b_this_page;
- if (buffer_async_write(bh)) {
- submit_bh(write_op, bh);///此时bh是在locked状态,在bh回调中释放,此时也是在page lock中submit bh》submit bio,make request,io只是在scsi queue中,不一定立即下发给LLDD,但也会很快,记得有2个阈值限定,3ms超时和4个request触发。
- nr_underway++;
- }
- bh = next;
- } while (bh != head);
- unlock_page(page);
- ............................................................
复制代码 但是假设有2个不同进程,一个在执行第一步,另一个在执行第二步,那么互斥做不到了。这就可能会出现page cache回写过程中又
被用户buffer覆盖的现象,是不是?
【回复】看了我对write full page的分析,第一步和第二步是不可能同时执行(同一个page,因为page lock),但是一个page是write back状态后,是可以再次被dirty的,这个不冲突,因为在设置write back前,该该IO已经被加入块设备的queue中了,大不了被第二次访问覆盖写了(很少有这种现象,即使有也没事)。此时可以理解为只有第二次覆盖写后的数据才是最新的。
page利用bh提交io的灵活性:如果此时page状态是write back,说明它至少已经提交了一个bh_a,假设page内的bh_b是第二次写请求弄脏的,即使bh_a还未执行完(即end bh),此时还是可以继续提交bh_b。只要你能lock这个bh,该io就可以向下层转发。 |
|