mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v4] mm/page_alloc: avoid direct compaction for costly __GFP_NORETRY allocations
@ 2026-09-04 11:56 Salvatore Dipietro
  2026-09-04 14:11 ` Vlastimil Babka (SUSE)
                   ` (3 more replies)
  0 siblings, 4 replies; 39+ messages in thread
From: Salvatore Dipietro @ 2026-09-04 11:56 UTC (permalink / raw)
  To: linux-kernel, hch
  Cc: abuehaze, akpm, alisaidi, blakgeof, brauner, dgc,
	dipietro.salvatore, dipiets, djwong, hannes, jackmanb,
	linux-fsdevel, linux-mm, linux-xfs, mhocko, ritesh.list,
	rvvandan, stable, surenb, vbabka, willy, ziy, Vlastimil Babka,
	David Hildenbrand, Christoph Hellwig, Brendan Jackman

Commit 5d8edfb900d5 ("iomap: Copy larger chunks from userspace")
introduced high-order folio allocations in the iomap buffered write
path.  When memory is fragmented, each failed costly-order allocation
enters __alloc_pages_slowpath() which runs direct compaction and
drain_all_pages(), causing a 0.38x throughput drop on PostgreSQL
pgbench (simple-update) with 1024 clients on a 96-vCPU arm64 system.

The root issue is that direct compaction is too expensive for hot
allocation paths that have fallbacks to smaller allocations.
__filemap_get_folio_mpol() already marks higher-order allocations with
__GFP_NORETRY | __GFP_NOWARN, signalling that the caller can handle
failure.  However, the page allocator still attempts full direct
compaction for costly orders with __GFP_NORETRY, which is unnecessarily
aggressive when the caller will simply retry at a lower order.

For costly-order allocations with __GFP_NORETRY, clear
__GFP_DIRECT_RECLAIM at the very start of the slowpath, before
can_direct_reclaim, can_compact and the nofail checks are evaluated.
This makes the entire slowpath treat the request as non-blocking: no
direct reclaim, no direct compaction and no drain_all_pages() IPI
across every CPU. kswapd (and in turn kcompactd) is still woken further
down for background defragmentation, so compaction keeps working for
long-term system health while being removed from the latency-critical
direct allocation path.

Allocations that also request __GFP_THISNODE are exempted.  That flag
pairing identifies the local-node-first THP attempt issued by
alloc_pages_mpol() (mempolicy.c), which relies on direct compaction to
form transparent huge pages.

Test environment:
  Hardware:  AWS EC2 m8g.24xlarge (96 vCPU, arm64)
             12x 1TB IO2 32000 IOPS RAID0 XFS
  OS:        AL2023
  Kernel:    v7.3-rc1
  Database:  PostgreSQL 18.4
  Workload:  pgbench simple-update, 1024 clients, 96 threads, 1200s

Results (average of 3 runs, TPS):

  Config                   Avg TPS      % vs Baseline
  baseline (no patch)       59,408       -
  With this patch          155,409      +161.6%

Link: https://lore.kernel.org/all/20260403193535.9970-1-dipiets@amazon.it/T/#t [v1]
Link: https://lore.kernel.org/linux-mm/20260420161404.642-1-dipiets@amazon.it/T/#u [v2]
Link: https://lore.kernel.org/all/20260710143437.12379-1-dipiets@amazon.it/T/#u [v3]
Fixes: 5d8edfb900d5 ("iomap: Copy larger chunks from userspace")
Cc: stable@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: David Hildenbrand <david@redhat.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <dgc@kernel.org>
Cc: Ritesh Harjani <ritesh.list@gmail.com>
Cc: linux-mm@kvack.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Salvatore Dipietro <dipiets@amazon.it>
---
v4: Clear __GFP_DIRECT_RECLAIM early in the slowpath and exempt
    __GFP_THISNODE so THP attempt keeps using direct compaction
