@@ -1558,6 +1558,10 @@ vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t pmd)
if (unlikely(!pmd_same(pmd, *vmf->pmd)))
goto out_unlock;
+ /* Only migrate if accessed twice */
+ if (!pmd_young(*vmf->pmd))
+ goto out_unlock;
+
/*
* If there are potential migrations, wait for completion and retry
* without disrupting NUMA hinting information. Do not relock and
@@ -1978,8 +1982,19 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
if (is_huge_zero_pmd(*pmd))
goto unlock;
- if (pmd_protnone(*pmd))
+ if (pmd_protnone(*pmd)) {
+ if (!(sysctl_numa_balancing_mode &
+ NUMA_BALANCING_MEMORY_TIERING))
+ goto unlock;
+
+ /*
+ * PMD young bit is used to record whether the
+ * page is accessed in last scan period
+ */
+ if (pmd_young(*pmd))
+ set_pmd_at(mm, addr, pmd, pmd_mkold(*pmd));
goto unlock;
+ }
page = pmd_page(*pmd);
/*
@@ -3811,10 +3811,8 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
*/
vmf->ptl = pte_lockptr(vma->vm_mm, vmf->pmd);
spin_lock(vmf->ptl);
- if (unlikely(!pte_same(*vmf->pte, vmf->orig_pte))) {
- pte_unmap_unlock(vmf->pte, vmf->ptl);
- goto out;
- }
+ if (unlikely(!pte_same(*vmf->pte, vmf->orig_pte)))
+ goto unmap_out;
/*
* Make it present again, Depending on how arch implementes non
@@ -3828,17 +3826,17 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
ptep_modify_prot_commit(vma, vmf->address, vmf->pte, old_pte, pte);
update_mmu_cache(vma, vmf->address, vmf->pte);
+ /* Only migrate if accessed twice */
+ if (!pte_young(old_pte))
+ goto unmap_out;
+
page = vm_normal_page(vma, vmf->address, pte);
- if (!page) {
- pte_unmap_unlock(vmf->pte, vmf->ptl);
- return 0;
- }
+ if (!page)
+ goto unmap_out;
/* TODO: handle PTE-mapped THP */
- if (PageCompound(page)) {
- pte_unmap_unlock(vmf->pte, vmf->ptl);
- return 0;
- }
+ if (PageCompound(page))
+ goto unmap_out;
/*
* Avoid grouping on RO pages in general. RO pages shouldn't hurt as
@@ -3876,10 +3874,14 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
} else
flags |= TNF_MIGRATE_FAIL;
-out:
if (page_nid != NUMA_NO_NODE)
task_numa_fault(last_cpupid, page_nid, 1, flags);
return 0;
+
+unmap_out:
+ pte_unmap_unlock(vmf->pte, vmf->ptl);
+out:
+ return 0;
}
static inline vm_fault_t create_huge_pmd(struct vm_fault *vmf)
@@ -83,8 +83,21 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
int nid;
/* Avoid TLB flush if possible */
- if (pte_protnone(oldpte))
+ if (pte_protnone(oldpte)) {
+ if (!(sysctl_numa_balancing_mode &
+ NUMA_BALANCING_MEMORY_TIERING))
+ continue;
+
+ /*
+ * PTE young bit is used to record
+ * whether the page is accessed in
+ * last scan period
+ */
+ if (pte_young(oldpte))
+ set_pte_at(vma->vm_mm, addr, pte,
+ pte_mkold(oldpte));
continue;
+ }
page = vm_normal_page(vma, addr, oldpte);
if (!page || PageKsm(page))