Re: [PATCH v3] mm/page_alloc: avoid direct compaction for costly __GFP_NORETRY allocations

From: Matthew Wilcox

Date: Fri Jul 10 2026 - 14:03:58 EST


On Fri, Jul 10, 2026 at 02:34:37PM +0000, Salvatore Dipietro wrote:
> Commit 5d8edfb900d5 ("iomap: Copy larger chunks from userspace")
> introduced high-order folio allocations in the iomap buffered write
> path.

https://lore.kernel.org/linux-mm/aeZzP6iQel-tkZOu@xxxxxxxxxxxxxxxxxxxx/

I just had a go at implementing what I thought might be the right design
(having a folio_alloc_orders(min, max, gfp)), but that's not really what
__filemap_get_folio_mpol() wants because it needs to integrate the actual
adding of folios to the page cache into the retry loop.

So instead, let's try this. The idea is that we want to try direct reclaim
_twice_. Once gently (ie with NORETRY specified) when we're trying to
allocate the maximum order folio. But now that we've tried that once,
there's no point trying direct reclaim for other sizes, we just want to
ask the page allocator if it can give us memory of any subsequent size.

Until we come to the minimum order. Then we want to try exactly as hard
as we were originally asked to try. So revert to the original gfp flags
and don't set the NOWARN or NORETRY flags.

diff --git a/mm/filemap.c b/mm/filemap.c
index 58eb9d240643..23eecaf9b328 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1983,6 +1983,7 @@ struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
if (!folio && (fgp_flags & FGP_CREAT)) {
unsigned int min_order = mapping_min_folio_order(mapping);
unsigned int order = max(min_order, FGF_GET_ORDER(fgp_flags));
+ gfp_t alloc_gfp = gfp | __GFP_NORETRY | __GFP_NOWARN;
int err;
index = mapping_align_index(mapping, index);

@@ -2004,12 +2005,11 @@ struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
order = __ffs(index);

do {
- gfp_t alloc_gfp = gfp;
-
err = -ENOMEM;
- if (order > min_order)
- alloc_gfp |= __GFP_NORETRY | __GFP_NOWARN;
+ if (order == min_order)
+ alloc_gfp = gfp;
folio = filemap_alloc_folio(alloc_gfp, order, policy);
+ alloc_gfp &= ~__GFP_DIRECT_RECLAIM;
if (!folio)
continue;