Revert "mm: speculative page fault handler return VMA"

This reverts commit f556cd74a7.

Bug: 128240262
Change-Id: Icc3edff62de261aee10658b1567b85ff7b5d58dd
Signed-off-by: Minchan Kim <minchan@google.com>
[dereference23: Forward port to msm-5.4]
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
This commit is contained in:
Minchan Kim 2019-03-11 11:37:52 +09:00 • committed by Alexander Winkowski
commit a45b2e061e
No known key found for this signature in database
GPG key ID: 72762A66704CDE44
2 changed files with 59 additions and 102 deletions

View file

@ -1666,37 +1666,25 @@ extern vm_fault_t handle_mm_fault(struct vm_area_struct *vma,
#ifdef CONFIG_SPECULATIVE_PAGE_FAULT
extern int __handle_speculative_fault(struct mm_struct *mm,
unsigned long address,
unsigned int flags,
struct vm_area_struct **vma);
unsigned int flags);
static inline int handle_speculative_fault(struct mm_struct *mm,
unsigned long address,
unsigned int flags,
struct vm_area_struct **vma)
unsigned int flags)
{
/*
* Try speculative page fault for multithreaded user space task only.
*/
if (!(flags & FAULT_FLAG_USER) || atomic_read(&mm->mm_users) == 1) {
*vma = NULL;
if (!(flags & FAULT_FLAG_USER) || atomic_read(&mm->mm_users) == 1)
return VM_FAULT_RETRY;
}
return __handle_speculative_fault(mm, address, flags, vma);
return __handle_speculative_fault(mm, address, flags);
}
extern bool can_reuse_spf_vma(struct vm_area_struct *vma,
unsigned long address);
#else
static inline int handle_speculative_fault(struct mm_struct *mm,
unsigned long address,
unsigned int flags,
struct vm_area_struct **vma)
unsigned int flags)
{
return VM_FAULT_RETRY;
}
static inline bool can_reuse_spf_vma(struct vm_area_struct *vma,
unsigned long address)
{
return false;
}
#endif /* CONFIG_SPECULATIVE_PAGE_FAULT */
extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,

View file

