aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@linux-foundation.org>2023-04-16 12:31:58 -0700
committerAndrew Morton <akpm@linux-foundation.org>2023-04-16 12:31:58 -0700
commite492cd61b986590a45c674ede7dd1c4dbf94cf24 (patch)
tree37dc59ea66842b5b7e57f32aba6cbce5143c1282 /mm/memory.c
parentd46031f40e0f7f7bf63914bb3f2e404ad3886ecd (diff)
parent2ff559f31a5d50c31a3f9d849f8af90dc36c7105 (diff)
downloadlinux-e492cd61b986590a45c674ede7dd1c4dbf94cf24.tar.gz
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.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/mm/memory.c b/mm/memory.c
index f77fccb5310cb9..387226d6094d79 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;