ANDROID: mm: preserve vma->anon_vma after MREMAP_DONTUNMAP for SPF
The optimizations [1] and [2] to reset vma->anon_vma during
MREMAP_DONTUNMAP can affect speculative page fault handler. If
vma->anon_vma reset happens after do_anonymous_page verified no
changes to the vma and obtained the ptl lock but before it calls
page_add_new_anon_rmap() then __page_set_anon_rmap() will stumble
on BUG_ON(!anon_vma). Disable these optimizations if SPF is enabled
to avoid such situations. As a result the reverse map walk will
consider the old VMA as it did before these optimizations were
introduced.
[1] 1583aa278f5f ("mm: mremap: unlink anon_vmas when mremap with MREMAP_DONTUNMAP success")
[2] ee8ab1903e3d ("mm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()")
Bug: 257443051
Change-Id: I4e7611137f4a49c94bfe73532b4b06cbb0d2405b
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
diff --git a/mm/mremap.c b/mm/mremap.c
index a46c810..6c87fc8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -683,6 +683,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
/* We always clear VM_LOCKED[ONFAULT] on the old vma */
vma->vm_flags &= VM_LOCKED_CLEAR_MASK;
+#ifndef CONFIG_SPECULATIVE_PAGE_FAULT
/*
* anon_vma links of the old vma is no longer needed after its page
* table has been moved.
@@ -690,6 +691,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
if (new_vma != vma && vma->vm_start == old_addr &&
vma->vm_end == (old_addr + old_len))
unlink_anon_vmas(vma);
+#endif
/* Because we won't unmap we don't need to touch locked_vm */
return new_addr;
diff --git a/mm/rmap.c b/mm/rmap.c
index 440085a..df89881c 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -422,11 +422,13 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
if (vma->anon_vma) {
vma->anon_vma->num_active_vmas--;
+#ifndef CONFIG_SPECULATIVE_PAGE_FAULT
/*
* vma would still be needed after unlink, and anon_vma will be prepared
* when handle fault.
*/
vma->anon_vma = NULL;
+#endif
}
unlock_anon_vma_root(root);