Re: [RFC PATCH v2 1/2] mm: allow smaller large folios to use lru_cache
From: Barry Song (Xiaomi)
Date: Wed Jul 29 2026 - 18:32:53 EST
On Wed, Jul 29, 2026 at 8:13 PM David Hildenbrand (Arm) <david@xxxxxxxxxx> wrote:
[...]
> > diff --git a/include/linux/swap.h b/include/linux/swap.h
> > index 8d19be675baf..9c5f7a11c7b0 100644
> > --- a/include/linux/swap.h
> > +++ b/include/linux/swap.h
> > @@ -316,9 +316,9 @@ static inline bool folio_may_be_lru_cached(struct folio *folio)
> > /*
> > * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.
> > * Holding small numbers of low-order mTHP folios in per-CPU LRU cache
> > - * will be sensible, but nobody has implemented and tested that yet.
> > + * will be sensible.
> > */
> > - return !folio_test_large(folio);
> > + return folio_order(folio) < PAGE_ALLOC_COSTLY_ORDER;
> > }
> >
> > extern atomic_t lru_disable_count;
>
> Sashiko rightfully raises that split_folio() can now fail more easily.
>
> So we might want to proactively drain (earlier?) on some more of the split paths.
Yes, this is a pain. I haven't tested it, but perhaps a
conceptual model could be something like this?
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 04e8a6b55343..fcd449dec96b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4069,6 +4069,8 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
struct folio *new_folio, *next;
int nr_shmem_dropped = 0;
enum ttu_flags ttu_flags = 0;
+ bool maybe_in_lru_cache;
+ int expected_ref_count;
int ret;
pgoff_t end = 0;
@@ -4154,7 +4156,15 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
* Racy check if we can split the page, before unmap_folio() will
* split PMDs
*/
- if (folio_expected_ref_count(folio) != folio_ref_count(folio) - 1) {
+ maybe_in_lru_cache = folio_may_be_lru_cached(folio) && !folio_test_lru(folio);
+ expected_ref_count = folio_expected_ref_count(folio);
+ if (expected_ref_count + maybe_in_lru_cache < folio_ref_count(folio) - 1) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+ if (maybe_in_lru_cache)
+ lru_add_drain_all();
+ if (expected_ref_count != folio_ref_count(folio) - 1) {
ret = -EAGAIN;
goto out_unlock;
}
Best Regards
Barry