diff options
Diffstat (limited to 'mm/mremap.c')
-rw-r--r-- | mm/mremap.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/mm/mremap.c b/mm/mremap.c index 6ccecc03f56a..30d7d2482eea 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -149,14 +149,18 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
149 | if (pte_none(*old_pte)) | 149 | if (pte_none(*old_pte)) |
150 | continue; | 150 | continue; |
151 | 151 | ||
152 | pte = ptep_get_and_clear(mm, old_addr, old_pte); | ||
152 | /* | 153 | /* |
153 | * We are remapping a dirty PTE, make sure to | 154 | * If we are remapping a dirty PTE, make sure |
154 | * flush TLB before we drop the PTL for the | 155 | * to flush TLB before we drop the PTL for the |
155 | * old PTE or we may race with page_mkclean(). | 156 | * old PTE or we may race with page_mkclean(). |
157 | * | ||
158 | * This check has to be done after we removed the | ||
159 | * old PTE from page tables or another thread may | ||
160 | * dirty it after the check and before the removal. | ||
156 | */ | 161 | */ |
157 | if (pte_present(*old_pte) && pte_dirty(*old_pte)) | 162 | if (pte_present(pte) && pte_dirty(pte)) |
158 | force_flush = true; | 163 | force_flush = true; |
159 | pte = ptep_get_and_clear(mm, old_addr, old_pte); | ||
160 | pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr); | 164 | pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr); |
161 | pte = move_soft_dirty_pte(pte); | 165 | pte = move_soft_dirty_pte(pte); |
162 | set_pte_at(mm, new_addr, new_pte, pte); | 166 | set_pte_at(mm, new_addr, new_pte, pte); |