2017-02-07

1. pagereferencedone对硬件页表的影响

linux-3.10.86/include/asm-generic/pgtable.h

page_referenced_one -> ptep_clear_flush_young_notify -> ptep_clear_flush_young -> ptep_test_and_clear_young
{
//pte_mkold 实现上是:PTE_BIT_FUNC(mkold,     &= ~L_PTE_YOUNG);
set_pte_at(vma->vm_mm, address, ptep, pte_mkold(pte));
}

linux-3.10.86/arch/arm/include/asm/pgtable.h

static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                  pte_t *ptep, pte_t pteval)
{
    unsigned long ext = 0;

    if (addr < TASK_SIZE && pte_present_user(pteval)) {
        __sync_icache_dcache(pteval);
        ext |= PTE_EXT_NG;
    }
    /*
    @pteval 是linux版的pte
    硬件版的会根据ext来生成
    */
    set_pte_ext(ptep, pteval, ext);
}

linux-3.10.86/arch/arm/include/asm/pgtable-2level-hwdef.h

#define PTE_EXT_NG      (_AT(pteval_t, 1) << 11)    /* v6 */    

这个后续没有用到, 忽略.

linux-3.10.86/arch/arm/include/asm/pgtable-2level.h

#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)

setpteat -> setpteext -> cpusetpteext -> cpuv7setpte_ext

我们想知道的是: ext中 LPTEYOUNG没有置位时, 硬件页表的变化.

linux-3.10.86/arch/arm/mm/proc-v7-2level.S

ENTRY(cpu_v7_set_pte_ext)
...
@r1是linux版
tst r1, #L_PTE_YOUNG
tstne   r1, #L_PTE_VALID
@#define L_PTE_NONE     (_AT(pteval_t, 1) << 11)
eorne   r1, r1, #L_PTE_NONE
tstne   r1, #L_PTE_NONE
moveq   r3, #0
...

当LPTEYOUNG没有置位时, 这里会执行moveq r3, #0, 也就是页表项修改为0, 然后存储到硬件版页表.

2. 后续访问相关page会如何

执行pagereferencedone之后, 由于硬件页表被清零, 后续访问引发异常, 会执行到handleptefault.

linux-3.10.86/mm/memory.c

handle_pte_fault
{
    if (!pte_present(entry)) {

        return ...
    }
    ...
    entry = pte_mkyoung(entry);
    ptep_set_access_flags() ->  set_pte_at()

}   

上面硬件页表被清零了, 但是linux版页表并没有清零, 只清掉LPTEYOUNG. 这里需要知道, if (!pte_present(entry))是否会成立.

linux-3.10.86/arch/arm/include/asm/pgtable.h

#define pte_present(pte)    (pte_isset((pte), L_PTE_PRESENT))

linux-3.10.86/arch/arm/include/asm/pgtable-2level.h

#define L_PTE_PRESENT       (_AT(pteval_t, 1) << 0)
#define L_PTE_YOUNG     (_AT(pteval_t, 1) << 1)

以通过mmap来访问文件为例, 看看创建的linux的pte.

mmap_region
|--vma->vm_flags = vm_flags;
|--vma->vm_page_prot = vm_get_page_prot(vm_flags);

vm_get_page_prot -> protection_map -> __PAGE_NONE

linux-3.10.86/arch/arm/include/asm/pgtable.h

#define __PAGE_NONE     __pgprot(_L_PTE_DEFAULT | ...省略...  )
#define _L_PTE_DEFAULT  L_PTE_PRESENT | L_PTE_YOUNG

_PAGENONE 和其他的_PAGExx 都含LPTEDEFAULT. 也就是说, 创建的linux版pte含有LPTE_PRESENT.

setpteat -> setpteext -> cpusetpteext -> cpuv7setpteext
cpu
v7setpteext不会修改到LPTEPRESENT.
也就是说, 后续异常时, L
PTEPRESENT是置位状态了, 后续若因reclaim的扫描, LPTEYOUNG会被清掉, 硬件页表也被清零, 若访问该页表相关的page, 不走if (!ptepresent(entry)), 而是会置位LPTEYOUNG, 并根据这个含有LPTEYOUNG的linux页表 重新设置硬件页表.

由于这个异常只有在该page被reclaim扫描到后才会发生, 故overhead并不严重.

本文地址: https://awakening-fong.github.io/posts/mm/reclaim_06_arm_l_pte_young

转载请注明出处: https://awakening-fong.github.io


若无法评论, 请打开JavaScript, 并通过proxy.


blog comments powered by Disqus