summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/mremap.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/mm/mremap.c b/mm/mremap.c
index 85b492d23b4b..8d7a636e8b2a 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -135,15 +135,17 @@ move_one_page(struct vm_area_struct *vma, unsigned long old_addr,
dst = alloc_one_pte_map(mm, new_addr);
if (src == NULL)
src = get_one_pte_map_nested(mm, old_addr);
- error = copy_one_pte(vma, old_addr, src, dst, &pte_chain);
- pte_unmap_nested(src);
- pte_unmap(dst);
- } else
/*
- * Why do we need this flush ? If there is no pte for
- * old_addr, then there must not be a pte for it as well.
+ * Since alloc_one_pte_map can drop and re-acquire
+ * page_table_lock, we should re-check the src entry...
*/
- flush_tlb_page(vma, old_addr);
+ if (src) {
+ error = copy_one_pte(vma, old_addr, src,
+ dst, &pte_chain);
+ pte_unmap_nested(src);
+ }
+ pte_unmap(dst);
+ }
spin_unlock(&mm->page_table_lock);
pte_chain_free(pte_chain);
out: