|
@@ -787,6 +787,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
|
|
|
pmd_t _pmd;
|
|
|
int ret = 0, i;
|
|
|
struct page **pages;
|
|
|
+ unsigned long mmun_start; /* For mmu_notifiers */
|
|
|
+ unsigned long mmun_end; /* For mmu_notifiers */
|
|
|
|
|
|
pages = kmalloc(sizeof(struct page *) * HPAGE_PMD_NR,
|
|
|
GFP_KERNEL);
|
|
@@ -823,12 +825,16 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
|
|
|
cond_resched();
|
|
|
}
|
|
|
|
|
|
+ mmun_start = haddr;
|
|
|
+ mmun_end = haddr + HPAGE_PMD_SIZE;
|
|
|
+ mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
|
|
|
+
|
|
|
spin_lock(&mm->page_table_lock);
|
|
|
if (unlikely(!pmd_same(*pmd, orig_pmd)))
|
|
|
goto out_free_pages;
|
|
|
VM_BUG_ON(!PageHead(page));
|
|
|
|
|
|
- pmdp_clear_flush_notify(vma, haddr, pmd);
|
|
|
+ pmdp_clear_flush(vma, haddr, pmd);
|
|
|
/* leave pmd empty until pte is filled */
|
|
|
|
|
|
pgtable = pgtable_trans_huge_withdraw(mm);
|
|
@@ -851,6 +857,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
|
|
|
page_remove_rmap(page);
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
|
|
|
+ mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
|
|
|
+
|
|
|
ret |= VM_FAULT_WRITE;
|
|
|
put_page(page);
|
|
|
|
|
@@ -859,6 +867,7 @@ out:
|
|
|
|
|
|
out_free_pages:
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
+ mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
|
|
|
mem_cgroup_uncharge_start();
|
|
|
for (i = 0; i < HPAGE_PMD_NR; i++) {
|
|
|
mem_cgroup_uncharge_page(pages[i]);
|
|
@@ -875,6 +884,8 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
int ret = 0;
|
|
|
struct page *page, *new_page;
|
|
|
unsigned long haddr;
|
|
|
+ unsigned long mmun_start; /* For mmu_notifiers */
|
|
|
+ unsigned long mmun_end; /* For mmu_notifiers */
|
|
|
|
|
|
VM_BUG_ON(!vma->anon_vma);
|
|
|
spin_lock(&mm->page_table_lock);
|
|
@@ -925,20 +936,24 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
copy_user_huge_page(new_page, page, haddr, vma, HPAGE_PMD_NR);
|
|
|
__SetPageUptodate(new_page);
|
|
|
|
|
|
+ mmun_start = haddr;
|
|
|
+ mmun_end = haddr + HPAGE_PMD_SIZE;
|
|
|
+ mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
|
|
|
+
|
|
|
spin_lock(&mm->page_table_lock);
|
|
|
put_page(page);
|
|
|
if (unlikely(!pmd_same(*pmd, orig_pmd))) {
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
mem_cgroup_uncharge_page(new_page);
|
|
|
put_page(new_page);
|
|
|
- goto out;
|
|
|
+ goto out_mn;
|
|
|
} else {
|
|
|
pmd_t entry;
|
|
|
VM_BUG_ON(!PageHead(page));
|
|
|
entry = mk_pmd(new_page, vma->vm_page_prot);
|
|
|
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
|
|
|
entry = pmd_mkhuge(entry);
|
|
|
- pmdp_clear_flush_notify(vma, haddr, pmd);
|
|
|
+ pmdp_clear_flush(vma, haddr, pmd);
|
|
|
page_add_new_anon_rmap(new_page, vma, haddr);
|
|
|
set_pmd_at(mm, haddr, pmd, entry);
|
|
|
update_mmu_cache(vma, address, pmd);
|
|
@@ -946,10 +961,14 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
put_page(page);
|
|
|
ret |= VM_FAULT_WRITE;
|
|
|
}
|
|
|
-out_unlock:
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
+out_mn:
|
|
|
+ mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
|
|
|
out:
|
|
|
return ret;
|
|
|
+out_unlock:
|
|
|
+ spin_unlock(&mm->page_table_lock);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
struct page *follow_trans_huge_pmd(struct mm_struct *mm,
|
|
@@ -1162,7 +1181,11 @@ static int __split_huge_page_splitting(struct page *page,
|
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
|
pmd_t *pmd;
|
|
|
int ret = 0;
|
|
|
+ /* For mmu_notifiers */
|
|
|
+ const unsigned long mmun_start = address;
|
|
|
+ const unsigned long mmun_end = address + HPAGE_PMD_SIZE;
|
|
|
|
|
|
+ mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
|
|
|
spin_lock(&mm->page_table_lock);
|
|
|
pmd = page_check_address_pmd(page, mm, address,
|
|
|
PAGE_CHECK_ADDRESS_PMD_NOTSPLITTING_FLAG);
|
|
@@ -1174,10 +1197,11 @@ static int __split_huge_page_splitting(struct page *page,
|
|
|
* and it won't wait on the anon_vma->root->mutex to
|
|
|
* serialize against split_huge_page*.
|
|
|
*/
|
|
|
- pmdp_splitting_flush_notify(vma, address, pmd);
|
|
|
+ pmdp_splitting_flush(vma, address, pmd);
|
|
|
ret = 1;
|
|
|
}
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
+ mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1898,6 +1922,8 @@ static void collapse_huge_page(struct mm_struct *mm,
|
|
|
spinlock_t *ptl;
|
|
|
int isolated;
|
|
|
unsigned long hstart, hend;
|
|
|
+ unsigned long mmun_start; /* For mmu_notifiers */
|
|
|
+ unsigned long mmun_end; /* For mmu_notifiers */
|
|
|
|
|
|
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
|
|
|
|
@@ -1952,6 +1978,9 @@ static void collapse_huge_page(struct mm_struct *mm,
|
|
|
pte = pte_offset_map(pmd, address);
|
|
|
ptl = pte_lockptr(mm, pmd);
|
|
|
|
|
|
+ mmun_start = address;
|
|
|
+ mmun_end = address + HPAGE_PMD_SIZE;
|
|
|
+ mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
|
|
|
spin_lock(&mm->page_table_lock); /* probably unnecessary */
|
|
|
/*
|
|
|
* After this gup_fast can't run anymore. This also removes
|
|
@@ -1959,8 +1988,9 @@ static void collapse_huge_page(struct mm_struct *mm,
|
|
|
* huge and small TLB entries for the same virtual address
|
|
|
* to avoid the risk of CPU bugs in that area.
|
|
|
*/
|
|
|
- _pmd = pmdp_clear_flush_notify(vma, address, pmd);
|
|
|
+ _pmd = pmdp_clear_flush(vma, address, pmd);
|
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
+ mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
|
|
|
|
|
|
spin_lock(ptl);
|
|
|
isolated = __collapse_huge_page_isolate(vma, address, pte);
|