[PATCH v3 20/26] mm/page_alloc: introduce ALLOC_NOBLOCK
From: Brendan Jackman
Date: Sun Jul 26 2026 - 18:24:32 EST
This flag is set unless we can be sure the caller isn't in an atomic
context.
The allocator will soon start needing to call set_direct_map_* APIs
which cannot be called with IRQs off. It will need to do this even
before direct reclaim is possible.
Despite the fact that, in principle, ALLOC_NOBLOCK is distinct from
__GFP_DIRECT_RECLAIM, in order to avoid introducing a GFP flag, just
infer the former based on whether the caller set the latter. This means
that, in practice, ALLOC_NOBLOCK is just !__GFP_DIRECT_RECLAIM, except
that it is not influenced by gfp_allowed_mask. This requires some rather
ugly plumbing to get it into the slowpath without clobbering it.
Call it ALLOC_NOBLOCK in order to try and mitigate confusion vs the
recently-removed ALLOC_NON_BLOCK, which meant something different.
Signed-off-by: Brendan Jackman <jackmanb@xxxxxxxxxx>
---
mm/page_alloc.c | 23 +++++++++++++++++++----
mm/page_alloc.h | 1 +
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index fb522a09f2e60..ecdd3780192e8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5286,6 +5286,19 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
return page;
}
+/* Set alloc flags before applying gfp_allowed_mask. */
+static inline unsigned int init_alloc_flags(gfp_t gfp_mask, unsigned int alloc_flags)
+{
+ /*
+ * If the caller allowed __GFP_DIRECT_RECLAIM, they can't be atomic.
+ * Note this is a separate determination from whether direct reclaim is
+ * actually allowed, it must happen before applying gfp_allowed_mask.
+ */
+ if (!(gfp_mask & __GFP_DIRECT_RECLAIM))
+ alloc_flags |= ALLOC_NOBLOCK;
+ return alloc_flags;
+}
+
static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,
int preferred_nid, nodemask_t *nodemask,
struct alloc_context *ac, gfp_t *alloc_gfp,
@@ -5364,8 +5377,10 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,
struct zoneref *z;
struct per_cpu_pages *pcp;
struct list_head *pcp_list;
- struct alloc_context ac;
- unsigned int alloc_flags = ALLOC_WMARK_LOW;
+ struct alloc_context ac = {
+ .alloc_flags = init_alloc_flags(gfp, ALLOC_DEFAULT),
+ };
+ unsigned int alloc_flags = ac.alloc_flags | ALLOC_WMARK_LOW;
int nr_populated = 0, nr_account = 0;
/*
@@ -5584,9 +5599,9 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
struct page *page;
gfp_t alloc_gfp; /* The gfp_t that was actually used for allocation */
struct alloc_context ac = {
- .alloc_flags = alloc_flags,
+ .alloc_flags = init_alloc_flags(gfp, alloc_flags),
};
- unsigned int fastpath_alloc_flags = alloc_flags;
+ unsigned int fastpath_alloc_flags = ac.alloc_flags;
/* Other flags could be supported later if needed. */
if (WARN_ON(alloc_flags & ~(ALLOC_NOLOCK | ALLOC_NO_CODETAG)))
diff --git a/mm/page_alloc.h b/mm/page_alloc.h
index 2307b173a459f..02db12c9a1dc2 100644
--- a/mm/page_alloc.h
+++ b/mm/page_alloc.h
@@ -75,6 +75,7 @@
*/
#define ALLOC_UNMAPPED 0x2000
#endif
+#define ALLOC_NOBLOCK 0x4000 /* Caller may be atomic */
/* Flags that allow allocations below the min watermark. */
#define ALLOC_RESERVES (ALLOC_HARDER|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)
--
2.54.0