| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/03 12:54 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING",
"CMA",
"PREEMPT_RT"
],
"FocusSymbols": [
"__alloc_frozen_pages_noprof",
"alloc_pages_node_noprof",
"alloc_pages_bulk_noprof",
"alloc_pages_nolock_noprof"
],
"Reasoning": "The patch modifies the core page allocator logic, specifically how allocation flags are passed and handled internally. It introduces an `alloc_flags` parameter to `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof`, replacing the internal `alloc_flags` variable. It also modifies `alloc_frozen_pages_nolock_noprof` to use `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`. It removes `__GFP_NO_OBJ_EXT` and replaces it with `ALLOC_NO_CODETAG` for memory allocation profiling. These are functional changes to the memory management subsystem that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/03 12:54 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 6dfe7850c5ea9108ced0b8273340ba220485ac33\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Jul 3 12:54:06 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/admin-guide/cgroup-v1/cpusets.rst b/Documentation/admin-guide/cgroup-v1/cpusets.rst\nindex c7909e5ac1361a..52a213aff04e5f 100644\n--- a/Documentation/admin-guide/cgroup-v1/cpusets.rst\n+++ b/Documentation/admin-guide/cgroup-v1/cpusets.rst\n@@ -284,7 +284,7 @@ take action.\n ==\u003e\n Unless this feature is enabled by writing \"1\" to the special file\n /dev/cpuset/memory_pressure_enabled, the hook in the rebalance\n- code of __alloc_pages() for this metric reduces to simply noticing\n+ code of the page allocator for this metric reduces to simply noticing\n that the cpuset_memory_pressure_enabled flag is zero. So only\n systems that enable this feature will compute the metric.\n \ndiff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst\nindex 23f8d13c2629d6..16f37135ed80df 100644\n--- a/Documentation/admin-guide/mm/transhuge.rst\n+++ b/Documentation/admin-guide/mm/transhuge.rst\n@@ -761,7 +761,7 @@ compact_fail\n \tbut failed.\n \n It is possible to establish how long the stalls were using the function\n-tracer to record how long was spent in __alloc_pages() and\n+tracer to record how long was spent in the page allocator and\n using the mm_page_alloc tracepoint to identify which allocations were\n for huge pages.\n \ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 29c302e9c17ba3..b359ff4e0a1a66 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17171,6 +17171,7 @@ F:\tmm/debug_page_alloc.c\n F:\tmm/debug_page_ref.c\n F:\tmm/fail_page_alloc.c\n F:\tmm/page_alloc.c\n+F:\tmm/page_alloc.h\n F:\tmm/page_ext.c\n F:\tmm/page_frag_cache.c\n F:\tmm/page_isolation.c\ndiff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c\nindex 91a093d8cf2e77..70be80211d8231 100644\n--- a/arch/x86/events/intel/ds.c\n+++ b/arch/x86/events/intel/ds.c\n@@ -832,7 +832,7 @@ static void *dsalloc_pages(size_t size, gfp_t flags, int cpu)\n \tint node = cpu_to_node(cpu);\n \tstruct page *page;\n \n-\tpage = __alloc_pages_node(node, flags | __GFP_ZERO, order);\n+\tpage = alloc_pages_node(node, flags | __GFP_ZERO, order);\n \treturn page ? page_address(page) : NULL;\n }\n \n@@ -1088,9 +1088,9 @@ void init_arch_pebs_on_cpu(int cpu)\n \n \t/*\n \t * 4KB-aligned pointer of the output buffer\n-\t * (__alloc_pages_node() return page aligned address)\n+\t * (alloc_pages_node() returns page aligned address)\n \t * Buffer Size = 4KB * 2^SIZE\n-\t * contiguous physical buffer (__alloc_pages_node() with order)\n+\t * contiguous physical buffer (alloc_pages_node() with order)\n \t */\n \tarch_pebs_base = virt_to_phys(cpuc-\u003epebs_vaddr) | PEBS_BUFFER_SHIFT;\n \twrmsrq_on_cpu(cpu, MSR_IA32_PEBS_BASE, arch_pebs_base);\ndiff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c\nindex 2325be57d3d75b..ad6a7fc6a54daf 100644\n--- a/arch/x86/kvm/vmx/vmx.c\n+++ b/arch/x86/kvm/vmx/vmx.c\n@@ -3028,7 +3028,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)\n \tstruct page *pages;\n \tstruct vmcs *vmcs;\n \n-\tpages = __alloc_pages_node(node, flags, 0);\n+\tpages = alloc_pages_node(node, flags, 0);\n \tif (!pages)\n \t\treturn NULL;\n \tvmcs = page_address(pages);\ndiff --git a/arch/x86/virt/hw.c b/arch/x86/virt/hw.c\nindex 7e9091c640be0b..a236447ac7a262 100644\n--- a/arch/x86/virt/hw.c\n+++ b/arch/x86/virt/hw.c\n@@ -196,7 +196,7 @@ static __init int __x86_vmx_init(void)\n \t\tstruct page *page;\n \t\tstruct vmcs *vmcs;\n \n-\t\tpage = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);\n+\t\tpage = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);\n \t\tif (WARN_ON_ONCE(!page)) {\n \t\t\tx86_vmx_exit();\n \t\t\treturn -ENOMEM;\ndiff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c\nindex 772c7872689327..79c2f00ed4d702 100644\n--- a/drivers/misc/sgi-xp/xpc_uv.c\n+++ b/drivers/misc/sgi-xp/xpc_uv.c\n@@ -170,9 +170,8 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,\n \tmq-\u003emmr_blade = uv_cpu_to_blade_id(cpu);\n \n \tnid = cpu_to_node(cpu);\n-\tpage = __alloc_pages_node(nid,\n-\t\t\t\t GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,\n-\t\t\t\t pg_order);\n+\tpage = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,\n+\t\t\t\tpg_order);\n \tif (page == NULL) {\n \t\tdev_err(xpc_part, \"xpc_create_gru_mq_uv() failed to alloc %d \"\n \t\t\t\"bytes of memory on nid=%d for GRU mq\\n\", mq_size, nid);\ndiff --git a/drivers/net/ethernet/fungible/funeth/funeth_rx.c b/drivers/net/ethernet/fungible/funeth/funeth_rx.c\nindex 7e2584895de39b..d7000017ac2bdc 100644\n--- a/drivers/net/ethernet/fungible/funeth/funeth_rx.c\n+++ b/drivers/net/ethernet/fungible/funeth/funeth_rx.c\n@@ -103,7 +103,7 @@ static int funeth_alloc_page(struct funeth_rxq *q, struct funeth_rxbuf *rb,\n \tif (cache_get(q, rb))\n \t\treturn 0;\n \n-\tp = __alloc_pages_node(node, gfp | __GFP_NOWARN, 0);\n+\tp = alloc_pages_node(node, gfp | __GFP_NOWARN, 0);\n \tif (unlikely(!p))\n \t\treturn -ENOMEM;\n \ndiff --git a/include/linux/alloc_tag.h b/include/linux/alloc_tag.h\nindex 068ba2e77c5d65..fcf90e6b242047 100644\n--- a/include/linux/alloc_tag.h\n+++ b/include/linux/alloc_tag.h\n@@ -163,11 +163,11 @@ static inline void alloc_tag_sub_check(union codetag_ref *ref)\n {\n \tWARN_ONCE(ref \u0026\u0026 !ref-\u003ect, \"alloc_tag was not set\\n\");\n }\n-void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags);\n+void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags);\n #else\n static inline void alloc_tag_add_check(union codetag_ref *ref, struct alloc_tag *tag) {}\n static inline void alloc_tag_sub_check(union codetag_ref *ref) {}\n-static inline void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags) {}\n+static inline void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags) {}\n #endif\n \n /* Caller should verify both ref and tag to be valid */\ndiff --git a/include/linux/gfp.h b/include/linux/gfp.h\nindex cdf95a9f0b87c1..4d57e9c0bf204d 100644\n--- a/include/linux/gfp.h\n+++ b/include/linux/gfp.h\n@@ -17,28 +17,6 @@ struct mempolicy;\n #define __default_gfp(a,b,...) b\n #define default_gfp(...) __default_gfp(,##__VA_ARGS__,GFP_KERNEL)\n \n-/* Convert GFP flags to their corresponding migrate type */\n-#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)\n-#define GFP_MOVABLE_SHIFT 3\n-\n-static inline int gfp_migratetype(const gfp_t gfp_flags)\n-{\n-\tVM_WARN_ON((gfp_flags \u0026 GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);\n-\tBUILD_BUG_ON((1UL \u003c\u003c GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);\n-\tBUILD_BUG_ON((___GFP_MOVABLE \u003e\u003e GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);\n-\tBUILD_BUG_ON((___GFP_RECLAIMABLE \u003e\u003e GFP_MOVABLE_SHIFT) != MIGRATE_RECLAIMABLE);\n-\tBUILD_BUG_ON(((___GFP_MOVABLE | ___GFP_RECLAIMABLE) \u003e\u003e\n-\t\t GFP_MOVABLE_SHIFT) != MIGRATE_HIGHATOMIC);\n-\n-\tif (unlikely(page_group_by_mobility_disabled))\n-\t\treturn MIGRATE_UNMOVABLE;\n-\n-\t/* Group based on mobility */\n-\treturn (__force unsigned long)(gfp_flags \u0026 GFP_MOVABLE_MASK) \u003e\u003e GFP_MOVABLE_SHIFT;\n-}\n-#undef GFP_MOVABLE_MASK\n-#undef GFP_MOVABLE_SHIFT\n-\n static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)\n {\n \treturn !!(gfp_flags \u0026 __GFP_DIRECT_RECLAIM);\n@@ -226,10 +204,6 @@ static inline void arch_free_page(struct page *page, int order) { }\n static inline void arch_alloc_page(struct page *page, int order) { }\n #endif\n \n-struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n-\t\tnodemask_t *nodemask);\n-#define __alloc_pages(...)\t\t\talloc_hooks(__alloc_pages_noprof(__VA_ARGS__))\n-\n struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n \t\tnodemask_t *nodemask);\n #define __folio_alloc(...)\t\t\talloc_hooks(__folio_alloc_noprof(__VA_ARGS__))\n@@ -278,21 +252,6 @@ static inline void warn_if_node_offline(int this_node, gfp_t gfp_mask)\n \tdump_stack();\n }\n \n-/*\n- * Allocate pages, preferring the node given as nid. The node must be valid and\n- * online. For more general interface, see alloc_pages_node().\n- */\n-static inline struct page *\n-__alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)\n-{\n-\tVM_BUG_ON(nid \u003c 0 || nid \u003e= MAX_NUMNODES);\n-\twarn_if_node_offline(nid, gfp_mask);\n-\n-\treturn __alloc_pages_noprof(gfp_mask, order, nid, NULL);\n-}\n-\n-#define __alloc_pages_node(...)\t\talloc_hooks(__alloc_pages_node_noprof(__VA_ARGS__))\n-\n static inline\n struct folio *__folio_alloc_node_noprof(gfp_t gfp, unsigned int order, int nid)\n {\n@@ -309,14 +268,7 @@ struct folio *__folio_alloc_node_noprof(gfp_t gfp, unsigned int order, int nid)\n * prefer the current CPU's closest node. Otherwise node must be valid and\n * online.\n */\n-static inline struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask,\n-\t\t\t\t\t\t unsigned int order)\n-{\n-\tif (nid == NUMA_NO_NODE)\n-\t\tnid = numa_mem_id();\n-\n-\treturn __alloc_pages_node_noprof(nid, gfp_mask, order);\n-}\n+struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order);\n \n #define alloc_pages_node(...)\t\t\talloc_hooks(alloc_pages_node_noprof(__VA_ARGS__))\n \n@@ -395,10 +347,6 @@ extern void free_pages(unsigned long addr, unsigned int order);\n #define __free_page(page) __free_pages((page), 0)\n #define free_page(addr) free_pages((addr), 0)\n \n-void page_alloc_init_cpuhp(void);\n-bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp);\n-void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);\n-void drain_all_pages(struct zone *zone);\n void drain_local_pages(struct zone *zone);\n \n void page_alloc_init_late(void);\ndiff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h\nindex 463b551d12d997..190191411009f2 100644\n--- a/include/linux/gfp_types.h\n+++ b/include/linux/gfp_types.h\n@@ -55,7 +55,6 @@ enum {\n #ifdef CONFIG_LOCKDEP\n \t___GFP_NOLOCKDEP_BIT,\n #endif\n-\t___GFP_NO_OBJ_EXT_BIT,\n \t___GFP_LAST_BIT\n };\n \n@@ -96,7 +95,6 @@ enum {\n #else\n #define ___GFP_NOLOCKDEP\t0\n #endif\n-#define ___GFP_NO_OBJ_EXT BIT(___GFP_NO_OBJ_EXT_BIT)\n \n /*\n * Physical address zone modifiers (see linux/mmzone.h - low four bits)\n@@ -138,17 +136,12 @@ enum {\n *\n * %__GFP_ACCOUNT causes the allocation to be accounted to the active\n * cgroup context.\n- *\n- * %__GFP_NO_OBJ_EXT causes slab allocation to have no object extension.\n- * mark_obj_codetag_empty() should be called upon freeing for objects allocated\n- * with this flag to indicate that their NULL tags are expected and normal.\n */\n #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)\n #define __GFP_WRITE\t((__force gfp_t)___GFP_WRITE)\n #define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)\n #define __GFP_THISNODE\t((__force gfp_t)___GFP_THISNODE)\n #define __GFP_ACCOUNT\t((__force gfp_t)___GFP_ACCOUNT)\n-#define __GFP_NO_OBJ_EXT ((__force gfp_t)___GFP_NO_OBJ_EXT)\n \n /**\n * DOC: Watermark modifiers\ndiff --git a/include/linux/skbuff.h b/include/linux/skbuff.h\nindex 22eda1d54a0e84..4431b026e429dc 100644\n--- a/include/linux/skbuff.h\n+++ b/include/linux/skbuff.h\n@@ -3573,7 +3573,7 @@ static inline struct page *__dev_alloc_pages_noprof(gfp_t gfp_mask,\n \t * 3. If requesting a order 0 page it will not be compound\n \t * due to the check to see if order has a value in prep_new_page\n \t * 4. __GFP_MEMALLOC is ignored if __GFP_NOMEMALLOC is set due to\n-\t * code in gfp_to_alloc_flags that should be enforcing this.\n+\t * code in alloc_flags_slowpath() that should be enforcing this.\n \t */\n \tgfp_mask |= __GFP_COMP | __GFP_MEMALLOC;\n \ndiff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h\nindex a6e5a44c9b4299..c1a05ff0feab00 100644\n--- a/include/trace/events/mmflags.h\n+++ b/include/trace/events/mmflags.h\n@@ -54,18 +54,10 @@\n # define TRACE_GFP_FLAGS_LOCKDEP\n #endif\n \n-#ifdef CONFIG_SLAB_OBJ_EXT\n-# define TRACE_GFP_FLAGS_SLAB\t\t\t\\\n-\tTRACE_GFP_EM(NO_OBJ_EXT)\n-#else\n-# define TRACE_GFP_FLAGS_SLAB\n-#endif\n-\n #define TRACE_GFP_FLAGS\t\t\t\t\\\n \tTRACE_GFP_FLAGS_GENERAL\t\t\t\\\n \tTRACE_GFP_FLAGS_KASAN\t\t\t\\\n-\tTRACE_GFP_FLAGS_LOCKDEP\t\t\t\\\n-\tTRACE_GFP_FLAGS_SLAB\n+\tTRACE_GFP_FLAGS_LOCKDEP\n \n #undef TRACE_GFP_EM\n #define TRACE_GFP_EM(a) TRACE_DEFINE_ENUM(___GFP_##a##_BIT);\ndiff --git a/mm/alloc_tag.c b/mm/alloc_tag.c\nindex d9be1cf5187d97..cf65e9992fda33 100644\n--- a/mm/alloc_tag.c\n+++ b/mm/alloc_tag.c\n@@ -15,6 +15,9 @@\n #include \u003clinux/vmalloc.h\u003e\n #include \u003clinux/kmemleak.h\u003e\n \n+#include \"internal.h\"\n+#include \"page_alloc.h\"\n+\n #define ALLOCINFO_FILE_NAME\t\t\"allocinfo\"\n #define MODULE_ALLOC_TAG_VMAP_SIZE\t(100000UL * sizeof(struct alloc_tag))\n #define SECTION_START(NAME)\t\t(CODETAG_SECTION_START_PREFIX NAME)\n@@ -783,19 +786,6 @@ struct pfn_pool {\n \n #define PFN_POOL_SIZE\t\t\t((PAGE_SIZE - offsetof(struct pfn_pool, pfns)) / \\\n \t\t\t\t\t sizeof(unsigned long))\n-\n-/*\n- * Skip early PFN recording for a page allocation. Reuses the\n- * %__GFP_NO_OBJ_EXT bit. Used by __alloc_tag_add_early_pfn() to avoid\n- * recursion when allocating pages for the early PFN tracking list\n- * itself.\n- *\n- * Codetags of the pages allocated with __GFP_NO_CODETAG should be\n- * cleared (via clear_page_tag_ref()) before freeing the pages to prevent\n- * alloc_tag_sub_check() from triggering a warning.\n- */\n-#define __GFP_NO_CODETAG\t\t__GFP_NO_OBJ_EXT\n-\n static struct pfn_pool *current_pfn_pool __initdata;\n \n static void __init __alloc_tag_add_early_pfn(unsigned long pfn)\n@@ -806,7 +796,8 @@ static void __init __alloc_tag_add_early_pfn(unsigned long pfn)\n \tdo {\n \t\tpool = READ_ONCE(current_pfn_pool);\n \t\tif (!pool || atomic_read(\u0026pool-\u003ecount) \u003e= PFN_POOL_SIZE) {\n-\t\t\tstruct page *new_page = alloc_page(__GFP_HIGH | __GFP_NO_CODETAG);\n+\t\t\tstruct page *new_page = __alloc_pages(__GFP_HIGH, 0, numa_mem_id(),\n+\t\t\t\t\t\t\t NULL, ALLOC_NO_CODETAG);\n \t\t\tstruct pfn_pool *new;\n \n \t\t\tif (!new_page) {\n@@ -837,7 +828,7 @@ typedef void alloc_tag_add_func(unsigned long pfn);\n static alloc_tag_add_func __rcu *alloc_tag_add_early_pfn_ptr __refdata =\n \tRCU_INITIALIZER(__alloc_tag_add_early_pfn);\n \n-void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags)\n+void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags)\n {\n \talloc_tag_add_func *alloc_tag_add;\n \n@@ -845,7 +836,7 @@ void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags)\n \t\treturn;\n \n \t/* Skip allocations for the tracking list itself to avoid recursion. */\n-\tif (gfp_flags \u0026 __GFP_NO_CODETAG)\n+\tif (alloc_flags \u0026 ALLOC_NO_CODETAG)\n \t\treturn;\n \n \trcu_read_lock();\ndiff --git a/mm/compaction.c b/mm/compaction.c\nindex f08765ade014ce..4b2318fad4eb59 100644\n--- a/mm/compaction.c\n+++ b/mm/compaction.c\n@@ -24,6 +24,7 @@\n #include \u003clinux/page_owner.h\u003e\n #include \u003clinux/psi.h\u003e\n #include \u003clinux/cpuset.h\u003e\n+#include \"page_alloc.h\"\n #include \"internal.h\"\n \n #ifdef CONFIG_COMPACTION\n@@ -82,7 +83,7 @@ static inline bool is_via_compact_memory(int order) { return false; }\n \n static struct page *mark_allocated_noprof(struct page *page, unsigned int order, gfp_t gfp_flags)\n {\n-\tpost_alloc_hook(page, order, __GFP_MOVABLE);\n+\tpost_alloc_hook(page, order, __GFP_MOVABLE, ALLOC_DEFAULT);\n \tset_page_refcounted(page);\n \treturn page;\n }\n@@ -1850,7 +1851,7 @@ static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long da\n \t}\n \tdst = (struct folio *)freepage;\n \n-\tpost_alloc_hook(\u0026dst-\u003epage, order, __GFP_MOVABLE);\n+\tpost_alloc_hook(\u0026dst-\u003epage, order, __GFP_MOVABLE, ALLOC_DEFAULT);\n \tset_page_refcounted(\u0026dst-\u003epage);\n \tif (order)\n \t\tprep_compound_page(\u0026dst-\u003epage, order);\ndiff --git a/mm/hugetlb.c b/mm/hugetlb.c\nindex 391739ca7f7117..48471503984c1c 100644\n--- a/mm/hugetlb.c\n+++ b/mm/hugetlb.c\n@@ -47,6 +47,7 @@\n #include \u003clinux/node.h\u003e\n #include \u003clinux/page_owner.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"hugetlb_vmemmap.h\"\n #include \"hugetlb_cma.h\"\n #include \"hugetlb_internal.h\"\n@@ -1789,7 +1790,8 @@ static struct folio *alloc_buddy_frozen_folio(int order, gfp_t gfp_mask,\n \tif (alloc_try_hard)\n \t\tgfp_mask |= __GFP_RETRY_MAYFAIL;\n \n-\tfolio = (struct folio *)__alloc_frozen_pages(gfp_mask, order, nid, nmask);\n+\tfolio = (struct folio *)__alloc_frozen_pages(gfp_mask, order, nid, nmask,\n+\t\t\t\t\t\t ALLOC_DEFAULT);\n \n \t/*\n \t * If we did not specify __GFP_RETRY_MAYFAIL, but still got a\ndiff --git a/mm/internal.h b/mm/internal.h\nindex fa4fb69444ecdc..0ae6ad22651252 100644\n--- a/mm/internal.h\n+++ b/mm/internal.h\n@@ -658,165 +658,6 @@ extern int defrag_mode;\n void setup_per_zone_wmarks(void);\n void calculate_min_free_kbytes(void);\n int __meminit init_per_zone_wmark_min(void);\n-void page_alloc_sysctl_init(void);\n-\n-/*\n- * Structure for holding the mostly immutable allocation parameters passed\n- * between functions involved in allocations, including the alloc_pages*\n- * family of functions.\n- *\n- * nodemask, migratetype and highest_zoneidx are initialized only once in\n- * __alloc_pages() and then never change.\n- *\n- * zonelist, preferred_zone and highest_zoneidx are set first in\n- * __alloc_pages() for the fast path, and might be later changed\n- * in __alloc_pages_slowpath(). All other functions pass the whole structure\n- * by a const pointer.\n- */\n-struct alloc_context {\n-\tstruct zonelist *zonelist;\n-\tconst nodemask_t *nodemask;\n-\tstruct zoneref *preferred_zoneref;\n-\tint migratetype;\n-\n-\t/*\n-\t * highest_zoneidx represents highest usable zone index of\n-\t * the allocation request. Due to the nature of the zone,\n-\t * memory on lower zone than the highest_zoneidx will be\n-\t * protected by lowmem_reserve[highest_zoneidx].\n-\t *\n-\t * highest_zoneidx is also used by reclaim/compaction to limit\n-\t * the target zone since higher zone than this index cannot be\n-\t * usable for this allocation request.\n-\t */\n-\tenum zone_type highest_zoneidx;\n-\tbool spread_dirty_pages;\n-};\n-\n-/*\n- * This function returns the order of a free page in the buddy system. In\n- * general, page_zone(page)-\u003elock must be held by the caller to prevent the\n- * page from being allocated in parallel and returning garbage as the order.\n- * If a caller does not hold page_zone(page)-\u003elock, it must guarantee that the\n- * page cannot be allocated or merged in parallel. Alternatively, it must\n- * handle invalid values gracefully, and use buddy_order_unsafe() below.\n- */\n-static inline unsigned int buddy_order(struct page *page)\n-{\n-\t/* PageBuddy() must be checked by the caller */\n-\treturn page_private(page);\n-}\n-\n-/*\n- * Like buddy_order(), but for callers who cannot afford to hold the zone lock.\n- * PageBuddy() should be checked first by the caller to minimize race window,\n- * and invalid values must be handled gracefully.\n- *\n- * READ_ONCE is used so that if the caller assigns the result into a local\n- * variable and e.g. tests it for valid range before using, the compiler cannot\n- * decide to remove the variable and inline the page_private(page) multiple\n- * times, potentially observing different values in the tests and the actual\n- * use of the result.\n- */\n-#define buddy_order_unsafe(page)\tREAD_ONCE(page_private(page))\n-\n-/*\n- * This function checks whether a page is free \u0026\u0026 is the buddy\n- * we can coalesce a page and its buddy if\n- * (a) the buddy is not in a hole (check before calling!) \u0026\u0026\n- * (b) the buddy is in the buddy system \u0026\u0026\n- * (c) a page and its buddy have the same order \u0026\u0026\n- * (d) a page and its buddy are in the same zone.\n- *\n- * For recording whether a page is in the buddy system, we set PageBuddy.\n- * Setting, clearing, and testing PageBuddy is serialized by zone-\u003elock.\n- *\n- * For recording page's order, we use page_private(page).\n- */\n-static inline bool page_is_buddy(struct page *page, struct page *buddy,\n-\t\t\t\t unsigned int order)\n-{\n-\tif (!page_is_guard(buddy) \u0026\u0026 !PageBuddy(buddy))\n-\t\treturn false;\n-\n-\tif (buddy_order(buddy) != order)\n-\t\treturn false;\n-\n-\t/*\n-\t * zone check is done late to avoid uselessly calculating\n-\t * zone/node ids for pages that could never merge.\n-\t */\n-\tif (page_zone_id(page) != page_zone_id(buddy))\n-\t\treturn false;\n-\n-\tVM_BUG_ON_PAGE(page_count(buddy) != 0, buddy);\n-\n-\treturn true;\n-}\n-\n-/*\n- * Locate the struct page for both the matching buddy in our\n- * pair (buddy1) and the combined O(n+1) page they form (page).\n- *\n- * 1) Any buddy B1 will have an order O twin B2 which satisfies\n- * the following equation:\n- * B2 = B1 ^ (1 \u003c\u003c O)\n- * For example, if the starting buddy (buddy2) is #8 its order\n- * 1 buddy is #10:\n- * B2 = 8 ^ (1 \u003c\u003c 1) = 8 ^ 2 = 10\n- *\n- * 2) Any buddy B will have an order O+1 parent P which\n- * satisfies the following equation:\n- * P = B \u0026 ~(1 \u003c\u003c O)\n- *\n- * Assumption: *_mem_map is contiguous at least up to MAX_PAGE_ORDER\n- */\n-static inline unsigned long\n-__find_buddy_pfn(unsigned long page_pfn, unsigned int order)\n-{\n-\treturn page_pfn ^ (1 \u003c\u003c order);\n-}\n-\n-/*\n- * Find the buddy of @page and validate it.\n- * @page: The input page\n- * @pfn: The pfn of the page, it saves a call to page_to_pfn() when the\n- * function is used in the performance-critical __free_one_page().\n- * @order: The order of the page\n- * @buddy_pfn: The output pointer to the buddy pfn, it also saves a call to\n- * page_to_pfn().\n- *\n- * The found buddy can be a non PageBuddy, out of @page's zone, or its order is\n- * not the same as @page. The validation is necessary before use it.\n- *\n- * Return: the found buddy page or NULL if not found.\n- */\n-static inline struct page *find_buddy_page_pfn(struct page *page,\n-\t\t\tunsigned long pfn, unsigned int order, unsigned long *buddy_pfn)\n-{\n-\tunsigned long __buddy_pfn = __find_buddy_pfn(pfn, order);\n-\tstruct page *buddy;\n-\n-\tbuddy = page + (__buddy_pfn - pfn);\n-\tif (buddy_pfn)\n-\t\t*buddy_pfn = __buddy_pfn;\n-\n-\tif (page_is_buddy(page, buddy, order))\n-\t\treturn buddy;\n-\treturn NULL;\n-}\n-\n-extern struct page *__pageblock_pfn_to_page(unsigned long start_pfn,\n-\t\t\t\tunsigned long end_pfn, struct zone *zone);\n-\n-static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn,\n-\t\t\t\tunsigned long end_pfn, struct zone *zone)\n-{\n-\tif (zone-\u003econtiguous)\n-\t\treturn pfn_to_page(start_pfn);\n-\n-\treturn __pageblock_pfn_to_page(start_pfn, end_pfn, zone);\n-}\n \n void set_zone_contiguous(struct zone *zone);\n bool pfn_range_intersects_zones(int nid, unsigned long start_pfn,\n@@ -831,8 +672,6 @@ extern int __isolate_free_page(struct page *page, unsigned int order);\n extern void __putback_isolated_page(struct page *page, unsigned int order,\n \t\t\t\t int mt);\n extern void memblock_free_pages(unsigned long pfn, unsigned int order);\n-extern void __free_pages_core(struct page *page, unsigned int order,\n-\t\tenum meminit_context context);\n \n /*\n * This will have no effect, other than possibly generating a warning, if the\n@@ -914,40 +753,6 @@ static inline void init_compound_tail(struct page *tail,\n \tprep_compound_tail(tail, head, order);\n }\n \n-void post_alloc_hook(struct page *page, unsigned int order, gfp_t gfp_flags);\n-extern bool free_pages_prepare(struct page *page, unsigned int order);\n-\n-extern int user_min_free_kbytes;\n-\n-struct page *__alloc_frozen_pages_noprof(gfp_t, unsigned int order, int nid,\n-\t\tnodemask_t *);\n-#define __alloc_frozen_pages(...) \\\n-\talloc_hooks(__alloc_frozen_pages_noprof(__VA_ARGS__))\n-void free_frozen_pages(struct page *page, unsigned int order);\n-void free_unref_folios(struct folio_batch *fbatch);\n-\n-#ifdef CONFIG_NUMA\n-struct page *alloc_frozen_pages_noprof(gfp_t, unsigned int order);\n-#else\n-static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)\n-{\n-\treturn __alloc_frozen_pages_noprof(gfp, order, numa_node_id(), NULL);\n-}\n-#endif\n-\n-#define alloc_frozen_pages(...) \\\n-\talloc_hooks(alloc_frozen_pages_noprof(__VA_ARGS__))\n-\n-struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);\n-#define alloc_frozen_pages_nolock(...) \\\n-\talloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))\n-void free_frozen_pages_nolock(struct page *page, unsigned int order);\n-\n-extern void zone_pcp_reset(struct zone *zone);\n-extern void zone_pcp_disable(struct zone *zone);\n-extern void zone_pcp_enable(struct zone *zone);\n-extern void zone_pcp_init(struct zone *zone);\n-\n extern void *memmap_alloc(phys_addr_t size, phys_addr_t align,\n \t\t\t phys_addr_t min_addr,\n \t\t\t int nid, bool exact_nid);\n@@ -1101,23 +906,6 @@ static inline void init_cma_pageblock(struct page *page)\n }\n #endif\n \n-enum fallback_result {\n-\t/* Found suitable migratetype, *mt_out is valid. */\n-\tFALLBACK_FOUND,\n-\t/* No fallback found in requested order. */\n-\tFALLBACK_EMPTY,\n-\t/* Passed @claimable, but claiming whole block is a bad idea. */\n-\tFALLBACK_NOCLAIM,\n-};\n-enum fallback_result\n-find_suitable_fallback(struct free_area *area, unsigned int order,\n-\t\t int migratetype, bool claimable, int *mt_out);\n-\n-static inline bool free_area_empty(struct free_area *area, int migratetype)\n-{\n-\treturn list_empty(\u0026area-\u003efree_list[migratetype]);\n-}\n-\n /* mm/util.c */\n struct anon_vma *folio_anon_vma(const struct folio *folio);\n \n@@ -1445,46 +1233,6 @@ extern unsigned long __must_check vm_mmap_pgoff(struct file *, unsigned long,\n unsigned long reclaim_pages(struct list_head *folio_list);\n unsigned int reclaim_clean_pages_from_list(struct zone *zone,\n \t\t\t\t\t struct list_head *folio_list);\n-/* The ALLOC_WMARK bits are used as an index to zone-\u003ewatermark */\n-#define ALLOC_WMARK_MIN\t\tWMARK_MIN\n-#define ALLOC_WMARK_LOW\t\tWMARK_LOW\n-#define ALLOC_WMARK_HIGH\tWMARK_HIGH\n-#define ALLOC_NO_WATERMARKS\t0x04 /* don't check watermarks at all */\n-\n-/* Mask to get the watermark bits */\n-#define ALLOC_WMARK_MASK\t(ALLOC_NO_WATERMARKS-1)\n-\n-/*\n- * Only MMU archs have async oom victim reclaim - aka oom_reaper so we\n- * cannot assume a reduced access to memory reserves is sufficient for\n- * !MMU\n- */\n-#ifdef CONFIG_MMU\n-#define ALLOC_OOM\t\t0x08\n-#else\n-#define ALLOC_OOM\t\tALLOC_NO_WATERMARKS\n-#endif\n-\n-#define ALLOC_NON_BLOCK\t\t 0x10 /* Caller cannot block. Allow access\n-\t\t\t\t * to 25% of the min watermark or\n-\t\t\t\t * 62.5% if __GFP_HIGH is set.\n-\t\t\t\t */\n-#define ALLOC_MIN_RESERVE\t 0x20 /* __GFP_HIGH set. Allow access to 50%\n-\t\t\t\t * of the min watermark.\n-\t\t\t\t */\n-#define ALLOC_CPUSET\t\t 0x40 /* check for correct cpuset */\n-#define ALLOC_CMA\t\t 0x80 /* allow allocations from CMA areas */\n-#ifdef CONFIG_ZONE_DMA32\n-#define ALLOC_NOFRAGMENT\t0x100 /* avoid mixing pageblock types */\n-#else\n-#define ALLOC_NOFRAGMENT\t 0x0\n-#endif\n-#define ALLOC_HIGHATOMIC\t0x200 /* Allows access to MIGRATE_HIGHATOMIC */\n-#define ALLOC_TRYLOCK\t\t0x400 /* Only use spin_trylock in allocation path */\n-#define ALLOC_KSWAPD\t\t0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */\n-\n-/* Flags that allow allocations below the min watermark. */\n-#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)\n \n enum ttu_flags;\n struct tlbflush_unmap_batch;\n@@ -1968,4 +1716,27 @@ static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)\n \t}\n }\n \n+static inline bool can_spin_trylock(void)\n+{\n+\t/*\n+\t * In PREEMPT_RT spin_trylock() will call raw_spin_lock() which is\n+\t * unsafe in NMI. If spin_trylock() is called from hard IRQ the current\n+\t * task may be waiting for one rt_spin_lock, but rt_spin_trylock() will\n+\t * mark the task as the owner of another rt_spin_lock which will\n+\t * confuse PI logic, so return immediately if called from hard IRQ or\n+\t * NMI.\n+\t *\n+\t * Note, irqs_disabled() case is ok. spin_trylock() can be called\n+\t * from raw_spin_lock_irqsave region.\n+\t */\n+\tif (IS_ENABLED(CONFIG_PREEMPT_RT) \u0026\u0026 (in_nmi() || in_hardirq()))\n+\t\treturn false;\n+\n+\t/* On UP, spin_trylock() always succeeds even when it is locked */\n+\tif (!IS_ENABLED(CONFIG_SMP) \u0026\u0026 in_nmi())\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n #endif\t/* __MM_INTERNAL_H */\ndiff --git a/mm/khugepaged.c b/mm/khugepaged.c\nindex 617bca76db49b6..58e14d1543ecb4 100644\n--- a/mm/khugepaged.c\n+++ b/mm/khugepaged.c\n@@ -26,6 +26,7 @@\n \n #include \u003casm/tlb.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"mm_slot.h\"\n \n enum scan_result {\ndiff --git a/mm/kmsan/init.c b/mm/kmsan/init.c\nindex b14ce3417e65e4..4983b6e9f7c998 100644\n--- a/mm/kmsan/init.c\n+++ b/mm/kmsan/init.c\n@@ -13,7 +13,7 @@\n #include \u003clinux/mm.h\u003e\n #include \u003clinux/memblock.h\u003e\n \n-#include \"../internal.h\"\n+#include \"../page_alloc.h\"\n \n #define NUM_FUTURE_RANGES 128\n struct start_end_pair {\ndiff --git a/mm/memory-failure.c b/mm/memory-failure.c\nindex 4916ab14532573..bf717ec595087d 100644\n--- a/mm/memory-failure.c\n+++ b/mm/memory-failure.c\n@@ -66,6 +66,7 @@\n #include \u003ctrace/events/memory-failure.h\u003e\n \n #include \"swap.h\"\n+#include \"page_alloc.h\"\n #include \"internal.h\"\n \n static int sysctl_memory_failure_early_kill __read_mostly;\ndiff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c\nindex 8b137328dcf014..11ab2f7bc7f3b8 100644\n--- a/mm/memory_hotplug.c\n+++ b/mm/memory_hotplug.c\n@@ -40,6 +40,7 @@\n #include \u003casm/tlbflush.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"shuffle.h\"\n \n enum {\ndiff --git a/mm/mempolicy.c b/mm/mempolicy.c\nindex bba65898aee175..914f81863db5a6 100644\n--- a/mm/mempolicy.c\n+++ b/mm/mempolicy.c\n@@ -119,6 +119,7 @@\n #include \u003clinux/memory.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n \n /* Internal flags */\n #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL \u003c\u003c 0)\t/* Skip checks for continuous vmas */\n@@ -2416,9 +2417,11 @@ static struct page *alloc_pages_preferred_many(gfp_t gfp, unsigned int order,\n \t */\n \tpreferred_gfp = gfp | __GFP_NOWARN;\n \tpreferred_gfp \u0026= ~(__GFP_DIRECT_RECLAIM | __GFP_NOFAIL);\n-\tpage = __alloc_frozen_pages_noprof(preferred_gfp, order, nid, nodemask);\n+\tpage = __alloc_frozen_pages_noprof(preferred_gfp, order, nid, nodemask,\n+\t\t\t\t\t ALLOC_DEFAULT);\n \tif (!page)\n-\t\tpage = __alloc_frozen_pages_noprof(gfp, order, nid, NULL);\n+\t\tpage = __alloc_frozen_pages_noprof(gfp, order, nid, NULL,\n+\t\t\t\t\t\t ALLOC_DEFAULT);\n \n \treturn page;\n }\n@@ -2466,7 +2469,7 @@ static struct page *alloc_pages_mpol(gfp_t gfp, unsigned int order,\n \t\t\t */\n \t\t\tpage = __alloc_frozen_pages_noprof(\n \t\t\t\tgfp | __GFP_THISNODE | __GFP_NORETRY, order,\n-\t\t\t\tnid, NULL);\n+\t\t\t\tnid, NULL, ALLOC_DEFAULT);\n \t\t\tif (page || !(gfp \u0026 __GFP_DIRECT_RECLAIM))\n \t\t\t\treturn page;\n \t\t\t/*\n@@ -2478,7 +2481,7 @@ static struct page *alloc_pages_mpol(gfp_t gfp, unsigned int order,\n \t\t}\n \t}\n \n-\tpage = __alloc_frozen_pages_noprof(gfp, order, nid, nodemask);\n+\tpage = __alloc_frozen_pages_noprof(gfp, order, nid, nodemask, ALLOC_DEFAULT);\n \n \tif (unlikely(pol-\u003emode == MPOL_INTERLEAVE ||\n \t\t pol-\u003emode == MPOL_WEIGHTED_INTERLEAVE) \u0026\u0026 page) {\ndiff --git a/mm/migrate.c b/mm/migrate.c\nindex a786549551e3d0..db50e7b66fbf8f 100644\n--- a/mm/migrate.c\n+++ b/mm/migrate.c\n@@ -49,6 +49,7 @@\n #include \u003ctrace/events/migrate.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"swap.h\"\n \n static const struct movable_operations *offline_movable_ops;\ndiff --git a/mm/mm_init.c b/mm/mm_init.c\nindex 07a8c74cf7ade1..537664974ab1c0 100644\n--- a/mm/mm_init.c\n+++ b/mm/mm_init.c\n@@ -33,6 +33,7 @@\n #include \u003clinux/kexec_handover.h\u003e\n #include \u003clinux/hugetlb.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"slab.h\"\n #include \"shuffle.h\"\n \ndiff --git a/mm/page_alloc.c b/mm/page_alloc.c\nindex 762d9b6bc792f1..a63733dac659e3 100644\n--- a/mm/page_alloc.c\n+++ b/mm/page_alloc.c\n@@ -56,6 +56,7 @@\n #include \u003clinux/pgalloc_tag.h\u003e\n #include \u003casm/div64.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"shuffle.h\"\n #include \"page_reporting.h\"\n \n@@ -1248,7 +1249,7 @@ void __clear_page_tag_ref(struct page *page)\n /* Should be called only if mem_alloc_profiling_enabled() */\n static noinline\n void __pgalloc_tag_add(struct page *page, struct task_struct *task,\n-\t\t unsigned int nr, gfp_t gfp_flags)\n+\t\t unsigned int nr, unsigned int alloc_flags)\n {\n \tunion pgtag_ref_handle handle;\n \tunion codetag_ref ref;\n@@ -1262,17 +1263,17 @@ void __pgalloc_tag_add(struct page *page, struct task_struct *task,\n \t\t * page_ext is not available yet, record the pfn so we can\n \t\t * clear the tag ref later when page_ext is initialized.\n \t\t */\n-\t\talloc_tag_add_early_pfn(page_to_pfn(page), gfp_flags);\n+\t\talloc_tag_add_early_pfn(page_to_pfn(page), alloc_flags);\n \t\tif (task-\u003ealloc_tag)\n \t\t\talloc_tag_set_inaccurate(task-\u003ealloc_tag);\n \t}\n }\n \n static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,\n-\t\t\t\t unsigned int nr, gfp_t gfp_flags)\n+\t\t\t\t unsigned int nr, unsigned int alloc_flags)\n {\n \tif (mem_alloc_profiling_enabled())\n-\t\t__pgalloc_tag_add(page, task, nr, gfp_flags);\n+\t\t__pgalloc_tag_add(page, task, nr, alloc_flags);\n }\n \n /* Should be called only if mem_alloc_profiling_enabled() */\n@@ -1305,7 +1306,7 @@ static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr)\n #else /* CONFIG_MEM_ALLOC_PROFILING */\n \n static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,\n-\t\t\t\t unsigned int nr, gfp_t gfp_flags) {}\n+\t\t\t\t unsigned int nr, unsigned int alloc_flags) {}\n static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {}\n static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {}\n \n@@ -1809,7 +1810,7 @@ static inline bool should_skip_init(gfp_t flags)\n }\n \n inline void post_alloc_hook(struct page *page, unsigned int order,\n-\t\t\t\tgfp_t gfp_flags)\n+\t\t\t\tgfp_t gfp_flags, unsigned int alloc_flags)\n {\n \tconst bool zero_tags = gfp_flags \u0026 __GFP_ZEROTAGS;\n \tbool init = !want_init_on_free() \u0026\u0026 want_init_on_alloc(gfp_flags) \u0026\u0026\n@@ -1860,13 +1861,13 @@ inline void post_alloc_hook(struct page *page, unsigned int order,\n \n \tset_page_owner(page, order, gfp_flags);\n \tpage_table_check_alloc(page, order);\n-\tpgalloc_tag_add(page, current, 1 \u003c\u003c order, gfp_flags);\n+\tpgalloc_tag_add(page, current, 1 \u003c\u003c order, alloc_flags);\n }\n \n static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,\n \t\t\t\t\t\t\tunsigned int alloc_flags)\n {\n-\tpost_alloc_hook(page, order, gfp_flags);\n+\tpost_alloc_hook(page, order, gfp_flags, alloc_flags);\n \n \tif (order \u0026\u0026 (gfp_flags \u0026 __GFP_COMP))\n \t\tprep_compound_page(page, order);\n@@ -2530,7 +2531,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,\n \tunsigned long flags;\n \tint i;\n \n-\tif (unlikely(alloc_flags \u0026 ALLOC_TRYLOCK)) {\n+\tif (unlikely(alloc_flags \u0026 ALLOC_NOLOCK)) {\n \t\tif (!spin_trylock_irqsave(\u0026zone-\u003elock, flags))\n \t\t\treturn 0;\n \t} else {\n@@ -3218,7 +3219,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,\n \n \tdo {\n \t\tpage = NULL;\n-\t\tif (unlikely(alloc_flags \u0026 ALLOC_TRYLOCK)) {\n+\t\tif (unlikely(alloc_flags \u0026 ALLOC_NOLOCK)) {\n \t\t\tif (!spin_trylock_irqsave(\u0026zone-\u003elock, flags))\n \t\t\t\treturn NULL;\n \t\t} else {\n@@ -3774,14 +3775,13 @@ alloc_flags_nofragment(struct zone *zone, gfp_t gfp_mask)\n }\n \n /* Must be called after current_gfp_context() which can change gfp_mask */\n-static inline unsigned int gfp_to_alloc_flags_cma(gfp_t gfp_mask,\n-\t\t\t\t\t\t unsigned int alloc_flags)\n+static inline unsigned int alloc_flags_cma(gfp_t gfp_mask)\n {\n #ifdef CONFIG_CMA\n \tif (gfp_migratetype(gfp_mask) == MIGRATE_MOVABLE)\n-\t\talloc_flags |= ALLOC_CMA;\n+\t\treturn ALLOC_CMA;\n #endif\n-\treturn alloc_flags;\n+\treturn ALLOC_DEFAULT;\n }\n \n /*\n@@ -4077,7 +4077,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,\n \t */\n \tpage = get_page_from_freelist((gfp_mask | __GFP_HARDWALL) \u0026\n \t\t\t\t ~__GFP_DIRECT_RECLAIM, order,\n-\t\t\t\t ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac);\n+\t\t\t\t ac-\u003ealloc_flags|ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac);\n \tif (page)\n \t\tgoto out;\n \n@@ -4123,7 +4123,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,\n \t\t */\n \t\tif (gfp_mask \u0026 __GFP_NOFAIL)\n \t\t\tpage = __alloc_pages_cpuset_fallback(gfp_mask, order,\n-\t\t\t\t\tALLOC_NO_WATERMARKS, ac);\n+\t\t\t\t\tac-\u003ealloc_flags|ALLOC_NO_WATERMARKS, ac);\n \t}\n out:\n \tmutex_unlock(\u0026oom_lock);\n@@ -4474,7 +4474,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask,\n }\n \n static inline unsigned int\n-gfp_to_alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)\n+alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)\n {\n \tunsigned int alloc_flags = 0;\n \n@@ -4497,7 +4497,7 @@ gfp_to_alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)\n }\n \n static inline unsigned int\n-gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)\n+alloc_flags_slowpath(gfp_t gfp_mask, unsigned int order)\n {\n \tunsigned int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;\n \n@@ -4512,7 +4512,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)\n \tif (gfp_mask \u0026 __GFP_KSWAPD_RECLAIM)\n \t\talloc_flags |= ALLOC_KSWAPD;\n \n-\talloc_flags |= gfp_to_alloc_flags_nonblocking(gfp_mask, order);\n+\talloc_flags |= alloc_flags_nonblocking(gfp_mask, order);\n \n \tif (!(gfp_mask \u0026 __GFP_DIRECT_RECLAIM)) {\n \t\t/*\n@@ -4525,7 +4525,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)\n \t} else if (unlikely(rt_or_dl_task(current)) \u0026\u0026 in_task())\n \t\talloc_flags |= ALLOC_MIN_RESERVE;\n \n-\talloc_flags = gfp_to_alloc_flags_cma(gfp_mask, alloc_flags);\n+\talloc_flags |= alloc_flags_cma(gfp_mask);\n \n \tif (defrag_mode)\n \t\talloc_flags |= ALLOC_NOFRAGMENT;\n@@ -4790,8 +4790,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\n \t * The fast path uses conservative alloc_flags to succeed only until\n \t * kswapd needs to be woken up, and to avoid the cost of setting up\n \t * alloc_flags precisely. So we do that now.\n+\t *\n+\t * Can't just or alloc_flags if it contains WMARK bits, but those flags\n+\t * shouldn't be set in ac-\u003ealloc_flags.\n \t */\n-\talloc_flags = gfp_to_alloc_flags(gfp_mask, order);\n+\tVM_WARN_ON(ac-\u003ealloc_flags \u0026 ALLOC_WMARK_MASK);\n+\talloc_flags = ac-\u003ealloc_flags | alloc_flags_slowpath(gfp_mask, order);\n \n \t/*\n \t * We need to recalculate the starting point for the zonelist iterator\n@@ -4832,8 +4836,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\n \n \treserve_flags = __gfp_pfmemalloc_flags(gfp_mask);\n \tif (reserve_flags)\n-\t\talloc_flags = gfp_to_alloc_flags_cma(gfp_mask, reserve_flags) |\n-\t\t\t\t\t (alloc_flags \u0026 ALLOC_KSWAPD);\n+\t\talloc_flags = alloc_flags_cma(gfp_mask) | reserve_flags |\n+\t\t\t\tac-\u003ealloc_flags | (alloc_flags \u0026 ALLOC_KSWAPD);\n \n \t/*\n \t * Reset the nodemask and zonelist iterators if memory policies can be\n@@ -5002,6 +5006,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\n \t * we always retry\n \t */\n \tif (unlikely(nofail)) {\n+\t\tunsigned int alloc_flags = ac-\u003ealloc_flags | ALLOC_MIN_RESERVE;\n+\n \t\t/*\n \t\t * Lacking direct_reclaim we can't do anything to reclaim memory,\n \t\t * we disregard these unreasonable nofail requests and still\n@@ -5017,7 +5023,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\n \t\t * could deplete whole memory reserves which would just make\n \t\t * the situation worse.\n \t\t */\n-\t\tpage = __alloc_pages_cpuset_fallback(gfp_mask, order, ALLOC_MIN_RESERVE, ac);\n+\t\tpage = __alloc_pages_cpuset_fallback(gfp_mask, order, alloc_flags, ac);\n \t\tif (page)\n \t\t\tgoto got_pg;\n \n@@ -5059,11 +5065,11 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,\n \t * Don't invoke should_fail logic, since it may call\n \t * get_random_u32() and printk() which need to spin_lock.\n \t */\n-\tif (!(*alloc_flags \u0026 ALLOC_TRYLOCK) \u0026\u0026\n+\tif (!(*alloc_flags \u0026 ALLOC_NOLOCK) \u0026\u0026\n \t should_fail_alloc_page(gfp_mask, order))\n \t\treturn false;\n \n-\t*alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, *alloc_flags);\n+\t*alloc_flags |= alloc_flags_cma(gfp_mask);\n \n \t/* Dirty zone balancing only done in the fast path */\n \tac-\u003espread_dirty_pages = (gfp_mask \u0026 __GFP_WRITE);\n@@ -5221,7 +5227,7 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n \t\t}\n \t\tnr_account++;\n \n-\t\tprep_new_page(page, 0, gfp, 0);\n+\t\tprep_new_page(page, 0, gfp, ALLOC_DEFAULT);\n \t\tset_page_refcounted(page);\n \t\tpage_array[nr_populated++] = page;\n \t}\n@@ -5235,7 +5241,7 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n \treturn nr_populated;\n \n failed:\n-\tpage = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask);\n+\tpage = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask, ALLOC_DEFAULT);\n \tif (page)\n \t\tpage_array[nr_populated++] = page;\n \tgoto out;\n@@ -5270,24 +5276,87 @@ void free_pages_bulk(struct page **page_array, unsigned long nr_pages)\n \t}\n }\n \n+static inline bool alloc_order_allowed(gfp_t gfp, unsigned int order,\n+\t\t\t\t unsigned int alloc_flags)\n+{\n+\tif (alloc_flags \u0026 ALLOC_NOLOCK)\n+\t\treturn pcp_allowed_order(order);\n+\n+\t/*\n+\t * There are several places where we assume that the order value is sane\n+\t * so bail out early if the request is out of bound.\n+\t */\n+\treturn !(WARN_ON_ONCE_GFP(order \u003e MAX_PAGE_ORDER, gfp));\n+}\n+\n+static inline bool alloc_nolock_allowed(void)\n+{\n+\tif (!can_spin_trylock())\n+\t\treturn false;\n+\n+\t/* Bailout, since _deferred_grow_zone() needs to take a lock */\n+\tif (deferred_pages_enabled())\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n+/*\n+ * GFP flags to set for ALLOC_NOLOCK i.e. alloc_pages_nolock().\n+ *\n+ * Do not specify __GFP_DIRECT_RECLAIM, since direct claim is not allowed.\n+ * Do not specify __GFP_KSWAPD_RECLAIM either, since wake up of kswapd\n+ * is not safe in arbitrary context.\n+ *\n+ * These two are the conditions for gfpflags_allow_spinning() being true.\n+ *\n+ * Specify __GFP_NOWARN since failing alloc_pages_nolock() is not a reason\n+ * to warn. Also warn would trigger printk() which is unsafe from\n+ * various contexts. We cannot use printk_deferred_enter() to mitigate,\n+ * since the running context is unknown.\n+ *\n+ * Specify __GFP_ZERO to make sure that call to kmsan_alloc_page() below\n+ * is safe in any context. Also zeroing the page is mandatory for\n+ * BPF use cases.\n+ *\n+ * Though __GFP_NOMEMALLOC is not checked in the code path below,\n+ * specify it here to highlight that alloc_pages_nolock()\n+ * doesn't want to deplete reserves.\n+ */\n+static const gfp_t gfp_nolock = __GFP_NOWARN | __GFP_ZERO | __GFP_NOMEMALLOC |\n+\t\t\t\t__GFP_COMP;\n+\n /*\n * This is the 'heart' of the zoned buddy allocator.\n */\n struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n-\t\tint preferred_nid, nodemask_t *nodemask)\n+\t\tint preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)\n {\n \tstruct page *page;\n-\tunsigned int alloc_flags = ALLOC_WMARK_LOW;\n \tgfp_t alloc_gfp; /* The gfp_t that was actually used for allocation */\n-\tstruct alloc_context ac = { };\n+\tstruct alloc_context ac = {\n+\t\t.alloc_flags = alloc_flags,\n+\t};\n+\tunsigned int fastpath_alloc_flags = alloc_flags;\n \n-\t/*\n-\t * There are several places where we assume that the order value is sane\n-\t * so bail out early if the request is out of bound.\n-\t */\n-\tif (WARN_ON_ONCE_GFP(order \u003e MAX_PAGE_ORDER, gfp))\n+\t/* Other flags could be supported later if needed. */\n+\tif (WARN_ON(alloc_flags \u0026 ~(ALLOC_NOLOCK | ALLOC_NO_CODETAG)))\n+\t\treturn NULL;\n+\n+\tif (!alloc_order_allowed(gfp, order, alloc_flags))\n \t\treturn NULL;\n \n+\tif (alloc_flags \u0026 ALLOC_NOLOCK) {\n+\t\t/* Certain other flags could be supported later if needed. */\n+\t\tVM_WARN_ON_ONCE(gfp \u0026 ~(__GFP_ACCOUNT | gfp_nolock));\n+\t\tif (!alloc_nolock_allowed())\n+\t\t\treturn NULL;\n+\t\tgfp |= gfp_nolock;\n+\t\tfastpath_alloc_flags |= ALLOC_WMARK_MIN;\n+\t} else {\n+\t\tfastpath_alloc_flags |= ALLOC_WMARK_LOW;\n+\t}\n+\n \tgfp \u0026= gfp_allowed_mask;\n \t/*\n \t * Apply scoped allocation constraints. This is mainly about GFP_NOFS\n@@ -5299,19 +5368,22 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n \tgfp = current_gfp_context(gfp);\n \talloc_gfp = gfp;\n \tif (!prepare_alloc_pages(gfp, order, preferred_nid, nodemask, \u0026ac,\n-\t\t\t\u0026alloc_gfp, \u0026alloc_flags))\n+\t\t\t\u0026alloc_gfp, \u0026fastpath_alloc_flags))\n \t\treturn NULL;\n \n-\t/*\n-\t * Forbid the first pass from falling back to types that fragment\n-\t * memory until all local zones are considered.\n-\t */\n-\talloc_flags |= alloc_flags_nofragment(zonelist_zone(ac.preferred_zoneref), gfp);\n-\talloc_flags |= gfp_to_alloc_flags_nonblocking(gfp, order) \u0026 ALLOC_HIGHATOMIC;\n+\tif (!(alloc_flags \u0026 ALLOC_NOLOCK)) {\n+\t\t/*\n+\t\t * Forbid the first pass from falling back to types that\n+\t\t * fragment memory until all local zones are considered.\n+\t\t */\n+\t\tfastpath_alloc_flags |= alloc_flags_nofragment(\n+\t\t\tzonelist_zone(ac.preferred_zoneref), gfp);\n+\t}\n+\tfastpath_alloc_flags |= alloc_flags_nonblocking(gfp, order) \u0026 ALLOC_HIGHATOMIC;\n \n-\t/* First allocation attempt */\n-\tpage = get_page_from_freelist(alloc_gfp, order, alloc_flags, \u0026ac);\n-\tif (likely(page))\n+\t/* First allocation attempt (or, for nolock, only attempt) */\n+\tpage = get_page_from_freelist(alloc_gfp, order, fastpath_alloc_flags, \u0026ac);\n+\tif (likely(page) || (alloc_flags \u0026 ALLOC_NOLOCK))\n \t\tgoto out;\n \n \talloc_gfp = gfp;\n@@ -5328,7 +5400,8 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n out:\n \tif (memcg_kmem_online() \u0026\u0026 (gfp \u0026 __GFP_ACCOUNT) \u0026\u0026 page \u0026\u0026\n \t unlikely(__memcg_kmem_charge_page(page, gfp, order) != 0)) {\n-\t\tfree_frozen_pages(page, order);\n+\t\t__free_frozen_pages(page, order,\n+\t\t\t\t alloc_flags \u0026 ALLOC_NOLOCK ? FPI_TRYLOCK : 0);\n \t\tpage = NULL;\n \t}\n \n@@ -5340,22 +5413,34 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n EXPORT_SYMBOL(__alloc_frozen_pages_noprof);\n \n struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,\n-\t\tint preferred_nid, nodemask_t *nodemask)\n+\t\tint preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)\n {\n \tstruct page *page;\n \n-\tpage = __alloc_frozen_pages_noprof(gfp, order, preferred_nid, nodemask);\n+\tpage = __alloc_frozen_pages_noprof(gfp, order, preferred_nid, nodemask,\n+\t\t\t\t\t alloc_flags);\n \tif (page)\n \t\tset_page_refcounted(page);\n \treturn page;\n }\n-EXPORT_SYMBOL(__alloc_pages_noprof);\n+\n+struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)\n+{\n+\tif (nid == NUMA_NO_NODE)\n+\t\tnid = numa_mem_id();\n+\n+\tVM_BUG_ON(nid \u003c 0 || nid \u003e= MAX_NUMNODES);\n+\twarn_if_node_offline(nid, gfp_mask);\n+\n+\treturn __alloc_pages_noprof(gfp_mask, order, nid, NULL, ALLOC_DEFAULT);\n+}\n+EXPORT_SYMBOL(alloc_pages_node_noprof);\n \n struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n \t\tnodemask_t *nodemask)\n {\n \tstruct page *page = __alloc_pages_noprof(gfp | __GFP_COMP, order,\n-\t\t\t\t\tpreferred_nid, nodemask);\n+\t\t\t\t\tpreferred_nid, nodemask, ALLOC_DEFAULT);\n \treturn page_rmappable_folio(page);\n }\n EXPORT_SYMBOL(__folio_alloc_noprof);\n@@ -7037,7 +7122,7 @@ static void split_free_frozen_pages(struct list_head *list, gfp_t gfp_mask)\n \t\tlist_for_each_entry_safe(page, next, \u0026list[order], lru) {\n \t\t\tint i;\n \n-\t\t\tpost_alloc_hook(page, order, gfp_mask);\n+\t\t\tpost_alloc_hook(page, order, gfp_mask, ALLOC_DEFAULT);\n \t\t\tif (!order)\n \t\t\t\tcontinue;\n \n@@ -7242,7 +7327,7 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,\n \t\tstruct page *head = pfn_to_page(start);\n \n \t\tcheck_new_pages(head, order);\n-\t\tprep_new_page(head, order, gfp_mask, 0);\n+\t\tprep_new_page(head, order, gfp_mask, ALLOC_DEFAULT);\n \t} else {\n \t\tret = -EINVAL;\n \t\tWARN(true, \"PFN range: requested [%lu, %lu), allocated [%lu, %lu)\\n\",\n@@ -7804,7 +7889,7 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order,\n \t\treturn false;\n \n \t/* Bailout, since try_to_accept_memory_one() needs to take a lock */\n-\tif (alloc_flags \u0026 ALLOC_TRYLOCK)\n+\tif (alloc_flags \u0026 ALLOC_NOLOCK)\n \t\treturn false;\n \n \twmark = promo_wmark_pages(zone);\n@@ -7874,80 +7959,10 @@ static bool __free_unaccepted(struct page *page)\n \n struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\n {\n-\t/*\n-\t * Do not specify __GFP_DIRECT_RECLAIM, since direct claim is not allowed.\n-\t * Do not specify __GFP_KSWAPD_RECLAIM either, since wake up of kswapd\n-\t * is not safe in arbitrary context.\n-\t *\n-\t * These two are the conditions for gfpflags_allow_spinning() being true.\n-\t *\n-\t * Specify __GFP_NOWARN since failing alloc_pages_nolock() is not a reason\n-\t * to warn. Also warn would trigger printk() which is unsafe from\n-\t * various contexts. We cannot use printk_deferred_enter() to mitigate,\n-\t * since the running context is unknown.\n-\t *\n-\t * Specify __GFP_ZERO to make sure that call to kmsan_alloc_page() below\n-\t * is safe in any context. Also zeroing the page is mandatory for\n-\t * BPF use cases.\n-\t *\n-\t * Though __GFP_NOMEMALLOC is not checked in the code path below,\n-\t * specify it here to highlight that alloc_pages_nolock()\n-\t * doesn't want to deplete reserves.\n-\t */\n-\tgfp_t alloc_gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_NOMEMALLOC | __GFP_COMP\n-\t\t\t| gfp_flags;\n-\tunsigned int alloc_flags = ALLOC_TRYLOCK;\n-\tstruct alloc_context ac = { };\n-\tstruct page *page;\n-\n-\tVM_WARN_ON_ONCE(gfp_flags \u0026 ~__GFP_ACCOUNT);\n-\t/*\n-\t * In PREEMPT_RT spin_trylock() will call raw_spin_lock() which is\n-\t * unsafe in NMI. If spin_trylock() is called from hard IRQ the current\n-\t * task may be waiting for one rt_spin_lock, but rt_spin_trylock() will\n-\t * mark the task as the owner of another rt_spin_lock which will\n-\t * confuse PI logic, so return immediately if called from hard IRQ or\n-\t * NMI.\n-\t *\n-\t * Note, irqs_disabled() case is ok. This function can be called\n-\t * from raw_spin_lock_irqsave region.\n-\t */\n-\tif (IS_ENABLED(CONFIG_PREEMPT_RT) \u0026\u0026 (in_nmi() || in_hardirq()))\n-\t\treturn NULL;\n-\n-\t/* On UP, spin_trylock() always succeeds even when it is locked */\n-\tif (!IS_ENABLED(CONFIG_SMP) \u0026\u0026 in_nmi())\n-\t\treturn NULL;\n-\n-\tif (!pcp_allowed_order(order))\n-\t\treturn NULL;\n-\n-\t/* Bailout, since _deferred_grow_zone() needs to take a lock */\n-\tif (deferred_pages_enabled())\n-\t\treturn NULL;\n-\n \tif (nid == NUMA_NO_NODE)\n \t\tnid = numa_node_id();\n \n-\tprepare_alloc_pages(alloc_gfp, order, nid, NULL, \u0026ac,\n-\t\t\t \u0026alloc_gfp, \u0026alloc_flags);\n-\n-\t/*\n-\t * Best effort allocation from percpu free list.\n-\t * If it's empty attempt to spin_trylock zone-\u003elock.\n-\t */\n-\tpage = get_page_from_freelist(alloc_gfp, order, alloc_flags, \u0026ac);\n-\n-\t/* Unlike regular alloc_pages() there is no __alloc_pages_slowpath(). */\n-\n-\tif (memcg_kmem_online() \u0026\u0026 page \u0026\u0026 (gfp_flags \u0026 __GFP_ACCOUNT) \u0026\u0026\n-\t unlikely(__memcg_kmem_charge_page(page, alloc_gfp, order) != 0)) {\n-\t\t__free_frozen_pages(page, order, FPI_TRYLOCK);\n-\t\tpage = NULL;\n-\t}\n-\ttrace_mm_page_alloc(page, order, alloc_gfp, ac.migratetype);\n-\tkmsan_alloc_page(page, order, alloc_gfp);\n-\treturn page;\n+\treturn __alloc_frozen_pages_noprof(gfp_flags, order, nid, NULL, ALLOC_NOLOCK);\n }\n /**\n * alloc_pages_nolock - opportunistic reentrant allocation from any context\ndiff --git a/mm/page_alloc.h b/mm/page_alloc.h\nnew file mode 100644\nindex 00000000000000..b9259deddb59d7\n--- /dev/null\n+++ b/mm/page_alloc.h\n@@ -0,0 +1,312 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * mm-internal API for the page (buddy) allocator. Public API lives in\n+ * include/linux/gfp.h.\n+ */\n+#ifndef __MM_PAGE_ALLOC_H\n+#define __MM_PAGE_ALLOC_H\n+\n+#include \u003clinux/mm.h\u003e\n+#include \u003clinux/mmzone.h\u003e\n+#include \u003clinux/nodemask.h\u003e\n+#include \u003clinux/types.h\u003e\n+\n+#define ALLOC_DEFAULT\t\t0\n+/* The ALLOC_WMARK bits are used as an index to zone-\u003ewatermark */\n+#define ALLOC_WMARK_MIN\t\tWMARK_MIN\n+#define ALLOC_WMARK_LOW\t\tWMARK_LOW\n+#define ALLOC_WMARK_HIGH\tWMARK_HIGH\n+#define ALLOC_NO_WATERMARKS\t0x04 /* don't check watermarks at all */\n+\n+/* Mask to get the watermark bits */\n+#define ALLOC_WMARK_MASK\t(ALLOC_NO_WATERMARKS-1)\n+\n+/*\n+ * Only MMU archs have async oom victim reclaim - aka oom_reaper so we\n+ * cannot assume a reduced access to memory reserves is sufficient for\n+ * !MMU\n+ */\n+#ifdef CONFIG_MMU\n+#define ALLOC_OOM\t\t0x08\n+#else\n+#define ALLOC_OOM\t\tALLOC_NO_WATERMARKS\n+#endif\n+\n+#define ALLOC_NON_BLOCK\t\t 0x10 /* Caller cannot block. Allow access\n+\t\t\t\t * to 25% of the min watermark or\n+\t\t\t\t * 62.5% if __GFP_HIGH is set.\n+\t\t\t\t */\n+#define ALLOC_MIN_RESERVE\t 0x20 /* __GFP_HIGH set. Allow access to 50%\n+\t\t\t\t * of the min watermark.\n+\t\t\t\t */\n+#define ALLOC_CPUSET\t\t 0x40 /* check for correct cpuset */\n+#define ALLOC_CMA\t\t 0x80 /* allow allocations from CMA areas */\n+#ifdef CONFIG_ZONE_DMA32\n+#define ALLOC_NOFRAGMENT\t0x100 /* avoid mixing pageblock types */\n+#else\n+#define ALLOC_NOFRAGMENT\t 0x0\n+#endif\n+#define ALLOC_HIGHATOMIC\t0x200 /* Allows access to MIGRATE_HIGHATOMIC */\n+#define ALLOC_NOLOCK\t\t0x400 /* Only use spin_trylock in allocation path */\n+#define ALLOC_KSWAPD\t\t0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */\n+/*\n+ * Avoid alloc_tag recursion for internal allocations.\n+ *\n+ * Callers must clear_page_tag_ref() before freeing to avoid warnings from\n+ * alloc_tag_sub_check().\n+ */\n+#define ALLOC_NO_CODETAG 0x1000\n+\n+/* Flags that allow allocations below the min watermark. */\n+#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)\n+\n+/*\n+ * Structure for holding the mostly immutable allocation parameters passed\n+ * between functions involved in allocations, including the alloc_pages*\n+ * family of functions.\n+ *\n+ * nodemask, migratetype and highest_zoneidx are initialized only once in\n+ * __alloc_pages() and then never change.\n+ *\n+ * zonelist, preferred_zone and highest_zoneidx are set first in\n+ * __alloc_pages() for the fast path, and might be later changed\n+ * in __alloc_pages_slowpath(). All other functions pass the whole structure\n+ * by a const pointer.\n+ */\n+struct alloc_context {\n+\tstruct zonelist *zonelist;\n+\tconst nodemask_t *nodemask;\n+\tstruct zoneref *preferred_zoneref;\n+\tint migratetype;\n+\n+\t/*\n+\t * highest_zoneidx represents highest usable zone index of\n+\t * the allocation request. Due to the nature of the zone,\n+\t * memory on lower zone than the highest_zoneidx will be\n+\t * protected by lowmem_reserve[highest_zoneidx].\n+\t *\n+\t * highest_zoneidx is also used by reclaim/compaction to limit\n+\t * the target zone since higher zone than this index cannot be\n+\t * usable for this allocation request.\n+\t */\n+\tenum zone_type highest_zoneidx;\n+\tbool spread_dirty_pages;\n+\t/* Only flags that are global to the whole allocation go here. */\n+\tunsigned int alloc_flags;\n+};\n+\n+/*\n+ * This function returns the order of a free page in the buddy system. In\n+ * general, page_zone(page)-\u003elock must be held by the caller to prevent the\n+ * page from being allocated in parallel and returning garbage as the order.\n+ * If a caller does not hold page_zone(page)-\u003elock, it must guarantee that the\n+ * page cannot be allocated or merged in parallel. Alternatively, it must\n+ * handle invalid values gracefully, and use buddy_order_unsafe() below.\n+ */\n+static inline unsigned int buddy_order(struct page *page)\n+{\n+\t/* PageBuddy() must be checked by the caller */\n+\treturn page_private(page);\n+}\n+\n+/*\n+ * Like buddy_order(), but for callers who cannot afford to hold the zone lock.\n+ * PageBuddy() should be checked first by the caller to minimize race window,\n+ * and invalid values must be handled gracefully.\n+ *\n+ * READ_ONCE is used so that if the caller assigns the result into a local\n+ * variable and e.g. tests it for valid range before using, the compiler cannot\n+ * decide to remove the variable and inline the page_private(page) multiple\n+ * times, potentially observing different values in the tests and the actual\n+ * use of the result.\n+ */\n+#define buddy_order_unsafe(page)\tREAD_ONCE(page_private(page))\n+\n+/*\n+ * This function checks whether a page is free \u0026\u0026 is the buddy\n+ * we can coalesce a page and its buddy if\n+ * (a) the buddy is not in a hole (check before calling!) \u0026\u0026\n+ * (b) the buddy is in the buddy system \u0026\u0026\n+ * (c) a page and its buddy have the same order \u0026\u0026\n+ * (d) a page and its buddy are in the same zone.\n+ *\n+ * For recording whether a page is in the buddy system, we set PageBuddy.\n+ * Setting, clearing, and testing PageBuddy is serialized by zone-\u003elock.\n+ *\n+ * For recording page's order, we use page_private(page).\n+ */\n+static inline bool page_is_buddy(struct page *page, struct page *buddy,\n+\t\t\t\t unsigned int order)\n+{\n+\tif (!page_is_guard(buddy) \u0026\u0026 !PageBuddy(buddy))\n+\t\treturn false;\n+\n+\tif (buddy_order(buddy) != order)\n+\t\treturn false;\n+\n+\t/*\n+\t * zone check is done late to avoid uselessly calculating\n+\t * zone/node ids for pages that could never merge.\n+\t */\n+\tif (page_zone_id(page) != page_zone_id(buddy))\n+\t\treturn false;\n+\n+\tVM_BUG_ON_PAGE(page_count(buddy) != 0, buddy);\n+\n+\treturn true;\n+}\n+\n+/*\n+ * Locate the struct page for both the matching buddy in our\n+ * pair (buddy1) and the combined O(n+1) page they form (page).\n+ *\n+ * 1) Any buddy B1 will have an order O twin B2 which satisfies\n+ * the following equation:\n+ * B2 = B1 ^ (1 \u003c\u003c O)\n+ * For example, if the starting buddy (buddy2) is #8 its order\n+ * 1 buddy is #10:\n+ * B2 = 8 ^ (1 \u003c\u003c 1) = 8 ^ 2 = 10\n+ *\n+ * 2) Any buddy B will have an order O+1 parent P which\n+ * satisfies the following equation:\n+ * P = B \u0026 ~(1 \u003c\u003c O)\n+ *\n+ * Assumption: *_mem_map is contiguous at least up to MAX_PAGE_ORDER\n+ */\n+static inline unsigned long\n+__find_buddy_pfn(unsigned long page_pfn, unsigned int order)\n+{\n+\treturn page_pfn ^ (1 \u003c\u003c order);\n+}\n+\n+/*\n+ * Find the buddy of @page and validate it.\n+ * @page: The input page\n+ * @pfn: The pfn of the page, it saves a call to page_to_pfn() when the\n+ * function is used in the performance-critical __free_one_page().\n+ * @order: The order of the page\n+ * @buddy_pfn: The output pointer to the buddy pfn, it also saves a call to\n+ * page_to_pfn().\n+ *\n+ * The found buddy can be a non PageBuddy, out of @page's zone, or its order is\n+ * not the same as @page. The validation is necessary before use it.\n+ *\n+ * Return: the found buddy page or NULL if not found.\n+ */\n+static inline struct page *find_buddy_page_pfn(struct page *page,\n+\t\t\tunsigned long pfn, unsigned int order, unsigned long *buddy_pfn)\n+{\n+\tunsigned long __buddy_pfn = __find_buddy_pfn(pfn, order);\n+\tstruct page *buddy;\n+\n+\tbuddy = page + (__buddy_pfn - pfn);\n+\tif (buddy_pfn)\n+\t\t*buddy_pfn = __buddy_pfn;\n+\n+\tif (page_is_buddy(page, buddy, order))\n+\t\treturn buddy;\n+\treturn NULL;\n+}\n+\n+extern struct page *__pageblock_pfn_to_page(unsigned long start_pfn,\n+\t\t\t\tunsigned long end_pfn, struct zone *zone);\n+\n+static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn,\n+\t\t\t\tunsigned long end_pfn, struct zone *zone)\n+{\n+\tif (zone-\u003econtiguous)\n+\t\treturn pfn_to_page(start_pfn);\n+\n+\treturn __pageblock_pfn_to_page(start_pfn, end_pfn, zone);\n+}\n+\n+extern void __free_pages_core(struct page *page, unsigned int order,\n+\t\tenum meminit_context context);\n+\n+void post_alloc_hook(struct page *page, unsigned int order, gfp_t gfp_flags,\n+\t\t unsigned int alloc_flags);\n+extern bool free_pages_prepare(struct page *page, unsigned int order);\n+\n+extern int user_min_free_kbytes;\n+\n+struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order, int nid,\n+\t\tnodemask_t *nodemask, unsigned int alloc_flags);\n+#define __alloc_frozen_pages(...) \\\n+\talloc_hooks(__alloc_frozen_pages_noprof(__VA_ARGS__))\n+void free_frozen_pages(struct page *page, unsigned int order);\n+void free_unref_folios(struct folio_batch *fbatch);\n+\n+#ifdef CONFIG_NUMA\n+struct page *alloc_frozen_pages_noprof(gfp_t, unsigned int order);\n+#else\n+static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)\n+{\n+\treturn __alloc_frozen_pages_noprof(gfp, order, numa_node_id(), NULL,\n+\t\t\t\t\t ALLOC_DEFAULT);\n+}\n+#endif\n+\n+#define alloc_frozen_pages(...) \\\n+\talloc_hooks(alloc_frozen_pages_noprof(__VA_ARGS__))\n+\n+struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);\n+#define alloc_frozen_pages_nolock(...) \\\n+\talloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))\n+void free_frozen_pages_nolock(struct page *page, unsigned int order);\n+\n+struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n+\t\tnodemask_t *nodemask, unsigned int alloc_flags);\n+#define __alloc_pages(...)\t\t\talloc_hooks(__alloc_pages_noprof(__VA_ARGS__))\n+\n+extern void zone_pcp_reset(struct zone *zone);\n+extern void zone_pcp_disable(struct zone *zone);\n+extern void zone_pcp_enable(struct zone *zone);\n+extern void zone_pcp_init(struct zone *zone);\n+\n+enum fallback_result {\n+\t/* Found suitable migratetype, *mt_out is valid. */\n+\tFALLBACK_FOUND,\n+\t/* No fallback found in requested order. */\n+\tFALLBACK_EMPTY,\n+\t/* Passed @claimable, but claiming whole block is a bad idea. */\n+\tFALLBACK_NOCLAIM,\n+};\n+enum fallback_result\n+find_suitable_fallback(struct free_area *area, unsigned int order,\n+\t\t int migratetype, bool claimable, int *mt_out);\n+\n+static inline bool free_area_empty(struct free_area *area, int migratetype)\n+{\n+\treturn list_empty(\u0026area-\u003efree_list[migratetype]);\n+}\n+\n+/* Convert GFP flags to their corresponding migrate type */\n+#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)\n+#define GFP_MOVABLE_SHIFT 3\n+\n+static inline int gfp_migratetype(const gfp_t gfp_flags)\n+{\n+\tVM_WARN_ON((gfp_flags \u0026 GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);\n+\tBUILD_BUG_ON((1UL \u003c\u003c GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);\n+\tBUILD_BUG_ON((___GFP_MOVABLE \u003e\u003e GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);\n+\tBUILD_BUG_ON((___GFP_RECLAIMABLE \u003e\u003e GFP_MOVABLE_SHIFT) != MIGRATE_RECLAIMABLE);\n+\tBUILD_BUG_ON(((___GFP_MOVABLE | ___GFP_RECLAIMABLE) \u003e\u003e\n+\t\t GFP_MOVABLE_SHIFT) != MIGRATE_HIGHATOMIC);\n+\n+\tif (unlikely(page_group_by_mobility_disabled))\n+\t\treturn MIGRATE_UNMOVABLE;\n+\n+\t/* Group based on mobility */\n+\treturn (__force unsigned long)(gfp_flags \u0026 GFP_MOVABLE_MASK) \u003e\u003e GFP_MOVABLE_SHIFT;\n+}\n+#undef GFP_MOVABLE_MASK\n+#undef GFP_MOVABLE_SHIFT\n+\n+bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp);\n+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);\n+void drain_all_pages(struct zone *zone);\n+\n+void page_alloc_init_cpuhp(void);\n+void page_alloc_sysctl_init(void);\n+\n+#endif /* __MM_PAGE_ALLOC_H */\ndiff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c\nindex d2423f30577e49..e63efe78b7d4b4 100644\n--- a/mm/page_frag_cache.c\n+++ b/mm/page_frag_cache.c\n@@ -18,7 +18,7 @@\n #include \u003clinux/init.h\u003e\n #include \u003clinux/mm.h\u003e\n #include \u003clinux/page_frag_cache.h\u003e\n-#include \"internal.h\"\n+#include \"page_alloc.h\"\n \n static unsigned long encoded_page_create(struct page *page, unsigned int order,\n \t\t\t\t\t bool pfmemalloc)\n@@ -57,10 +57,10 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,\n \tgfp_mask = (gfp_mask \u0026 ~__GFP_DIRECT_RECLAIM) | __GFP_COMP |\n \t\t __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;\n \tpage = __alloc_pages(gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER,\n-\t\t\t numa_mem_id(), NULL);\n+\t\t\t numa_mem_id(), NULL, ALLOC_DEFAULT);\n #endif\n \tif (unlikely(!page)) {\n-\t\tpage = __alloc_pages(gfp, 0, numa_mem_id(), NULL);\n+\t\tpage = __alloc_pages(gfp, 0, numa_mem_id(), NULL, ALLOC_DEFAULT);\n \t\torder = 0;\n \t}\n \ndiff --git a/mm/page_isolation.c b/mm/page_isolation.c\nindex 32ce8a7d9df355..e5dfc7bf494460 100644\n--- a/mm/page_isolation.c\n+++ b/mm/page_isolation.c\n@@ -11,6 +11,7 @@\n #include \u003clinux/page_owner.h\u003e\n #include \u003clinux/migrate.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n \n #define CREATE_TRACE_POINTS\n #include \u003ctrace/events/page_isolation.h\u003e\ndiff --git a/mm/page_owner.c b/mm/page_owner.c\nindex 26d6ab6530ce05..e399ebed27234e 100644\n--- a/mm/page_owner.c\n+++ b/mm/page_owner.c\n@@ -13,7 +13,7 @@\n #include \u003clinux/memcontrol.h\u003e\n #include \u003clinux/sched/clock.h\u003e\n \n-#include \"internal.h\"\n+#include \"page_alloc.h\"\n \n /*\n * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack)\ndiff --git a/mm/page_reporting.c b/mm/page_reporting.c\nindex 7418f2e500bb48..c7325704c3202e 100644\n--- a/mm/page_reporting.c\n+++ b/mm/page_reporting.c\n@@ -8,6 +8,7 @@\n #include \u003clinux/delay.h\u003e\n #include \u003clinux/scatterlist.h\u003e\n \n+#include \"page_alloc.h\"\n #include \"page_reporting.h\"\n #include \"internal.h\"\n \ndiff --git a/mm/show_mem.c b/mm/show_mem.c\nindex 1b721a8ade67dd..d1288b4c2b6401 100644\n--- a/mm/show_mem.c\n+++ b/mm/show_mem.c\n@@ -16,6 +16,7 @@\n #include \u003clinux/vmstat.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"swap.h\"\n \n atomic_long_t _totalram_pages __read_mostly;\ndiff --git a/mm/shuffle.c b/mm/shuffle.c\nindex fb1393b8b3a9d6..82a2c7725a08ab 100644\n--- a/mm/shuffle.c\n+++ b/mm/shuffle.c\n@@ -7,6 +7,7 @@\n #include \u003clinux/random.h\u003e\n #include \u003clinux/moduleparam.h\u003e\n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"shuffle.h\"\n \n DEFINE_STATIC_KEY_FALSE(page_alloc_shuffle_key);\ndiff --git a/mm/slub.c b/mm/slub.c\nindex 9ec774dc700969..b19dc46de73c56 100644\n--- a/mm/slub.c\n+++ b/mm/slub.c\n@@ -53,6 +53,7 @@\n #include \u003ctrace/events/kmem.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n \n /*\n * Lock order:\n@@ -3291,7 +3292,8 @@ static inline struct slab *alloc_slab_page(gfp_t flags, int node,\n \telse if (node == NUMA_NO_NODE)\n \t\tpage = alloc_frozen_pages(flags, order);\n \telse\n-\t\tpage = __alloc_frozen_pages(flags, order, node, NULL);\n+\t\tpage = __alloc_frozen_pages(flags, order, node, NULL,\n+\t\t\t\t\t ALLOC_DEFAULT);\n \n \tif (!page)\n \t\treturn NULL;\n@@ -5301,7 +5303,8 @@ static void *___kmalloc_large_node(size_t size, gfp_t flags, int node)\n \tif (node == NUMA_NO_NODE)\n \t\tpage = alloc_frozen_pages_noprof(flags, order);\n \telse\n-\t\tpage = __alloc_frozen_pages_noprof(flags, order, node, NULL);\n+\t\tpage = __alloc_frozen_pages_noprof(flags, order, node, NULL,\n+\t\t\t\t\t\t ALLOC_DEFAULT);\n \n \tif (page) {\n \t\tptr = page_address(page);\n@@ -5405,15 +5408,7 @@ static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_f\n \tif (unlikely(!size))\n \t\treturn ZERO_SIZE_PTR;\n \n-\t/*\n-\t * See the comment for the same check in\n-\t * alloc_frozen_pages_nolock_noprof()\n-\t */\n-\tif (IS_ENABLED(CONFIG_PREEMPT_RT) \u0026\u0026 (in_nmi() || in_hardirq()))\n-\t\treturn NULL;\n-\n-\t/* On UP, spin_trylock() always succeeds even when it is locked */\n-\tif (!IS_ENABLED(CONFIG_SMP) \u0026\u0026 in_nmi())\n+\tif (!can_spin_trylock())\n \t\treturn NULL;\n \n retry:\ndiff --git a/mm/swap.c b/mm/swap.c\nindex 58e4eff698cc4e..d25131305c94cb 100644\n--- a/mm/swap.c\n+++ b/mm/swap.c\n@@ -39,6 +39,7 @@\n #include \u003clinux/buffer_head.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n \n #define CREATE_TRACE_POINTS\n #include \u003ctrace/events/pagemap.h\u003e\ndiff --git a/mm/vmscan.c b/mm/vmscan.c\nindex 56fe5393f30f82..1474a7234ea16c 100644\n--- a/mm/vmscan.c\n+++ b/mm/vmscan.c\n@@ -66,6 +66,7 @@\n #include \u003clinux/sched/sysctl.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n #include \"swap.h\"\n \n #define CREATE_TRACE_POINTS\ndiff --git a/mm/vmstat.c b/mm/vmstat.c\nindex 7b93fbf9af0926..3b5cb1031f7209 100644\n--- a/mm/vmstat.c\n+++ b/mm/vmstat.c\n@@ -30,6 +30,7 @@\n #include \u003clinux/sched/isolation.h\u003e\n \n #include \"internal.h\"\n+#include \"page_alloc.h\"\n \n #ifdef CONFIG_PROC_FS\n #ifdef CONFIG_NUMA\ndiff --git a/tools/include/linux/gfp_types.h b/tools/include/linux/gfp_types.h\nindex 6c75df30a281d1..a93b8bd200b760 100644\n--- a/tools/include/linux/gfp_types.h\n+++ b/tools/include/linux/gfp_types.h\n@@ -55,7 +55,6 @@ enum {\n #ifdef CONFIG_LOCKDEP\n \t___GFP_NOLOCKDEP_BIT,\n #endif\n-\t___GFP_NO_OBJ_EXT_BIT,\n \t___GFP_LAST_BIT\n };\n \n@@ -96,7 +95,6 @@ enum {\n #else\n #define ___GFP_NOLOCKDEP\t0\n #endif\n-#define ___GFP_NO_OBJ_EXT BIT(___GFP_NO_OBJ_EXT_BIT)\n \n /*\n * Physical address zone modifiers (see linux/mmzone.h - low four bits)\n@@ -137,17 +135,12 @@ enum {\n * node with no fallbacks or placement policy enforcements.\n *\n * %__GFP_ACCOUNT causes the allocation to be accounted to kmemcg.\n- *\n- * %__GFP_NO_OBJ_EXT causes slab allocation to have no object extension.\n- * mark_obj_codetag_empty() should be called upon freeing for objects allocated\n- * with this flag to indicate that their NULL tags are expected and normal.\n */\n #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)\n #define __GFP_WRITE\t((__force gfp_t)___GFP_WRITE)\n #define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)\n #define __GFP_THISNODE\t((__force gfp_t)___GFP_THISNODE)\n #define __GFP_ACCOUNT\t((__force gfp_t)___GFP_ACCOUNT)\n-#define __GFP_NO_OBJ_EXT ((__force gfp_t)___GFP_NO_OBJ_EXT)\n \n /**\n * DOC: Watermark modifiers\n"
} |
| 2/1 | 2026/07/03 12:54 | agent | patch-evaluator |
2mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING",
"CMA",
"PREEMPT_RT"
],
"FocusSymbols": [
"__alloc_frozen_pages_noprof",
"alloc_pages_node_noprof",
"alloc_pages_bulk_noprof",
"alloc_pages_nolock_noprof"
],
"Reasoning": "The patch modifies the core page allocator logic, specifically how allocation flags are passed and handled internally. It introduces an `alloc_flags` parameter to `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof`, replacing the internal `alloc_flags` variable. It also modifies `alloc_frozen_pages_nolock_noprof` to use `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`. It removes `__GFP_NO_OBJ_EXT` and replaces it with `ALLOC_NO_CODETAG` for memory allocation profiling. These are functional changes to the memory management subsystem that should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 6dfe7850c5ea9108ced0b8273340ba220485ac33
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Jul 3 12:54:06 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/admin-guide/cgroup-v1/cpusets.rst b/Documentation/admin-guide/cgroup-v1/cpusets.rst
index c7909e5ac1361a..52a213aff04e5f 100644
--- a/Documentation/admin-guide/cgroup-v1/cpusets.rst
+++ b/Documentation/admin-guide/cgroup-v1/cpusets.rst
@@ -284,7 +284,7 @@ take action.
==>
Unless this feature is enabled by writing "1" to the special file
/dev/cpuset/memory_pressure_enabled, the hook in the rebalance
- code of __alloc_pages() for this metric reduces to simply noticing
+ code of the page allocator for this metric reduces to simply noticing
that the cpuset_memory_pressure_enabled flag is zero. So only
systems that enable this feature will compute the metric.
diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index 23f8d13c2629d6..16f37135ed80df 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -761,7 +761,7 @@ compact_fail
but failed.
It is possible to establish how long the stalls were using the function
-tracer to record how long was spent in __alloc_pages() and
+tracer to record how long was spent in the page allocator and
using the mm_page_alloc tracepoint to identify which allocations were
for huge pages.
diff --git a/MAINTAINERS b/MAINTAINERS
index 29c302e9c17ba3..b359ff4e0a1a66 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17171,6 +17171,7 @@ F: mm/debug_page_alloc.c
F: mm/debug_page_ref.c
F: mm/fail_page_alloc.c
F: mm/page_alloc.c
+F: mm/page_alloc.h
F: mm/page_ext.c
F: mm/page_frag_cache.c
F: mm/page_isolation.c
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 91a093d8cf2e77..70be80211d8231 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -832,7 +832,7 @@ static void *dsalloc_pages(size_t size, gfp_t flags, int cpu)
int node = cpu_to_node(cpu);
struct page *page;
- page = __alloc_pages_node(node, flags | __GFP_ZERO, order);
+ page = alloc_pages_node(node, flags | __GFP_ZERO, order);
return page ? page_address(page) : NULL;
}
@@ -1088,9 +1088,9 @@ void init_arch_pebs_on_cpu(int cpu)
/*
* 4KB-aligned pointer of the output buffer
- * (__alloc_pages_node() return page aligned address)
+ * (alloc_pages_node() returns page aligned address)
* Buffer Size = 4KB * 2^SIZE
- * contiguous physical buffer (__alloc_pages_node() with order)
+ * contiguous physical buffer (alloc_pages_node() with order)
*/
arch_pebs_base = virt_to_phys(cpuc->pebs_vaddr) | PEBS_BUFFER_SHIFT;
wrmsrq_on_cpu(cpu, MSR_IA32_PEBS_BASE, arch_pebs_base);
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 2325be57d3d75b..ad6a7fc6a54daf 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -3028,7 +3028,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
struct page *pages;
struct vmcs *vmcs;
- pages = __alloc_pages_node(node, flags, 0);
+ pages = alloc_pages_node(node, flags, 0);
if (!pages)
return NULL;
vmcs = page_address(pages);
diff --git a/arch/x86/virt/hw.c b/arch/x86/virt/hw.c
index 7e9091c640be0b..a236447ac7a262 100644
--- a/arch/x86/virt/hw.c
+++ b/arch/x86/virt/hw.c
@@ -196,7 +196,7 @@ static __init int __x86_vmx_init(void)
struct page *page;
struct vmcs *vmcs;
- page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
+ page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
if (WARN_ON_ONCE(!page)) {
x86_vmx_exit();
return -ENOMEM;
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 772c7872689327..79c2f00ed4d702 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -170,9 +170,8 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
mq->mmr_blade = uv_cpu_to_blade_id(cpu);
nid = cpu_to_node(cpu);
- page = __alloc_pages_node(nid,
- GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
- pg_order);
+ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
+ pg_order);
if (page == NULL) {
dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
"bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
diff --git a/drivers/net/ethernet/fungible/funeth/funeth_rx.c b/drivers/net/ethernet/fungible/funeth/funeth_rx.c
index 7e2584895de39b..d7000017ac2bdc 100644
--- a/drivers/net/ethernet/fungible/funeth/funeth_rx.c
+++ b/drivers/net/ethernet/fungible/funeth/funeth_rx.c
@@ -103,7 +103,7 @@ static int funeth_alloc_page(struct funeth_rxq *q, struct funeth_rxbuf *rb,
if (cache_get(q, rb))
return 0;
- p = __alloc_pages_node(node, gfp | __GFP_NOWARN, 0);
+ p = alloc_pages_node(node, gfp | __GFP_NOWARN, 0);
if (unlikely(!p))
return -ENOMEM;
diff --git a/include/linux/alloc_tag.h b/include/linux/alloc_tag.h
index 068ba2e77c5d65..fcf90e6b242047 100644
--- a/include/linux/alloc_tag.h
+++ b/include/linux/alloc_tag.h
@@ -163,11 +163,11 @@ static inline void alloc_tag_sub_check(union codetag_ref *ref)
{
WARN_ONCE(ref && !ref->ct, "alloc_tag was not set\n");
}
-void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags);
+void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags);
#else
static inline void alloc_tag_add_check(union codetag_ref *ref, struct alloc_tag *tag) {}
static inline void alloc_tag_sub_check(union codetag_ref *ref) {}
-static inline void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags) {}
+static inline void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags) {}
#endif
/* Caller should verify both ref and tag to be valid */
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index cdf95a9f0b87c1..4d57e9c0bf204d 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -17,28 +17,6 @@ struct mempolicy;
#define __default_gfp(a,b,...) b
#define default_gfp(...) __default_gfp(,##__VA_ARGS__,GFP_KERNEL)
-/* Convert GFP flags to their corresponding migrate type */
-#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
-#define GFP_MOVABLE_SHIFT 3
-
-static inline int gfp_migratetype(const gfp_t gfp_flags)
-{
- VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);
- BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);
- BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);
- BUILD_BUG_ON((___GFP_RECLAIMABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_RECLAIMABLE);
- BUILD_BUG_ON(((___GFP_MOVABLE | ___GFP_RECLAIMABLE) >>
- GFP_MOVABLE_SHIFT) != MIGRATE_HIGHATOMIC);
-
- if (unlikely(page_group_by_mobility_disabled))
- return MIGRATE_UNMOVABLE;
-
- /* Group based on mobility */
- return (__force unsigned long)(gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;
-}
-#undef GFP_MOVABLE_MASK
-#undef GFP_MOVABLE_SHIFT
-
static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
{
return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
@@ -226,10 +204,6 @@ static inline void arch_free_page(struct page *page, int order) { }
static inline void arch_alloc_page(struct page *page, int order) { }
#endif
-struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,
- nodemask_t *nodemask);
-#define __alloc_pages(...) alloc_hooks(__alloc_pages_noprof(__VA_ARGS__))
-
struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,
nodemask_t *nodemask);
#define __folio_alloc(...) alloc_hooks(__folio_alloc_noprof(__VA_ARGS__))
@@ -278,21 +252,6 @@ static inline void warn_if_node_offline(int this_node, gfp_t gfp_mask)
dump_stack();
}
-/*
- * Allocate pages, preferring the node given as nid. The node must be valid and
- * online. For more general interface, see alloc_pages_node().
- */
-static inline struct page *
-__alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)
-{
- VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
- warn_if_node_offline(nid, gfp_mask);
-
- return __alloc_pages_noprof(gfp_mask, order, nid, NULL);
-}
-
-#define __alloc_pages_node(...) alloc_hooks(__alloc_pages_node_noprof(__VA_ARGS__))
-
static inline
struct folio *__folio_alloc_node_noprof(gfp_t gfp, unsigned int order, int nid)
{
@@ -309,14 +268,7 @@ struct folio *__folio_alloc_node_noprof(gfp_t gfp, unsigned int order, int nid)
* prefer the current CPU's closest node. Otherwise node must be valid and
* online.
*/
-static inline struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask,
- unsigned int order)
-{
- if (nid == NUMA_NO_NODE)
- nid = numa_mem_id();
-
- return __alloc_pages_node_noprof(nid, gfp_mask, order);
-}
+struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order);
#define alloc_pages_node(...) alloc_hooks(alloc_pages_node_noprof(__VA_ARGS__))
@@ -395,10 +347,6 @@ extern void free_pages(unsigned long addr, unsigned int order);
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)
-void page_alloc_init_cpuhp(void);
-bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp);
-void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
-void drain_all_pages(struct zone *zone);
void drain_local_pages(struct zone *zone);
void page_alloc_init_late(void);
diff --git a/include/linux/gfp_types.h b/include/linux/gfp_types.h
index 463b551d12d997..190191411009f2 100644
--- a/include/linux/gfp_types.h
+++ b/include/linux/gfp_types.h
@@ -55,7 +55,6 @@ enum {
#ifdef CONFIG_LOCKDEP
___GFP_NOLOCKDEP_BIT,
#endif
- ___GFP_NO_OBJ_EXT_BIT,
___GFP_LAST_BIT
};
@@ -96,7 +95,6 @@ enum {
#else
#define ___GFP_NOLOCKDEP 0
#endif
-#define ___GFP_NO_OBJ_EXT BIT(___GFP_NO_OBJ_EXT_BIT)
/*
* Physical address zone modifiers (see linux/mmzone.h - low four bits)
@@ -138,17 +136,12 @@ enum {
*
* %__GFP_ACCOUNT causes the allocation to be accounted to the active
* cgroup context.
- *
- * %__GFP_NO_OBJ_EXT causes slab allocation to have no object extension.
- * mark_obj_codetag_empty() should be called upon freeing for objects allocated
- * with this flag to indicate that their NULL tags are expected and normal.
*/
#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)
#define __GFP_WRITE ((__force gfp_t)___GFP_WRITE)
#define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)
#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)
#define __GFP_ACCOUNT ((__force gfp_t)___GFP_ACCOUNT)
-#define __GFP_NO_OBJ_EXT ((__force gfp_t)___GFP_NO_OBJ_EXT)
/**
* DOC: Watermark modifiers
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 22eda1d54a0e84..4431b026e429dc 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3573,7 +3573,7 @@ static inline struct page *__dev_alloc_pages_noprof(gfp_t gfp_mask,
* 3. If requesting a order 0 page it will not be compound
* due to the check to see if order has a value in prep_new_page
* 4. __GFP_MEMALLOC is ignored if __GFP_NOMEMALLOC is set due to
- * code in gfp_to_alloc_flags that should be enforcing this.
+ * code in alloc_flags_slowpath() that should be enforcing this.
*/
gfp_mask |= __GFP_COMP | __GFP_MEMALLOC;
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index a6e5a44c9b4299..c1a05ff0feab00 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -54,18 +54,10 @@
# define TRACE_GFP_FLAGS_LOCKDEP
#endif
-#ifdef CONFIG_SLAB_OBJ_EXT
-# define TRACE_GFP_FLAGS_SLAB \
- TRACE_GFP_EM(NO_OBJ_EXT)
-#else
-# define TRACE_GFP_FLAGS_SLAB
-#endif
-
#define TRACE_GFP_FLAGS \
TRACE_GFP_FLAGS_GENERAL \
TRACE_GFP_FLAGS_KASAN \
- TRACE_GFP_FLAGS_LOCKDEP \
- TRACE_GFP_FLAGS_SLAB
+ TRACE_GFP_FLAGS_LOCKDEP
#undef TRACE_GFP_EM
#define TRACE_GFP_EM(a) TRACE_DEFINE_ENUM(___GFP_##a##_BIT);
diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c
index d9be1cf5187d97..cf65e9992fda33 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -15,6 +15,9 @@
#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
+#include "internal.h"
+#include "page_alloc.h"
+
#define ALLOCINFO_FILE_NAME "allocinfo"
#define MODULE_ALLOC_TAG_VMAP_SIZE (100000UL * sizeof(struct alloc_tag))
#define SECTION_START(NAME) (CODETAG_SECTION_START_PREFIX NAME)
@@ -783,19 +786,6 @@ struct pfn_pool {
#define PFN_POOL_SIZE ((PAGE_SIZE - offsetof(struct pfn_pool, pfns)) / \
sizeof(unsigned long))
-
-/*
- * Skip early PFN recording for a page allocation. Reuses the
- * %__GFP_NO_OBJ_EXT bit. Used by __alloc_tag_add_early_pfn() to avoid
- * recursion when allocating pages for the early PFN tracking list
- * itself.
- *
- * Codetags of the pages allocated with __GFP_NO_CODETAG should be
- * cleared (via clear_page_tag_ref()) before freeing the pages to prevent
- * alloc_tag_sub_check() from triggering a warning.
- */
-#define __GFP_NO_CODETAG __GFP_NO_OBJ_EXT
-
static struct pfn_pool *current_pfn_pool __initdata;
static void __init __alloc_tag_add_early_pfn(unsigned long pfn)
@@ -806,7 +796,8 @@ static void __init __alloc_tag_add_early_pfn(unsigned long pfn)
do {
pool = READ_ONCE(current_pfn_pool);
if (!pool || atomic_read(&pool->count) >= PFN_POOL_SIZE) {
- struct page *new_page = alloc_page(__GFP_HIGH | __GFP_NO_CODETAG);
+ struct page *new_page = __alloc_pages(__GFP_HIGH, 0, numa_mem_id(),
+ NULL, ALLOC_NO_CODETAG);
struct pfn_pool *new;
if (!new_page) {
@@ -837,7 +828,7 @@ typedef void alloc_tag_add_func(unsigned long pfn);
static alloc_tag_add_func __rcu *alloc_tag_add_early_pfn_ptr __refdata =
RCU_INITIALIZER(__alloc_tag_add_early_pfn);
-void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags)
+void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags)
{
alloc_tag_add_func *alloc_tag_add;
@@ -845,7 +836,7 @@ void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags)
return;
/* Skip allocations for the tracking list itself to avoid recursion. */
- if (gfp_flags & __GFP_NO_CODETAG)
+ if (alloc_flags & ALLOC_NO_CODETAG)
return;
rcu_read_lock();
diff --git a/mm/compaction.c b/mm/compaction.c
index f08765ade014ce..4b2318fad4eb59 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -24,6 +24,7 @@
#include <linux/page_owner.h>
#include <linux/psi.h>
#include <linux/cpuset.h>
+#include "page_alloc.h"
#include "internal.h"
#ifdef CONFIG_COMPACTION
@@ -82,7 +83,7 @@ static inline bool is_via_compact_memory(int order) { return false; }
static struct page *mark_allocated_noprof(struct page *page, unsigned int order, gfp_t gfp_flags)
{
- post_alloc_hook(page, order, __GFP_MOVABLE);
+ post_alloc_hook(page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
set_page_refcounted(page);
return page;
}
@@ -1850,7 +1851,7 @@ static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long da
}
dst = (struct folio *)freepage;
- post_alloc_hook(&dst->page, order, __GFP_MOVABLE);
+ post_alloc_hook(&dst->page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
set_page_refcounted(&dst->page);
if (order)
prep_compound_page(&dst->page, order);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 391739ca7f7117..48471503984c1c 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -47,6 +47,7 @@
#include <linux/node.h>
#include <linux/page_owner.h>
#include "internal.h"
+#include "page_alloc.h"
#include "hugetlb_vmemmap.h"
#include "hugetlb_cma.h"
#include "hugetlb_internal.h"
@@ -1789,7 +1790,8 @@ static struct folio *alloc_buddy_frozen_folio(int order, gfp_t gfp_mask,
if (alloc_try_hard)
gfp_mask |= __GFP_RETRY_MAYFAIL;
- folio = (struct folio *)__alloc_frozen_pages(gfp_mask, order, nid, nmask);
+ folio = (struct folio *)__alloc_frozen_pages(gfp_mask, order, nid, nmask,
+ ALLOC_DEFAULT);
/*
* If we did not specify __GFP_RETRY_MAYFAIL, but still got a
diff --git a/mm/internal.h b/mm/internal.h
index fa4fb69444ecdc..0ae6ad22651252 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -658,165 +658,6 @@ extern int defrag_mode;
void setup_per_zone_wmarks(void);
void calculate_min_free_kbytes(void);
int __meminit init_per_zone_wmark_min(void);
-void page_alloc_sysctl_init(void);
-
-/*
- * Structure for holding the mostly immutable allocation parameters passed
- * between functions involved in allocations, including the alloc_pages*
- * family of functions.
- *
- * nodemask, migratetype and highest_zoneidx are initialized only once in
- * __alloc_pages() and then never change.
- *
- * zonelist, preferred_zone and highest_zoneidx are set first in
- * __alloc_pages() for the fast path, and might be later changed
- * in __alloc_pages_slowpath(). All other functions pass the whole structure
- * by a const pointer.
- */
-struct alloc_context {
- struct zonelist *zonelist;
- const nodemask_t *nodemask;
- struct zoneref *preferred_zoneref;
- int migratetype;
-
- /*
- * highest_zoneidx represents highest usable zone index of
- * the allocation request. Due to the nature of the zone,
- * memory on lower zone than the highest_zoneidx will be
- * protected by lowmem_reserve[highest_zoneidx].
- *
- * highest_zoneidx is also used by reclaim/compaction to limit
- * the target zone since higher zone than this index cannot be
- * usable for this allocation request.
- */
- enum zone_type highest_zoneidx;
- bool spread_dirty_pages;
-};
-
-/*
- * This function returns the order of a free page in the buddy system. In
- * general, page_zone(page)->lock must be held by the caller to prevent the
- * page from being allocated in parallel and returning garbage as the order.
- * If a caller does not hold page_zone(page)->lock, it must guarantee that the
- * page cannot be allocated or merged in parallel. Alternatively, it must
- * handle invalid values gracefully, and use buddy_order_unsafe() below.
- */
-static inline unsigned int buddy_order(struct page *page)
-{
- /* PageBuddy() must be checked by the caller */
- return page_private(page);
-}
-
-/*
- * Like buddy_order(), but for callers who cannot afford to hold the zone lock.
- * PageBuddy() should be checked first by the caller to minimize race window,
- * and invalid values must be handled gracefully.
- *
- * READ_ONCE is used so that if the caller assigns the result into a local
- * variable and e.g. tests it for valid range before using, the compiler cannot
- * decide to remove the variable and inline the page_private(page) multiple
- * times, potentially observing different values in the tests and the actual
- * use of the result.
- */
-#define buddy_order_unsafe(page) READ_ONCE(page_private(page))
-
-/*
- * This function checks whether a page is free && is the buddy
- * we can coalesce a page and its buddy if
- * (a) the buddy is not in a hole (check before calling!) &&
- * (b) the buddy is in the buddy system &&
- * (c) a page and its buddy have the same order &&
- * (d) a page and its buddy are in the same zone.
- *
- * For recording whether a page is in the buddy system, we set PageBuddy.
- * Setting, clearing, and testing PageBuddy is serialized by zone->lock.
- *
- * For recording page's order, we use page_private(page).
- */
-static inline bool page_is_buddy(struct page *page, struct page *buddy,
- unsigned int order)
-{
- if (!page_is_guard(buddy) && !PageBuddy(buddy))
- return false;
-
- if (buddy_order(buddy) != order)
- return false;
-
- /*
- * zone check is done late to avoid uselessly calculating
- * zone/node ids for pages that could never merge.
- */
- if (page_zone_id(page) != page_zone_id(buddy))
- return false;
-
- VM_BUG_ON_PAGE(page_count(buddy) != 0, buddy);
-
- return true;
-}
-
-/*
- * Locate the struct page for both the matching buddy in our
- * pair (buddy1) and the combined O(n+1) page they form (page).
- *
- * 1) Any buddy B1 will have an order O twin B2 which satisfies
- * the following equation:
- * B2 = B1 ^ (1 << O)
- * For example, if the starting buddy (buddy2) is #8 its order
- * 1 buddy is #10:
- * B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
- *
- * 2) Any buddy B will have an order O+1 parent P which
- * satisfies the following equation:
- * P = B & ~(1 << O)
- *
- * Assumption: *_mem_map is contiguous at least up to MAX_PAGE_ORDER
- */
-static inline unsigned long
-__find_buddy_pfn(unsigned long page_pfn, unsigned int order)
-{
- return page_pfn ^ (1 << order);
-}
-
-/*
- * Find the buddy of @page and validate it.
- * @page: The input page
- * @pfn: The pfn of the page, it saves a call to page_to_pfn() when the
- * function is used in the performance-critical __free_one_page().
- * @order: The order of the page
- * @buddy_pfn: The output pointer to the buddy pfn, it also saves a call to
- * page_to_pfn().
- *
- * The found buddy can be a non PageBuddy, out of @page's zone, or its order is
- * not the same as @page. The validation is necessary before use it.
- *
- * Return: the found buddy page or NULL if not found.
- */
-static inline struct page *find_buddy_page_pfn(struct page *page,
- unsigned long pfn, unsigned int order, unsigned long *buddy_pfn)
-{
- unsigned long __buddy_pfn = __find_buddy_pfn(pfn, order);
- struct page *buddy;
-
- buddy = page + (__buddy_pfn - pfn);
- if (buddy_pfn)
- *buddy_pfn = __buddy_pfn;
-
- if (page_is_buddy(page, buddy, order))
- return buddy;
- return NULL;
-}
-
-extern struct page *__pageblock_pfn_to_page(unsigned long start_pfn,
- unsigned long end_pfn, struct zone *zone);
-
-static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn,
- unsigned long end_pfn, struct zone *zone)
-{
- if (zone->contiguous)
- return pfn_to_page(start_pfn);
-
- return __pageblock_pfn_to_page(start_pfn, end_pfn, zone);
-}
void set_zone_contiguous(struct zone *zone);
bool pfn_range_intersects_zones(int nid, unsigned long start_pfn,
@@ -831,8 +672,6 @@ extern int __isolate_free_page(struct page *page, unsigned int order);
extern void __putback_isolated_page(struct page *page, unsigned int order,
int mt);
extern void memblock_free_pages(unsigned long pfn, unsigned int order);
-extern void __free_pages_core(struct page *page, unsigned int order,
- enum meminit_context context);
/*
* This will have no effect, other than possibly generating a warning, if the
@@ -914,40 +753,6 @@ static inline void init_compound_tail(struct page *tail,
prep_compound_tail(tail, head, order);
}
-void post_alloc_hook(struct page *page, unsigned int order, gfp_t gfp_flags);
-extern bool free_pages_prepare(struct page *page, unsigned int order);
-
-extern int user_min_free_kbytes;
-
-struct page *__alloc_frozen_pages_noprof(gfp_t, unsigned int order, int nid,
- nodemask_t *);
-#define __alloc_frozen_pages(...) \
- alloc_hooks(__alloc_frozen_pages_noprof(__VA_ARGS__))
-void free_frozen_pages(struct page *page, unsigned int order);
-void free_unref_folios(struct folio_batch *fbatch);
-
-#ifdef CONFIG_NUMA
-struct page *alloc_frozen_pages_noprof(gfp_t, unsigned int order);
-#else
-static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)
-{
- return __alloc_frozen_pages_noprof(gfp, order, numa_node_id(), NULL);
-}
-#endif
-
-#define alloc_frozen_pages(...) \
- alloc_hooks(alloc_frozen_pages_noprof(__VA_ARGS__))
-
-struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);
-#define alloc_frozen_pages_nolock(...) \
- alloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))
-void free_frozen_pages_nolock(struct page *page, unsigned int order);
-
-extern void zone_pcp_reset(struct zone *zone);
-extern void zone_pcp_disable(struct zone *zone);
-extern void zone_pcp_enable(struct zone *zone);
-extern void zone_pcp_init(struct zone *zone);
-
extern void *memmap_alloc(phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr,
int nid, bool exact_nid);
@@ -1101,23 +906,6 @@ static inline void init_cma_pageblock(struct page *page)
}
#endif
-enum fallback_result {
- /* Found suitable migratetype, *mt_out is valid. */
- FALLBACK_FOUND,
- /* No fallback found in requested order. */
- FALLBACK_EMPTY,
- /* Passed @claimable, but claiming whole block is a bad idea. */
- FALLBACK_NOCLAIM,
-};
-enum fallback_result
-find_suitable_fallback(struct free_area *area, unsigned int order,
- int migratetype, bool claimable, int *mt_out);
-
-static inline bool free_area_empty(struct free_area *area, int migratetype)
-{
- return list_empty(&area->free_list[migratetype]);
-}
-
/* mm/util.c */
struct anon_vma *folio_anon_vma(const struct folio *folio);
@@ -1445,46 +1233,6 @@ extern unsigned long __must_check vm_mmap_pgoff(struct file *, unsigned long,
unsigned long reclaim_pages(struct list_head *folio_list);
unsigned int reclaim_clean_pages_from_list(struct zone *zone,
struct list_head *folio_list);
-/* The ALLOC_WMARK bits are used as an index to zone->watermark */
-#define ALLOC_WMARK_MIN WMARK_MIN
-#define ALLOC_WMARK_LOW WMARK_LOW
-#define ALLOC_WMARK_HIGH WMARK_HIGH
-#define ALLOC_NO_WATERMARKS 0x04 /* don't check watermarks at all */
-
-/* Mask to get the watermark bits */
-#define ALLOC_WMARK_MASK (ALLOC_NO_WATERMARKS-1)
-
-/*
- * Only MMU archs have async oom victim reclaim - aka oom_reaper so we
- * cannot assume a reduced access to memory reserves is sufficient for
- * !MMU
- */
-#ifdef CONFIG_MMU
-#define ALLOC_OOM 0x08
-#else
-#define ALLOC_OOM ALLOC_NO_WATERMARKS
-#endif
-
-#define ALLOC_NON_BLOCK 0x10 /* Caller cannot block. Allow access
- * to 25% of the min watermark or
- * 62.5% if __GFP_HIGH is set.
- */
-#define ALLOC_MIN_RESERVE 0x20 /* __GFP_HIGH set. Allow access to 50%
- * of the min watermark.
- */
-#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
-#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */
-#ifdef CONFIG_ZONE_DMA32
-#define ALLOC_NOFRAGMENT 0x100 /* avoid mixing pageblock types */
-#else
-#define ALLOC_NOFRAGMENT 0x0
-#endif
-#define ALLOC_HIGHATOMIC 0x200 /* Allows access to MIGRATE_HIGHATOMIC */
-#define ALLOC_TRYLOCK 0x400 /* Only use spin_trylock in allocation path */
-#define ALLOC_KSWAPD 0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */
-
-/* Flags that allow allocations below the min watermark. */
-#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)
enum ttu_flags;
struct tlbflush_unmap_batch;
@@ -1968,4 +1716,27 @@ static inline void mm_prepare_for_swap_entries(struct mm_struct *mm)
}
}
+static inline bool can_spin_trylock(void)
+{
+ /*
+ * In PREEMPT_RT spin_trylock() will call raw_spin_lock() which is
+ * unsafe in NMI. If spin_trylock() is called from hard IRQ the current
+ * task may be waiting for one rt_spin_lock, but rt_spin_trylock() will
+ * mark the task as the owner of another rt_spin_lock which will
+ * confuse PI logic, so return immediately if called from hard IRQ or
+ * NMI.
+ *
+ * Note, irqs_disabled() case is ok. spin_trylock() can be called
+ * from raw_spin_lock_irqsave region.
+ */
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
+ return false;
+
+ /* On UP, spin_trylock() always succeeds even when it is locked */
+ if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
+ return false;
+
+ return true;
+}
+
#endif /* __MM_INTERNAL_H */
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 617bca76db49b6..58e14d1543ecb4 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -26,6 +26,7 @@
#include <asm/tlb.h>
#include "internal.h"
+#include "page_alloc.h"
#include "mm_slot.h"
enum scan_result {
diff --git a/mm/kmsan/init.c b/mm/kmsan/init.c
index b14ce3417e65e4..4983b6e9f7c998 100644
--- a/mm/kmsan/init.c
+++ b/mm/kmsan/init.c
@@ -13,7 +13,7 @@
#include <linux/mm.h>
#include <linux/memblock.h>
-#include "../internal.h"
+#include "../page_alloc.h"
#define NUM_FUTURE_RANGES 128
struct start_end_pair {
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 4916ab14532573..bf717ec595087d 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -66,6 +66,7 @@
#include <trace/events/memory-failure.h>
#include "swap.h"
+#include "page_alloc.h"
#include "internal.h"
static int sysctl_memory_failure_early_kill __read_mostly;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 8b137328dcf014..11ab2f7bc7f3b8 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -40,6 +40,7 @@
#include <asm/tlbflush.h>
#include "internal.h"
+#include "page_alloc.h"
#include "shuffle.h"
enum {
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index bba65898aee175..914f81863db5a6 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -119,6 +119,7 @@
#include <linux/memory.h>
#include "internal.h"
+#include "page_alloc.h"
/* Internal flags */
#define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */
@@ -2416,9 +2417,11 @@ static struct page *alloc_pages_preferred_many(gfp_t gfp, unsigned int order,
*/
preferred_gfp = gfp | __GFP_NOWARN;
preferred_gfp &= ~(__GFP_DIRECT_RECLAIM | __GFP_NOFAIL);
- page = __alloc_frozen_pages_noprof(preferred_gfp, order, nid, nodemask);
+ page = __alloc_frozen_pages_noprof(preferred_gfp, order, nid, nodemask,
+ ALLOC_DEFAULT);
if (!page)
- page = __alloc_frozen_pages_noprof(gfp, order, nid, NULL);
+ page = __alloc_frozen_pages_noprof(gfp, order, nid, NULL,
+ ALLOC_DEFAULT);
return page;
}
@@ -2466,7 +2469,7 @@ static struct page *alloc_pages_mpol(gfp_t gfp, unsigned int order,
*/
page = __alloc_frozen_pages_noprof(
gfp | __GFP_THISNODE | __GFP_NORETRY, order,
- nid, NULL);
+ nid, NULL, ALLOC_DEFAULT);
if (page || !(gfp & __GFP_DIRECT_RECLAIM))
return page;
/*
@@ -2478,7 +2481,7 @@ static struct page *alloc_pages_mpol(gfp_t gfp, unsigned int order,
}
}
- page = __alloc_frozen_pages_noprof(gfp, order, nid, nodemask);
+ page = __alloc_frozen_pages_noprof(gfp, order, nid, nodemask, ALLOC_DEFAULT);
if (unlikely(pol->mode == MPOL_INTERLEAVE ||
pol->mode == MPOL_WEIGHTED_INTERLEAVE) && page) {
diff --git a/mm/migrate.c b/mm/migrate.c
index a786549551e3d0..db50e7b66fbf8f 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -49,6 +49,7 @@
#include <trace/events/migrate.h>
#include "internal.h"
+#include "page_alloc.h"
#include "swap.h"
static const struct movable_operations *offline_movable_ops;
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 07a8c74cf7ade1..537664974ab1c0 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -33,6 +33,7 @@
#include <linux/kexec_handover.h>
#include <linux/hugetlb.h>
#include "internal.h"
+#include "page_alloc.h"
#include "slab.h"
#include "shuffle.h"
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 762d9b6bc792f1..a63733dac659e3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -56,6 +56,7 @@
#include <linux/pgalloc_tag.h>
#include <asm/div64.h>
#include "internal.h"
+#include "page_alloc.h"
#include "shuffle.h"
#include "page_reporting.h"
@@ -1248,7 +1249,7 @@ void __clear_page_tag_ref(struct page *page)
/* Should be called only if mem_alloc_profiling_enabled() */
static noinline
void __pgalloc_tag_add(struct page *page, struct task_struct *task,
- unsigned int nr, gfp_t gfp_flags)
+ unsigned int nr, unsigned int alloc_flags)
{
union pgtag_ref_handle handle;
union codetag_ref ref;
@@ -1262,17 +1263,17 @@ void __pgalloc_tag_add(struct page *page, struct task_struct *task,
* page_ext is not available yet, record the pfn so we can
* clear the tag ref later when page_ext is initialized.
*/
- alloc_tag_add_early_pfn(page_to_pfn(page), gfp_flags);
+ alloc_tag_add_early_pfn(page_to_pfn(page), alloc_flags);
if (task->alloc_tag)
alloc_tag_set_inaccurate(task->alloc_tag);
}
}
static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
- unsigned int nr, gfp_t gfp_flags)
+ unsigned int nr, unsigned int alloc_flags)
{
if (mem_alloc_profiling_enabled())
- __pgalloc_tag_add(page, task, nr, gfp_flags);
+ __pgalloc_tag_add(page, task, nr, alloc_flags);
}
/* Should be called only if mem_alloc_profiling_enabled() */
@@ -1305,7 +1306,7 @@ static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr)
#else /* CONFIG_MEM_ALLOC_PROFILING */
static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
- unsigned int nr, gfp_t gfp_flags) {}
+ unsigned int nr, unsigned int alloc_flags) {}
static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {}
static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {}
@@ -1809,7 +1810,7 @@ static inline bool should_skip_init(gfp_t flags)
}
inline void post_alloc_hook(struct page *page, unsigned int order,
- gfp_t gfp_flags)
+ gfp_t gfp_flags, unsigned int alloc_flags)
{
const bool zero_tags = gfp_flags & __GFP_ZEROTAGS;
bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
@@ -1860,13 +1861,13 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
set_page_owner(page, order, gfp_flags);
page_table_check_alloc(page, order);
- pgalloc_tag_add(page, current, 1 << order, gfp_flags);
+ pgalloc_tag_add(page, current, 1 << order, alloc_flags);
}
static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
unsigned int alloc_flags)
{
- post_alloc_hook(page, order, gfp_flags);
+ post_alloc_hook(page, order, gfp_flags, alloc_flags);
if (order && (gfp_flags & __GFP_COMP))
prep_compound_page(page, order);
@@ -2530,7 +2531,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
unsigned long flags;
int i;
- if (unlikely(alloc_flags & ALLOC_TRYLOCK)) {
+ if (unlikely(alloc_flags & ALLOC_NOLOCK)) {
if (!spin_trylock_irqsave(&zone->lock, flags))
return 0;
} else {
@@ -3218,7 +3219,7 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,
do {
page = NULL;
- if (unlikely(alloc_flags & ALLOC_TRYLOCK)) {
+ if (unlikely(alloc_flags & ALLOC_NOLOCK)) {
if (!spin_trylock_irqsave(&zone->lock, flags))
return NULL;
} else {
@@ -3774,14 +3775,13 @@ alloc_flags_nofragment(struct zone *zone, gfp_t gfp_mask)
}
/* Must be called after current_gfp_context() which can change gfp_mask */
-static inline unsigned int gfp_to_alloc_flags_cma(gfp_t gfp_mask,
- unsigned int alloc_flags)
+static inline unsigned int alloc_flags_cma(gfp_t gfp_mask)
{
#ifdef CONFIG_CMA
if (gfp_migratetype(gfp_mask) == MIGRATE_MOVABLE)
- alloc_flags |= ALLOC_CMA;
+ return ALLOC_CMA;
#endif
- return alloc_flags;
+ return ALLOC_DEFAULT;
}
/*
@@ -4077,7 +4077,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
*/
page = get_page_from_freelist((gfp_mask | __GFP_HARDWALL) &
~__GFP_DIRECT_RECLAIM, order,
- ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac);
+ ac->alloc_flags|ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac);
if (page)
goto out;
@@ -4123,7 +4123,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
*/
if (gfp_mask & __GFP_NOFAIL)
page = __alloc_pages_cpuset_fallback(gfp_mask, order,
- ALLOC_NO_WATERMARKS, ac);
+ ac->alloc_flags|ALLOC_NO_WATERMARKS, ac);
}
out:
mutex_unlock(&oom_lock);
@@ -4474,7 +4474,7 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask,
}
static inline unsigned int
-gfp_to_alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)
+alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)
{
unsigned int alloc_flags = 0;
@@ -4497,7 +4497,7 @@ gfp_to_alloc_flags_nonblocking(gfp_t gfp_mask, unsigned int order)
}
static inline unsigned int
-gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
+alloc_flags_slowpath(gfp_t gfp_mask, unsigned int order)
{
unsigned int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
@@ -4512,7 +4512,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
if (gfp_mask & __GFP_KSWAPD_RECLAIM)
alloc_flags |= ALLOC_KSWAPD;
- alloc_flags |= gfp_to_alloc_flags_nonblocking(gfp_mask, order);
+ alloc_flags |= alloc_flags_nonblocking(gfp_mask, order);
if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {
/*
@@ -4525,7 +4525,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
} else if (unlikely(rt_or_dl_task(current)) && in_task())
alloc_flags |= ALLOC_MIN_RESERVE;
- alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, alloc_flags);
+ alloc_flags |= alloc_flags_cma(gfp_mask);
if (defrag_mode)
alloc_flags |= ALLOC_NOFRAGMENT;
@@ -4790,8 +4790,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* The fast path uses conservative alloc_flags to succeed only until
* kswapd needs to be woken up, and to avoid the cost of setting up
* alloc_flags precisely. So we do that now.
+ *
+ * Can't just or alloc_flags if it contains WMARK bits, but those flags
+ * shouldn't be set in ac->alloc_flags.
*/
- alloc_flags = gfp_to_alloc_flags(gfp_mask, order);
+ VM_WARN_ON(ac->alloc_flags & ALLOC_WMARK_MASK);
+ alloc_flags = ac->alloc_flags | alloc_flags_slowpath(gfp_mask, order);
/*
* We need to recalculate the starting point for the zonelist iterator
@@ -4832,8 +4836,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
reserve_flags = __gfp_pfmemalloc_flags(gfp_mask);
if (reserve_flags)
- alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, reserve_flags) |
- (alloc_flags & ALLOC_KSWAPD);
+ alloc_flags = alloc_flags_cma(gfp_mask) | reserve_flags |
+ ac->alloc_flags | (alloc_flags & ALLOC_KSWAPD);
/*
* Reset the nodemask and zonelist iterators if memory policies can be
@@ -5002,6 +5006,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* we always retry
*/
if (unlikely(nofail)) {
+ unsigned int alloc_flags = ac->alloc_flags | ALLOC_MIN_RESERVE;
+
/*
* Lacking direct_reclaim we can't do anything to reclaim memory,
* we disregard these unreasonable nofail requests and still
@@ -5017,7 +5023,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* could deplete whole memory reserves which would just make
* the situation worse.
*/
- page = __alloc_pages_cpuset_fallback(gfp_mask, order, ALLOC_MIN_RESERVE, ac);
+ page = __alloc_pages_cpuset_fallback(gfp_mask, order, alloc_flags, ac);
if (page)
goto got_pg;
@@ -5059,11 +5065,11 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,
* Don't invoke should_fail logic, since it may call
* get_random_u32() and printk() which need to spin_lock.
*/
- if (!(*alloc_flags & ALLOC_TRYLOCK) &&
+ if (!(*alloc_flags & ALLOC_NOLOCK) &&
should_fail_alloc_page(gfp_mask, order))
return false;
- *alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, *alloc_flags);
+ *alloc_flags |= alloc_flags_cma(gfp_mask);
/* Dirty zone balancing only done in the fast path */
ac->spread_dirty_pages = (gfp_mask & __GFP_WRITE);
@@ -5221,7 +5227,7 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,
}
nr_account++;
- prep_new_page(page, 0, gfp, 0);
+ prep_new_page(page, 0, gfp, ALLOC_DEFAULT);
set_page_refcounted(page);
page_array[nr_populated++] = page;
}
@@ -5235,7 +5241,7 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,
return nr_populated;
failed:
- page = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask);
+ page = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask, ALLOC_DEFAULT);
if (page)
page_array[nr_populated++] = page;
goto out;
@@ -5270,24 +5276,87 @@ void free_pages_bulk(struct page **page_array, unsigned long nr_pages)
}
}
+static inline bool alloc_order_allowed(gfp_t gfp, unsigned int order,
+ unsigned int alloc_flags)
+{
+ if (alloc_flags & ALLOC_NOLOCK)
+ return pcp_allowed_order(order);
+
+ /*
+ * There are several places where we assume that the order value is sane
+ * so bail out early if the request is out of bound.
+ */
+ return !(WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp));
+}
+
+static inline bool alloc_nolock_allowed(void)
+{
+ if (!can_spin_trylock())
+ return false;
+
+ /* Bailout, since _deferred_grow_zone() needs to take a lock */
+ if (deferred_pages_enabled())
+ return false;
+
+ return true;
+}
+
+/*
+ * GFP flags to set for ALLOC_NOLOCK i.e. alloc_pages_nolock().
+ *
+ * Do not specify __GFP_DIRECT_RECLAIM, since direct claim is not allowed.
+ * Do not specify __GFP_KSWAPD_RECLAIM either, since wake up of kswapd
+ * is not safe in arbitrary context.
+ *
+ * These two are the conditions for gfpflags_allow_spinning() being true.
+ *
+ * Specify __GFP_NOWARN since failing alloc_pages_nolock() is not a reason
+ * to warn. Also warn would trigger printk() which is unsafe from
+ * various contexts. We cannot use printk_deferred_enter() to mitigate,
+ * since the running context is unknown.
+ *
+ * Specify __GFP_ZERO to make sure that call to kmsan_alloc_page() below
+ * is safe in any context. Also zeroing the page is mandatory for
+ * BPF use cases.
+ *
+ * Though __GFP_NOMEMALLOC is not checked in the code path below,
+ * specify it here to highlight that alloc_pages_nolock()
+ * doesn't want to deplete reserves.
+ */
+static const gfp_t gfp_nolock = __GFP_NOWARN | __GFP_ZERO | __GFP_NOMEMALLOC |
+ __GFP_COMP;
+
/*
* This is the 'heart' of the zoned buddy allocator.
*/
struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
- int preferred_nid, nodemask_t *nodemask)
+ int preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)
{
struct page *page;
- unsigned int alloc_flags = ALLOC_WMARK_LOW;
gfp_t alloc_gfp; /* The gfp_t that was actually used for allocation */
- struct alloc_context ac = { };
+ struct alloc_context ac = {
+ .alloc_flags = alloc_flags,
+ };
+ unsigned int fastpath_alloc_flags = alloc_flags;
- /*
- * There are several places where we assume that the order value is sane
- * so bail out early if the request is out of bound.
- */
- if (WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp))
+ /* Other flags could be supported later if needed. */
+ if (WARN_ON(alloc_flags & ~(ALLOC_NOLOCK | ALLOC_NO_CODETAG)))
+ return NULL;
+
+ if (!alloc_order_allowed(gfp, order, alloc_flags))
return NULL;
+ if (alloc_flags & ALLOC_NOLOCK) {
+ /* Certain other flags could be supported later if needed. */
+ VM_WARN_ON_ONCE(gfp & ~(__GFP_ACCOUNT | gfp_nolock));
+ if (!alloc_nolock_allowed())
+ return NULL;
+ gfp |= gfp_nolock;
+ fastpath_alloc_flags |= ALLOC_WMARK_MIN;
+ } else {
+ fastpath_alloc_flags |= ALLOC_WMARK_LOW;
+ }
+
gfp &= gfp_allowed_mask;
/*
* Apply scoped allocation constraints. This is mainly about GFP_NOFS
@@ -5299,19 +5368,22 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
gfp = current_gfp_context(gfp);
alloc_gfp = gfp;
if (!prepare_alloc_pages(gfp, order, preferred_nid, nodemask, &ac,
- &alloc_gfp, &alloc_flags))
+ &alloc_gfp, &fastpath_alloc_flags))
return NULL;
- /*
- * Forbid the first pass from falling back to types that fragment
- * memory until all local zones are considered.
- */
- alloc_flags |= alloc_flags_nofragment(zonelist_zone(ac.preferred_zoneref), gfp);
- alloc_flags |= gfp_to_alloc_flags_nonblocking(gfp, order) & ALLOC_HIGHATOMIC;
+ if (!(alloc_flags & ALLOC_NOLOCK)) {
+ /*
+ * Forbid the first pass from falling back to types that
+ * fragment memory until all local zones are considered.
+ */
+ fastpath_alloc_flags |= alloc_flags_nofragment(
+ zonelist_zone(ac.preferred_zoneref), gfp);
+ }
+ fastpath_alloc_flags |= alloc_flags_nonblocking(gfp, order) & ALLOC_HIGHATOMIC;
- /* First allocation attempt */
- page = get_page_from_freelist(alloc_gfp, order, alloc_flags, &ac);
- if (likely(page))
+ /* First allocation attempt (or, for nolock, only attempt) */
+ page = get_page_from_freelist(alloc_gfp, order, fastpath_alloc_flags, &ac);
+ if (likely(page) || (alloc_flags & ALLOC_NOLOCK))
goto out;
alloc_gfp = gfp;
@@ -5328,7 +5400,8 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
out:
if (memcg_kmem_online() && (gfp & __GFP_ACCOUNT) && page &&
unlikely(__memcg_kmem_charge_page(page, gfp, order) != 0)) {
- free_frozen_pages(page, order);
+ __free_frozen_pages(page, order,
+ alloc_flags & ALLOC_NOLOCK ? FPI_TRYLOCK : 0);
page = NULL;
}
@@ -5340,22 +5413,34 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
EXPORT_SYMBOL(__alloc_frozen_pages_noprof);
struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,
- int preferred_nid, nodemask_t *nodemask)
+ int preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)
{
struct page *page;
- page = __alloc_frozen_pages_noprof(gfp, order, preferred_nid, nodemask);
+ page = __alloc_frozen_pages_noprof(gfp, order, preferred_nid, nodemask,
+ alloc_flags);
if (page)
set_page_refcounted(page);
return page;
}
-EXPORT_SYMBOL(__alloc_pages_noprof);
+
+struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)
+{
+ if (nid == NUMA_NO_NODE)
+ nid = numa_mem_id();
+
+ VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
+ warn_if_node_offline(nid, gfp_mask);
+
+ return __alloc_pages_noprof(gfp_mask, order, nid, NULL, ALLOC_DEFAULT);
+}
+EXPORT_SYMBOL(alloc_pages_node_noprof);
struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,
nodemask_t *nodemask)
{
struct page *page = __alloc_pages_noprof(gfp | __GFP_COMP, order,
- preferred_nid, nodemask);
+ preferred_nid, nodemask, ALLOC_DEFAULT);
return page_rmappable_folio(page);
}
EXPORT_SYMBOL(__folio_alloc_noprof);
@@ -7037,7 +7122,7 @@ static void split_free_frozen_pages(struct list_head *list, gfp_t gfp_mask)
list_for_each_entry_safe(page, next, &list[order], lru) {
int i;
- post_alloc_hook(page, order, gfp_mask);
+ post_alloc_hook(page, order, gfp_mask, ALLOC_DEFAULT);
if (!order)
continue;
@@ -7242,7 +7327,7 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
struct page *head = pfn_to_page(start);
check_new_pages(head, order);
- prep_new_page(head, order, gfp_mask, 0);
+ prep_new_page(head, order, gfp_mask, ALLOC_DEFAULT);
} else {
ret = -EINVAL;
WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
@@ -7804,7 +7889,7 @@ static bool cond_accept_memory(struct zone *zone, unsigned int order,
return false;
/* Bailout, since try_to_accept_memory_one() needs to take a lock */
- if (alloc_flags & ALLOC_TRYLOCK)
+ if (alloc_flags & ALLOC_NOLOCK)
return false;
wmark = promo_wmark_pages(zone);
@@ -7874,80 +7959,10 @@ static bool __free_unaccepted(struct page *page)
struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)
{
- /*
- * Do not specify __GFP_DIRECT_RECLAIM, since direct claim is not allowed.
- * Do not specify __GFP_KSWAPD_RECLAIM either, since wake up of kswapd
- * is not safe in arbitrary context.
- *
- * These two are the conditions for gfpflags_allow_spinning() being true.
- *
- * Specify __GFP_NOWARN since failing alloc_pages_nolock() is not a reason
- * to warn. Also warn would trigger printk() which is unsafe from
- * various contexts. We cannot use printk_deferred_enter() to mitigate,
- * since the running context is unknown.
- *
- * Specify __GFP_ZERO to make sure that call to kmsan_alloc_page() below
- * is safe in any context. Also zeroing the page is mandatory for
- * BPF use cases.
- *
- * Though __GFP_NOMEMALLOC is not checked in the code path below,
- * specify it here to highlight that alloc_pages_nolock()
- * doesn't want to deplete reserves.
- */
- gfp_t alloc_gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_NOMEMALLOC | __GFP_COMP
- | gfp_flags;
- unsigned int alloc_flags = ALLOC_TRYLOCK;
- struct alloc_context ac = { };
- struct page *page;
-
- VM_WARN_ON_ONCE(gfp_flags & ~__GFP_ACCOUNT);
- /*
- * In PREEMPT_RT spin_trylock() will call raw_spin_lock() which is
- * unsafe in NMI. If spin_trylock() is called from hard IRQ the current
- * task may be waiting for one rt_spin_lock, but rt_spin_trylock() will
- * mark the task as the owner of another rt_spin_lock which will
- * confuse PI logic, so return immediately if called from hard IRQ or
- * NMI.
- *
- * Note, irqs_disabled() case is ok. This function can be called
- * from raw_spin_lock_irqsave region.
- */
- if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
- return NULL;
-
- /* On UP, spin_trylock() always succeeds even when it is locked */
- if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
- return NULL;
-
- if (!pcp_allowed_order(order))
- return NULL;
-
- /* Bailout, since _deferred_grow_zone() needs to take a lock */
- if (deferred_pages_enabled())
- return NULL;
-
if (nid == NUMA_NO_NODE)
nid = numa_node_id();
- prepare_alloc_pages(alloc_gfp, order, nid, NULL, &ac,
- &alloc_gfp, &alloc_flags);
-
- /*
- * Best effort allocation from percpu free list.
- * If it's empty attempt to spin_trylock zone->lock.
- */
- page = get_page_from_freelist(alloc_gfp, order, alloc_flags, &ac);
-
- /* Unlike regular alloc_pages() there is no __alloc_pages_slowpath(). */
-
- if (memcg_kmem_online() && page && (gfp_flags & __GFP_ACCOUNT) &&
- unlikely(__memcg_kmem_charge_page(page, alloc_gfp, order) != 0)) {
- __free_frozen_pages(page, order, FPI_TRYLOCK);
- page = NULL;
- }
- trace_mm_page_alloc(page, order, alloc_gfp, ac.migratetype);
- kmsan_alloc_page(page, order, alloc_gfp);
- return page;
+ return __alloc_frozen_pages_noprof(gfp_flags, order, nid, NULL, ALLOC_NOLOCK);
}
/**
* alloc_pages_nolock - opportunistic reentrant allocation from any context
diff --git a/mm/page_alloc.h b/mm/page_alloc.h
new file mode 100644
index 00000000000000..b9259deddb59d7
--- /dev/null
+++ b/mm/page_alloc.h
@@ -0,0 +1,312 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * mm-internal API for the page (buddy) allocator. Public API lives in
+ * include/linux/gfp.h.
+ */
+#ifndef __MM_PAGE_ALLOC_H
+#define __MM_PAGE_ALLOC_H
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/nodemask.h>
+#include <linux/types.h>
+
+#define ALLOC_DEFAULT 0
+/* The ALLOC_WMARK bits are used as an index to zone->watermark */
+#define ALLOC_WMARK_MIN WMARK_MIN
+#define ALLOC_WMARK_LOW WMARK_LOW
+#define ALLOC_WMARK_HIGH WMARK_HIGH
+#define ALLOC_NO_WATERMARKS 0x04 /* don't check watermarks at all */
+
+/* Mask to get the watermark bits */
+#define ALLOC_WMARK_MASK (ALLOC_NO_WATERMARKS-1)
+
+/*
+ * Only MMU archs have async oom victim reclaim - aka oom_reaper so we
+ * cannot assume a reduced access to memory reserves is sufficient for
+ * !MMU
+ */
+#ifdef CONFIG_MMU
+#define ALLOC_OOM 0x08
+#else
+#define ALLOC_OOM ALLOC_NO_WATERMARKS
+#endif
+
+#define ALLOC_NON_BLOCK 0x10 /* Caller cannot block. Allow access
+ * to 25% of the min watermark or
+ * 62.5% if __GFP_HIGH is set.
+ */
+#define ALLOC_MIN_RESERVE 0x20 /* __GFP_HIGH set. Allow access to 50%
+ * of the min watermark.
+ */
+#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
+#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */
+#ifdef CONFIG_ZONE_DMA32
+#define ALLOC_NOFRAGMENT 0x100 /* avoid mixing pageblock types */
+#else
+#define ALLOC_NOFRAGMENT 0x0
+#endif
+#define ALLOC_HIGHATOMIC 0x200 /* Allows access to MIGRATE_HIGHATOMIC */
+#define ALLOC_NOLOCK 0x400 /* Only use spin_trylock in allocation path */
+#define ALLOC_KSWAPD 0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */
+/*
+ * Avoid alloc_tag recursion for internal allocations.
+ *
+ * Callers must clear_page_tag_ref() before freeing to avoid warnings from
+ * alloc_tag_sub_check().
+ */
+#define ALLOC_NO_CODETAG 0x1000
+
+/* Flags that allow allocations below the min watermark. */
+#define ALLOC_RESERVES (ALLOC_NON_BLOCK|ALLOC_MIN_RESERVE|ALLOC_HIGHATOMIC|ALLOC_OOM)
+
+/*
+ * Structure for holding the mostly immutable allocation parameters passed
+ * between functions involved in allocations, including the alloc_pages*
+ * family of functions.
+ *
+ * nodemask, migratetype and highest_zoneidx are initialized only once in
+ * __alloc_pages() and then never change.
+ *
+ * zonelist, preferred_zone and highest_zoneidx are set first in
+ * __alloc_pages() for the fast path, and might be later changed
+ * in __alloc_pages_slowpath(). All other functions pass the whole structure
+ * by a const pointer.
+ */
+struct alloc_context {
+ struct zonelist *zonelist;
+ const nodemask_t *nodemask;
+ struct zoneref *preferred_zoneref;
+ int migratetype;
+
+ /*
+ * highest_zoneidx represents highest usable zone index of
+ * the allocation request. Due to the nature of the zone,
+ * memory on lower zone than the highest_zoneidx will be
+ * protected by lowmem_reserve[highest_zoneidx].
+ *
+ * highest_zoneidx is also used by reclaim/compaction to limit
+ * the target zone since higher zone than this index cannot be
+ * usable for this allocation request.
+ */
+ enum zone_type highest_zoneidx;
+ bool spread_dirty_pages;
+ /* Only flags that are global to the whole allocation go here. */
+ unsigned int alloc_flags;
+};
+
+/*
+ * This function returns the order of a free page in the buddy system. In
+ * general, page_zone(page)->lock must be held by the caller to prevent the
+ * page from being allocated in parallel and returning garbage as the order.
+ * If a caller does not hold page_zone(page)->lock, it must guarantee that the
+ * page cannot be allocated or merged in parallel. Alternatively, it must
+ * handle invalid values gracefully, and use buddy_order_unsafe() below.
+ */
+static inline unsigned int buddy_order(struct page *page)
+{
+ /* PageBuddy() must be checked by the caller */
+ return page_private(page);
+}
+
+/*
+ * Like buddy_order(), but for callers who cannot afford to hold the zone lock.
+ * PageBuddy() should be checked first by the caller to minimize race window,
+ * and invalid values must be handled gracefully.
+ *
+ * READ_ONCE is used so that if the caller assigns the result into a local
+ * variable and e.g. tests it for valid range before using, the compiler cannot
+ * decide to remove the variable and inline the page_private(page) multiple
+ * times, potentially observing different values in the tests and the actual
+ * use of the result.
+ */
+#define buddy_order_unsafe(page) READ_ONCE(page_private(page))
+
+/*
+ * This function checks whether a page is free && is the buddy
+ * we can coalesce a page and its buddy if
+ * (a) the buddy is not in a hole (check before calling!) &&
+ * (b) the buddy is in the buddy system &&
+ * (c) a page and its buddy have the same order &&
+ * (d) a page and its buddy are in the same zone.
+ *
+ * For recording whether a page is in the buddy system, we set PageBuddy.
+ * Setting, clearing, and testing PageBuddy is serialized by zone->lock.
+ *
+ * For recording page's order, we use page_private(page).
+ */
+static inline bool page_is_buddy(struct page *page, struct page *buddy,
+ unsigned int order)
+{
+ if (!page_is_guard(buddy) && !PageBuddy(buddy))
+ return false;
+
+ if (buddy_order(buddy) != order)
+ return false;
+
+ /*
+ * zone check is done late to avoid uselessly calculating
+ * zone/node ids for pages that could never merge.
+ */
+ if (page_zone_id(page) != page_zone_id(buddy))
+ return false;
+
+ VM_BUG_ON_PAGE(page_count(buddy) != 0, buddy);
+
+ return true;
+}
+
+/*
+ * Locate the struct page for both the matching buddy in our
+ * pair (buddy1) and the combined O(n+1) page they form (page).
+ *
+ * 1) Any buddy B1 will have an order O twin B2 which satisfies
+ * the following equation:
+ * B2 = B1 ^ (1 << O)
+ * For example, if the starting buddy (buddy2) is #8 its order
+ * 1 buddy is #10:
+ * B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
+ *
+ * 2) Any buddy B will have an order O+1 parent P which
+ * satisfies the following equation:
+ * P = B & ~(1 << O)
+ *
+ * Assumption: *_mem_map is contiguous at least up to MAX_PAGE_ORDER
+ */
+static inline unsigned long
+__find_buddy_pfn(unsigned long page_pfn, unsigned int order)
+{
+ return page_pfn ^ (1 << order);
+}
+
+/*
+ * Find the buddy of @page and validate it.
+ * @page: The input page
+ * @pfn: The pfn of the page, it saves a call to page_to_pfn() when the
+ * function is used in the performance-critical __free_one_page().
+ * @order: The order of the page
+ * @buddy_pfn: The output pointer to the buddy pfn, it also saves a call to
+ * page_to_pfn().
+ *
+ * The found buddy can be a non PageBuddy, out of @page's zone, or its order is
+ * not the same as @page. The validation is necessary before use it.
+ *
+ * Return: the found buddy page or NULL if not found.
+ */
+static inline struct page *find_buddy_page_pfn(struct page *page,
+ unsigned long pfn, unsigned int order, unsigned long *buddy_pfn)
+{
+ unsigned long __buddy_pfn = __find_buddy_pfn(pfn, order);
+ struct page *buddy;
+
+ buddy = page + (__buddy_pfn - pfn);
+ if (buddy_pfn)
+ *buddy_pfn = __buddy_pfn;
+
+ if (page_is_buddy(page, buddy, order))
+ return buddy;
+ return NULL;
+}
+
+extern struct page *__pageblock_pfn_to_page(unsigned long start_pfn,
+ unsigned long end_pfn, struct zone *zone);
+
+static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn,
+ unsigned long end_pfn, struct zone *zone)
+{
+ if (zone->contiguous)
+ return pfn_to_page(start_pfn);
+
+ return __pageblock_pfn_to_page(start_pfn, end_pfn, zone);
+}
+
+extern void __free_pages_core(struct page *page, unsigned int order,
+ enum meminit_context context);
+
+void post_alloc_hook(struct page *page, unsigned int order, gfp_t gfp_flags,
+ unsigned int alloc_flags);
+extern bool free_pages_prepare(struct page *page, unsigned int order);
+
+extern int user_min_free_kbytes;
+
+struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order, int nid,
+ nodemask_t *nodemask, unsigned int alloc_flags);
+#define __alloc_frozen_pages(...) \
+ alloc_hooks(__alloc_frozen_pages_noprof(__VA_ARGS__))
+void free_frozen_pages(struct page *page, unsigned int order);
+void free_unref_folios(struct folio_batch *fbatch);
+
+#ifdef CONFIG_NUMA
+struct page *alloc_frozen_pages_noprof(gfp_t, unsigned int order);
+#else
+static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)
+{
+ return __alloc_frozen_pages_noprof(gfp, order, numa_node_id(), NULL,
+ ALLOC_DEFAULT);
+}
+#endif
+
+#define alloc_frozen_pages(...) \
+ alloc_hooks(alloc_frozen_pages_noprof(__VA_ARGS__))
+
+struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);
+#define alloc_frozen_pages_nolock(...) \
+ alloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))
+void free_frozen_pages_nolock(struct page *page, unsigned int order);
+
+struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,
+ nodemask_t *nodemask, unsigned int alloc_flags);
+#define __alloc_pages(...) alloc_hooks(__alloc_pages_noprof(__VA_ARGS__))
+
+extern void zone_pcp_reset(struct zone *zone);
+extern void zone_pcp_disable(struct zone *zone);
+extern void zone_pcp_enable(struct zone *zone);
+extern void zone_pcp_init(struct zone *zone);
+
+enum fallback_result {
+ /* Found suitable migratetype, *mt_out is valid. */
+ FALLBACK_FOUND,
+ /* No fallback found in requested order. */
+ FALLBACK_EMPTY,
+ /* Passed @claimable, but claiming whole block is a bad idea. */
+ FALLBACK_NOCLAIM,
+};
+enum fallback_result
+find_suitable_fallback(struct free_area *area, unsigned int order,
+ int migratetype, bool claimable, int *mt_out);
+
+static inline bool free_area_empty(struct free_area *area, int migratetype)
+{
+ return list_empty(&area->free_list[migratetype]);
+}
+
+/* Convert GFP flags to their corresponding migrate type */
+#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
+#define GFP_MOVABLE_SHIFT 3
+
+static inline int gfp_migratetype(const gfp_t gfp_flags)
+{
+ VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);
+ BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);
+ BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);
+ BUILD_BUG_ON((___GFP_RECLAIMABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_RECLAIMABLE);
+ BUILD_BUG_ON(((___GFP_MOVABLE | ___GFP_RECLAIMABLE) >>
+ GFP_MOVABLE_SHIFT) != MIGRATE_HIGHATOMIC);
+
+ if (unlikely(page_group_by_mobility_disabled))
+ return MIGRATE_UNMOVABLE;
+
+ /* Group based on mobility */
+ return (__force unsigned long)(gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;
+}
+#undef GFP_MOVABLE_MASK
+#undef GFP_MOVABLE_SHIFT
+
+bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp);
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
+void drain_all_pages(struct zone *zone);
+
+void page_alloc_init_cpuhp(void);
+void page_alloc_sysctl_init(void);
+
+#endif /* __MM_PAGE_ALLOC_H */
diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c
index d2423f30577e49..e63efe78b7d4b4 100644
--- a/mm/page_frag_cache.c
+++ b/mm/page_frag_cache.c
@@ -18,7 +18,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/page_frag_cache.h>
-#include "internal.h"
+#include "page_alloc.h"
static unsigned long encoded_page_create(struct page *page, unsigned int order,
bool pfmemalloc)
@@ -57,10 +57,10 @@ static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP |
__GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;
page = __alloc_pages(gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER,
- numa_mem_id(), NULL);
+ numa_mem_id(), NULL, ALLOC_DEFAULT);
#endif
if (unlikely(!page)) {
- page = __alloc_pages(gfp, 0, numa_mem_id(), NULL);
+ page = __alloc_pages(gfp, 0, numa_mem_id(), NULL, ALLOC_DEFAULT);
order = 0;
}
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 32ce8a7d9df355..e5dfc7bf494460 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -11,6 +11,7 @@
#include <linux/page_owner.h>
#include <linux/migrate.h>
#include "internal.h"
+#include "page_alloc.h"
#define CREATE_TRACE_POINTS
#include <trace/events/page_isolation.h>
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 26d6ab6530ce05..e399ebed27234e 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -13,7 +13,7 @@
#include <linux/memcontrol.h>
#include <linux/sched/clock.h>
-#include "internal.h"
+#include "page_alloc.h"
/*
* TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack)
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index 7418f2e500bb48..c7325704c3202e 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/scatterlist.h>
+#include "page_alloc.h"
#include "page_reporting.h"
#include "internal.h"
diff --git a/mm/show_mem.c b/mm/show_mem.c
index 1b721a8ade67dd..d1288b4c2b6401 100644
--- a/mm/show_mem.c
+++ b/mm/show_mem.c
@@ -16,6 +16,7 @@
#include <linux/vmstat.h>
#include "internal.h"
+#include "page_alloc.h"
#include "swap.h"
atomic_long_t _totalram_pages __read_mostly;
diff --git a/mm/shuffle.c b/mm/shuffle.c
index fb1393b8b3a9d6..82a2c7725a08ab 100644
--- a/mm/shuffle.c
+++ b/mm/shuffle.c
@@ -7,6 +7,7 @@
#include <linux/random.h>
#include <linux/moduleparam.h>
#include "internal.h"
+#include "page_alloc.h"
#include "shuffle.h"
DEFINE_STATIC_KEY_FALSE(page_alloc_shuffle_key);
diff --git a/mm/slub.c b/mm/slub.c
index 9ec774dc700969..b19dc46de73c56 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -53,6 +53,7 @@
#include <trace/events/kmem.h>
#include "internal.h"
+#include "page_alloc.h"
/*
* Lock order:
@@ -3291,7 +3292,8 @@ static inline struct slab *alloc_slab_page(gfp_t flags, int node,
else if (node == NUMA_NO_NODE)
page = alloc_frozen_pages(flags, order);
else
- page = __alloc_frozen_pages(flags, order, node, NULL);
+ page = __alloc_frozen_pages(flags, order, node, NULL,
+ ALLOC_DEFAULT);
if (!page)
return NULL;
@@ -5301,7 +5303,8 @@ static void *___kmalloc_large_node(size_t size, gfp_t flags, int node)
if (node == NUMA_NO_NODE)
page = alloc_frozen_pages_noprof(flags, order);
else
- page = __alloc_frozen_pages_noprof(flags, order, node, NULL);
+ page = __alloc_frozen_pages_noprof(flags, order, node, NULL,
+ ALLOC_DEFAULT);
if (page) {
ptr = page_address(page);
@@ -5405,15 +5408,7 @@ static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_f
if (unlikely(!size))
return ZERO_SIZE_PTR;
- /*
- * See the comment for the same check in
- * alloc_frozen_pages_nolock_noprof()
- */
- if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
- return NULL;
-
- /* On UP, spin_trylock() always succeeds even when it is locked */
- if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
+ if (!can_spin_trylock())
return NULL;
retry:
diff --git a/mm/swap.c b/mm/swap.c
index 58e4eff698cc4e..d25131305c94cb 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -39,6 +39,7 @@
#include <linux/buffer_head.h>
#include "internal.h"
+#include "page_alloc.h"
#define CREATE_TRACE_POINTS
#include <trace/events/pagemap.h>
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 56fe5393f30f82..1474a7234ea16c 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -66,6 +66,7 @@
#include <linux/sched/sysctl.h>
#include "internal.h"
+#include "page_alloc.h"
#include "swap.h"
#define CREATE_TRACE_POINTS
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 7b93fbf9af0926..3b5cb1031f7209 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -30,6 +30,7 @@
#include <linux/sched/isolation.h>
#include "internal.h"
+#include "page_alloc.h"
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_NUMA
diff --git a/tools/include/linux/gfp_types.h b/tools/include/linux/gfp_types.h
index 6c75df30a281d1..a93b8bd200b760 100644
--- a/tools/include/linux/gfp_types.h
+++ b/tools/include/linux/gfp_types.h
@@ -55,7 +55,6 @@ enum {
#ifdef CONFIG_LOCKDEP
___GFP_NOLOCKDEP_BIT,
#endif
- ___GFP_NO_OBJ_EXT_BIT,
___GFP_LAST_BIT
};
@@ -96,7 +95,6 @@ enum {
#else
#define ___GFP_NOLOCKDEP 0
#endif
-#define ___GFP_NO_OBJ_EXT BIT(___GFP_NO_OBJ_EXT_BIT)
/*
* Physical address zone modifiers (see linux/mmzone.h - low four bits)
@@ -137,17 +135,12 @@ enum {
* node with no fallbacks or placement policy enforcements.
*
* %__GFP_ACCOUNT causes the allocation to be accounted to kmemcg.
- *
- * %__GFP_NO_OBJ_EXT causes slab allocation to have no object extension.
- * mark_obj_codetag_empty() should be called upon freeing for objects allocated
- * with this flag to indicate that their NULL tags are expected and normal.
*/
#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE)
#define __GFP_WRITE ((__force gfp_t)___GFP_WRITE)
#define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL)
#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)
#define __GFP_ACCOUNT ((__force gfp_t)___GFP_ACCOUNT)
-#define __GFP_NO_OBJ_EXT ((__force gfp_t)___GFP_NO_OBJ_EXT)
/**
* DOC: Watermark modifiers
|
| 3/2 | 2026/07/03 12:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27547 output: 26 thoughts: 1134 Thoughts: **Analyzing the Page Allocator Patch** Okay, so I'm looking at this patch for the Linux kernel's page allocator. It's making some pretty significant changes, so let's break it down. First, it seems to be refactoring things, moving internal definitions from `mm/internal.h` to `mm/page_alloc.h`. That's standard housekeeping, but it's important to note because it shows they're reorganizing the core structures. The meat of it is that the patch alters the signatures of key allocation functions: `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof`. Now, they both accept an `alloc_flags` parameter. That's a big deal – it indicates a shift in how these functions are being configured during allocation. It seems to be centralizing the allocation flags management. The patch also deprecates `__GFP_NO_OBJ_EXT` in favor of `ALLOC_NO_CODETAG`, again, a tidier approach. `alloc_pages_nolock` is also modified, which I need to investigate in more detail as it's a common path. Moreover, `alloc_pages_node` is no longer inlined, suggesting a performance trade-off or architectural change. Also, `alloc_tag_add_early_pfn` and `post_alloc_hook` are updated to align with the new `alloc_flags` scheme. The modifications to `__alloc_pages_slowpath` and `get_page_from_freelist` to use `ac->alloc_flags` further reinforce the theme of flag management. Functionally, I can see this is about how `alloc_flags` are propagated and used within the page allocator. The change to `alloc_frozen_pages_nolock_noprof` to use `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK` is another piece of the puzzle. Now, to zero in on the key areas, I need to focus on these functions: `__alloc_frozen_pages_noprof`, `__alloc_pages_noprof`, `alloc_pages_node_noprof`, and `alloc_frozen_pages_nolock_noprof`. Hang on, `alloc_pages_node_noprof` is a *new* function exported in `mm/page_alloc.c` and `__alloc_frozen_pages_noprof` is heavily modified, as is `alloc_frozen_pages_nolock_noprof`. Gotta check those. Ok, `alloc_frozen_pages_nolock_noprof` is used in `mm/slub.c` within `__kmalloc_nolock_noprof`, but that's not new. Then, `alloc_tag_add_early_pfn` is touched in `mm/alloc_tag.c` and `mm/page_alloc.c` which I need to check in more detail, as it relates to profiling. Also, I see `alloc_pages_node_noprof` is used in `include/linux/gfp.h`, and the same applies to `__alloc_pages_noprof`. `__alloc_frozen_pages_noprof` is used in multiple places (`mm/page_alloc.c`, `mm/mempolicy.c`, `mm/slub.c`), so this is a crucial point. Furthermore, `alloc_frozen_pages_nolock_noprof` is only used in `mm/page_alloc.c`. The removal of `__GFP_NO_OBJ_EXT` in favor of `ALLOC_NO_CODETAG` (defined in `mm/page_alloc.h`) is another small but notable change. Given all this, I'd say this patch is absolutely worth fuzzing. The changes are touching core page allocator logic and modifying flag management which is critical. Here's a refined list of functions to target: `__alloc_frozen_pages_noprof`, `alloc_frozen_pages_nolock_noprof`, `alloc_pages_node_noprof`, `__alloc_pages_slowpath`, `__alloc_pages_may_oom`, and `alloc_pages_bulk_noprof`. Ah, `__alloc_pages_slowpath` and `__alloc_pages_may_oom` are static though, which limits their direct exposure, but still need to be considered in the call chains. At least `alloc_pages_node_noprof` and `__alloc_frozen_pages_noprof` are exported. I'll need to check if `alloc_frozen_pages_nolock_noprof` is |
| 4/2 | 2026/07/03 12:54 | tool | grepper |
0mArgs:{
"Expression": "alloc_frozen_pages_nolock_noprof"
}Results: {
"Output": "mm/page_alloc.c=7952=static bool __free_unaccepted(struct page *page)\n--\nmm/page_alloc.c-7959-\nmm/page_alloc.c:7960:struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\nmm/page_alloc.c-7961-{\n--\nmm/page_alloc.c=7983=struct page *alloc_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\n--\nmm/page_alloc.c-7986-\nmm/page_alloc.c:7987:\tpage = alloc_frozen_pages_nolock_noprof(gfp_flags, nid, order);\nmm/page_alloc.c-7988-\tif (page)\n--\nmm/page_alloc.h=242=static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)\n--\nmm/page_alloc.h-251-\nmm/page_alloc.h:252:struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);\nmm/page_alloc.h-253-#define alloc_frozen_pages_nolock(...) \\\nmm/page_alloc.h:254:\talloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))\nmm/page_alloc.h-255-void free_frozen_pages_nolock(struct page *page, unsigned int order);\n"
} |
| 5/2 | 2026/07/03 12:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30159 output: 23 thoughts: 46 Thoughts: Okay, here's my interpretation of this thought process, keeping in mind my expertise: **Diving into Page Allocation Logic** Right, so I see `alloc_frozen_pages_nolock_noprof` being called from `alloc_pages_nolock_noprof`. That immediately flags something interesting. The "frozen" and "nolock" hints at a potential optimization or a specific allocation strategy, likely bypassing some usual locking mechanisms. My initial thought is to trace the execution path and understand the conditions under which this specific function gets used. Is it related to some kind of early boot-up process, or is it for certain memory types like those needed during kthread initialization? The "noprof" part, of course, raises another flag. It's obviously related to performance as it hints at the disabling of profiling in this path. The code is clearly attempting to speed up the page allocation as much as possible, for something that it considers very performance critical, by not collecting data in this path. This makes me immediately think of looking for the `CONFIG_MEM_ALLOC_PROFILING` config option. I need to understand if its enabled or disabled to properly understand the execution path here. Its value is likely to influence the code's behavior and the optimization strategy being employed. Let me now dig into the code and see how the config option plays a role here. |
| 6/2 | 2026/07/03 12:54 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_MEM_ALLOC_PROFILING"
}Results: {
"Output": "Documentation/admin-guide/sysctl/vm.rst=25=Currently, these files are in /proc/sys/vm:\n--\nDocumentation/admin-guide/sysctl/vm.rst-46-- max_map_count\nDocumentation/admin-guide/sysctl/vm.rst:47:- mem_profiling (only if CONFIG_MEM_ALLOC_PROFILING=y)\nDocumentation/admin-guide/sysctl/vm.rst-48-- memory_failure_early_kill\n--\nDocumentation/admin-guide/sysctl/vm.rst=479=mem_profiling\n--\nDocumentation/admin-guide/sysctl/vm.rst-481-\nDocumentation/admin-guide/sysctl/vm.rst:482:Enable memory profiling (when CONFIG_MEM_ALLOC_PROFILING=y)\nDocumentation/admin-guide/sysctl/vm.rst-483-\n--\nDocumentation/admin-guide/sysctl/vm.rst=489=memory allocations.\nDocumentation/admin-guide/sysctl/vm.rst-490-\nDocumentation/admin-guide/sysctl/vm.rst:491:The default value depends on CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT.\nDocumentation/admin-guide/sysctl/vm.rst-492-\nDocumentation/admin-guide/sysctl/vm.rst:493:When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, this control is read-only to avoid\nDocumentation/admin-guide/sysctl/vm.rst-494-warnings produced by allocations made while profiling is disabled and freed\n--\nDocumentation/mm/allocation-profiling.rst=11=kconfig options:\nDocumentation/mm/allocation-profiling.rst:12:- CONFIG_MEM_ALLOC_PROFILING\nDocumentation/mm/allocation-profiling.rst-13-\nDocumentation/mm/allocation-profiling.rst:14:- CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\nDocumentation/mm/allocation-profiling.rst-15-\nDocumentation/mm/allocation-profiling.rst:16:- CONFIG_MEM_ALLOC_PROFILING_DEBUG\nDocumentation/mm/allocation-profiling.rst-17- adds warnings for allocations that weren't accounted because of a\n--\nDocumentation/mm/allocation-profiling.rst=20=Boot parameter:\n--\nDocumentation/mm/allocation-profiling.rst-24- cannot be enabled at runtime (sysctl becomes read-only).\nDocumentation/mm/allocation-profiling.rst:25: When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y, default value is \"1\".\nDocumentation/mm/allocation-profiling.rst:26: When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=n, default value is \"never\".\nDocumentation/mm/allocation-profiling.rst-27- \"compressed\" optional parameter will try to store page tag references in a\n--\nDocumentation/mm/allocation-profiling.rst=33=sysctl:\n--\nDocumentation/mm/allocation-profiling.rst-39-\nDocumentation/mm/allocation-profiling.rst:40: The default value depends on CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT.\nDocumentation/mm/allocation-profiling.rst-41-\nDocumentation/mm/allocation-profiling.rst:42: When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, this control is read-only to avoid\nDocumentation/mm/allocation-profiling.rst-43- warnings produced by allocations made while profiling is disabled and freed\n--\ninclude/asm-generic/codetag.lds.h-4-\ninclude/asm-generic/codetag.lds.h:5:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/asm-generic/codetag.lds.h-6-#define IF_MEM_ALLOC_PROFILING(...) __VA_ARGS__\n--\ninclude/linux/alloc_tag.h=38=struct alloc_tag_module_section {\n--\ninclude/linux/alloc_tag.h-47-\ninclude/linux/alloc_tag.h:48:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\ninclude/linux/alloc_tag.h-49-\n--\ninclude/linux/alloc_tag.h=57=static inline void set_codetag_empty(union codetag_ref *ref)\n--\ninclude/linux/alloc_tag.h-62-\ninclude/linux/alloc_tag.h:63:#else /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\ninclude/linux/alloc_tag.h-64-\n--\ninclude/linux/alloc_tag.h=67=static inline void set_codetag_empty(union codetag_ref *ref)\n--\ninclude/linux/alloc_tag.h-72-\ninclude/linux/alloc_tag.h:73:#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\ninclude/linux/alloc_tag.h-74-\ninclude/linux/alloc_tag.h:75:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/alloc_tag.h-76-\n--\ninclude/linux/alloc_tag.h=97=DECLARE_PER_CPU(struct alloc_tag_counters, _shared_alloc_tag);\n--\ninclude/linux/alloc_tag.h-127-\ninclude/linux/alloc_tag.h:128:DECLARE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,\ninclude/linux/alloc_tag.h-129-\t\t\tmem_alloc_profiling_key);\n--\ninclude/linux/alloc_tag.h=131=static inline bool mem_alloc_profiling_enabled(void)\ninclude/linux/alloc_tag.h-132-{\ninclude/linux/alloc_tag.h:133:\treturn static_branch_maybe(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,\ninclude/linux/alloc_tag.h-134-\t\t\t\t \u0026mem_alloc_profiling_key);\n--\ninclude/linux/alloc_tag.h=137=static inline struct alloc_tag_counters alloc_tag_read(struct alloc_tag *tag)\n--\ninclude/linux/alloc_tag.h-151-\ninclude/linux/alloc_tag.h:152:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\ninclude/linux/alloc_tag.h-153-static inline void alloc_tag_add_check(union codetag_ref *ref, struct alloc_tag *tag)\n--\ninclude/linux/alloc_tag.h=231=static inline bool alloc_tag_is_inaccurate(struct alloc_tag *tag)\n--\ninclude/linux/alloc_tag.h-237-\ninclude/linux/alloc_tag.h:238:#else /* CONFIG_MEM_ALLOC_PROFILING */\ninclude/linux/alloc_tag.h-239-\n--\ninclude/linux/alloc_tag.h=246=static inline bool alloc_tag_is_inaccurate(struct alloc_tag *tag) { return false; }\n--\ninclude/linux/alloc_tag.h-248-\ninclude/linux/alloc_tag.h:249:#endif /* CONFIG_MEM_ALLOC_PROFILING */\ninclude/linux/alloc_tag.h-250-\n--\ninclude/linux/memcontrol.h=1447=struct slabobj_ext {\n--\ninclude/linux/memcontrol.h-1450-#endif\ninclude/linux/memcontrol.h:1451:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/memcontrol.h-1452-\tunion codetag_ref ref;\n--\ninclude/linux/pgalloc_tag.h-9-\ninclude/linux/pgalloc_tag.h:10:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/pgalloc_tag.h-11-\n--\ninclude/linux/pgalloc_tag.h=202=void __init alloc_tag_sec_init(void);\ninclude/linux/pgalloc_tag.h-203-\ninclude/linux/pgalloc_tag.h:204:#else /* CONFIG_MEM_ALLOC_PROFILING */\ninclude/linux/pgalloc_tag.h-205-\n--\ninclude/linux/pgalloc_tag.h=210=static inline struct alloc_tag *pgalloc_tag_get(struct page *page) { return NULL; }\ninclude/linux/pgalloc_tag.h-211-\ninclude/linux/pgalloc_tag.h:212:#endif /* CONFIG_MEM_ALLOC_PROFILING */\ninclude/linux/pgalloc_tag.h-213-\n--\ninclude/linux/rhashtable-types.h=86=struct rhashtable {\n--\ninclude/linux/rhashtable-types.h-96-\tatomic_t\t\t\tnelems;\ninclude/linux/rhashtable-types.h:97:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/rhashtable-types.h-98-\tstruct alloc_tag\t\t*alloc_tag;\n--\ninclude/linux/sched.h=826=struct task_struct {\n--\ninclude/linux/sched.h-850-\ninclude/linux/sched.h:851:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/sched.h-852-\tstruct alloc_tag\t\t*alloc_tag;\n--\ninclude/linux/sched.h=2342=extern void sched_set_stop_task(int cpu, struct task_struct *stop);\ninclude/linux/sched.h-2343-\ninclude/linux/sched.h:2344:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/sched.h-2345-static __always_inline struct alloc_tag *alloc_tag_save(struct alloc_tag *tag)\n--\ninclude/linux/sched.h=2351=static __always_inline void alloc_tag_restore(struct alloc_tag *tag, struct alloc_tag *old)\ninclude/linux/sched.h-2352-{\ninclude/linux/sched.h:2353:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\ninclude/linux/sched.h-2354-\tWARN(current-\u003ealloc_tag != tag, \"current-\u003ealloc_tag was changed:\\n\");\n--\nmm/Makefile=149=obj-$(CONFIG_LAZY_MMU_MODE_KUNIT_TEST) += tests/lazy_mmu_mode_kunit.o\nmm/Makefile:150:obj-$(CONFIG_MEM_ALLOC_PROFILING) += alloc_tag.o\n--\nmm/alloc_tag.c-25-\nmm/alloc_tag.c:26:#ifdef CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\nmm/alloc_tag.c-27-static bool mem_profiling_support = true;\n--\nmm/alloc_tag.c=36=EXPORT_SYMBOL(_shared_alloc_tag);\n--\nmm/alloc_tag.c-38-\nmm/alloc_tag.c:39:DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,\nmm/alloc_tag.c-40-\t\t\tmem_alloc_profiling_key);\n--\nmm/alloc_tag.c=763=static __init bool need_page_alloc_tagging(void)\n--\nmm/alloc_tag.c-770-\nmm/alloc_tag.c:771:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/alloc_tag.c-772-/*\n--\nmm/alloc_tag.c=849=static void __init clear_early_alloc_pfn_tag_refs(void)\n--\nmm/alloc_tag.c-902-}\nmm/alloc_tag.c:903:#else /* !CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/alloc_tag.c-904-static inline void __init clear_early_alloc_pfn_tag_refs(void) {}\nmm/alloc_tag.c:905:#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/alloc_tag.c-906-\n--\nmm/alloc_tag.c=924=static int proc_mem_profiling_handler(const struct ctl_table *table, int write,\n--\nmm/alloc_tag.c-935-\nmm/alloc_tag.c:936:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/alloc_tag.c-937-\t\t/* User can't toggle profiling while debugging */\n--\nmm/page_alloc.c=1219=static void clear_highpages_kasan_tagged(struct page *page, int numpages)\n--\nmm/page_alloc.c-1233-\nmm/page_alloc.c:1234:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/page_alloc.c-1235-\n--\nmm/page_alloc.c=1300=static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr)\n--\nmm/page_alloc.c-1305-\nmm/page_alloc.c:1306:#else /* CONFIG_MEM_ALLOC_PROFILING */\nmm/page_alloc.c-1307-\n--\nmm/page_alloc.c=1311=static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {}\nmm/page_alloc.c-1312-\nmm/page_alloc.c:1313:#endif /* CONFIG_MEM_ALLOC_PROFILING */\nmm/page_alloc.c-1314-\n--\nmm/page_ext.c=80=static struct page_ext_operations *page_ext_ops[] __initdata = {\n--\nmm/page_ext.c-86-#endif\nmm/page_ext.c:87:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/page_ext.c-88-\t\u0026page_alloc_tagging_ops,\n--\nmm/page_ext.c=100=static unsigned long total_usage;\nmm/page_ext.c-101-\nmm/page_ext.c:102:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/page_ext.c-103-/*\n--\nmm/percpu-internal.h=35=struct pcpuobj_ext {\n--\nmm/percpu-internal.h-38-#endif\nmm/percpu-internal.h:39:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/percpu-internal.h-40-\tunion codetag_ref\ttag;\n--\nmm/percpu-internal.h-43-\nmm/percpu-internal.h:44:#if defined(CONFIG_MEMCG) || defined(CONFIG_MEM_ALLOC_PROFILING)\nmm/percpu-internal.h-45-#define NEED_PCPUOBJ_EXT\n--\nmm/percpu-internal.h=90=static inline bool need_pcpuobj_ext(void)\nmm/percpu-internal.h-91-{\nmm/percpu-internal.h:92:\tif (IS_ENABLED(CONFIG_MEM_ALLOC_PROFILING))\nmm/percpu-internal.h-93-\t\treturn true;\n--\nmm/percpu.c=1690=static void pcpu_memcg_free_hook(struct pcpu_chunk *chunk, int off, size_t size)\n--\nmm/percpu.c-1694-\nmm/percpu.c:1695:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/percpu.c-1696-static void pcpu_alloc_tag_alloc_hook(struct pcpu_chunk *chunk, int off,\n--\nmm/show_mem.c=408=void __show_mem(unsigned int filter, const nodemask_t *nodemask,\n--\nmm/show_mem.c-434-#endif\nmm/show_mem.c:435:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/show_mem.c-436-\tstatic DEFINE_SPINLOCK(mem_alloc_profiling_spinlock);\n--\nmm/slub.c=2046=static inline void dec_slabs_node(struct kmem_cache *s, int node,\n--\nmm/slub.c-2063-\nmm/slub.c:2064:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/slub.c-2065-\n--\nmm/slub.c=2097=static inline void handle_failed_objexts_alloc(unsigned long obj_exts,\n--\nmm/slub.c-2112-\nmm/slub.c:2113:#else /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/slub.c-2114-\n--\nmm/slub.c=2117=static inline void handle_failed_objexts_alloc(unsigned long obj_exts,\n--\nmm/slub.c-2119-\nmm/slub.c:2120:#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/slub.c-2121-\n--\nmm/slub.c=2342=static inline void alloc_slab_obj_exts_early(struct kmem_cache *s,\n--\nmm/slub.c-2348-\nmm/slub.c:2349:#ifdef CONFIG_MEM_ALLOC_PROFILING\nmm/slub.c-2350-\n--\nmm/slub.c=2437=alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,\n--\nmm/slub.c-2443-\nmm/slub.c:2444:#else /* CONFIG_MEM_ALLOC_PROFILING */\nmm/slub.c-2445-\n--\nmm/slub.c=2453=alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,\n--\nmm/slub.c-2457-\nmm/slub.c:2458:#endif /* CONFIG_MEM_ALLOC_PROFILING */\nmm/slub.c-2459-\n"
} |
| 7/2 | 2026/07/03 12:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35096 output: 22 thoughts: 97 Thoughts: **Analyzing Memory Allocation Tagging** Okay, so I'm seeing this patch touching `alloc_tag_add_early_pfn`, and the connection to `CONFIG_MEM_ALLOC_PROFILING` is immediately obvious. It looks like the core change is shifting from using `gfp_flags` to `alloc_flags` within `alloc_tag_add_early_pfn`. That makes sense; `alloc_flags` is probably providing more fine-grained control or a different semantic context for allocation-related tags. And I can see it's replacing `__GFP_NO_CODETAG` with `ALLOC_NO_CODETAG`, which likely indicates a cleaner, potentially more maintainable way to signal that a code tag shouldn't be associated with the allocation. Let me just quickly cross-reference that against `CONFIG_SLAB_OBJ_EXT` to make sure I understand how this impacts, or is impacted by, object extension within slab allocators. I need to keep the broader implications in mind. |
| 8/2 | 2026/07/03 12:54 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_SLAB_OBJ_EXT"
}Results: {
"Output": "include/linux/mm_types.h=80=struct page {\n--\ninclude/linux/mm_types.h-188-\tunsigned long memcg_data;\ninclude/linux/mm_types.h:189:#elif defined(CONFIG_SLAB_OBJ_EXT)\ninclude/linux/mm_types.h-190-\tunsigned long _unused_slab_obj_exts;\n--\ninclude/linux/mm_types.h=313=typedef swp_entry_t softleaf_t;\ninclude/linux/mm_types.h-314-\ninclude/linux/mm_types.h:315:#if defined(CONFIG_MEMCG) || defined(CONFIG_SLAB_OBJ_EXT)\ninclude/linux/mm_types.h-316-/* We have some extra room after the refcount in tail pages. */\n--\ninclude/linux/mm_types.h=402=struct folio {\n--\ninclude/linux/mm_types.h-435-\t\t\tunsigned long memcg_data;\ninclude/linux/mm_types.h:436:#elif defined(CONFIG_SLAB_OBJ_EXT)\ninclude/linux/mm_types.h-437-\t\t\tunsigned long _unused_slab_obj_exts;\n--\ninclude/linux/slab.h=26=enum _slab_flag_bits {\n--\ninclude/linux/slab.h-61-\t_SLAB_NO_OBJ_EXT,\ninclude/linux/slab.h:62:#if defined(CONFIG_SLAB_OBJ_EXT) \u0026\u0026 defined(CONFIG_64BIT)\ninclude/linux/slab.h-63-\t_SLAB_OBJ_EXT_IN_OBJ,\n--\ninclude/linux/slab.h-244-\ninclude/linux/slab.h:245:#if defined(CONFIG_SLAB_OBJ_EXT) \u0026\u0026 defined(CONFIG_64BIT)\ninclude/linux/slab.h-246-#define SLAB_OBJ_EXT_IN_OBJ\t__SLAB_FLAG_BIT(_SLAB_OBJ_EXT_IN_OBJ)\n--\nmm/slab.h=98=struct slab {\n--\nmm/slab.h-112-\tatomic_t __page_refcount;\nmm/slab.h:113:#ifdef CONFIG_SLAB_OBJ_EXT\nmm/slab.h-114-\tunsigned long obj_exts;\n--\nmm/slab.h=124=SLAB_MATCH(memcg_data, obj_exts);\nmm/slab.h:125:#elif defined(CONFIG_SLAB_OBJ_EXT)\nmm/slab.h-126-SLAB_MATCH(_unused_slab_obj_exts, obj_exts);\n--\nmm/slab.h=526=static inline void metadata_access_disable(void)\n--\nmm/slab.h-531-\nmm/slab.h:532:#ifdef CONFIG_SLAB_OBJ_EXT\nmm/slab.h-533-\n--\nmm/slab.h=629=int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,\n--\nmm/slab.h-631-\nmm/slab.h:632:#else /* CONFIG_SLAB_OBJ_EXT */\nmm/slab.h-633-\n--\nmm/slab.h=647=static inline unsigned int slab_get_stride(struct slab *slab) { return 0; }\n--\nmm/slab.h-649-\nmm/slab.h:650:#endif /* CONFIG_SLAB_OBJ_EXT */\nmm/slab.h-651-\n--\nmm/slub.c=762=static inline unsigned long get_orig_size(struct kmem_cache *s, void *object)\n--\nmm/slub.c-777-\nmm/slub.c:778:#ifdef CONFIG_SLAB_OBJ_EXT\nmm/slub.c-779-\n--\nmm/slub.c=866=static inline bool obj_exts_in_slab(struct kmem_cache *s, struct slab *slab)\n--\nmm/slub.c-872-\nmm/slub.c:873:#if defined(CONFIG_SLAB_OBJ_EXT) \u0026\u0026 defined(CONFIG_64BIT)\nmm/slub.c-874-static bool obj_exts_in_object(struct kmem_cache *s, struct slab *slab)\n--\nmm/slub.c=2046=static inline void dec_slabs_node(struct kmem_cache *s, int node,\n--\nmm/slub.c-2061-\nmm/slub.c:2062:#ifdef CONFIG_SLAB_OBJ_EXT\nmm/slub.c-2063-\n--\nmm/slub.c=2277=static void alloc_slab_obj_exts_early(struct kmem_cache *s, struct slab *slab)\n--\nmm/slub.c-2321-\nmm/slub.c:2322:#else /* CONFIG_SLAB_OBJ_EXT */\nmm/slub.c-2323-\n--\nmm/slub.c=2342=static inline void alloc_slab_obj_exts_early(struct kmem_cache *s,\n--\nmm/slub.c-2346-\nmm/slub.c:2347:#endif /* CONFIG_SLAB_OBJ_EXT */\nmm/slub.c-2348-\n--\nmm/slub.c=7838=static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)\n--\nmm/slub.c-7952-\taligned_size = ALIGN(size, s-\u003ealign);\nmm/slub.c:7953:#if defined(CONFIG_SLAB_OBJ_EXT) \u0026\u0026 defined(CONFIG_64BIT)\nmm/slub.c-7954-\tif (slab_args_unmergeable(args, s-\u003eflags) \u0026\u0026\n"
} |
| 9/2 | 2026/07/03 12:54 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36942 output: 27 thoughts: 2235 Thoughts: **Analysis of Page Allocator Modifications** Okay, so this patch is clearly touching some core components of the memory management system, specifically the page allocator. My initial assessment is that these are functional changes and will need a thorough review. First, I see the core functions `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof` are being modified to accept an `alloc_flags` argument. This is a significant change, likely to enable finer-grained control over the allocation process, potentially for debugging, tracing, or specific memory management strategies. The removal of `__GFP_NO_OBJ_EXT` and the introduction of `ALLOC_NO_CODETAG` are also indicators of internal refactoring or the introduction of a new allocation tracking system. The function `alloc_frozen_pages_nolock_noprof` has been updated. This is interesting: they've effectively replaced its custom logic with a direct call to `__alloc_frozen_pages_noprof`, passing the `ALLOC_NOLOCK` flag. This suggests a consolidation of logic and a possible reduction in code duplication. I need to understand what this `ALLOC_NOLOCK` flag means in the context of the allocator. Looking at `__alloc_frozen_pages_noprof` itself, it now handles these `alloc_flags`. The code includes basic validation of the flags, which is good practice. I note that `ALLOC_NOLOCK` seems to affect the `gfp` flags passed, enabling the `gfp_nolock` flag. I'm curious about the specific implications of this flag on concurrency and lock contention, especially if `gfp_nolock` is a new or recently changed feature. The function `alloc_pages_node_noprof` is exposed and a call point to the `__alloc_pages_noprof`. This function is core to the page allocation path, and any changes will be widely felt. The `__alloc_pages_noprof` function is a wrapper for `__alloc_frozen_pages_noprof` and sets the `set_page_refcounted`. This appears to be a crucial path. The inclusion of `alloc_pages_bulk_noprof` adds another path, and I'll need to review the role of `prep_new_page`. I should track the `ALLOC_DEFAULT` being passed to `__alloc_pages_noprof`. The static function `__alloc_pages_slowpath` is a point of potential interest, particularly how `alloc_flags_slowpath` is now being integrated into the allocation process. Now, the inclusion of `alloc_tag_add_early_pfn`, `__pgalloc_tag_add` and `post_alloc_hook` signals the introduction of, or improvement of, some form of memory allocation tracing. This will need to be studied. It's likely related to tracking where memory is allocated or maybe to aid in debugging memory leaks or fragmentation. The conditional use of `ALLOC_NO_CODETAG` in this context is significant; it indicates that the code is attempting to avoid recursion in the tag allocation. And of the paths listed in the patch, I should focus on the global functions: * `__alloc_frozen_pages_noprof` * `alloc_frozen_pages_nolock_noprof` * `alloc_pages_node_noprof` * `__alloc_pages_noprof` * `alloc_pages_bulk_noprof` * `alloc_tag_add_early_pfn` I'll need to check the configuration for `CONFIG_MEM_ALLOC_PROFILING`. Enabling it should expose the code related to `ALLOC_NO_CODETAG` and `alloc_tag_add_early_pfn`. This could be a valuable configuration for testing these changes. I'll need to test this in various scenarios. Finally, I'll need to understand the impact of removing the `EXPORT_SYMBOL(__alloc_pages_noprof);`, but I think it is in a different function, so this does not matter. The symbol still exists. Overall, this patch has the potential for significant impact. I need to focus my fuzzing efforts on the core functions and ensure that the new `alloc_flags` are handled correctly in various allocation scenarios. I'll be particularly interested in any performance regressions. |
| 10/2 | 2026/07/03 12:54 | tool | grepper |
0mError:no matches Args: {
"Expression": "EXPORT_SYMBOL\\(__alloc_pages_noprof\\)"
}Results: {
"error": "no matches"
} |
| 11/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 40179 output: 22 thoughts: 64 Thoughts: **Investigating the Removal of `__alloc_pages_noprof`** Okay, it seems like `__alloc_pages_noprof` has been removed, which is inconvenient. This is a common situation with kernel development, so I need to understand the implications quickly. Now, hold on a second... isn't `__alloc_pages_noprof` used in `include/linux/gfp.h`? That's definitely where I would expect to find such a core memory allocation function being used. I need to confirm this before I go any further down this rabbit hole. Best to double-check that header file and see what's going on in its immediate vicinity. Let's take a look at `include/linux/gfp.h` and find out what's using it (or used to use it). This will give me a better understanding of the changes and how this might impact the related kernel subsystems. |
| 12/2 | 2026/07/03 12:55 | tool | grepper |
0mArgs:{
"Expression": "__alloc_pages_noprof"
}Results: {
"Output": "mm/page_alloc.c=5109=unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n--\nmm/page_alloc.c-5243-failed:\nmm/page_alloc.c:5244:\tpage = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask, ALLOC_DEFAULT);\nmm/page_alloc.c-5245-\tif (page)\n--\nmm/page_alloc.c=5413=EXPORT_SYMBOL(__alloc_frozen_pages_noprof);\nmm/page_alloc.c-5414-\nmm/page_alloc.c:5415:struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,\nmm/page_alloc.c-5416-\t\tint preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)\n--\nmm/page_alloc.c=5427=struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)\n--\nmm/page_alloc.c-5434-\nmm/page_alloc.c:5435:\treturn __alloc_pages_noprof(gfp_mask, order, nid, NULL, ALLOC_DEFAULT);\nmm/page_alloc.c-5436-}\n--\nmm/page_alloc.c=5439=struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n--\nmm/page_alloc.c-5441-{\nmm/page_alloc.c:5442:\tstruct page *page = __alloc_pages_noprof(gfp | __GFP_COMP, order,\nmm/page_alloc.c-5443-\t\t\t\t\tpreferred_nid, nodemask, ALLOC_DEFAULT);\n--\nmm/page_alloc.h=255=void free_frozen_pages_nolock(struct page *page, unsigned int order);\nmm/page_alloc.h-256-\nmm/page_alloc.h:257:struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\nmm/page_alloc.h-258-\t\tnodemask_t *nodemask, unsigned int alloc_flags);\nmm/page_alloc.h:259:#define __alloc_pages(...)\t\t\talloc_hooks(__alloc_pages_noprof(__VA_ARGS__))\nmm/page_alloc.h-260-\n"
} |
| 13/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 41124 output: 18 thoughts: 69 Thoughts: Okay, here's my take on those thoughts, framed from my own perspective: **Tracking Page Allocation Functions** Right, so I'm just quickly trying to get a handle on the current state of page allocation within the kernel. I see that the `__alloc_pages_noprof` function is now formally defined in `mm/page_alloc.h`, and it seems to be primarily utilized within the `mm/` directory. That's good; it means we have a central definition for it. Wait a second...I'm also seeing a macro called `__alloc_pages` also defined in that same header file, `mm/page_alloc.h`. I need to figure out how these relate. Are they aliases? One a helper for the other? Is one for regular allocations and the other some kind of more specialized allocation? I need to dig deeper here and trace how these are used throughout the core memory management. I should probably also check `include/linux/gfp.h`, as I know that's where the allocation flags are typically defined. I need to make sure I understand the interaction between `gfp` flags and these functions. The flags will determine how the allocations are handled. They're critical to how any of these work, I can't just overlook that. |
| 14/2 | 2026/07/03 12:55 | tool | grepper |
0mArgs:{
"Expression": "__alloc_pages"
}Results: {
"Output": "Documentation/mm/page_owner.rst=75=To sort and analyze page_owner output:\n--\nDocumentation/mm/page_owner.rst-93-\t get_page_from_freelist+0xd01/0xd80\nDocumentation/mm/page_owner.rst:94:\t __alloc_pages+0x39e/0x7e0\nDocumentation/mm/page_owner.rst-95-\t allocate_slab+0xbc/0x3f0\n--\nDocumentation/mm/page_owner.rst-115-\t get_page_from_freelist+0xd01/0xd80\nDocumentation/mm/page_owner.rst:116:\t __alloc_pages+0x39e/0x7e0\nDocumentation/mm/page_owner.rst-117-\t alloc_pages_mpol+0x22e/0x490\n--\nDocumentation/mm/page_owner.rst-142-\t get_page_from_freelist+0xd01/0xd80\nDocumentation/mm/page_owner.rst:143:\t __alloc_pages+0x39e/0x7e0\nDocumentation/mm/page_owner.rst-144-\t alloc_pages_mpol+0x22e/0x490\n--\nDocumentation/translations/zh_CN/mm/page_owner.rst=32=page owner在默认情况下是禁用的。所以,如果你想使用它,你需要在你的启动cmdline\n--\nDocumentation/translations/zh_CN/mm/page_owner.rst-69-\t get_page_from_freelist+0xd01/0xd80\nDocumentation/translations/zh_CN/mm/page_owner.rst:70:\t __alloc_pages+0x39e/0x7e0\nDocumentation/translations/zh_CN/mm/page_owner.rst-71-\t allocate_slab+0xbc/0x3f0\n--\nDocumentation/translations/zh_CN/mm/page_owner.rst-91-\t get_page_from_freelist+0xd01/0xd80\nDocumentation/translations/zh_CN/mm/page_owner.rst:92:\t __alloc_pages+0x39e/0x7e0\nDocumentation/translations/zh_CN/mm/page_owner.rst-93-\t alloc_pages_mpol+0x22e/0x490\n--\ninclude/linux/gfp.h=211=unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n--\ninclude/linux/gfp.h-213-\t\t\t\tstruct page **page_array);\ninclude/linux/gfp.h:214:#define __alloc_pages_bulk(...)\t\t\talloc_hooks(alloc_pages_bulk_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-215-\n--\ninclude/linux/gfp.h=218=unsigned long alloc_pages_bulk_mempolicy_noprof(gfp_t gfp,\n--\ninclude/linux/gfp.h-225-#define alloc_pages_bulk(_gfp, _nr_pages, _page_array)\t\t\\\ninclude/linux/gfp.h:226:\t__alloc_pages_bulk(_gfp, numa_mem_id(), NULL, _nr_pages, _page_array)\ninclude/linux/gfp.h-227-\n--\nkernel/cgroup/cpuset.c=4171=static struct cpuset *nearest_hardwall_ancestor(struct cpuset *cs)\n--\nkernel/cgroup/cpuset.c-4195- * Scanning up parent cpusets requires callback_lock. The\nkernel/cgroup/cpuset.c:4196: * __alloc_pages() routine only calls here with __GFP_HARDWALL bit\nkernel/cgroup/cpuset.c-4197- * _not_ set if it's a GFP_KERNEL allocation, and all nodes in the\n--\nkernel/cgroup/cpuset.c-4209- * The second pass through get_page_from_freelist() doesn't even call\nkernel/cgroup/cpuset.c:4210: * here for GFP_ATOMIC calls. For those calls, the __alloc_pages()\nkernel/cgroup/cpuset.c-4211- * variable 'wait' is not set, and the bit ALLOC_CPUSET is not set\n--\nkernel/cgroup/cpuset.c=4273=void cpuset_nodes_allowed(struct cgroup *cgroup, nodemask_t *mask)\n--\nkernel/cgroup/cpuset.c-4330- * the node where the search should start. The zonelist passed to\nkernel/cgroup/cpuset.c:4331: * __alloc_pages() will include all nodes. If the slab allocator\nkernel/cgroup/cpuset.c-4332- * is passed an offline node, it will fall back to the local node.\n--\nmm/alloc_tag.c=791=static void __init __alloc_tag_add_early_pfn(unsigned long pfn)\n--\nmm/alloc_tag.c-798-\t\tif (!pool || atomic_read(\u0026pool-\u003ecount) \u003e= PFN_POOL_SIZE) {\nmm/alloc_tag.c:799:\t\t\tstruct page *new_page = __alloc_pages(__GFP_HIGH, 0, numa_mem_id(),\nmm/alloc_tag.c-800-\t\t\t\t\t\t\t NULL, ALLOC_NO_CODETAG);\n--\nmm/kasan/shadow.c=327=static void ___free_pages_bulk(struct page **pages, int nr_pages)\n--\nmm/kasan/shadow.c-338-\nmm/kasan/shadow.c:339:static int ___alloc_pages_bulk(struct page **pages, int nr_pages, gfp_t gfp_mask)\nmm/kasan/shadow.c-340-{\n--\nmm/kasan/shadow.c=357=static int __kasan_populate_vmalloc_do(unsigned long start, unsigned long end, gfp_t gfp_mask)\n--\nmm/kasan/shadow.c-369-\t\tnr_pages = min(nr_total, PAGE_SIZE / sizeof(data.pages[0]));\nmm/kasan/shadow.c:370:\t\tret = ___alloc_pages_bulk(data.pages, nr_pages, gfp_mask);\nmm/kasan/shadow.c-371-\t\tif (ret)\n--\nmm/mempolicy.c=2624=static unsigned long alloc_pages_bulk_weighted_interleave(gfp_t gfp,\n--\nmm/mempolicy.c-2662-\t\tnode_pages = min(rem_pages, weight);\nmm/mempolicy.c:2663:\t\tnr_allocated = __alloc_pages_bulk(gfp, node, NULL, node_pages,\nmm/mempolicy.c-2664-\t\t\t\t\t\t page_array);\n--\nmm/mempolicy.c-2699-\t/*\nmm/mempolicy.c:2700:\t * Calculate rounds/partial rounds to minimize __alloc_pages_bulk calls.\nmm/mempolicy.c-2701-\t * Track which node weighted interleave should resume from.\n--\nmm/mempolicy.c-2727-\t\t\tbreak;\nmm/mempolicy.c:2728:\t\tnr_allocated = __alloc_pages_bulk(gfp, node, NULL, node_pages,\nmm/mempolicy.c-2729-\t\t\t\t\t\t page_array);\n--\nmm/oom_kill.c-11- * The routines in this file are used to kill a process when\nmm/oom_kill.c:12: * we're seriously out of memory. This gets called from __alloc_pages()\nmm/oom_kill.c-13- * in mm/page_alloc.c when we really run out of memory.\n--\nmm/page_alloc.c=4027=static inline struct page *\nmm/page_alloc.c:4028:__alloc_pages_cpuset_fallback(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4029-\t\t\t unsigned int alloc_flags,\n--\nmm/page_alloc.c=4046=static inline struct page *\nmm/page_alloc.c:4047:__alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4048-\tconst struct alloc_context *ac, unsigned long *did_some_progress)\n--\nmm/page_alloc.c-4124-\t\tif (gfp_mask \u0026 __GFP_NOFAIL)\nmm/page_alloc.c:4125:\t\t\tpage = __alloc_pages_cpuset_fallback(gfp_mask, order,\nmm/page_alloc.c-4126-\t\t\t\t\tac-\u003ealloc_flags|ALLOC_NO_WATERMARKS, ac);\n--\nmm/page_alloc.c=4141=static struct page *\nmm/page_alloc.c:4142:__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4143-\t\tunsigned int alloc_flags, const struct alloc_context *ac,\n--\nmm/page_alloc.c=4269=static inline struct page *\nmm/page_alloc.c:4270:__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4271-\t\tunsigned int alloc_flags, const struct alloc_context *ac,\n--\nmm/page_alloc.c=4417=static inline struct page *\nmm/page_alloc.c:4418:__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4419-\t\tunsigned int alloc_flags, const struct alloc_context *ac,\n--\nmm/page_alloc.c=4732=static inline struct page *\nmm/page_alloc.c:4733:__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4734-\t\t\t\t\t\tstruct alloc_context *ac)\n--\nmm/page_alloc.c-4887-\tif (!compact_first) {\nmm/page_alloc.c:4888:\t\tpage = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags,\nmm/page_alloc.c-4889-\t\t\t\t\t\t\tac, \u0026did_some_progress);\n--\nmm/page_alloc.c-4894-\t/* Try direct compaction and then allocating */\nmm/page_alloc.c:4895:\tpage = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,\nmm/page_alloc.c-4896-\t\t\t\t\tcompact_priority, \u0026compact_result);\n--\nmm/page_alloc.c-4978-\t/* Reclaim has failed us, start killing things */\nmm/page_alloc.c:4979:\tpage = __alloc_pages_may_oom(gfp_mask, order, ac, \u0026did_some_progress);\nmm/page_alloc.c-4980-\tif (page)\n--\nmm/page_alloc.c-5025-\t\t */\nmm/page_alloc.c:5026:\t\tpage = __alloc_pages_cpuset_fallback(gfp_mask, order, alloc_flags, ac);\nmm/page_alloc.c-5027-\t\tif (page)\n--\nmm/page_alloc.c=5040=static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,\n--\nmm/page_alloc.c-5088-/*\nmm/page_alloc.c:5089: * __alloc_pages_bulk - Allocate a number of order-0 pages to an array\nmm/page_alloc.c-5090- * @gfp: GFP flags for the allocation\n--\nmm/page_alloc.c=5109=unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n--\nmm/page_alloc.c-5243-failed:\nmm/page_alloc.c:5244:\tpage = __alloc_pages_noprof(gfp, 0, preferred_nid, nodemask, ALLOC_DEFAULT);\nmm/page_alloc.c-5245-\tif (page)\n--\nmm/page_alloc.c=5332=struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n--\nmm/page_alloc.c-5397-\nmm/page_alloc.c:5398:\tpage = __alloc_pages_slowpath(alloc_gfp, order, \u0026ac);\nmm/page_alloc.c-5399-\n--\nmm/page_alloc.c=5413=EXPORT_SYMBOL(__alloc_frozen_pages_noprof);\nmm/page_alloc.c-5414-\nmm/page_alloc.c:5415:struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order,\nmm/page_alloc.c-5416-\t\tint preferred_nid, nodemask_t *nodemask, unsigned int alloc_flags)\n--\nmm/page_alloc.c=5427=struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order)\n--\nmm/page_alloc.c-5434-\nmm/page_alloc.c:5435:\treturn __alloc_pages_noprof(gfp_mask, order, nid, NULL, ALLOC_DEFAULT);\nmm/page_alloc.c-5436-}\n--\nmm/page_alloc.c=5439=struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n--\nmm/page_alloc.c-5441-{\nmm/page_alloc.c:5442:\tstruct page *page = __alloc_pages_noprof(gfp | __GFP_COMP, order,\nmm/page_alloc.c-5443-\t\t\t\t\tpreferred_nid, nodemask, ALLOC_DEFAULT);\n--\nmm/page_alloc.c=6449=static void calculate_totalreserve_pages(void)\n--\nmm/page_alloc.c-6496- *\thas a correct pages reserved value, so an adequate number of\nmm/page_alloc.c:6497: *\tpages are left in the zone after a successful __alloc_pages().\nmm/page_alloc.c-6498- */\n--\nmm/page_alloc.h-68- * nodemask, migratetype and highest_zoneidx are initialized only once in\nmm/page_alloc.h:69: * __alloc_pages() and then never change.\nmm/page_alloc.h-70- *\nmm/page_alloc.h-71- * zonelist, preferred_zone and highest_zoneidx are set first in\nmm/page_alloc.h:72: * __alloc_pages() for the fast path, and might be later changed\nmm/page_alloc.h:73: * in __alloc_pages_slowpath(). All other functions pass the whole structure\nmm/page_alloc.h-74- * by a const pointer.\n--\nmm/page_alloc.h=255=void free_frozen_pages_nolock(struct page *page, unsigned int order);\nmm/page_alloc.h-256-\nmm/page_alloc.h:257:struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\nmm/page_alloc.h-258-\t\tnodemask_t *nodemask, unsigned int alloc_flags);\nmm/page_alloc.h:259:#define __alloc_pages(...)\t\t\talloc_hooks(__alloc_pages_noprof(__VA_ARGS__))\nmm/page_alloc.h-260-\n--\nmm/page_frag_cache.c=49=static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,\n--\nmm/page_frag_cache.c-58-\t\t __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;\nmm/page_frag_cache.c:59:\tpage = __alloc_pages(gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER,\nmm/page_frag_cache.c-60-\t\t\t numa_mem_id(), NULL, ALLOC_DEFAULT);\n--\nmm/page_frag_cache.c-62-\tif (unlikely(!page)) {\nmm/page_frag_cache.c:63:\t\tpage = __alloc_pages(gfp, 0, numa_mem_id(), NULL, ALLOC_DEFAULT);\nmm/page_frag_cache.c-64-\t\torder = 0;\n--\nmm/vmscan.c=7392=static int kswapd(void *p)\n--\nmm/vmscan.c-7401-\t * and that if we need more memory we should get access to it\nmm/vmscan.c:7402:\t * regardless (see \"__alloc_pages()\"). \"kswapd\" should\nmm/vmscan.c-7403-\t * never get caught in the normal page freeing logic.\n--\ntools/perf/Documentation/perf-intel-pt.txt=1989=For example:\n--\ntools/perf/Documentation/perf-intel-pt.txt-1999-\ntools/perf/Documentation/perf-intel-pt.txt:2000: Tracing __alloc_pages() using kprobes:\ntools/perf/Documentation/perf-intel-pt.txt-2001-\ntools/perf/Documentation/perf-intel-pt.txt:2002: $ sudo perf probe --add '__alloc_pages order'\ntools/perf/Documentation/perf-intel-pt.txt:2003: Added new event: probe:__alloc_pages (on __alloc_pages with order)\ntools/perf/Documentation/perf-intel-pt.txt:2004: $ sudo perf probe --add __alloc_pages%return\ntools/perf/Documentation/perf-intel-pt.txt:2005: Added new event: probe:__alloc_pages__return (on __alloc_pages%return)\ntools/perf/Documentation/perf-intel-pt.txt:2006: $ sudo perf record --kcore -aR -e intel_pt/aux-action=start-paused/k -e probe:__alloc_pages/aux-action=resume/ -e probe:__alloc_pages__return/aux-actio...\ntools/perf/Documentation/perf-intel-pt.txt-2007- [ perf record: Woken up 1 times to write data ]\n"
} |
| 15/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 46244 output: 32 thoughts: 89 Thoughts: Okay, let me put on my thinking cap. Here's how I'd approach this... **Dissecting the `__alloc_pages` Usage** Alright, so I'm looking at `__alloc_pages`, and my first thought is, "Where exactly is *that* defined?" A quick scan tells me it's hanging out in `mm/page_alloc.h`. Makes sense, considering it's dealing with page allocation, a core memory management function. Now, I'm already starting to think about *how* it's being used. I see it's called within `mm/page_frag_cache.c` and `mm/alloc_tag.c`. That's interesting - seems like it's involved in some page-related caching and allocation tagging scenarios. I need to keep those contexts in mind. Wait a second. Is this function actually visible outside of the kernel's memory management subsystem? I don't recall seeing it as part of any module's API. Let me quickly confirm. It's likely not exported since I'm not seeing it used by other modules. Okay, let's double check `include/linux/gfp.h`, just to be certain. I know the GFP flags are critical in page allocation, so a quick verification there is a good idea to confirm `__alloc_pages`' behavior. |
| 16/2 | 2026/07/03 12:55 | tool | grepper |
0mArgs:{
"Expression": "__alloc_pages",
"PathPrefix": "include/linux/gfp.h"
}Results: {
"Output": "include/linux/gfp.h=211=unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n--\ninclude/linux/gfp.h-213-\t\t\t\tstruct page **page_array);\ninclude/linux/gfp.h:214:#define __alloc_pages_bulk(...)\t\t\talloc_hooks(alloc_pages_bulk_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-215-\n--\ninclude/linux/gfp.h=218=unsigned long alloc_pages_bulk_mempolicy_noprof(gfp_t gfp,\n--\ninclude/linux/gfp.h-225-#define alloc_pages_bulk(_gfp, _nr_pages, _page_array)\t\t\\\ninclude/linux/gfp.h:226:\t__alloc_pages_bulk(_gfp, numa_mem_id(), NULL, _nr_pages, _page_array)\ninclude/linux/gfp.h-227-\n"
} |
| 17/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 46925 output: 31 thoughts: 193 Thoughts: **Analyzing the Latest Kernel Patch: `__alloc_pages` Relocation** Okay, so the patch has done something interesting with memory allocation. First glance… yes, they've taken `__alloc_pages` out of `include/linux/gfp.h`. Let's just double-check that diff to be absolutely sure. ```diff -struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, int preferred_nid, - nodemask_t *nodemask); -#define __alloc_pages(...) alloc_hooks(__alloc_pages_noprof(__VA_ARGS__)) - ``` Yep, confirmed. It's been removed, and the macro definition has gone with it. Ah, now I get it. It was moved to `mm/page_alloc.h`. That's a sensible refactoring, keeping the internal details within the `mm/` subsystem where they belong. So, `__alloc_pages` is now effectively an internal function, hidden from external headers. But that raises another question - I need to be sure that `alloc_pages` wasn't moved, too. Does `alloc_pages` still exist in `include/linux/gfp.h`? |
| 18/2 | 2026/07/03 12:55 | tool | grepper |
0mArgs:{
"Expression": "alloc_pages",
"PathPrefix": "include/linux/gfp.h"
}Results: {
"Output": "include/linux/gfp.h=25=static inline bool gfpflags_allow_spinning(const gfp_t gfp_flags)\n--\ninclude/linux/gfp.h-30-\t * All GFP_* flags including GFP_NOWAIT use one or both flags.\ninclude/linux/gfp.h:31:\t * alloc_pages_nolock() is the only API that doesn't specify either flag.\ninclude/linux/gfp.h-32-\t *\n--\ninclude/linux/gfp.h-36-\t * on any locks (i.e. only trylocks). There is no high level\ninclude/linux/gfp.h:37:\t * GFP_$FOO flag for this use in alloc_pages_nolock() as the\ninclude/linux/gfp.h-38-\t * regular page allocator doesn't fully support this\n--\ninclude/linux/gfp.h=207=struct folio *__folio_alloc_noprof(gfp_t gfp, unsigned int order, int preferred_nid,\n--\ninclude/linux/gfp.h-210-\ninclude/linux/gfp.h:211:unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\ninclude/linux/gfp.h-212-\t\t\t\tnodemask_t *nodemask, int nr_pages,\ninclude/linux/gfp.h-213-\t\t\t\tstruct page **page_array);\ninclude/linux/gfp.h:214:#define __alloc_pages_bulk(...)\t\t\talloc_hooks(alloc_pages_bulk_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-215-\ninclude/linux/gfp.h=216=void free_pages_bulk(struct page **page_array, unsigned long nr_pages);\ninclude/linux/gfp.h-217-\ninclude/linux/gfp.h:218:unsigned long alloc_pages_bulk_mempolicy_noprof(gfp_t gfp,\ninclude/linux/gfp.h-219-\t\t\t\tunsigned long nr_pages,\ninclude/linux/gfp.h-220-\t\t\t\tstruct page **page_array);\ninclude/linux/gfp.h:221:#define alloc_pages_bulk_mempolicy(...)\t\t\t\t\\\ninclude/linux/gfp.h:222:\talloc_hooks(alloc_pages_bulk_mempolicy_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-223-\ninclude/linux/gfp.h-224-/* Bulk allocate order-0 pages */\ninclude/linux/gfp.h:225:#define alloc_pages_bulk(_gfp, _nr_pages, _page_array)\t\t\\\ninclude/linux/gfp.h:226:\t__alloc_pages_bulk(_gfp, numa_mem_id(), NULL, _nr_pages, _page_array)\ninclude/linux/gfp.h-227-\ninclude/linux/gfp.h=228=static inline unsigned long\ninclude/linux/gfp.h:229:alloc_pages_bulk_node_noprof(gfp_t gfp, int nid, unsigned long nr_pages,\ninclude/linux/gfp.h-230-\t\t\t\t struct page **page_array)\n--\ninclude/linux/gfp.h-234-\ninclude/linux/gfp.h:235:\treturn alloc_pages_bulk_noprof(gfp, nid, NULL, nr_pages, page_array);\ninclude/linux/gfp.h-236-}\ninclude/linux/gfp.h-237-\ninclude/linux/gfp.h:238:#define alloc_pages_bulk_node(...)\t\t\t\t\\\ninclude/linux/gfp.h:239:\talloc_hooks(alloc_pages_bulk_node_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-240-\n--\ninclude/linux/gfp.h=256=struct folio *__folio_alloc_node_noprof(gfp_t gfp, unsigned int order, int nid)\n--\ninclude/linux/gfp.h-270- */\ninclude/linux/gfp.h:271:struct page *alloc_pages_node_noprof(int nid, gfp_t gfp_mask, unsigned int order);\ninclude/linux/gfp.h-272-\ninclude/linux/gfp.h:273:#define alloc_pages_node(...)\t\t\talloc_hooks(alloc_pages_node_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-274-\ninclude/linux/gfp.h-275-#ifdef CONFIG_NUMA\ninclude/linux/gfp.h:276:struct page *alloc_pages_noprof(gfp_t gfp, unsigned int order);\ninclude/linux/gfp.h-277-struct folio *folio_alloc_noprof(gfp_t gfp, unsigned int order);\n--\ninclude/linux/gfp.h=280=struct folio *vma_alloc_folio_noprof(gfp_t gfp, int order, struct vm_area_struct *vma,\n--\ninclude/linux/gfp.h-282-#else\ninclude/linux/gfp.h:283:static inline struct page *alloc_pages_noprof(gfp_t gfp_mask, unsigned int order)\ninclude/linux/gfp.h-284-{\ninclude/linux/gfp.h:285:\treturn alloc_pages_node_noprof(numa_node_id(), gfp_mask, order);\ninclude/linux/gfp.h-286-}\n--\ninclude/linux/gfp.h=296=static inline struct folio *vma_alloc_folio_noprof(gfp_t gfp, int order,\n--\ninclude/linux/gfp.h-302-\ninclude/linux/gfp.h:303:#define alloc_pages(...)\t\t\talloc_hooks(alloc_pages_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-304-#define folio_alloc(...)\t\t\talloc_hooks(folio_alloc_noprof(__VA_ARGS__))\n--\ninclude/linux/gfp.h-307-\ninclude/linux/gfp.h:308:#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)\ninclude/linux/gfp.h-309-\ninclude/linux/gfp.h=310=static inline struct page *alloc_page_vma_noprof(gfp_t gfp,\n--\ninclude/linux/gfp.h-318-\ninclude/linux/gfp.h:319:struct page *alloc_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);\ninclude/linux/gfp.h:320:#define alloc_pages_nolock(...)\t\t\talloc_hooks(alloc_pages_nolock_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-321-\n--\ninclude/linux/gfp.h=325=extern unsigned long get_zeroed_page_noprof(gfp_t gfp_mask);\n--\ninclude/linux/gfp.h-327-\ninclude/linux/gfp.h:328:void *alloc_pages_exact_noprof(size_t size, gfp_t gfp_mask) __alloc_size(1);\ninclude/linux/gfp.h:329:#define alloc_pages_exact(...)\t\t\talloc_hooks(alloc_pages_exact_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-330-\ninclude/linux/gfp.h=331=void free_pages_exact(void *virt, size_t size);\ninclude/linux/gfp.h-332-\ninclude/linux/gfp.h:333:__meminit void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mask) __alloc_size(2);\ninclude/linux/gfp.h:334:#define alloc_pages_exact_nid(...)\t\t\t\t\t\\\ninclude/linux/gfp.h:335:\talloc_hooks(alloc_pages_exact_nid_noprof(__VA_ARGS__))\ninclude/linux/gfp.h-336-\n"
} |
| 19/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 49527 output: 30 thoughts: 2998 Thoughts: **Analysis of Allocation Functions and Configuration Dependencies** Okay, here's the breakdown, from an expert's perspective, of the code changes and the implications for fuzzing and testing. My initial thought was that `alloc_pages_noprof` was the core, and in a sense it is, but the patch digs deeper. Specifically, `alloc_pages_node_noprof` and related functions now become more interesting targets. It's a key function for non-NUMA systems and a specific allocation path when NUMA is *enabled*. The focus has shifted from an inline implementation of `alloc_pages_node_noprof` towards a defined implementation. I need to look into a few key functions: * `__alloc_frozen_pages_noprof` * `alloc_pages_node_noprof` * `alloc_pages_bulk_noprof` * `alloc_frozen_pages_nolock_noprof` * `alloc_tag_add_early_pfn` The critical thing is to determine the relevant configurations. The most important seems to be `MEM_ALLOC_PROFILING` because it affects `alloc_tag_add_early_pfn` and the removal of the old `__GFP_NO_OBJ_EXT`. `ALLOC_NO_CODETAG` is key for fuzzing. `CMA` is also important as it is checked in `alloc_flags_cma`. `NUMA` remains relevant because it changes the path taken by `alloc_pages_noprof` and `alloc_pages_node_noprof`. `PREEMPT_RT` is also relevant because it changes `can_spin_trylock`, which is used in `__kmalloc_nolock_noprof` and `alloc_nolock_allowed`. Although, I am not completely sure this is relevant. So, the configurations that I need to enable are: * `MEM_ALLOC_PROFILING` * `CMA` * `NUMA` * `PREEMPT_RT` Even with those set, I need to remember the core functions: * `__alloc_frozen_pages_noprof` * `alloc_pages_node_noprof` * `alloc_pages_bulk_noprof` * `alloc_frozen_pages_nolock_noprof` I need to make sure to fuzz the functions with and without `NUMA`, to check all the different paths. `alloc_tag_add_early_pfn` isn't directly exported, but is called from `__pgalloc_tag_add`. So as long as `MEM_ALLOC_PROFILING` is enabled and a normal page allocation is performed, that function will be called, so the path is reachable. |
| 20/2 | 2026/07/03 12:55 | tool | grepper |
0mError:no matches Args: {
"Expression": "EXPORT_SYMBOL.*alloc_frozen_pages_nolock_noprof"
}Results: {
"error": "no matches"
} |
| 21/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 53191 output: 28 thoughts: 24 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Kernel Symbol Visibility & Memory Allocation** Hmm, so it looks like that specific symbol I was hoping to use isn't directly exported. That's a bit of a setback, but not necessarily a showstopper. However, and this is key, `alloc_pages_nolock_noprof` *is* exported, which is interesting. It immediately makes me think about potential workarounds. I'll need to dig into the relationship between these functions. What are the key differences between them? Is there a subtle performance trade-off? My mind is racing. Is `alloc_pages_nolock_noprof` a lower-level primitive that I can leverage to achieve what I need? Can I use it as a foundation and build my functionality on top of that? The presence of `nolock` implies performance considerations around synchronization, while `noprof` flags likely mean that profiling information isn't collected, which could affect observability. I need to understand whether those omissions are acceptable in my use case, and what the overall impact will be. I also need to verify what the semantics are. |
| 22/2 | 2026/07/03 12:55 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*alloc_pages_nolock_noprof"
}Results: {
"Output": "mm/page_alloc.c=7983=struct page *alloc_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\n--\nmm/page_alloc.c-7991-}\nmm/page_alloc.c:7992:EXPORT_SYMBOL_GPL(alloc_pages_nolock_noprof);\n"
} |
| 23/2 | 2026/07/03 12:55 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 53596 output: 28 thoughts: 164 Thoughts: **My Fuzzing Strategy** Okay, so `alloc_pages_nolock_noprof` *is* exported, that's good news. That means it's accessible. Therefore, these functions are my primary targets for fuzzing: `__alloc_frozen_pages_noprof`, `alloc_pages_node_noprof`, `alloc_pages_bulk_noprof`, and of course, `alloc_pages_nolock_noprof` itself. Now, let me double-check. I recall `alloc_pages_nolock_noprof` calling `alloc_frozen_pages_nolock_noprof`, and I know *that* function has seen some changes. So, fuzzing `alloc_pages_nolock_noprof` should indeed trigger the modified code within `alloc_frozen_pages_nolock_noprof` -- that's my entry point. Next, I should confirm if `__alloc_frozen_pages_noprof` is exported. |
| 24/2 | 2026/07/03 12:56 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*__alloc_frozen_pages_noprof"
}Results: {
"Output": "mm/page_alloc.c=5332=struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,\n--\nmm/page_alloc.c-5412-}\nmm/page_alloc.c:5413:EXPORT_SYMBOL(__alloc_frozen_pages_noprof);\nmm/page_alloc.c-5414-\n"
} |
| 25/2 | 2026/07/03 12:56 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 54120 output: 27 thoughts: 26 Thoughts: Okay, here's my summary, tailored for an expert audience, in the first person: **Checking Kernel Symbol Export Status** Right, so the initial assumption is confirmed: we're dealing with an exported symbol. Now, the next crucial step is to verify whether `alloc_pages_bulk_noprof` itself is exported. This is a common situation, and one I know well. I'll need to confirm that this specific function is available for external modules or use, and I need to be sure before I move forward with any assumptions regarding usage. The status of this symbol will determine my next steps. |
| 26/2 | 2026/07/03 12:56 | tool | grepper |
0mArgs:{
"Expression": "EXPORT_SYMBOL.*alloc_pages_bulk_noprof"
}Results: {
"Output": "mm/page_alloc.c=5109=unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,\n--\nmm/page_alloc.c-5248-}\nmm/page_alloc.c:5249:EXPORT_SYMBOL_GPL(alloc_pages_bulk_noprof);\nmm/page_alloc.c-5250-\n"
} |
| 27/2 | 2026/07/03 12:56 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 54413 output: 248 thoughts: 1545 Thoughts: **Analysis of Memory Allocation Function Changes**
Okay, so this is about exported memory allocation functions that have been modified. I see that the code changes are focused around how allocation flags are handled, particularly with the introduction of an `alloc_flags` parameter. It looks like the key functions to focus on are:
* `__alloc_frozen_pages_noprof`
* `alloc_pages_node_noprof`
* `alloc_pages_bulk_noprof`
* `alloc_pages_nolock_noprof`
I've confirmed those names are correct. The original analysis also identified other functions like `__folio_alloc_noprof`, `alloc_contig_frozen_range_noprof`, `alloc_pages_preferred_many`, `alloc_pages_mpol`, `alloc_slab_page`, and `___kmalloc_large_node`. They all call the core functions with the new `ALLOC_DEFAULT` parameter. The critical changes are indeed inside `mm/page_alloc.c`.
Now, regarding the necessary configuration options:
* `MEM_ALLOC_PROFILING`: This is definitely needed to test `ALLOC_NO_CODETAG`.
* `CMA`: This one's necessary to test `alloc_flags_cma`.
* `PREEMPT_RT`: Hmmm, this one introduces significant changes across the kernel. While the modified code does check for `PREEMPT_RT`, I wonder if it's strictly *required* for testing these core changes. I should check how `can_spin_trylock()` works with and without it, given that it's also connected to `!IS_ENABLED(CONFIG_SMP)`. It seems the code is reachable without `PREEMPT_RT`. However, I'll include it anyway since it is explicitly checked in the updated code.
The reasoning is solid: This patch modifies how allocation flags are passed and handled within the page allocator, impacting core memory management. It's a functional change that should be properly fuzzed.
So, to summarize:
* **Focus Functions:**
* `__alloc_frozen_pages_noprof`
* `alloc_pages_node_noprof`
* `alloc_pages_bulk_noprof`
* `alloc_pages_nolock_noprof`
* **Configs:**
* `MEM_ALLOC_PROFILING`
* `CMA`
* `PREEMPT_RT`
Let's proceed with calling `set-results`.
|
| 28/2 | 2026/07/03 12:56 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MEM_ALLOC_PROFILING",
"CMA",
"PREEMPT_RT"
],
"FocusSymbols": [
"__alloc_frozen_pages_noprof",
"alloc_pages_node_noprof",
"alloc_pages_bulk_noprof",
"alloc_pages_nolock_noprof"
],
"Reasoning": "The patch modifies the core page allocator logic, specifically how allocation flags are passed and handled internally. It introduces an `alloc_flags` parameter to `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof`, replacing the internal `alloc_flags` variable. It also modifies `alloc_frozen_pages_nolock_noprof` to use `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`. It removes `__GFP_NO_OBJ_EXT` and replaces it with `ALLOC_NO_CODETAG` for memory allocation profiling. These are functional changes to the memory management subsystem that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING",
"CMA",
"PREEMPT_RT"
],
"FocusSymbols": [
"__alloc_frozen_pages_noprof",
"alloc_pages_node_noprof",
"alloc_pages_bulk_noprof",
"alloc_pages_nolock_noprof"
],
"Reasoning": "The patch modifies the core page allocator logic, specifically how allocation flags are passed and handled internally. It introduces an `alloc_flags` parameter to `__alloc_frozen_pages_noprof` and `__alloc_pages_noprof`, replacing the internal `alloc_flags` variable. It also modifies `alloc_frozen_pages_nolock_noprof` to use `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`. It removes `__GFP_NO_OBJ_EXT` and replaces it with `ALLOC_NO_CODETAG` for memory allocation profiling. These are functional changes to the memory management subsystem that should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|