All of lore.kernel.org
 help / color / mirror / Atom feed
From: Minchan Kim <minchan@kernel.org>
To: "David Hildenbrand (Arm)" <david@kernel.org>
Cc: akpm@linux-foundation.org, mhocko@suse.com, brauner@kernel.org,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	surenb@google.com, timmurray@google.com
Subject: Re: [RFC 1/3] mm: process_mrelease: expedite clean file folio reclaim via mmu_gather
Date: Tue, 14 Apr 2026 13:21:04 -0700	[thread overview]
Message-ID: <ad6hsAPPCVlc2fsg@google.com> (raw)
In-Reply-To: <48cd6ee2-d650-4731-a40b-832a17b07237@kernel.org>

On Tue, Apr 14, 2026 at 09:45:42AM +0200, David Hildenbrand (Arm) wrote:
> On 4/14/26 00:39, Minchan Kim wrote:
> > Currently, process_mrelease() unmaps the pages but leaves clean file
> > folios on the LRU list, relying on standard memory reclaim to eventually
> > free them. This delays the immediate recovery of system memory under OOM
> > or container shutdown scenarios.
> 
> process_mrelease() calls __oom_reap_task_mm().
> 
> There, we skip any MAP_SHARED file mappings.
> 
> So I assume what you describe only applies to MAP_PRIVATE file mappings?
> What about MAP_SHARED?

That's true. My primary target was MAP_PRIVATE because MAP_SHARED pages
are often not exclusive to the target process.

> 
> Also "leaves ... on the LRU list" is rather confusing. They are not
> evicted and stay in the pagecache?

Yes, they are not evicted and remain in the pagecache, which is the
problem this patch addresses.

> 
> > 
> > This patch implements an expedited eviction mechanism for clean file
> > folios by integrating directly into the low-level TLB batching
> > infrastructure (mmu_gather).
> 
> Is this a complicated way of saying "Handle clean pagecache folios
> similar to swapcache folios in mmu_gather code, dropping them from the
> swapcache (i.e., evicting them) if they are completely unmapped during
> reaping"?

Much better description. Thanks.

> 
> > 
> > Instead of repeatedly locking and evicting folios one by one inside the
> > unmap loop (zap_present_folio_ptes), we pass the MMF_UNSTABLE flag
> > status down to free_pages_and_swap_cache(). Within this single unified
> > loop, anonymous pages are released via free_swap_cache(), and
> > file-backed folios are symmetrically truncated via mapping_evict_folio().
> 
> ... where you still evict them one-by-one. Rather confusing.

I initially considered implementing this within zap_present_folio_ptes,
but concluded that mmu_gather is the appropriate place.  To avoid
confusion, I will remove the "Instead of...unmap_loop" line in the next
revision.

> 
> > 
> > This avoids introducing unnecessary data structures, preserves TLB flush
> > safety, and removes duplicate tree traversals, resulting in an extremely
> > lean and highly responsive process_mrelease() implementation.
> 
> I don't think this paragraph adds a lot of value, really.
> 
> Which "duplicate tree traversal"? Which unnecessary data structures?

I had considered gathering these folios into a separate data structure
for cleanup, but realized mmu_gather is the best place to avoid
duplicate traversals for both anon and file folios.

> 
> Is that AI generated text? A lot of the stuff here reads AI generated. I
> yet have to meet a developer (not a sales person) that would just say
> "extremely lean and highly responsive process_mrelease() implementation"

That's too business words, I agree. Let me removing them.

