mirror of https://gitee.com/openkylin/linux.git
mmu_notifier: call mmu_notifier_invalidate_range() from VMM
Add calls to the new mmu_notifier_invalidate_range() function to all places in the VMM that need it. Signed-off-by: Joerg Roedel <jroedel@suse.de> Reviewed-by: Andrea Arcangeli <aarcange@redhat.com> Reviewed-by: Jérôme Glisse <jglisse@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Rik van Riel <riel@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Johannes Weiner <jweiner@redhat.com> Cc: Jay Cornwall <Jay.Cornwall@amd.com> Cc: Oded Gabbay <Oded.Gabbay@amd.com> Cc: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Oded Gabbay <oded.gabbay@amd.com>
This commit is contained in:
parent
1897bdc4d3
commit
34ee645e83
|
@ -284,6 +284,44 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
|
||||||
__young; \
|
__young; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define ptep_clear_flush_notify(__vma, __address, __ptep) \
|
||||||
|
({ \
|
||||||
|
unsigned long ___addr = __address & PAGE_MASK; \
|
||||||
|
struct mm_struct *___mm = (__vma)->vm_mm; \
|
||||||
|
pte_t ___pte; \
|
||||||
|
\
|
||||||
|
___pte = ptep_clear_flush(__vma, __address, __ptep); \
|
||||||
|
mmu_notifier_invalidate_range(___mm, ___addr, \
|
||||||
|
___addr + PAGE_SIZE); \
|
||||||
|
\
|
||||||
|
___pte; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define pmdp_clear_flush_notify(__vma, __haddr, __pmd) \
|
||||||
|
({ \
|
||||||
|
unsigned long ___haddr = __haddr & HPAGE_PMD_MASK; \
|
||||||
|
struct mm_struct *___mm = (__vma)->vm_mm; \
|
||||||
|
pmd_t ___pmd; \
|
||||||
|
\
|
||||||
|
___pmd = pmdp_clear_flush(__vma, __haddr, __pmd); \
|
||||||
|
mmu_notifier_invalidate_range(___mm, ___haddr, \
|
||||||
|
___haddr + HPAGE_PMD_SIZE); \
|
||||||
|
\
|
||||||
|
___pmd; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define pmdp_get_and_clear_notify(__mm, __haddr, __pmd) \
|
||||||
|
({ \
|
||||||
|
unsigned long ___haddr = __haddr & HPAGE_PMD_MASK; \
|
||||||
|
pmd_t ___pmd; \
|
||||||
|
\
|
||||||
|
___pmd = pmdp_get_and_clear(__mm, __haddr, __pmd); \
|
||||||
|
mmu_notifier_invalidate_range(__mm, ___haddr, \
|
||||||
|
___haddr + HPAGE_PMD_SIZE); \
|
||||||
|
\
|
||||||
|
___pmd; \
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set_pte_at_notify() sets the pte _after_ running the notifier.
|
* set_pte_at_notify() sets the pte _after_ running the notifier.
|
||||||
* This is safe to start by updating the secondary MMUs, because the primary MMU
|
* This is safe to start by updating the secondary MMUs, because the primary MMU
|
||||||
|
@ -362,6 +400,9 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
|
||||||
|
|
||||||
#define ptep_clear_flush_young_notify ptep_clear_flush_young
|
#define ptep_clear_flush_young_notify ptep_clear_flush_young
|
||||||
#define pmdp_clear_flush_young_notify pmdp_clear_flush_young
|
#define pmdp_clear_flush_young_notify pmdp_clear_flush_young
|
||||||
|
#define ptep_clear_flush_notify ptep_clear_flush
|
||||||
|
#define pmdp_clear_flush_notify pmdp_clear_flush
|
||||||
|
#define pmdp_get_and_clear_notify pmdp_get_and_clear
|
||||||
#define set_pte_at_notify set_pte_at
|
#define set_pte_at_notify set_pte_at
|
||||||
|
|
||||||
#endif /* CONFIG_MMU_NOTIFIER */
|
#endif /* CONFIG_MMU_NOTIFIER */
|
||||||
|
|
|
@ -193,7 +193,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_cache_page(vma, addr, pte_pfn(*ptep));
|
flush_cache_page(vma, addr, pte_pfn(*ptep));
|
||||||
ptep_clear_flush(vma, addr, ptep);
|
ptep_clear_flush_notify(vma, addr, ptep);
|
||||||
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
|
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
|
||||||
|
|
||||||
page_remove_rmap(page);
|
page_remove_rmap(page);
|
||||||
|
|
|
@ -37,7 +37,7 @@ static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
|
|
||||||
if (pte_present(pte)) {
|
if (pte_present(pte)) {
|
||||||
flush_cache_page(vma, addr, pte_pfn(pte));
|
flush_cache_page(vma, addr, pte_pfn(pte));
|
||||||
pte = ptep_clear_flush(vma, addr, ptep);
|
pte = ptep_clear_flush_notify(vma, addr, ptep);
|
||||||
page = vm_normal_page(vma, addr, pte);
|
page = vm_normal_page(vma, addr, pte);
|
||||||
if (page) {
|
if (page) {
|
||||||
if (pte_dirty(pte))
|
if (pte_dirty(pte))
|
||||||
|
|
|
@ -1036,7 +1036,7 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
|
||||||
goto out_free_pages;
|
goto out_free_pages;
|
||||||
VM_BUG_ON_PAGE(!PageHead(page), page);
|
VM_BUG_ON_PAGE(!PageHead(page), page);
|
||||||
|
|
||||||
pmdp_clear_flush(vma, haddr, pmd);
|
pmdp_clear_flush_notify(vma, haddr, pmd);
|
||||||
/* leave pmd empty until pte is filled */
|
/* leave pmd empty until pte is filled */
|
||||||
|
|
||||||
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
||||||
|
@ -1179,7 +1179,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
pmd_t entry;
|
pmd_t entry;
|
||||||
entry = mk_huge_pmd(new_page, vma->vm_page_prot);
|
entry = mk_huge_pmd(new_page, vma->vm_page_prot);
|
||||||
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
|
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
|
||||||
pmdp_clear_flush(vma, haddr, pmd);
|
pmdp_clear_flush_notify(vma, haddr, pmd);
|
||||||
page_add_new_anon_rmap(new_page, vma, haddr);
|
page_add_new_anon_rmap(new_page, vma, haddr);
|
||||||
mem_cgroup_commit_charge(new_page, memcg, false);
|
mem_cgroup_commit_charge(new_page, memcg, false);
|
||||||
lru_cache_add_active_or_unevictable(new_page, vma);
|
lru_cache_add_active_or_unevictable(new_page, vma);
|
||||||
|
@ -1512,7 +1512,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
||||||
pmd_t entry;
|
pmd_t entry;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (!prot_numa) {
|
if (!prot_numa) {
|
||||||
entry = pmdp_get_and_clear(mm, addr, pmd);
|
entry = pmdp_get_and_clear_notify(mm, addr, pmd);
|
||||||
if (pmd_numa(entry))
|
if (pmd_numa(entry))
|
||||||
entry = pmd_mknonnuma(entry);
|
entry = pmd_mknonnuma(entry);
|
||||||
entry = pmd_modify(entry, newprot);
|
entry = pmd_modify(entry, newprot);
|
||||||
|
@ -1644,6 +1644,7 @@ static int __split_huge_page_splitting(struct page *page,
|
||||||
* serialize against split_huge_page*.
|
* serialize against split_huge_page*.
|
||||||
*/
|
*/
|
||||||
pmdp_splitting_flush(vma, address, pmd);
|
pmdp_splitting_flush(vma, address, pmd);
|
||||||
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
spin_unlock(ptl);
|
spin_unlock(ptl);
|
||||||
}
|
}
|
||||||
|
@ -2834,7 +2835,7 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
|
||||||
pmd_t _pmd;
|
pmd_t _pmd;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pmdp_clear_flush(vma, haddr, pmd);
|
pmdp_clear_flush_notify(vma, haddr, pmd);
|
||||||
/* leave pmd empty until pte is filled */
|
/* leave pmd empty until pte is filled */
|
||||||
|
|
||||||
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
||||||
|
|
|
@ -2598,8 +2598,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
||||||
}
|
}
|
||||||
set_huge_pte_at(dst, addr, dst_pte, entry);
|
set_huge_pte_at(dst, addr, dst_pte, entry);
|
||||||
} else {
|
} else {
|
||||||
if (cow)
|
if (cow) {
|
||||||
huge_ptep_set_wrprotect(src, addr, src_pte);
|
huge_ptep_set_wrprotect(src, addr, src_pte);
|
||||||
|
mmu_notifier_invalidate_range(src, mmun_start,
|
||||||
|
mmun_end);
|
||||||
|
}
|
||||||
entry = huge_ptep_get(src_pte);
|
entry = huge_ptep_get(src_pte);
|
||||||
ptepage = pte_page(entry);
|
ptepage = pte_page(entry);
|
||||||
get_page(ptepage);
|
get_page(ptepage);
|
||||||
|
@ -2899,6 +2902,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
|
|
||||||
/* Break COW */
|
/* Break COW */
|
||||||
huge_ptep_clear_flush(vma, address, ptep);
|
huge_ptep_clear_flush(vma, address, ptep);
|
||||||
|
mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
|
||||||
set_huge_pte_at(mm, address, ptep,
|
set_huge_pte_at(mm, address, ptep,
|
||||||
make_huge_pte(vma, new_page, 1));
|
make_huge_pte(vma, new_page, 1));
|
||||||
page_remove_rmap(old_page);
|
page_remove_rmap(old_page);
|
||||||
|
@ -3374,6 +3378,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
|
||||||
* and that page table be reused and filled with junk.
|
* and that page table be reused and filled with junk.
|
||||||
*/
|
*/
|
||||||
flush_tlb_range(vma, start, end);
|
flush_tlb_range(vma, start, end);
|
||||||
|
mmu_notifier_invalidate_range(mm, start, end);
|
||||||
mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
||||||
mmu_notifier_invalidate_range_end(mm, start, end);
|
mmu_notifier_invalidate_range_end(mm, start, end);
|
||||||
|
|
||||||
|
|
4
mm/ksm.c
4
mm/ksm.c
|
@ -892,7 +892,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page,
|
||||||
* this assure us that no O_DIRECT can happen after the check
|
* this assure us that no O_DIRECT can happen after the check
|
||||||
* or in the middle of the check.
|
* or in the middle of the check.
|
||||||
*/
|
*/
|
||||||
entry = ptep_clear_flush(vma, addr, ptep);
|
entry = ptep_clear_flush_notify(vma, addr, ptep);
|
||||||
/*
|
/*
|
||||||
* Check that no O_DIRECT or similar I/O is in progress on the
|
* Check that no O_DIRECT or similar I/O is in progress on the
|
||||||
* page
|
* page
|
||||||
|
@ -960,7 +960,7 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
|
||||||
page_add_anon_rmap(kpage, vma, addr);
|
page_add_anon_rmap(kpage, vma, addr);
|
||||||
|
|
||||||
flush_cache_page(vma, addr, pte_pfn(*ptep));
|
flush_cache_page(vma, addr, pte_pfn(*ptep));
|
||||||
ptep_clear_flush(vma, addr, ptep);
|
ptep_clear_flush_notify(vma, addr, ptep);
|
||||||
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
|
set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
|
||||||
|
|
||||||
page_remove_rmap(page);
|
page_remove_rmap(page);
|
||||||
|
|
|
@ -238,6 +238,7 @@ static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
|
||||||
{
|
{
|
||||||
tlb->need_flush = 0;
|
tlb->need_flush = 0;
|
||||||
tlb_flush(tlb);
|
tlb_flush(tlb);
|
||||||
|
mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end);
|
||||||
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
||||||
tlb_table_flush(tlb);
|
tlb_table_flush(tlb);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2234,7 +2235,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
* seen in the presence of one thread doing SMC and another
|
* seen in the presence of one thread doing SMC and another
|
||||||
* thread doing COW.
|
* thread doing COW.
|
||||||
*/
|
*/
|
||||||
ptep_clear_flush(vma, address, page_table);
|
ptep_clear_flush_notify(vma, address, page_table);
|
||||||
page_add_new_anon_rmap(new_page, vma, address);
|
page_add_new_anon_rmap(new_page, vma, address);
|
||||||
mem_cgroup_commit_charge(new_page, memcg, false);
|
mem_cgroup_commit_charge(new_page, memcg, false);
|
||||||
lru_cache_add_active_or_unevictable(new_page, vma);
|
lru_cache_add_active_or_unevictable(new_page, vma);
|
||||||
|
|
|
@ -1854,7 +1854,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
|
||||||
*/
|
*/
|
||||||
flush_cache_range(vma, mmun_start, mmun_end);
|
flush_cache_range(vma, mmun_start, mmun_end);
|
||||||
page_add_anon_rmap(new_page, vma, mmun_start);
|
page_add_anon_rmap(new_page, vma, mmun_start);
|
||||||
pmdp_clear_flush(vma, mmun_start, pmd);
|
pmdp_clear_flush_notify(vma, mmun_start, pmd);
|
||||||
set_pmd_at(mm, mmun_start, pmd, entry);
|
set_pmd_at(mm, mmun_start, pmd, entry);
|
||||||
flush_tlb_range(vma, mmun_start, mmun_end);
|
flush_tlb_range(vma, mmun_start, mmun_end);
|
||||||
update_mmu_cache_pmd(vma, address, &entry);
|
update_mmu_cache_pmd(vma, address, &entry);
|
||||||
|
@ -1862,6 +1862,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
|
||||||
if (page_count(page) != 2) {
|
if (page_count(page) != 2) {
|
||||||
set_pmd_at(mm, mmun_start, pmd, orig_entry);
|
set_pmd_at(mm, mmun_start, pmd, orig_entry);
|
||||||
flush_tlb_range(vma, mmun_start, mmun_end);
|
flush_tlb_range(vma, mmun_start, mmun_end);
|
||||||
|
mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
|
||||||
update_mmu_cache_pmd(vma, address, &entry);
|
update_mmu_cache_pmd(vma, address, &entry);
|
||||||
page_remove_rmap(new_page);
|
page_remove_rmap(new_page);
|
||||||
goto fail_putback;
|
goto fail_putback;
|
||||||
|
|
|
@ -1378,7 +1378,7 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
|
||||||
|
|
||||||
/* Nuke the page table entry. */
|
/* Nuke the page table entry. */
|
||||||
flush_cache_page(vma, address, pte_pfn(*pte));
|
flush_cache_page(vma, address, pte_pfn(*pte));
|
||||||
pteval = ptep_clear_flush(vma, address, pte);
|
pteval = ptep_clear_flush_notify(vma, address, pte);
|
||||||
|
|
||||||
/* If nonlinear, store the file page offset in the pte. */
|
/* If nonlinear, store the file page offset in the pte. */
|
||||||
if (page->index != linear_page_index(vma, address)) {
|
if (page->index != linear_page_index(vma, address)) {
|
||||||
|
|
Loading…
Reference in New Issue