回写路径 2017-01-01

方式1. 前期tag dirty

linux-3.10.86/mm/page-writeback.c


write_cache_pages
{

    while (...) {

        nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
                  min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
        if (nr_pages == 0)
            break;

        ...
            lock_page(page);
        ...
            /*常见的有__mpage_writepage 或者 __writepage*/
            ret = (*writepage)(page, wbc, data);


}

ARM的一些汇编 2016-12-31

1. ^后缀

ARM ® Developer Suite Version 1.2 Assembler Guide P128

4.2.4 LDM and STM
^ is an optional suffix. You must not use it in User mode or System mode.
It has two purposes:
• If op is LDM and reglist contains the pc (r15), in addition to the normal multiple register transfer, the SPSR is copied into the CPSR. This is for returning from exception handlers. Use this only from exception modes.
• Otherwise, data is transferred into or out of the User mode registers instead of the current mode registers.

例如

  • 只有当pop/LDM列表中有pc时, 才会cpsr:=spsr. 例 ldmia sp,{r0-pc}^ 这里^表示 将spsr复制到cpsr.

  • stmdb r0, {sp, lr}^ 这里^表示访问的是usr 模式下的寄存器

generic_perform_write流程 2016-12-31

generic_perform_write
{

        /*
        ==0==计算没有和PAGE_CACHE_SIZE对齐的那部分的大小, 代码中的bytes.

        杂问题:
        假定PAGE_CACHE_SIZE为4, pos为5, iov_iter_count()大于2个PAGE_CACHE_SIZE,
        则offset为1, bytes为3
        所以, 代码中的bytes就是示意图中|///|那部分:
      pos==0    pos==5
        ^         ^
        |         |
        |----|  |-.---|  |----|
                  |///|
                  读取
        */
        offset = (pos & (PAGE_CACHE_SIZE - 1));
        bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
                        iov_iter_count(i));
again:
        /*
        如何防止dead lock可参考
        https://lkml.org/lkml/2015/6/30/631
        */
        iov_iter_fault_in_readable(...);

        /*
        ==1==准备page
        答:
        如果在address_space中没有该pos对应的page, 则分配page并添加到address_space.
        如果没有写完整的一个sector, 则需要先从磁盘读出原sector.
        */
        status = a_ops->write_begin(file, mapping, pos, bytes, flags,
                        &page, &fsdata);

        /*
        ==2==填充page cache
        */
        /*
        flush_dcache_page 见https://awakening-fong.github.io/posts/flush_dcache_page
        */
        if (mapping_writably_mapped(mapping))
            flush_dcache_page(page);
        pagefault_disable();
        copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
        pagefault_enable();
        flush_dcache_page(page);
        /*
        ==3==标记为dirty, 处理short write
        short wrtie是让 copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);复制bytes, 结果实际只复制copied. 若发生short write, 则重来.
        */
        a_ops->write_end(...);

}

set_buffer_new 2016-12-31

本文主要解释BH_New的含义, 以及何时设置该标志.

flush_dcache_page 2016-12-31

1. flushdcachepage的实现

问题:flushdcachepage()到底是 invalid, 还是 clean and invalid, 还是仅清掉dirty bit

linux-3.10.86/arch/arm/mm/flush.c

flush_dcache_page -> __flush_dcache_page
{
    /*
     * Writeback ...
    */

}

是Writeback, 所以, 可以理解为 clean and invalid, 尽管实现上可能采用lazy什么的.

2. 读写中的使用

linux-3.10.86/mm/filemap.c