@ -4418,22 +4418,13 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,
/* This is required by vm_normal_page() */
#error "Speculative page fault handler requires CONFIG_ARCH_HAS_PTE_SPECIAL"
#endif
/*
* vm_normal_page() adds some processing which should be done while
* hodling the mmap_sem.
*/
/*
* Tries to handle the page fault in a speculative way, without grabbing the
* mmap_sem.
* When VM_FAULT_RETRY is returned, the vma pointer is valid and this vma must
* be checked later when the mmap_sem has been grabbed by calling
* can_reuse_spf_vma().
* This is needed as the returned vma is kept in memory until the call to
* can_reuse_spf_vma() is made.
*/
int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
unsigned int flags, struct vm_area_struct **vma)
unsigned int flags)
{
struct vm_fault vmf = {
.address = address,
@ -4441,22 +4432,22 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
pgd_t *pgd, pgdval;
p4d_t *p4d, p4dval;
pud_t pudval;
int seq, ret;
int seq, ret = VM_FAULT_RETRY;
struct vm_area_struct *vma;
/* Clear flags that may lead to release the mmap_sem to retry */
flags &= ~(FAULT_FLAG_ALLOW_RETRY|FAULT_FLAG_KILLABLE);
flags |= FAULT_FLAG_SPECULATIVE;
*vma = get_vma(mm, address);
if (!*vma)
return VM_FAULT_RETRY;
vmf.vma = *vma;
vma = get_vma(mm, address);
if (!vma)
return ret;
/* rmb <-> seqlock,vma_rb_erase() */
seq = raw_read_seqcount(&vmf.vma->vm_sequence);
seq = raw_read_seqcount(&vma->vm_sequence);
if (seq & 1) {
trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
trace_spf_vma_changed(_RET_IP_, vma, address);
goto out_put;
}
/*
@ -4464,9 +4455,9 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
* with the VMA.
* This include huge page from hugetlbfs.
*/
if (vmf.vma->vm_ops) {
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
if (vma->vm_ops) {
trace_spf_vma_notsup(_RET_IP_, vma, address);
goto out_put;
}
/*
@ -4474,18 +4465,18 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
* because vm_next and vm_prev must be safe. This can't be guaranteed
* in the speculative path.
*/
if (unlikely(!vmf.vma->anon_vma)) {
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
if (unlikely(!vma->anon_vma)) {
trace_spf_vma_notsup(_RET_IP_, vma, address);
goto out_put;
}
vmf.vma_flags = READ_ONCE(vmf.vma->vm_flags);
vmf.vma_page_prot = READ_ONCE(vmf.vma->vm_page_prot);
vmf.vma_flags = READ_ONCE(vma->vm_flags);
vmf.vma_page_prot = READ_ONCE(vma->vm_page_prot);
/* Can't call userland page fault handler in the speculative path */
if (unlikely(vmf.vma_flags & VM_UFFD_MISSING)) {
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
trace_spf_vma_notsup(_RET_IP_, vma, address);
goto out_put;
}
if (vmf.vma_flags & VM_GROWSDOWN || vmf.vma_flags & VM_GROWSUP) {
@ -4494,27 +4485,36 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
* boundaries but we want to trace it as not supported instead
* of changed.
*/
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
trace_spf_vma_notsup(_RET_IP_, vma, address);
goto out_put;
}
if (address < READ_ONCE(vmf.vma->vm_start)
|| READ_ONCE(vmf.vma->vm_end) <= address) {
trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
if (address < READ_ONCE(vma->vm_start)
|| READ_ONCE(vma->vm_end) <= address) {
trace_spf_vma_changed(_RET_IP_, vma, address);
goto out_put;
}
if (!arch_vma_access_permitted(vmf.vma, flags & FAULT_FLAG_WRITE,
if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
flags & FAULT_FLAG_INSTRUCTION,
flags & FAULT_FLAG_REMOTE))
goto out_segv;
flags & FAULT_FLAG_REMOTE)) {
trace_spf_vma_access(_RET_IP_, vma, address);
ret = VM_FAULT_SIGSEGV;
goto out_put;
}
/* This is one is required to check that the VMA has write access set */
if (flags & FAULT_FLAG_WRITE) {
if (unlikely(!(vmf.vma_flags & VM_WRITE)))
goto out_segv;
} else if (unlikely(!(vmf.vma_flags & (VM_READ|VM_EXEC|VM_WRITE))))
goto out_segv;
if (unlikely(!(vmf.vma_flags & VM_WRITE))) {
trace_spf_vma_access(_RET_IP_, vma, address);
ret = VM_FAULT_SIGSEGV;
goto out_put;
}
} else if (unlikely(!(vmf.vma_flags & (VM_READ|VM_EXEC|VM_WRITE)))) {
trace_spf_vma_access(_RET_IP_, vma, address);
ret = VM_FAULT_SIGSEGV;
goto out_put;
}
#ifdef CONFIG_NUMA
struct mempolicy *pol;
@ -4524,13 +4524,13 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
* mpol_misplaced() which are not compatible with the
*speculative page fault processing.
*/
pol = __get_vma_policy(vmf.vma, address);
pol = __get_vma_policy(vma, address);
if (!pol)
pol = get_task_policy(current);
if (!pol)
if (pol && pol->mode == MPOL_INTERLEAVE) {
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
trace_spf_vma_notsup(_RET_IP_, vma, address);
goto out_put;
}
#endif
@ -4592,8 +4592,9 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
vmf.pte = NULL;
}
vmf.pgoff = linear_page_index(vmf.vma, address);
vmf.gfp_mask = __get_fault_gfp_mask(vmf.vma);
vmf.vma = vma;
vmf.pgoff = linear_page_index(vma, address);
vmf.gfp_mask = __get_fault_gfp_mask(vma);
vmf.sequence = seq;
vmf.flags = flags;
@ -4603,22 +4604,16 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
* We need to re-validate the VMA after checking the bounds, otherwise
* we might have a false positive on the bounds.
*/
if (read_seqcount_retry(&vmf.vma->vm_sequence, seq)) {
trace_spf_vma_changed(_RET_IP_, vmf.vma, address);
return VM_FAULT_RETRY;
if (read_seqcount_retry(&vma->vm_sequence, seq)) {
trace_spf_vma_changed(_RET_IP_, vma, address);
goto out_put;
}
mem_cgroup_enter_user_fault();
ret = handle_pte_fault(&vmf);
mem_cgroup_exit_user_fault();
/*
* If there is no need to retry, don't return the vma to the caller.
*/
if (ret != VM_FAULT_RETRY) {
put_vma(vmf.vma);
*vma = NULL;
}
put_vma(vma);
/*
* The task may have entered a memcg OOM situation but
@ -4631,35 +4626,9 @@ int __handle_speculative_fault(struct mm_struct *mm, unsigned long address,
return ret;
out_walk:
trace_spf_vma_notsup(_RET_IP_, vmf.vma, address);
trace_spf_vma_notsup(_RET_IP_, vma, address);
local_irq_enable();
return VM_FAULT_RETRY;
out_segv:
trace_spf_vma_access(_RET_IP_, vmf.vma, address);
/*
* We don't return VM_FAULT_RETRY so the caller is not expected to
* retrieve the fetched VMA.
*/
put_vma(vmf.vma);
*vma = NULL;
return VM_FAULT_SIGSEGV;
}
/*
* This is used to know if the vma fetch in the speculative page fault handler
* is still valid when trying the regular fault path while holding the
* mmap_sem.
* The call to put_vma(vma) must be made after checking the vma's fields, as
* the vma may be freed by put_vma(). In such a case it is expected that false
* is returned.
*/
bool can_reuse_spf_vma(struct vm_area_struct *vma, unsigned long address)
{
bool ret;
ret = !RB_EMPTY_NODE(&vma->vm_rb) &&
vma->vm_start <= address && address < vma->vm_end;
out_put:
put_vma(vma);
return ret;
}