> 
> If it is AI generated, throw it away and write it yourself from scratch.
> Use AI only to polish your English.
> 
> > 
> > Signed-off-by: Minchan Kim <minchan@kernel.org>
> > ---
> >  arch/s390/include/asm/tlb.h |  2 +-
> >  include/linux/swap.h        |  9 ++++++---
> >  mm/mmu_gather.c             |  8 +++++---
> >  mm/swap_state.c             | 19 +++++++++++++++++--
> >  4 files changed, 29 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
> > index 619fd41e710e..554842345ccd 100644
> > --- a/arch/s390/include/asm/tlb.h
> > +++ b/arch/s390/include/asm/tlb.h
> > @@ -62,7 +62,7 @@ static inline bool __tlb_remove_folio_pages(struct mmu_gather *tlb,
> >  	VM_WARN_ON_ONCE(delay_rmap);
> >  	VM_WARN_ON_ONCE(page_folio(page) != page_folio(page + nr_pages - 1));
> >  
> > -	free_pages_and_swap_cache(encoded_pages, ARRAY_SIZE(encoded_pages));
> > +	free_pages_and_caches(encoded_pages, ARRAY_SIZE(encoded_pages), false);
> 
> As we dislike boolean parameters, we either try to avoid them (e.g., use
> flags) or document the parameters using something like

I like your suggestion "try_evict_file_folios"

> 
> "/* parameter_name= */false"
> 
> >  	return false;
> >  }
> >  
> > diff --git a/include/linux/swap.h b/include/linux/swap.h
> > index 62fc7499b408..e7b929b062f8 100644
> > --- a/include/linux/swap.h
> > +++ b/include/linux/swap.h
> > @@ -433,7 +433,7 @@ static inline unsigned long total_swapcache_pages(void)
> >  
> >  void free_swap_cache(struct folio *folio);
> >  void free_folio_and_swap_cache(struct folio *folio);
> > -void free_pages_and_swap_cache(struct encoded_page **, int);
> > +void free_pages_and_caches(struct encoded_page **pages, int nr, bool free_unmapped_file);
> >  /* linux/mm/swapfile.c */
> >  extern atomic_long_t nr_swap_pages;
> >  extern long total_swap_pages;
> > @@ -510,8 +510,11 @@ static inline void put_swap_device(struct swap_info_struct *si)
> >  	do { (val)->freeswap = (val)->totalswap = 0; } while (0)
> >  #define free_folio_and_swap_cache(folio) \
> >  	folio_put(folio)
> > -#define free_pages_and_swap_cache(pages, nr) \
> > -	release_pages((pages), (nr));
> > +static inline void free_pages_and_caches(struct encoded_page **pages,
> > +		int nr, bool free_unmapped_file)
> > +{
> > +	release_pages(pages, nr);
> > +}
> 
> Why should !CONFIG_SWAP not take care of free_unmapped_file?

There is no reason to exclude it bust just missed this one.
I will make sure to address this in the next respin.

