免费注册 查看新帖 |

Chinaunix

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

[内存管理] 请教pagecache的writeback问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-03-27 10:00 |只看该作者 |倒序浏览
本帖最后由 leil 于 2013-03-27 10:16 编辑

如果一个page,正在被writeback,这时候上层应用正好又要写这个page。系统是如何保证互斥的?

上层应用写page的时候,是在page lock保护下进行。
但submit_bio()将page提交给下面后,已经不再会有page lock加/解锁操作了。
所以很纳闷。

论坛徽章:
0
2 [报告]
发表于 2013-03-27 10:50 |只看该作者
generic_perform_write()
->ext2_write_begin()
->grab_cache_page_write_begin()
如果这个时候发现page的PG_Writeback被设置了就会等待知道完成。
/*
* Wait for a page to complete writeback
*/
static inline void wait_on_page_writeback(struct page *page)
{
        if (PageWriteback(page))
                wait_on_page_bit(page, PG_writeback);
}



//////////////////////////////////////////////////////////////////
bdi回写的时候:
wb_do_writeback()
->__writeback_single_inode()
->do_writepages
->ext2_writepage()  //mapping->a_ops->writepage
->block_write_full_page_endio  //这个里面会先设置page的PG_writeback标志。
->submit_bh
->submit_bio


///////////////////////
驱动完成写请求后,执行bh回调
end_buffer_async_write()
如果page内相关的所有bh都是最新的了,则调用end_page_writeback清楚标志进行唤醒。
void end_page_writeback(struct page *page)
{
        if (TestClearPageReclaim(page))
                rotate_reclaimable_page(page);

        if (!test_clear_page_writeback(page))
                BUG();

        smp_mb__after_clear_bit();
        wake_up_page(page, PG_writeback);
}


评分

参与人数 1可用积分 +4 收起 理由
瀚海书香 + 4 赞一个!

查看全部评分

论坛徽章:
0
3 [报告]
发表于 2013-03-27 11:10 |只看该作者
本帖最后由 leil 于 2013-03-27 11:12 编辑

我是以ext3来看的:
generic_perform_write()
  ->ext3_write_begin()
      ->grab_cache_page_write_begin()                                   获取到page lock,没看到有wait on page writeback动作。
      ->block_write_begin()->__block_prepare_write()             将数据写到page中去。
  ->ext3_writeback_write_end()                                              解锁page lock

我也仔细看了如上流程,反正是没看到有wait on page writeback的地方。
难道还有看漏的地方?
BTW,我看的代码是2.6.32系列。

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2013-03-27 11:11 |只看该作者
本帖最后由 chishanmingshen 于 2013-03-27 11:13 编辑

怎么判断所有的bh的啊?

buffer_async_write():怎么找不到这个函数的定义?

回复 2# blake326


   

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2013-03-27 11:23 |只看该作者

/*
* Find or create a page at the given pagecache position. Return the locked
* page. This function is specifically for buffered writes.
*/
struct page *grab_cache_page_write_begin(struct address_space *mapping,
                                        pgoff_t index, unsigned flags)
{
        int status;
        gfp_t gfp_mask;
        struct page *page;
        gfp_t gfp_notmask = 0;

        gfp_mask = mapping_gfp_mask(mapping);
        if (mapping_cap_account_dirty(mapping))
                gfp_mask |= __GFP_WRITE;
        if (flags & AOP_FLAG_NOFS)
                gfp_notmask = __GFP_FS;
repeat:
        page = find_lock_page(mapping, index);
        if (page)
                goto found;

        page = __page_cache_alloc(gfp_mask & ~gfp_notmask);
        if (!page)
                return NULL;
        status = add_to_page_cache_lru(page, mapping, index,
                                                GFP_KERNEL & ~gfp_notmask);
        if (unlikely(status)) {
                page_cache_release(page);
                if (status == -EEXIST)
                        goto repeat;
                return NULL;
        }
found:
        wait_on_page_writeback(page);<------------------HERE
        return page;
}

FROM KERNEL 3.7


回复 3# leil


   

论坛徽章:
0
6 [报告]
发表于 2013-03-27 11:38 |只看该作者
kernel 3.0

int block_write_full_page(struct page *page, get_block_t *get_block,
                        struct writeback_control *wbc)
{
        return block_write_full_page_endio(page, get_block, wbc, end_buffer_async_write);
}
....
mark_buffer_async_write_endio(bh, end_buffer_async_write);

end_buffer_async_write() {
.....
        first = page_buffers(page);
        local_irq_save(flags);
        bit_spin_lock(BH_Uptodate_Lock, &first->b_state);

        clear_buffer_async_write(bh);
        unlock_buffer(bh);
        tmp = bh->b_this_page; //这个地方在循环page上所有的bh,有bh还在async write的话,就不会清除page的writeback。
        while (tmp != bh) {
                if (buffer_async_write(tmp)) {
                        BUG_ON(!buffer_locked(tmp));
                        goto still_busy;
                }
                tmp = tmp->b_this_page;
        }
        bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
        local_irq_restore(flags);
        end_page_writeback(page);
        return;

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2013-03-27 12:27 |只看该作者
有2个疑问。。。请指点下,谢谢。

1. 这里的tmp只是在入参指定的bh之前的所有bh啊,貌似并不是该page的全部bh。

2. buffer_async_write定义在哪里啊?找不到定义的地方?

回复 6# blake326


   

论坛徽章:
0
8 [报告]
发表于 2013-03-27 12:37 |只看该作者
struct page *grab_cache_page_write_begin(struct address_space *mapping,
                                        pgoff_t index, unsigned flags)
{
        int status;
        struct page *page;
        gfp_t gfp_notmask = 0;
        if (flags & AOP_FLAG_NOFS)
                gfp_notmask = __GFP_FS;
repeat:
        page = find_lock_page(mapping, index);
        if (likely(page))
                return page;

        page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);
        if (!page)
                return NULL;
        status = add_to_page_cache_lru(page, mapping, index,
                                                GFP_KERNEL & ~gfp_notmask);
        if (unlikely(status)) {
                page_cache_release(page);
                if (status == -EEXIST)
                        goto repeat;
                return NULL;
        }
        return page;
}
EXPORT_SYMBOL(grab_cache_page_write_begin);

这是我看的sles11sp1的代码。看样子是版本之间的差异了。

论坛徽章:
0
9 [报告]
发表于 2013-03-27 15:25 |只看该作者
回复 7# chishanmingshen

1.
tmp = bh->b_this_page;
b_this_page指向当前bh的下一个bh。通过b_this_page可以遍历page上的所有bh。

2.
这是宏定义的,在buffer_head.h中:
#define BUFFER_FNS(bit, name)                                                \
static inline void set_buffer_##name(struct buffer_head *bh)                \
{                                                                        \
        set_bit(BH_##bit, &(bh)->b_state);                                \
}                                                                        \
static inline void clear_buffer_##name(struct buffer_head *bh)                \
{                                                                        \
        clear_bit(BH_##bit, &(bh)->b_state);                                \
}                                                                        \
static inline int buffer_##name(const struct buffer_head *bh)                \
{                                                                        \
        return test_bit(BH_##bit, &(bh)->b_state);                        \
}

BUFFER_FNS(Async_Write, async_write)



   

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
10 [报告]
发表于 2013-03-27 16:16 |只看该作者
谢谢指点。。。。

回复 9# blake326


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP