mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
FROMLIST: mm: make pte_unmap_same compatible with SPF
pte_unmap_same() is making the assumption that the page table are still around because the mmap_sem is held. This is no more the case when running a speculative page fault and additional check must be made to ensure that the final page table are still there. This is now done by calling pte_spinlock() to check for the VMA's consistency while locking for the page tables. This is requiring passing a vm_fault structure to pte_unmap_same() which is containing all the needed parameters. As pte_spinlock() may fail in the case of a speculative page fault, if the VMA has been touched in our back, pte_unmap_same() should now return 3 cases : 1. pte are the same (0) 2. pte are different (VM_FAULT_PTNOTSAME) 3. a VMA's changes has been detected (VM_FAULT_RETRY) The case 2 is handled by the introduction of a new VM_FAULT flag named VM_FAULT_PTNOTSAME which is then trapped in cow_user_page(). If VM_FAULT_RETRY is returned, it is passed up to the callers to retry the page fault while holding the mmap_sem. Change-Id: Iaccfa0d877334f4343f8b0ec3400af5070ff5864 Acked-by: David Rientjes <rientjes@google.com> Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com> Link: https://lore.kernel.org/lkml/1523975611-15978-7-git-send-email-ldufour@linux.vnet.ibm.com/ Bug: 161210518 Signed-off-by: Vinayak Menon <vinmenon@codeaurora.org> Signed-off-by: Charan Teja Reddy <charante@codeaurora.org>
This commit is contained in:
committed by
Suren Baghdasaryan
parent
b23ffc113b
commit
5835d87162
@@ -735,6 +735,7 @@ enum vm_fault_reason {
|
||||
VM_FAULT_FALLBACK = (__force vm_fault_t)0x000800,
|
||||
VM_FAULT_DONE_COW = (__force vm_fault_t)0x001000,
|
||||
VM_FAULT_NEEDDSYNC = (__force vm_fault_t)0x002000,
|
||||
VM_FAULT_PTNOTSAME = (__force vm_fault_t)0x004000,
|
||||
VM_FAULT_HINDEX_MASK = (__force vm_fault_t)0x0f0000,
|
||||
};
|
||||
|
||||
|
||||
41
mm/memory.c
41
mm/memory.c
@@ -2595,21 +2595,29 @@ EXPORT_SYMBOL_GPL(apply_to_existing_page_range);
|
||||
* parts, do_swap_page must check under lock before unmapping the pte and
|
||||
* proceeding (but do_wp_page is only called after already making such a check;
|
||||
* and do_anonymous_page can safely check later on).
|
||||
*
|
||||
* pte_unmap_same() returns:
|
||||
* 0 if the PTE are the same
|
||||
* VM_FAULT_PTNOTSAME if the PTE are different
|
||||
* VM_FAULT_RETRY if the VMA has changed in our back during
|
||||
* a speculative page fault handling.
|
||||
*/
|
||||
static inline int pte_unmap_same(struct mm_struct *mm, pmd_t *pmd,
|
||||
pte_t *page_table, pte_t orig_pte)
|
||||
static inline int pte_unmap_same(struct vm_fault *vmf)
|
||||
{
|
||||
int same = 1;
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPTION)
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
|
||||
if (sizeof(pte_t) > sizeof(unsigned long)) {
|
||||
spinlock_t *ptl = pte_lockptr(mm, pmd);
|
||||
spin_lock(ptl);
|
||||
same = pte_same(*page_table, orig_pte);
|
||||
spin_unlock(ptl);
|
||||
if (pte_spinlock(vmf)) {
|
||||
if (!pte_same(*vmf->pte, vmf->orig_pte))
|
||||
ret = VM_FAULT_PTNOTSAME;
|
||||
spin_unlock(vmf->ptl);
|
||||
} else
|
||||
ret = VM_FAULT_RETRY;
|
||||
}
|
||||
#endif
|
||||
pte_unmap(page_table);
|
||||
return same;
|
||||
pte_unmap(vmf->pte);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool cow_user_page(struct page *dst, struct page *src,
|
||||
@@ -3289,11 +3297,20 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
|
||||
pte_t pte;
|
||||
int locked;
|
||||
int exclusive = 0;
|
||||
vm_fault_t ret = 0;
|
||||
vm_fault_t ret;
|
||||
void *shadow = NULL;
|
||||
|
||||
if (!pte_unmap_same(vma->vm_mm, vmf->pmd, vmf->pte, vmf->orig_pte))
|
||||
ret = pte_unmap_same(vmf);
|
||||
if (ret) {
|
||||
/*
|
||||
* If pte != orig_pte, this means another thread did the
|
||||
* swap operation in our back.
|
||||
* So nothing else to do.
|
||||
*/
|
||||
if (ret == VM_FAULT_PTNOTSAME)
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
entry = pte_to_swp_entry(vmf->orig_pte);
|
||||
if (unlikely(non_swap_entry(entry))) {
|
||||
|
||||
Reference in New Issue
Block a user