diff options
author | Andrew Morton <akpm@linux-foundation.org> | 2023-04-16 12:31:58 -0700 |
---|---|---|
committer | Andrew Morton <akpm@linux-foundation.org> | 2023-04-16 12:31:58 -0700 |
commit | e492cd61b986590a45c674ede7dd1c4dbf94cf24 (patch) | |
tree | 37dc59ea66842b5b7e57f32aba6cbce5143c1282 /mm/memory.c | |
parent | d46031f40e0f7f7bf63914bb3f2e404ad3886ecd (diff) | |
parent | 2ff559f31a5d50c31a3f9d849f8af90dc36c7105 (diff) |
sync mm-stable with mm-hotfixes-stable to pick up depended-upon upstream changes
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/mm/memory.c b/mm/memory.c index f77fccb5310c..387226d6094d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3569,8 +3569,21 @@ static vm_fault_t remove_device_exclusive_entry(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; struct mmu_notifier_range range; - if (!folio_lock_or_retry(folio, vma->vm_mm, vmf->flags)) + /* + * We need a reference to lock the folio because we don't hold + * the PTL so a racing thread can remove the device-exclusive + * entry and unmap it. If the folio is free the entry must + * have been removed already. If it happens to have already + * been re-allocated after being freed all we do is lock and + * unlock it. + */ + if (!folio_try_get(folio)) + return 0; + + if (!folio_lock_or_retry(folio, vma->vm_mm, vmf->flags)) { + folio_put(folio); return VM_FAULT_RETRY; + } mmu_notifier_range_init_owner(&range, MMU_NOTIFY_EXCLUSIVE, 0, vma->vm_mm, vmf->address & PAGE_MASK, (vmf->address & PAGE_MASK) + PAGE_SIZE, NULL); @@ -3583,6 +3596,7 @@ static vm_fault_t remove_device_exclusive_entry(struct vm_fault *vmf) pte_unmap_unlock(vmf->pte, vmf->ptl); folio_unlock(folio); + folio_put(folio); mmu_notifier_invalidate_range_end(&range); return 0; |