> 
> 
> >  
> >  static inline void free_swap_cache(struct folio *folio)
> >  {
> > diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c
> > index fe5b6a031717..5ce5824db07f 100644
> > --- a/mm/mmu_gather.c
> > +++ b/mm/mmu_gather.c
> > @@ -100,7 +100,8 @@ void tlb_flush_rmaps(struct mmu_gather *tlb, struct vm_area_struct *vma)
> >   */
> >  #define MAX_NR_FOLIOS_PER_FREE		512
> >  
> > -static void __tlb_batch_free_encoded_pages(struct mmu_gather_batch *batch)
> > +static void __tlb_batch_free_encoded_pages(struct mm_struct *mm,
> > +		struct mmu_gather_batch *batch)
> >  {
> >  	struct encoded_page **pages = batch->encoded_pages;
> >  	unsigned int nr, nr_pages;
> > @@ -135,7 +136,8 @@ static void __tlb_batch_free_encoded_pages(struct mmu_gather_batch *batch)
> >  			}
> >  		}
> >  
> > -		free_pages_and_swap_cache(pages, nr);
> > +		free_pages_and_caches(pages, nr,
> > +				      mm_flags_test(MMF_UNSTABLE, mm));
> >  		pages += nr;
> >  		batch->nr -= nr;
> >  
> > @@ -148,7 +150,7 @@ static void tlb_batch_pages_flush(struct mmu_gather *tlb)
> >  	struct mmu_gather_batch *batch;
> >  
> >  	for (batch = &tlb->local; batch && batch->nr; batch = batch->next)
> > -		__tlb_batch_free_encoded_pages(batch);
> > +		__tlb_batch_free_encoded_pages(tlb->mm, batch);
> >  	tlb->active = &tlb->local;
> >  }
> >  
> > diff --git a/mm/swap_state.c b/mm/swap_state.c
> > index 6d0eef7470be..e70a52ead6d3 100644
> > --- a/mm/swap_state.c
> > +++ b/mm/swap_state.c
> > @@ -400,11 +400,22 @@ void free_folio_and_swap_cache(struct folio *folio)
> >  		folio_put(folio);
> >  }
> >  
> > +static inline void free_file_cache(struct folio *folio)
> > +{
> > +	if (folio_trylock(folio)) {
> > +		mapping_evict_folio(folio_mapping(folio), folio);
> > +		folio_unlock(folio);
> > +	}
> > +}
> > +
> >  /*
> >   * Passed an array of pages, drop them all from swapcache and then release
> >   * them.  They are removed from the LRU and freed if this is their last use.
> > + *
> > + * If @free_unmapped_file is true, this function will proactively evict clean
> > + * file-backed folios if they are no longer mapped.
> 
> The parameter name is not really expressive.
> 
> You are not freeing unmapped files.
> 
> "try_evict_file_folios" maybe?

+1

Thanks.


  reply	other threads:[~2026-04-14 20:21 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-13 22:39 [RFC 0/3] mm: process_mrelease: expedited reclaim and auto-kill support Minchan Kim
2026-04-13 22:39 ` [RFC 1/3] mm: process_mrelease: expedite clean file folio reclaim via mmu_gather Minchan Kim
2026-04-14  7:45   ` David Hildenbrand (Arm)
2026-04-14 20:21     ` Minchan Kim [this message]
2026-04-13 22:39 ` [RFC 2/3] mm: process_mrelease: skip LRU movement for exclusive file folios Minchan Kim
2026-04-14  7:20   ` David Hildenbrand (Arm)
2026-04-14 20:22     ` Minchan Kim
2026-04-13 22:39 ` [RFC 3/3] mm: process_mrelease: introduce PROCESS_MRELEASE_REAP_KILL flag Minchan Kim
2026-04-16  9:13   ` Christian Brauner
2026-04-17  6:30     ` Minchan Kim
2026-04-17  7:04       ` Michal Hocko
2026-04-20 21:47         ` Minchan Kim
2026-04-23  7:17           ` Michal Hocko
2026-04-23 23:43             ` Minchan Kim
2026-04-24  7:38               ` Michal Hocko
2026-04-14  6:57 ` [RFC 0/3] mm: process_mrelease: expedited reclaim and auto-kill support Michal Hocko
2026-04-14 20:00   ` Minchan Kim
2026-04-15  7:38     ` Michal Hocko
2026-04-15 23:26       ` Minchan Kim
2026-04-16  6:54         ` Michal Hocko
2026-04-17  6:20           ` Minchan Kim
2026-04-17  7:11             ` Michal Hocko
2026-04-20 21:53               ` Minchan Kim
2026-04-23  7:50                 ` Michal Hocko
2026-04-23  9:49                   ` David Hildenbrand (Arm)
2026-04-23 22:36                     ` Suren Baghdasaryan
2026-04-24  0:08                       ` Minchan Kim
2026-04-24  7:40                       ` Michal Hocko
2026-04-24  7:41                       ` David Hildenbrand (Arm)
2026-04-27 16:14                         ` Suren Baghdasaryan
2026-04-23 23:58                   ` Minchan Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ad6hsAPPCVlc2fsg@google.com \
    --to=minchan@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=brauner@kernel.org \
    --cc=david@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@suse.com \
    --cc=surenb@google.com \
    --cc=timmurray@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.