page reclaim 06:ARM和L_PTE_YOUNG
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
cpuv7setpteext不会修改到LPTEPRESENT.
也就是说, 后续异常时, LPTEPRESENT是置位状态了, 后续若因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