v3: Move to mm/page_alloc.c, wake kcompactd instead of avoiding it
v2: Move from fs/iomap/buffered-io.c to mm/filemap.c
v1: Avoid compaction in iomap folio allocation

 mm/page_alloc.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 12fac9084c48..542c2ec31061 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4784,10 +4784,10 @@ static inline struct page *
 __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
 						struct alloc_context *ac)
 {
-	bool can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM;
-	bool can_compact = can_direct_reclaim && gfp_compaction_allowed(gfp_mask);
-	bool nofail = gfp_mask & __GFP_NOFAIL;
 	const bool costly_order = order > PAGE_ALLOC_COSTLY_ORDER;
+	bool can_direct_reclaim;
+	bool can_compact;
+	bool nofail;
 	struct page *page = NULL;
 	unsigned int alloc_flags;
 	unsigned long did_some_progress;
@@ -4802,6 +4802,18 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
 	bool can_retry_reserves = true;
 	unsigned long alloc_start_time = jiffies;
 
+	/*
+	 * Costly __GFP_NORETRY callers have a cheap fallback, so don't stall
+	 * them in reclaim or compaction. __GFP_THISNODE callers are exempt.
+	 */
+	if (costly_order && (gfp_mask & __GFP_NORETRY) &&
+	    !(gfp_mask & __GFP_THISNODE))
+		gfp_mask &= ~__GFP_DIRECT_RECLAIM;
+
+	can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM;
+	can_compact = can_direct_reclaim && gfp_compaction_allowed(gfp_mask);
+	nofail = gfp_mask & __GFP_NOFAIL;
+
 	if (unlikely(nofail)) {
 		/*
 		 * Also we don't support __GFP_NOFAIL without __GFP_DIRECT_RECLAIM,
-- 
2.50.1




AMAZON DEVELOPMENT CENTER ITALY SRL, viale Monte Grappa 3/5, 20124 Milano, Italia, Registro delle Imprese di Milano Monza Brianza Lodi REA n. 2504859, Capitale Sociale: 10.000 EUR i.v., Cod. Fisc. e P.IVA 10100050961, Societa con Socio Unico




^ permalink raw reply	[flat|nested] 39+ messages in thread
* [PATCH v2 0/2] mm: page_alloc: fix reserve access for non-blocking requests
@ 2026-10-28 17:15 Johannes Weiner
  2026-10-28 17:15 ` [PATCH 1/2] mm: page_alloc: do not give all non-blocking requests reserve access Johannes Weiner
  0 siblings, 1 reply; 39+ messages in thread
From: Johannes Weiner @ 2026-10-28 17:15 UTC (permalink / raw)
  To: Andrew Morton, Vlastimil Babka
  Cc: Matthew Wilcox, Salvatore Dipietro, Christoph Hellwig,
	Dave Chinner, Matt Fleming, Mel Gorman, Michal Hocko,
	Suren Baghdasaryan, Brendan Jackman, Zi Yan, linux-mm,
	linux-kernel

Hi Andrew,

Two fixes for how non-blocking allocations interact with the
highatomic reserve. v1 was posted inside Salvatore's thread on
skipping direct reclaim and compaction for costly __GFP_NORETRY
allocations [1]. This is the same code as a standalone series, rebased
to mm-hotfixes-unstable, with the changelog clarifications from
review. Salvatore's patch is parked in mm-new behind these [2]:
mm-page_alloc-avoid-direct-reclaim-and-compaction-for-costly-__gfp_noretry-allocations.patch

Patch 1 narrows which requests may physically take highatomic pages,
patch 2 narrows which requests may count them in their watermark check.

Both are prerequisites for Salvatore's patch: it clears
__GFP_DIRECT_RECLAIM for costly __GFP_NORETRY requests, which turns
every large page cache folio allocation that reaches the slowpath into
a non-blocking one. Without patch 1, those requests may fall back to
the highatomic freelists reserved for atomic requests. Without patch
2, they count the free highatomic pages in their watermark check while
being served from regular memory, so they can consume regular
high-order blocks below the min watermark by the size of the
reserve. GFP_NOWAIT requests hit both paths today, so these are
existing problems worthy of their own stable backports; but
Salvatore's patch would widen them significantly.

Patch 2 reproduction: a GFP_NOWAIT burst under memory pressure can
drain regular free memory to zero while the highatomic reserve sits
idle. Measured on a 32G box with an anonymous working set, swap, and a
full 290M reserve, three synthetic bursts drove the 28G Normal zone's
regular free memory to 28M, 0.8M and 0.6M against a 60M min
watermark. Swapout failed its swap table allocation inside reclaim,
reclaim scanned 13M pages to free 200k, and page faults stalled for
tens to hundreds of milliseconds. With the fix the burst stops at the
min watermark and nothing else happens. This was found in review and
reproduced synthetically; it has not been observed in production.

GFP_ATOMIC order-0 requests have a milder version of the same problem:
They are entitled to the reserve but are served regular memory first,
so the fix there has to change the watermark check and the freelist
order together. Salvatore's change doesn't interact with this, though;
fixing that is left for a separate patch.

Changes since v1:
- rebased to mm-hotfixes-unstable (2026-10-27)
- 2/2: changelog states the bug was found in review and reproduced
  with a synthetic burst rather than observed in production
  (Vlastimil); notes the remaining GFP_ATOMIC order-0 problem as
  follow-up work
- kept the ALLOC_MASK_ATOMIC check inline in rmqueue_buddy() rather
  than adding a helper, as discussed: it pairs with the
  ALLOC_HIGHATOMIC attempt above it, which is what makes it order-0
  by construction

[1] https://lore.kernel.org/linux-mm/arFBWvzXPYrKuIYi@cmpxchg.org/
[2] https://lore.kernel.org/linux-mm/20261001082152.2879289-1-dipiets@amazon.it/

 mm/page_alloc.c |  4 +++-
 mm/page_alloc.h | 14 ++++++++------
 2 files changed, 11 insertions(+), 7 deletions(-)


^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2026-10-28 17:21 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 11:56 [PATCH v4] mm/page_alloc: avoid direct compaction for costly __GFP_NORETRY allocations Salvatore Dipietro
2026-09-04 14:11 ` Vlastimil Babka (SUSE)
2026-09-04 15:08   ` Zi Yan
2026-09-07  7:30     ` Vlastimil Babka (SUSE)
2026-09-09  2:33       ` Zi Yan
2026-09-09  8:51         ` Vlastimil Babka (SUSE)
2026-09-04 16:10 ` Johannes Weiner
2026-09-06  0:42 ` Andrew Morton
2026-09-06 23:05   ` Dave Chinner
2026-09-10 11:46   ` Salvatore Dipietro
2026-09-10 22:00     ` Andrew Morton
2026-09-11 14:30       ` Salvatore Dipietro
2026-09-11 15:59     ` Johannes Weiner
2026-09-16 11:24       ` Vlastimil Babka (SUSE)
2026-09-16 15:58         ` Johannes Weiner
2026-09-16 22:34           ` Andrew Morton
2026-09-16 22:35             ` Andrew Morton
2026-09-19  4:13               ` Matthew Wilcox
2026-09-21  9:35                 ` Vlastimil Babka (SUSE)
2026-09-23  9:25                   ` Salvatore Dipietro
2026-09-18  7:05           ` Vlastimil Babka (SUSE)
2026-09-18 21:28             ` Andrew Morton
2026-09-22  8:44               ` Vlastimil Babka (SUSE)
2026-09-21 14:37             ` Johannes Weiner
2026-09-21 14:38               ` [PATCH 1/2] mm: page_alloc: do not give all non-blocking requests reserve access Johannes Weiner
2026-09-21 14:54                 ` Matthew Wilcox
2026-09-21 15:58                   ` Johannes Weiner
2026-09-22 11:52                     ` Vlastimil Babka (SUSE)
2026-09-22 13:56                       ` Johannes Weiner
2026-09-24 14:34                         ` Vlastimil Babka (SUSE)
2026-09-21 14:39               ` [PATCH 2/2] mm: page_alloc: remove ALLOC_NON_BLOCK from ALLOC_RESERVES Johannes Weiner
2026-09-22 12:06                 ` Vlastimil Babka (SUSE)
2026-09-22 14:00                   ` Johannes Weiner
2026-10-27 15:00                 ` [PATCH 1/2] mm: page_alloc: do not give all non-blocking requests reserve access Salvatore Dipietro
2026-10-28 14:41                   ` Christoph Hellwig
2026-10-28 15:19                   ` Johannes Weiner
2026-10-28 17:21                     ` Johannes Weiner
2026-09-07  5:54 ` [PATCH v4] mm/page_alloc: avoid direct compaction for costly __GFP_NORETRY allocations Christoph Hellwig
2026-10-28 17:15 [PATCH v2 0/2] mm: page_alloc: fix reserve access for non-blocking requests Johannes Weiner
2026-10-28 17:15 ` [PATCH 1/2] mm: page_alloc: do not give all non-blocking requests reserve access Johannes Weiner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®