summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/rmap.c87
1 files changed, 48 insertions, 39 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index 9cb496d7b375..dd1309d72e37 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -2068,6 +2068,50 @@ range_end:
return ret;
}
+static bool ttu_anon_lazyfree_folio(struct vm_area_struct *vma,
+ struct folio *folio, unsigned long nr_pages)
+{
+ int ref_count, map_count;
+
+ /*
+ * Synchronize with gup_pte_range():
+ * - clear PTE; barrier; read refcount
+ * - inc refcount; barrier; read PTE
+ */
+ smp_mb();
+
+ ref_count = folio_ref_count(folio);
+ map_count = folio_mapcount(folio);
+
+ /*
+ * Order reads for page refcount and dirty flag
+ * (see comments in __remove_mapping()).
+ */
+ smp_rmb();
+
+ if (folio_test_dirty(folio) && !(vma->vm_flags & VM_DROPPABLE)) {
+ /*
+ * redirtied either using the page table or a previously
+ * obtained GUP reference.
+ */
+ folio_set_swapbacked(folio);
+ return false;
+ }
+
+ /*
+ * Additional references could be due to GUP or speculative lookups.
+ * GUP users must mark the folio dirty if there was a modification.
+ * This folio cannot be reclaimed right now either way, so act just
+ * like nothing happened. We'll come back here later and detect if the
+ * folio was dirtied when the additional reference is gone.
+ */
+ if (ref_count != 1 + map_count)
+ return false;
+
+ add_mm_counter(vma->vm_mm, MM_ANONPAGES, -nr_pages);
+ return true;
+}
+
/*
* @arg: enum ttu_flags will be passed to this argument
*/
@@ -2261,47 +2305,12 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
/* MADV_FREE page check */
if (!folio_test_swapbacked(folio)) {
- int ref_count, map_count;
-
- /*
- * Synchronize with gup_pte_range():
- * - clear PTE; barrier; read refcount
- * - inc refcount; barrier; read PTE
- */
- smp_mb();
-
- ref_count = folio_ref_count(folio);
- map_count = folio_mapcount(folio);
-
- /*
- * Order reads for page refcount and dirty flag
- * (see comments in __remove_mapping()).
- */
- smp_rmb();
-
- if (folio_test_dirty(folio) && !(vma->vm_flags & VM_DROPPABLE)) {
- /*
- * redirtied either using the page table or a previously
- * obtained GUP reference.
- */
- set_ptes(mm, address, pvmw.pte, pteval, nr_pages);
- folio_set_swapbacked(folio);
- goto walk_abort;
- } else if (ref_count != 1 + map_count) {
- /*
- * Additional reference. Could be a GUP reference or any
- * speculative reference. GUP users must mark the folio
- * dirty if there was a modification. This folio cannot be
- * reclaimed right now either way, so act just like nothing
- * happened.
- * We'll come back here later and detect if the folio was
- * dirtied when the additional reference is gone.
- */
+ if (!ttu_anon_lazyfree_folio(vma, folio,
+ nr_pages)) {
set_ptes(mm, address, pvmw.pte, pteval, nr_pages);
goto walk_abort;
}
- add_mm_counter(mm, MM_ANONPAGES, -nr_pages);
- goto discard;
+ goto finish_unmap;
}
if (folio_dup_swap(folio, subpage) < 0) {
@@ -2359,7 +2368,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
*/
add_mm_counter(mm, mm_counter_file(folio), -nr_pages);
}
-discard:
+finish_unmap:
folio_remove_rmap_ptes(folio, subpage, nr_pages, vma);
if (vma->vm_flags & VM_LOCKED)
mlock_drain_local();