* [RFC PATCH 1/3] mm: avoid unnecessary lru drain for wp_can_reuse_anon_folio()
2026-06-11 10:51 [RFC PATCH 0/3] mm: drop redundant lru_add_drain in anon folio reuse paths Barry Song (Xiaomi)
@ 2026-06-11 10:51 ` Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 2/3] mm: drop stale folio_ref_count()==1 check in do_swap_page reuse logic Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 3/3] mm: entirely remove lru_add_drain in do_swap_page Barry Song (Xiaomi)
2 siblings, 0 replies; 4+ messages in thread
From: Barry Song (Xiaomi) @ 2026-06-11 10:51 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, david, ljs, liam, vbabka, rppt, surenb, mhocko,
chrisl, kasong, shikemeng, nphamcs, baoquan.he, youngjun.park,
jp.kobryn, usama.arif, shakeel.butt, Barry Song (Xiaomi)
We always unconditionally drain the LRU before retrying anon folio
reuse in wp_can_reuse_anon_folio(). Instead, assume !LRU anon folios
are in lru_cache, and use the refcount to avoid many unnecessary LRU
drains.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
---
mm/memory.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/mm/memory.c b/mm/memory.c
index 56be920c56d7..487a34377a7b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4193,12 +4193,18 @@ static bool wp_can_reuse_anon_folio(struct folio *folio,
*/
if (folio_test_ksm(folio) || folio_ref_count(folio) > 3)
return false;
- if (!folio_test_lru(folio))
+ if (!folio_test_lru(folio)) {
+ /*
+ * Assume folio is on lru_cache and holds a cache reference.
+ */
+ if (folio_ref_count(folio) > 2 + folio_test_swapcache(folio))
+ return false;
/*
* We cannot easily detect+handle references from
* remote LRU caches or references to LRU folios.
*/
lru_add_drain();
+ }
if (folio_ref_count(folio) > 1 + folio_test_swapcache(folio))
return false;
if (!folio_trylock(folio))
--
2.39.3 (Apple Git-146)
^ permalink raw reply related [flat|nested] 4+ messages in thread* [RFC PATCH 2/3] mm: drop stale folio_ref_count()==1 check in do_swap_page reuse logic
2026-06-11 10:51 [RFC PATCH 0/3] mm: drop redundant lru_add_drain in anon folio reuse paths Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 1/3] mm: avoid unnecessary lru drain for wp_can_reuse_anon_folio() Barry Song (Xiaomi)
@ 2026-06-11 10:51 ` Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 3/3] mm: entirely remove lru_add_drain in do_swap_page Barry Song (Xiaomi)
2 siblings, 0 replies; 4+ messages in thread
From: Barry Song (Xiaomi) @ 2026-06-11 10:51 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, david, ljs, liam, vbabka, rppt, surenb, mhocko,
chrisl, kasong, shikemeng, nphamcs, baoquan.he, youngjun.park,
jp.kobryn, usama.arif, shakeel.butt, Barry Song (Xiaomi)
The "we just allocated them without exposing them to the swapcache"
case no longer exists, as Kairui has routed synchronous I/O through
the swapcache as well in his series "unify swapin use swap cache and
cleanup flags"[1]. As a result, folio_ref_count() should never be 1
in this path, since at least two references are held (base ref plus
swapcache). Remove the folio_ref_count()==1 check and update the
comment accordingly.
[1] https://lore.kernel.org/all/20251220-swap-table-p2-v5-0-8862a265a033@tencent.com/
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
---
mm/memory.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/mm/memory.c b/mm/memory.c
index 487a34377a7b..ce8ef27e7a54 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5049,12 +5049,9 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
/*
* Same logic as in do_wp_page(); however, optimize for pages that are
- * certainly not shared either because we just allocated them without
- * exposing them to the swapcache or because the swap entry indicates
- * exclusivity.
+ * certainly not because the swap entry indicates exclusivity.
*/
- if (!folio_test_ksm(folio) &&
- (exclusive || folio_ref_count(folio) == 1)) {
+ if (!folio_test_ksm(folio) && exclusive) {
if ((vma->vm_flags & VM_WRITE) && !userfaultfd_pte_wp(vma, pte) &&
!pte_needs_soft_dirty_wp(vma, pte)) {
pte = pte_mkwrite(pte, vma);
--
2.39.3 (Apple Git-146)
^ permalink raw reply related [flat|nested] 4+ messages in thread* [RFC PATCH 3/3] mm: entirely remove lru_add_drain in do_swap_page
2026-06-11 10:51 [RFC PATCH 0/3] mm: drop redundant lru_add_drain in anon folio reuse paths Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 1/3] mm: avoid unnecessary lru drain for wp_can_reuse_anon_folio() Barry Song (Xiaomi)
2026-06-11 10:51 ` [RFC PATCH 2/3] mm: drop stale folio_ref_count()==1 check in do_swap_page reuse logic Barry Song (Xiaomi)
@ 2026-06-11 10:51 ` Barry Song (Xiaomi)
2 siblings, 0 replies; 4+ messages in thread
From: Barry Song (Xiaomi) @ 2026-06-11 10:51 UTC (permalink / raw)
To: akpm, linux-mm
Cc: linux-kernel, david, ljs, liam, vbabka, rppt, surenb, mhocko,
chrisl, kasong, shikemeng, nphamcs, baoquan.he, youngjun.park,
jp.kobryn, usama.arif, shakeel.butt, Barry Song (Xiaomi)
We are doing a lot of redundant lru_add_drain() calls in
do_swap_page(), especially for synchronous I/O devices. For
example, the test program below currently ends up draining
lru_cache 100% of the time:
int main(int argc, char *argv[])
{
int i;
#define SIZE 100*1024*1024
while(1) {
volatile int *p = mmap(0, SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
for (int i = 0; i < SIZE/sizeof(int); i++)
p[i] = i%64;
madvise((void *)p, SIZE, MADV_PAGEOUT);
for (int i = 0; i < SIZE/sizeof(int); i++)
p[i] = i%64;
munmap(p, SIZE);
}
return 0;
}
Folio reuse now relies primarily on the exclusive hint, making
lru_cache draining to drop the refcount in lru_cache largely
irrelevant.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
---
mm/memory.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/mm/memory.c b/mm/memory.c
index ce8ef27e7a54..b5a78670bcc8 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4903,16 +4903,6 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
} else if (folio != swapcache)
page = folio_page(folio, 0);
- /*
- * If we want to map a page that's in the swapcache writable, we
- * have to detect via the refcount if we're really the exclusive
- * owner. Try removing the extra reference from the local LRU
- * caches if required.
- */
- if ((vmf->flags & FAULT_FLAG_WRITE) &&
- !folio_test_ksm(folio) && !folio_test_lru(folio))
- lru_add_drain();
-
folio_throttle_swaprate(folio, GFP_KERNEL);
/*
--
2.39.3 (Apple Git-146)
^ permalink raw reply related [flat|nested] 4+ messages in thread