| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/02 03:29 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING"
],
"FocusSymbols": [
"alloc_frozen_pages_nolock_noprof",
"alloc_pages_node_noprof"
],
"Reasoning": "The patch refactors the internal page allocator API by introducing `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, replacing `__GFP_NO_OBJ_EXT` and `ALLOC_TRYLOCK` with `ALLOC_NO_CODETAG` and `ALLOC_NOLOCK`. It also moves `alloc_pages_node_noprof` out-of-line. These are functional changes to core memory management code that should be fuzzed to ensure no regressions in page allocation, especially in non-blocking/nolock contexts and memory profiling.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/02 03:29 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit ebf40183e6fbf27046c88e56484d71706d00b3ab\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Jul 2 03:29:34 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 db3d8c441e4c00..de87921176b0dc 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17181,6 +17181,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 e86e4ba91e1b37..8940f0292229f5 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 a03add00f923ec..26f15584d4b505 100644\n--- a/arch/x86/kvm/vmx/vmx.c\n+++ b/arch/x86/kvm/vmx/vmx.c\n@@ -3040,7 +3040,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..aacff702042416 100644\n--- a/drivers/misc/sgi-xp/xpc_uv.c\n+++ b/drivers/misc/sgi-xp/xpc_uv.c\n@@ -170,7 +170,7 @@ 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+\tpage = alloc_pages_node(nid,\n \t\t\t\t GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,\n \t\t\t\t pg_order);\n \tif (page == NULL) {\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/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/mm/alloc_tag.c b/mm/alloc_tag.c\nindex d9be1cf5187d97..a32a94e759b94b 100644\n--- a/mm/alloc_tag.c\n+++ b/mm/alloc_tag.c\n@@ -15,6 +15,8 @@\n #include \u003clinux/vmalloc.h\u003e\n #include \u003clinux/kmemleak.h\u003e\n \n+#include \"internal.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 +785,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 +795,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 +827,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 +835,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 e1bb81631d5eb0..997a08ba35423d 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@@ -1805,7 +1806,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 430aa72a457581..369c656c63fa80 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,51 +1233,10 @@ 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 \n-\n /*\n * only for MM internal work items which do not depend on\n * any allocations or locks which might depend on allocations\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/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 7ac19fab226324..9539e40c478edb 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 36699fabd3c223..41d630f0ea8212 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@@ -2425,9 +2426,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@@ -2475,7 +2478,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@@ -2487,7 +2490,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/mm_init.c b/mm/mm_init.c\nindex 6b89e2e7743112..35641fac109d53 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 62f71ece7ca177..803b32e5a5e47f 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@@ -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,8 +3775,8 @@ 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+\t\t\t\t\t unsigned int alloc_flags)\n {\n #ifdef CONFIG_CMA\n \tif (gfp_migratetype(gfp_mask) == MIGRATE_MOVABLE)\n@@ -4474,7 +4475,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 +4498,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 +4513,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 +4526,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, alloc_flags);\n \n \tif (defrag_mode)\n \t\talloc_flags |= ALLOC_NOFRAGMENT;\n@@ -4790,8 +4791,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 +4837,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@@ -5059,11 +5064,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, *alloc_flags);\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 +5226,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 +5240,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 +5275,101 @@ 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_trylock_allowed(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. 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 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+\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_trylock_allowed())\n+\t\t\treturn NULL;\n+\t\tgfp |= gfp_nolock;\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 +5381,19 @@ 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+\tfastpath_alloc_flags |= alloc_flags_nofragment(zonelist_zone(ac.preferred_zoneref), gfp);\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 +5410,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 +5423,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 +7132,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 +7337,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 +7899,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 +7969,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..2614bff6795b08\n--- /dev/null\n+++ b/mm/page_alloc.h\n@@ -0,0 +1,316 @@\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+ * Skip early PFN recording for a page allocation. Used by\n+ * __alloc_tag_add_early_pfn() to avoid recursion when allocating pages for the\n+ * early PFN tracking list 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 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 0 /* 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+void drain_local_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 ffbaba3d69d3ce..290e47e1fa09e1 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/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/slub.c b/mm/slub.c\nindex 9f754cf1c1874c..ff44f4373d522b 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@@ -5275,7 +5277,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);\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 754c5f5d716aad..de1879db39160b 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/02 03:29 | agent | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING"
],
"FocusSymbols": [
"alloc_frozen_pages_nolock_noprof",
"alloc_pages_node_noprof"
],
"Reasoning": "The patch refactors the internal page allocator API by introducing `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, replacing `__GFP_NO_OBJ_EXT` and `ALLOC_TRYLOCK` with `ALLOC_NO_CODETAG` and `ALLOC_NOLOCK`. It also moves `alloc_pages_node_noprof` out-of-line. These are functional changes to core memory management code that should be fuzzed to ensure no regressions in page allocation, especially in non-blocking/nolock contexts and memory profiling.",
"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 ebf40183e6fbf27046c88e56484d71706d00b3ab
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Jul 2 03:29:34 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 db3d8c441e4c00..de87921176b0dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17181,6 +17181,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 e86e4ba91e1b37..8940f0292229f5 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 a03add00f923ec..26f15584d4b505 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -3040,7 +3040,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..aacff702042416 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -170,7 +170,7 @@ 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,
+ page = alloc_pages_node(nid,
GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
pg_order);
if (page == NULL) {
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/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/mm/alloc_tag.c b/mm/alloc_tag.c
index d9be1cf5187d97..a32a94e759b94b 100644
--- a/mm/alloc_tag.c
+++ b/mm/alloc_tag.c
@@ -15,6 +15,8 @@
#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
+#include "internal.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 +785,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 +795,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 +827,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 +835,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 e1bb81631d5eb0..997a08ba35423d 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"
@@ -1805,7 +1806,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 430aa72a457581..369c656c63fa80 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,51 +1233,10 @@ 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;
-
/*
* only for MM internal work items which do not depend on
* any allocations or locks which might depend on allocations
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/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 7ac19fab226324..9539e40c478edb 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 36699fabd3c223..41d630f0ea8212 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 */
@@ -2425,9 +2426,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;
}
@@ -2475,7 +2478,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;
/*
@@ -2487,7 +2490,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/mm_init.c b/mm/mm_init.c
index 6b89e2e7743112..35641fac109d53 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 62f71ece7ca177..803b32e5a5e47f 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() */
@@ -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,8 +3775,8 @@ 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,
+ unsigned int alloc_flags)
{
#ifdef CONFIG_CMA
if (gfp_migratetype(gfp_mask) == MIGRATE_MOVABLE)
@@ -4474,7 +4475,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 +4498,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 +4513,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 +4526,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, alloc_flags);
if (defrag_mode)
alloc_flags |= ALLOC_NOFRAGMENT;
@@ -4790,8 +4791,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 +4837,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
@@ -5059,11 +5064,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, *alloc_flags);
/* Dirty zone balancing only done in the fast path */
ac->spread_dirty_pages = (gfp_mask & __GFP_WRITE);
@@ -5221,7 +5226,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 +5240,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 +5275,101 @@ 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_trylock_allowed(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. This function 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;
+
+ /* 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_trylock_allowed())
+ return NULL;
+ gfp |= gfp_nolock;
+ } else {
+ fastpath_alloc_flags |= ALLOC_WMARK_LOW;
+ }
+
gfp &= gfp_allowed_mask;
/*
* Apply scoped allocation constraints. This is mainly about GFP_NOFS
@@ -5299,19 +5381,19 @@ 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;
+ 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 +5410,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 +5423,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 +7132,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 +7337,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 +7899,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 +7969,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..2614bff6795b08
--- /dev/null
+++ b/mm/page_alloc.h
@@ -0,0 +1,316 @@
+/* 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 */
+/*
+ * Skip early PFN recording for a page allocation. 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 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,
+ 0 /* 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 drain_local_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 ffbaba3d69d3ce..290e47e1fa09e1 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/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/slub.c b/mm/slub.c
index 9f754cf1c1874c..ff44f4373d522b 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;
@@ -5275,7 +5277,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);
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 754c5f5d716aad..de1879db39160b 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/02 03:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 24465 output: 23 thoughts: 476 Thoughts: **Refactoring the Linux Kernel's Page Allocator** Okay, so I'm looking at a patch that dives deep into the Linux kernel's page allocator. It looks like a significant refactoring of the internal APIs, which is always a bit nerve-wracking given how fundamental and frequently used this code is. The core of this work seems to be aimed at making things cleaner and potentially more flexible for future development. The patch creates a new header, `mm/page_alloc.h`, and shifts some internal definitions from `mm/internal.h` over there. That's good hygiene; separating concerns is always a solid move. They're also modifying the signatures of `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof` to take an `alloc_flags` argument. Replacing specific flags like `__GFP_NO_OBJ_EXT` and `__GFP_NO_CODETAG` with a consolidated `alloc_flags` and `ALLOC_NO_CODETAG` is another welcome change. The old lock definition is also changed from `ALLOC_TRYLOCK` to `ALLOC_NOLOCK` and the function `alloc_pages_node_noprof` is out of lined from `include/linux/gfp.h`, while `gfp_to_alloc_flags` is replaced with `alloc_flags_slowpath` and `gfp_to_alloc_flags_cma` is replaced with `alloc_flags_cma`. Given that it touches `mm/page_alloc.c`, `mm/internal.h`, `mm/page_alloc.h`, and `include/linux/gfp.h`, I need to quickly scan to see if this introduces any new configuration dependencies. The page allocator is always enabled, so that's a good start. But I need to check if things like `CONFIG_NUMA`, `CONFIG_MEMCG`, or maybe even `CONFIG_MEM_ALLOC_PROFILING` come into play here. The use of `ALLOC_NO_CODETAG` in `mm/alloc_tag.c` feels like it could be related to `CONFIG_MEM_ALLOC_PROFILING`. I think I'll use `grepper` to be sure about the `CONFIG_MEM_ALLOC_PROFILING` dependency. Let's make sure before we push this upstream. |
| 4/2 | 2026/07/02 03:29 | 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=824=struct task_struct {\n--\ninclude/linux/sched.h-848-\ninclude/linux/sched.h:849:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/sched.h-850-\tstruct alloc_tag\t\t*alloc_tag;\n--\ninclude/linux/sched.h=2339=extern void sched_set_stop_task(int cpu, struct task_struct *stop);\ninclude/linux/sched.h-2340-\ninclude/linux/sched.h:2341:#ifdef CONFIG_MEM_ALLOC_PROFILING\ninclude/linux/sched.h-2342-static __always_inline struct alloc_tag *alloc_tag_save(struct alloc_tag *tag)\n--\ninclude/linux/sched.h=2348=static __always_inline void alloc_tag_restore(struct alloc_tag *tag, struct alloc_tag *old)\ninclude/linux/sched.h-2349-{\ninclude/linux/sched.h:2350:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\ninclude/linux/sched.h-2351-\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-24-\nmm/alloc_tag.c:25:#ifdef CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\nmm/alloc_tag.c-26-static bool mem_profiling_support = true;\n--\nmm/alloc_tag.c=35=EXPORT_SYMBOL(_shared_alloc_tag);\n--\nmm/alloc_tag.c-37-\nmm/alloc_tag.c:38:DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,\nmm/alloc_tag.c-39-\t\t\tmem_alloc_profiling_key);\n--\nmm/alloc_tag.c=762=static __init bool need_page_alloc_tagging(void)\n--\nmm/alloc_tag.c-769-\nmm/alloc_tag.c:770:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/alloc_tag.c-771-/*\n--\nmm/alloc_tag.c=848=static void __init clear_early_alloc_pfn_tag_refs(void)\n--\nmm/alloc_tag.c-901-}\nmm/alloc_tag.c:902:#else /* !CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/alloc_tag.c-903-static inline void __init clear_early_alloc_pfn_tag_refs(void) {}\nmm/alloc_tag.c:904:#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */\nmm/alloc_tag.c-905-\n--\nmm/alloc_tag.c=923=static int proc_mem_profiling_handler(const struct ctl_table *table, int write,\n--\nmm/alloc_tag.c-934-\nmm/alloc_tag.c:935:#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG\nmm/alloc_tag.c-936-\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"
} |
| 5/2 | 2026/07/02 03:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30053 output: 22 thoughts: 207 Thoughts: **Analyzing the Page Allocation Patch** Okay, so this patch is digging into some pretty fundamental stuff – `mm/page_alloc.c` and `mm/alloc_tag.c`. My immediate thought is, why these two files? The mention of `ALLOC_NO_CODETAG` in `mm/alloc_tag.c` is the key. That’s conditional on `CONFIG_MEM_ALLOC_PROFILING`. So, it's pretty clear: we need to make sure that profiling configuration is enabled. And the changes to `mm/page_alloc.c` are significant. It's the heart of the kernel's page allocation logic. It looks like the patch is touching several functions with the `noprof` suffix: `__alloc_pages_noprof`, `__alloc_frozen_pages_noprof`, `alloc_pages_node_noprof`, and `alloc_frozen_pages_nolock_noprof`. Right away, the "noprof" indicates it's related to the profiling. But these are core allocation functions, heavily used, which means even a small bug here would have a huge impact. I need to understand the implications of these changes in this context, especially since they impact allocation logic. `alloc_frozen_pages_nolock_noprof` stands out a bit. It is used for reentrant allocation, which can be tricky. I'm going to track down the callers of that function and review them very carefully to see how the changes interact within those opportunistic contexts. |
| 6/2 | 2026/07/02 03:29 | tool | grepper |
0mArgs:{
"Expression": "alloc_frozen_pages_nolock"
}Results: {
"Output": "mm/page_alloc.c=7962=static bool __free_unaccepted(struct page *page)\n--\nmm/page_alloc.c-7969-\nmm/page_alloc.c:7970:struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\nmm/page_alloc.c-7971-{\n--\nmm/page_alloc.c=7993=struct page *alloc_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order)\n--\nmm/page_alloc.c-7996-\nmm/page_alloc.c:7997:\tpage = alloc_frozen_pages_nolock_noprof(gfp_flags, nid, order);\nmm/page_alloc.c-7998-\tif (page)\n--\nmm/page_alloc.h=245=static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order)\n--\nmm/page_alloc.h-254-\nmm/page_alloc.h:255:struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);\nmm/page_alloc.h:256:#define alloc_frozen_pages_nolock(...) \\\nmm/page_alloc.h:257:\talloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))\nmm/page_alloc.h-258-void free_frozen_pages_nolock(struct page *page, unsigned int order);\n--\nmm/slub.c=3281=static inline struct slab *alloc_slab_page(gfp_t flags, int node,\n--\nmm/slub.c-3289-\tif (unlikely(!allow_spin))\nmm/slub.c:3290:\t\tpage = alloc_frozen_pages_nolock(0/* __GFP_COMP is implied */,\nmm/slub.c-3291-\t\t\t\t\t\t\t\t node, order);\n--\nmm/slub.c=5369=static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags,\n--\nmm/slub.c-5386-\t * See the comment for the same check in\nmm/slub.c:5387:\t * alloc_frozen_pages_nolock_noprof()\nmm/slub.c-5388-\t */\n"
} |
| 7/2 | 2026/07/02 03:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 31270 output: 24 thoughts: 723 Thoughts: **Fuzzing Focus: Kernel Memory Allocation Patches** Okay, so I'm looking at this patch and immediately, my spider senses are tingling – this needs fuzzing, definitely. I see that `alloc_frozen_pages_nolock` is being used within `slub.c` for both `alloc_slab_page` and `__kmalloc_nolock_noprof`, and the patch also dives into the core page allocation functions: `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`. Now, the instructions are clear: avoid listing *generic* hot-path functions to prevent test distribution skew. So, while `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof` are *critical*, they're too common to be primary fuzzing targets here. I need to get more targeted. I see that `alloc_pages_node_noprof` is also being touched, but that's also pretty generic. Let me review the changes in `mm/page_alloc.c` again – it's crucial I don't miss anything. Okay, so in addition to the core functions mentioned previously: * `__alloc_frozen_pages_noprof` * `__alloc_pages_noprof` * `alloc_pages_node_noprof` * `alloc_frozen_pages_nolock_noprof` I see `alloc_tag_add_early_pfn` in `mm/alloc_tag.c` is being modified. `post_alloc_hook`, `prep_new_page`, and several `gfp_to_alloc_flags` functions are being changed, and some new functions `alloc_order_allowed` and `alloc_trylock_allowed`. Given the need for focused fuzzing and to stay within the spirit of the instructions, I think a prime candidate emerges: `alloc_frozen_pages_nolock_noprof`. It's a specific API that's now leveraging `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`, and that's an interesting intersection. Plus, I need to make sure I understand the new calls that have to be protected from reentrant allocation by this path. And, `alloc_tag_add_early_pfn` is a strong second. I'll need to dig into both of those and fully understand the implications. |
| 8/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "alloc_tag_add_early_pfn"
}Results: {
"Output": "include/linux/alloc_tag.h=162=static inline void alloc_tag_sub_check(union codetag_ref *ref)\n--\ninclude/linux/alloc_tag.h-165-}\ninclude/linux/alloc_tag.h:166:void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags);\ninclude/linux/alloc_tag.h-167-#else\n--\ninclude/linux/alloc_tag.h=169=static inline void alloc_tag_sub_check(union codetag_ref *ref) {}\ninclude/linux/alloc_tag.h:170:static inline void alloc_tag_add_early_pfn(unsigned long pfn, gfp_t gfp_flags) {}\ninclude/linux/alloc_tag.h-171-#endif\n--\nmm/alloc_tag.c=788=static struct pfn_pool *current_pfn_pool __initdata;\nmm/alloc_tag.c-789-\nmm/alloc_tag.c:790:static void __init __alloc_tag_add_early_pfn(unsigned long pfn)\nmm/alloc_tag.c-791-{\n--\nmm/alloc_tag.c=826=typedef void alloc_tag_add_func(unsigned long pfn);\nmm/alloc_tag.c:827:static alloc_tag_add_func __rcu *alloc_tag_add_early_pfn_ptr __refdata =\nmm/alloc_tag.c:828:\tRCU_INITIALIZER(__alloc_tag_add_early_pfn);\nmm/alloc_tag.c-829-\nmm/alloc_tag.c:830:void alloc_tag_add_early_pfn(unsigned long pfn, unsigned int alloc_flags)\nmm/alloc_tag.c-831-{\n--\nmm/alloc_tag.c-841-\trcu_read_lock();\nmm/alloc_tag.c:842:\talloc_tag_add = rcu_dereference(alloc_tag_add_early_pfn_ptr);\nmm/alloc_tag.c-843-\tif (alloc_tag_add)\n--\nmm/alloc_tag.c=848=static void __init clear_early_alloc_pfn_tag_refs(void)\n--\nmm/alloc_tag.c-856-\nmm/alloc_tag.c:857:\trcu_assign_pointer(alloc_tag_add_early_pfn_ptr, NULL);\nmm/alloc_tag.c:858:\t/* Make sure we are not racing with __alloc_tag_add_early_pfn() */\nmm/alloc_tag.c-859-\tsynchronize_rcu();\n--\nmm/page_alloc.c=1251=void __pgalloc_tag_add(struct page *page, struct task_struct *task,\n--\nmm/page_alloc.c-1265-\t\t */\nmm/page_alloc.c:1266:\t\talloc_tag_add_early_pfn(page_to_pfn(page), alloc_flags);\nmm/page_alloc.c-1267-\t\tif (task-\u003ealloc_tag)\n--\nmm/page_alloc.h-53- * Skip early PFN recording for a page allocation. Used by\nmm/page_alloc.h:54: * __alloc_tag_add_early_pfn() to avoid recursion when allocating pages for the\nmm/page_alloc.h-55- * early PFN tracking list itself.\n"
} |
| 9/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 33454 output: 24 thoughts: 95 Thoughts: Here's my analysis of the provided code snippets: **Early Initialization vs. Fuzzing Target** Alright, let's break this down. Seeing `alloc_tag_add_early_pfn` tagged as an `__init` or early boot function immediately tells me that's not going to be a fruitful target for fuzzing. It's essentially off-limits during the normal runtime and operation. My interest lies elsewhere. The next point zeroes in on `alloc_frozen_pages_nolock_noprof`. Now, that's more interesting. Knowing it's utilized within `slub.c` for both `alloc_slab_page` *and* `__kmalloc_nolock_noprof` suggests it's a critical component of the memory allocation machinery. This means it's worth taking a closer look at `__kmalloc_nolock_noprof` now. The main question now becomes: is `__kmalloc_nolock_noprof` actually reachable during the fuzzing stage? If it's a path that can be exercised dynamically, then we have a potential entry point for uncovering memory allocation flaws. This would require some investigation to determine its calling context and triggering conditions. |
| 10/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "__kmalloc_nolock_noprof"
}Results: {
"Output": "mm/slub.c=5367=EXPORT_SYMBOL(__kmalloc_noprof);\nmm/slub.c-5368-\nmm/slub.c:5369:static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags,\nmm/slub.c-5370-\t\t\t\t int node, const struct slab_alloc_context *ac)\n--\nmm/slub.c=5454=void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node)\n--\nmm/slub.c-5461-\nmm/slub.c:5462:\treturn __kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(size, token),\nmm/slub.c-5463-\t\t\t\t gfp_flags, node, \u0026ac);\n--\nmm/slub.c=5523=void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\n--\nmm/slub.c-5535-\t} else {\nmm/slub.c:5536:\t\treturn __kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(size, token),\nmm/slub.c-5537-\t\t\t\t\t flags, node, \u0026ac);\n"
} |
| 11/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34204 output: 23 thoughts: 51 Thoughts: Okay, here's my interpretation of those thoughts, presented as my own mental processing as an expert in my field: **Digging into Kernel Memory Allocation with Flags and Profiles** Alright, let's break this down. It seems like we're looking at kernel memory allocation, specifically using `kmalloc`. I see that `__kmalloc_flags_noprof` is a wrapper function that calls `__kmalloc_nolock_noprof`. The "noprof" suffix probably means it's designed to avoid certain profiling overhead, which is a key optimization technique. The significant point here is likely where `__kmalloc_flags_noprof` is deployed. The mention of BPF and "other specific contexts" immediately flags this as interesting. This strongly suggests that `__kmalloc_flags_noprof` is crucial in scenarios where low overhead and latency are paramount. BPF, in particular, is notorious for its strict performance requirements, since BPF programs directly interact with the kernel in real time. We are talking about critical path code here. I'd want to check which flags are being passed into `__kmalloc_flags_noprof`. It's possible that these are `GFP_NOWAIT`, `GFP_ATOMIC`, or possibly a custom set of flags. The intent here is to minimize latency, by avoiding blocking. The 'nolock' part of the call suggests it does not need to block on locks. Given the contexts listed, I'd bet these allocations need to be super fast and potentially non-blocking to avoid deadlocks. This sounds right, given the context in which it's being used. Understanding the *why* behind this particular choice of allocation routine will be critical. Further investigation is warranted to fully understand the context where `__kmalloc_flags_noprof` is used, and it's use relative to other allocation routines. |
| 12/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "__kmalloc_flags_noprof"
}Results: {
"Output": "mm/slab.h=26=static inline bool alloc_flags_allow_spinning(const unsigned int alloc_flags)\n--\nmm/slab.h-30-\nmm/slab.h:31:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slab.h-32-\t\t\t\t unsigned int alloc_flags, int node)\n--\nmm/slab.h=35=static __always_inline __alloc_size(1) void *_kmalloc_flags_noprof(size_t size,\n--\nmm/slab.h-37-{\nmm/slab.h:38:\treturn __kmalloc_flags_noprof(PASS_TOKEN_PARAMS(size, token), flags, alloc_flags, node);\nmm/slab.h-39-}\n--\nmm/slub.c=5516=EXPORT_SYMBOL(__kmalloc_cache_node_noprof);\n--\nmm/slub.c-5522- */\nmm/slub.c:5523:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slub.c-5524-\t\t\t unsigned int alloc_flags, int node)\n"
} |
| 13/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35004 output: 23 thoughts: 15 Thoughts: Okay, here's my summary, presented as a stream of thought: **Tracing the Usage of `_kmalloc_flags_noprof`** Alright, so the question is, where exactly is this `_kmalloc_flags_noprof` thing being used? It's that subtle detail that likely tells a story about optimization, or perhaps a niche case within the kernel's memory allocation system. I need to figure out the context. Let me think... is it a macro? A function? I'll probably need to crack open the code and do a find-all, but that's just the starting point. I can't just look for it; I need to understand *why* it's being used there. What specific flags or allocations is it avoiding? Is it related to performance, to a particular subsystem, or perhaps a low-latency requirement? Is there some part of the kernel which needs kmalloc with a different profile? Has it been removed in later kernels? Perhaps this is a historical artifact. Was it even ever used? What dependencies does it have? I'll need to look at call sites, cross-references, and ultimately, follow the execution flow to form an understanding of the code in context. That is the only thing that matters. |
| 14/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "_kmalloc_flags_noprof"
}Results: {
"Output": "mm/slab.h=26=static inline bool alloc_flags_allow_spinning(const unsigned int alloc_flags)\n--\nmm/slab.h-30-\nmm/slab.h:31:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slab.h-32-\t\t\t\t unsigned int alloc_flags, int node)\n--\nmm/slab.h-34-\nmm/slab.h:35:static __always_inline __alloc_size(1) void *_kmalloc_flags_noprof(size_t size,\nmm/slab.h-36-\t\tgfp_t flags, unsigned int alloc_flags, int node, kmalloc_token_t token)\nmm/slab.h-37-{\nmm/slab.h:38:\treturn __kmalloc_flags_noprof(PASS_TOKEN_PARAMS(size, token), flags, alloc_flags, node);\nmm/slab.h-39-}\nmm/slab.h:40:#define kmalloc_flags_noprof(...)\t_kmalloc_flags_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))\nmm/slab.h-41-#define kmalloc_flags(...)\t\talloc_hooks(kmalloc_flags_noprof(__VA_ARGS__))\n--\nmm/slub.c=5516=EXPORT_SYMBOL(__kmalloc_cache_node_noprof);\n--\nmm/slub.c-5522- */\nmm/slub.c:5523:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slub.c-5524-\t\t\t unsigned int alloc_flags, int node)\n"
} |
| 15/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 35755 output: 18 thoughts: 10 Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert: **Tracing `kmalloc_flags` Usage** Alright, so the first thing that pops into my head is, "Where exactly does `kmalloc_flags` come into play in the kernel?" It's always a good starting point for understanding how a particular flag is implemented, how the kernel is acting, and whether I can rely on a given assumption about it. I need to figure out the scope, the context. I'm thinking I'll need to dig through some of the kernel source to see which functions, which subsystems, even which drivers, are making use of this. It's a fundamental question - I need to know the landscape before I can evaluate a particular use case. Let's start the search... |
| 16/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "kmalloc_flags"
}Results: {
"Output": "drivers/usb/gadget/function/u_serial.c=168=struct usb_request *\ndrivers/usb/gadget/function/u_serial.c:169:gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)\ndrivers/usb/gadget/function/u_serial.c-170-{\n--\ndrivers/usb/gadget/function/u_serial.c-172-\ndrivers/usb/gadget/function/u_serial.c:173:\treq = usb_ep_alloc_request(ep, kmalloc_flags);\ndrivers/usb/gadget/function/u_serial.c-174-\n--\ndrivers/usb/gadget/function/u_serial.c-176-\t\treq-\u003elength = len;\ndrivers/usb/gadget/function/u_serial.c:177:\t\treq-\u003ebuf = kmalloc(len, kmalloc_flags);\ndrivers/usb/gadget/function/u_serial.c-178-\t\tif (req-\u003ebuf == NULL) {\n--\nmm/slab.h=26=static inline bool alloc_flags_allow_spinning(const unsigned int alloc_flags)\n--\nmm/slab.h-30-\nmm/slab.h:31:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slab.h-32-\t\t\t\t unsigned int alloc_flags, int node)\n--\nmm/slab.h-34-\nmm/slab.h:35:static __always_inline __alloc_size(1) void *_kmalloc_flags_noprof(size_t size,\nmm/slab.h-36-\t\tgfp_t flags, unsigned int alloc_flags, int node, kmalloc_token_t token)\nmm/slab.h-37-{\nmm/slab.h:38:\treturn __kmalloc_flags_noprof(PASS_TOKEN_PARAMS(size, token), flags, alloc_flags, node);\nmm/slab.h-39-}\nmm/slab.h:40:#define kmalloc_flags_noprof(...)\t_kmalloc_flags_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))\nmm/slab.h:41:#define kmalloc_flags(...)\t\talloc_hooks(kmalloc_flags_noprof(__VA_ARGS__))\nmm/slab.h-42-\n--\nmm/slub.c=2163=int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,\n--\nmm/slub.c-2181-\t/* This will use kmalloc_nolock() if alloc_flags say so */\nmm/slub.c:2182:\tvec = kmalloc_flags(sz, gfp | __GFP_ZERO, alloc_flags, slab_nid(slab));\nmm/slub.c-2183-\n--\nmm/slub.c=2765=static struct slab_sheaf *__alloc_empty_sheaf(struct kmem_cache *s, gfp_t gfp,\n--\nmm/slub.c-2779-\tsheaf_size = struct_size(sheaf, objects, capacity);\nmm/slub.c:2780:\tsheaf = kmalloc_flags(sheaf_size, gfp | __GFP_ZERO, alloc_flags, NUMA_NO_NODE);\nmm/slub.c-2781-\n--\nmm/slub.c=5516=EXPORT_SYMBOL(__kmalloc_cache_node_noprof);\n--\nmm/slub.c-5522- */\nmm/slub.c:5523:void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\nmm/slub.c-5524-\t\t\t unsigned int alloc_flags, int node)\n"
} |
| 17/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 36942 output: 26 thoughts: 260 Thoughts: **My Initial Investigation into Memory Allocation Functions** Okay, so I'm digging into memory allocation within the kernel, specifically focusing on potential fuzzing targets. I see that `kmalloc_flags` is utilized within `mm/slub.c` specifically by `alloc_slab_obj_exts` and `__alloc_empty_sheaf`. The former, `alloc_slab_obj_exts`, deals with allocating object extensions for slab objects, which seems like a reachable and potentially interesting area to explore. I'll make a mental note of that. Next, I started looking at `alloc_frozen_pages_nolock_noprof` and `alloc_pages_node_noprof`, and it immediately strikes me that `alloc_pages_node_noprof` is extremely common. Ah, yes, `alloc_pages_node` is a macro that calls `alloc_pages_node_noprof`, and it's practically ubiquitous in the code. Directly fuzzing something that fundamental would likely be too broad to be effective at this stage. But what about `alloc_frozen_pages_nolock_noprof`? Is that another candidate? Let me check quickly if it's an exported symbol. Hmm, no, it's not exported. It appears to be used internally within `mm/page_alloc.c` and also within `mm/slub.c`. Ah, there's `alloc_frozen_pages_nolock` which is a macro that calls `alloc_frozen_pages_nolock_noprof`. I'll have to investigate that to see if it's exported. |
| 18/2 | 2026/07/02 03:30 | tool | grepper |
0mError:no matches Args: {
"Expression": "EXPORT_SYMBOL.*alloc_frozen_pages_nolock"
}Results: {
"error": "no matches"
} |
| 19/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 37593 output: 17 thoughts: 486 Thoughts: **Analyzing the Page Allocator API Changes** Okay, so I'm looking at this patch and trying to understand its implications on the page allocator. First things first: is this functionality even *accessible* from outside the kernel? Let's check which symbols are exported. Hmm, `__kmalloc_nolock_noprof` isn't. But, `__alloc_frozen_pages_noprof`, `__alloc_pages_noprof`, and `alloc_pages_node_noprof` are. Excellent, they're exported. Since the patch touches the core allocator, these changes are definitely impactful and *reachable* code. The patch introduces `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, and adds `ALLOC_NOLOCK` and `ALLOC_NO_CODETAG`. That's where the interesting stuff is, so I need to hone in on functions that *use* these new flags. I see `alloc_frozen_pages_nolock_noprof` uses `ALLOC_NOLOCK`, while `__alloc_tag_add_early_pfn` uses `ALLOC_NO_CODETAG`. Also `alloc_pages_node_noprof`, `alloc_pages_bulk_noprof`, and `__folio_alloc_noprof` use `ALLOC_DEFAULT`. Alright, let's zero in on `alloc_frozen_pages_nolock_noprof`. It looks like a prime fuzzing target. It's a specific API that uses `__alloc_frozen_pages_noprof` with `ALLOC_NOLOCK`, and the patch changed it. Wait a minute... it's *not* exported, meaning it can't be called directly from kernel modules. But, it could still be reached via `kmalloc` with `ALLOC_NOLOCK` or via `alloc_slab_page` when `allow_spin` is false. Interesting! So, `alloc_slab_page` uses `alloc_frozen_pages_nolock` when `allow_spin` is false. I need to figure out the cases where `allow_spin` is false. That's the key to reaching this code path. |
| 20/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "allow_spin"
}Results: {
"Output": "include/linux/gfp.h=20=static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)\n--\ninclude/linux/gfp.h-24-\ninclude/linux/gfp.h:25:static inline bool gfpflags_allow_spinning(const gfp_t gfp_flags)\ninclude/linux/gfp.h-26-{\n--\ninclude/linux/memcontrol.h=980=void __memcg_memory_event(struct mem_cgroup *memcg,\ninclude/linux/memcontrol.h:981:\t\t\t enum memcg_memory_event event, bool allow_spinning);\ninclude/linux/memcontrol.h-982-\n--\nkernel/printk/printk.c=3027=bool printk_get_next_message(struct printk_message *pmsg, u64 seq,\n--\nkernel/printk/printk.c-3087-#ifdef CONFIG_PREEMPT_RT\nkernel/printk/printk.c:3088:static inline void printk_legacy_allow_spinlock_enter(void) { }\nkernel/printk/printk.c:3089:static inline void printk_legacy_allow_spinlock_exit(void) { }\nkernel/printk/printk.c-3090-#else\nkernel/printk/printk.c=3091=static DEFINE_WAIT_OVERRIDE_MAP(printk_legacy_map, LD_WAIT_CONFIG);\nkernel/printk/printk.c-3092-\nkernel/printk/printk.c:3093:static inline void printk_legacy_allow_spinlock_enter(void)\nkernel/printk/printk.c-3094-{\n--\nkernel/printk/printk.c-3097-\nkernel/printk/printk.c:3098:static inline void printk_legacy_allow_spinlock_exit(void)\nkernel/printk/printk.c-3099-{\n--\nkernel/printk/printk.c=3126=static bool console_emit_next_record(struct console *con, bool *handover, int cookie)\n--\nkernel/printk/printk.c-3181-\nkernel/printk/printk.c:3182:\t\tprintk_legacy_allow_spinlock_enter();\nkernel/printk/printk.c-3183-\t\tcon-\u003ewrite(con, outbuf, pmsg.outbuf_len);\nkernel/printk/printk.c:3184:\t\tprintk_legacy_allow_spinlock_exit();\nkernel/printk/printk.c-3185-\n--\nlib/stackdepot.c=641=depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,\n--\nlib/stackdepot.c-650-\tvoid *prealloc = NULL;\nlib/stackdepot.c:651:\tbool allow_spin = gfpflags_allow_spinning(alloc_flags);\nlib/stackdepot.c:652:\tbool can_alloc = (depot_flags \u0026 STACK_DEPOT_FLAG_CAN_ALLOC) \u0026\u0026 allow_spin;\nlib/stackdepot.c-653-\tunsigned long flags;\n--\nlib/stackdepot.c-690-\nlib/stackdepot.c:691:\tif (in_nmi() || !allow_spin) {\nlib/stackdepot.c-692-\t\t/* We can never allocate in NMI context. */\n--\nlib/stackdepot.c-731-\t\t/* Stack depot didn't use this memory, free it. */\nlib/stackdepot.c:732:\t\tif (!allow_spin)\nlib/stackdepot.c-733-\t\t\tfree_pages_nolock(virt_to_page(prealloc), DEPOT_POOL_ORDER);\n--\nmm/memcontrol.c=1854=void __memcg_memory_event(struct mem_cgroup *memcg,\nmm/memcontrol.c:1855:\t\t\t enum memcg_memory_event event, bool allow_spinning)\nmm/memcontrol.c-1856-{\n--\nmm/memcontrol.c-1859-\nmm/memcontrol.c:1860:\t/* For now only MEMCG_MAX can happen with !allow_spinning context. */\nmm/memcontrol.c:1861:\tVM_WARN_ON_ONCE(!allow_spinning \u0026\u0026 event != MEMCG_MAX);\nmm/memcontrol.c-1862-\nmm/memcontrol.c-1863-\tatomic_long_inc(\u0026memcg-\u003ememory_events_local[event]);\nmm/memcontrol.c:1864:\tif (!swap_event \u0026\u0026 allow_spinning)\nmm/memcontrol.c-1865-\t\tcgroup_file_notify(\u0026memcg-\u003eevents_local_file);\n--\nmm/memcontrol.c-1868-\t\tatomic_long_inc(\u0026memcg-\u003ememory_events[event]);\nmm/memcontrol.c:1869:\t\tif (allow_spinning) {\nmm/memcontrol.c-1870-\t\t\tif (swap_event)\n--\nmm/memcontrol.c=2595=static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,\n--\nmm/memcontrol.c-2607-\tunsigned long pflags;\nmm/memcontrol.c:2608:\tbool allow_spinning = gfpflags_allow_spinning(gfp_mask);\nmm/memcontrol.c-2609-\n--\nmm/memcontrol.c-2613-\nmm/memcontrol.c:2614:\tif (!allow_spinning)\nmm/memcontrol.c-2615-\t\t/* Avoid the refill and flush of the older stock */\n--\nmm/memcontrol.c-2650-\nmm/memcontrol.c:2651:\t__memcg_memory_event(mem_over_limit, MEMCG_MAX, allow_spinning);\nmm/memcontrol.c-2652-\traised_max_event = true;\n--\nmm/memcontrol.c-2717-\tif (!raised_max_event)\nmm/memcontrol.c:2718:\t\t__memcg_memory_event(mem_over_limit, MEMCG_MAX, allow_spinning);\nmm/memcontrol.c-2719-\n--\nmm/page_alloc.c=5291=static inline bool alloc_trylock_allowed(void)\n--\nmm/page_alloc.c-5324- *\nmm/page_alloc.c:5325: * These two are the conditions for gfpflags_allow_spinning() being true.\nmm/page_alloc.c-5326- *\n--\nmm/page_owner.c=193=static void add_stack_record_to_list(struct stack_record *stack_record,\n--\nmm/page_owner.c-198-\nmm/page_owner.c:199:\tif (!gfpflags_allow_spinning(gfp_mask))\nmm/page_owner.c-200-\t\treturn;\n--\nmm/page_owner.c=317=void __reset_page_owner(struct page *page, unsigned short order)\n--\nmm/page_owner.c-333-\t/*\nmm/page_owner.c:334:\t * Do not specify GFP_NOWAIT to make gfpflags_allow_spinning() == false\nmm/page_owner.c-335-\t * to prevent issues in stack_depot_save().\n--\nmm/slab.h-25-\nmm/slab.h:26:static inline bool alloc_flags_allow_spinning(const unsigned int alloc_flags)\nmm/slab.h-27-{\n--\nmm/slub.c=2163=int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,\n--\nmm/slub.c-2165-{\nmm/slub.c:2166:\tconst bool allow_spin = alloc_flags_allow_spinning(alloc_flags);\nmm/slub.c-2167-\tunsigned int objects = objs_per_slab(s, slab);\n--\nmm/slub.c-2221-\t\tmark_obj_codetag_empty(vec);\nmm/slub.c:2222:\t\tif (unlikely(!allow_spin))\nmm/slub.c-2223-\t\t\tkfree_nolock(vec);\n--\nmm/slub.c-2231-\nmm/slub.c:2232:\tif (allow_spin)\nmm/slub.c-2233-\t\tkmemleak_not_leak(vec);\n--\nmm/slub.c-2236-\nmm/slub.c:2237:static inline void free_slab_obj_exts(struct slab *slab, bool allow_spin)\nmm/slub.c-2238-{\n--\nmm/slub.c-2264-\tmark_obj_codetag_empty(obj_exts);\nmm/slub.c:2265:\tif (allow_spin)\nmm/slub.c-2266-\t\tkfree(obj_exts);\n--\nmm/slub.c=2332=static int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,\n--\nmm/slub.c-2337-\nmm/slub.c:2338:static inline void free_slab_obj_exts(struct slab *slab, bool allow_spin)\nmm/slub.c-2339-{\n--\nmm/slub.c=3089=static struct slab_sheaf *barn_get_empty_sheaf(struct node_barn *barn,\nmm/slub.c:3090:\t\t\t\t\t bool allow_spin)\nmm/slub.c-3091-{\n--\nmm/slub.c-3097-\nmm/slub.c:3098:\tif (likely(allow_spin))\nmm/slub.c-3099-\t\tspin_lock_irqsave(\u0026barn-\u003elock, flags);\n--\nmm/slub.c=3178=barn_replace_empty_sheaf(struct node_barn *barn, struct slab_sheaf *empty,\nmm/slub.c:3179:\t\t\t bool allow_spin)\nmm/slub.c-3180-{\n--\nmm/slub.c-3186-\nmm/slub.c:3187:\tif (likely(allow_spin))\nmm/slub.c-3188-\t\tspin_lock_irqsave(\u0026barn-\u003elock, flags);\n--\nmm/slub.c=3211=barn_replace_full_sheaf(struct node_barn *barn, struct slab_sheaf *full,\nmm/slub.c:3212:\t\t\tbool allow_spin)\nmm/slub.c-3213-{\n--\nmm/slub.c-3222-\nmm/slub.c:3223:\tif (likely(allow_spin))\nmm/slub.c-3224-\t\tspin_lock_irqsave(\u0026barn-\u003elock, flags);\n--\nmm/slub.c=3281=static inline struct slab *alloc_slab_page(gfp_t flags, int node,\nmm/slub.c-3282-\t\t\t\t\t struct kmem_cache_order_objects oo,\nmm/slub.c:3283:\t\t\t\t\t bool allow_spin)\nmm/slub.c-3284-{\n--\nmm/slub.c-3288-\nmm/slub.c:3289:\tif (unlikely(!allow_spin))\nmm/slub.c-3290-\t\tpage = alloc_frozen_pages_nolock(0/* __GFP_COMP is implied */,\n--\nmm/slub.c=3374=static __always_inline void unaccount_slab(struct slab *slab, int order,\nmm/slub.c:3375:\t\t\t\t\t struct kmem_cache *s, bool allow_spin)\nmm/slub.c-3376-{\n--\nmm/slub.c-3381-\t */\nmm/slub.c:3382:\tfree_slab_obj_exts(slab, allow_spin);\nmm/slub.c-3383-\n--\nmm/slub.c=3389=static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags,\n--\nmm/slub.c-3391-{\nmm/slub.c:3392:\tbool allow_spin = alloc_flags_allow_spinning(alloc_flags);\nmm/slub.c-3393-\tstruct slab *slab;\n--\nmm/slub.c-3409-\nmm/slub.c:3410:\tslab = alloc_slab_page(alloc_gfp, node, oo, allow_spin);\nmm/slub.c-3411-\tif (unlikely(!slab)) {\n--\nmm/slub.c-3417-\t\t */\nmm/slub.c:3418:\t\tslab = alloc_slab_page(alloc_gfp, node, oo, allow_spin);\nmm/slub.c-3419-\t\tif (unlikely(!slab))\n--\nmm/slub.c=3446=static struct slab *new_slab(struct kmem_cache *s, gfp_t flags,\n--\nmm/slub.c-3458-\nmm/slub.c:3459:static void __free_slab(struct kmem_cache *s, struct slab *slab, bool allow_spin)\nmm/slub.c-3460-{\n--\nmm/slub.c-3468-\tmm_account_reclaimed_pages(pages);\nmm/slub.c:3469:\tunaccount_slab(slab, order, s, allow_spin);\nmm/slub.c:3470:\tif (allow_spin)\nmm/slub.c-3471-\t\tfree_frozen_pages(page, order);\n--\nmm/slub.c=3661=static inline void init_slab_obj_iter(struct kmem_cache *s, struct slab *slab,\nmm/slub.c-3662-\t\t\t\t struct slab_obj_iter *iter,\nmm/slub.c:3663:\t\t\t\t bool allow_spin)\nmm/slub.c-3664-{\n--\nmm/slub.c-3675-\nmm/slub.c:3676:\tif (allow_spin) {\nmm/slub.c-3677-\t\titer-\u003epos = get_random_u32_below(iter-\u003efreelist_count);\n--\nmm/slub.c=3697=static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,\n--\nmm/slub.c-3699-{\nmm/slub.c:3700:\tbool allow_spin = alloc_flags_allow_spinning(ac-\u003ealloc_flags);\nmm/slub.c-3701-\tstruct kmem_cache_node *n;\n--\nmm/slub.c-3706-\nmm/slub.c:3707:\tinit_slab_obj_iter(s, slab, \u0026iter, allow_spin);\nmm/slub.c-3708-\tobject = next_slab_obj(s, \u0026iter);\n--\nmm/slub.c-3727-\tn = get_node(s, slab_nid(slab));\nmm/slub.c:3728:\tif (allow_spin) {\nmm/slub.c-3729-\t\tspin_lock_irqsave(\u0026n-\u003elist_lock, flags);\n--\nmm/slub.c=3757=static bool get_partial_node_bulk(struct kmem_cache *s,\n--\nmm/slub.c-3759-\t\t\t\t struct partial_bulk_context *pc,\nmm/slub.c:3760:\t\t\t\t bool allow_spin)\nmm/slub.c-3761-{\n--\nmm/slub.c-3772-\nmm/slub.c:3773:\tif (allow_spin)\nmm/slub.c-3774-\t\tspin_lock_irqsave(\u0026n-\u003elist_lock, flags);\n--\nmm/slub.c=3828=static void *get_from_partial_node(struct kmem_cache *s,\n--\nmm/slub.c-3845-\nmm/slub.c:3846:\tif (alloc_flags_allow_spinning(ac-\u003ealloc_flags))\nmm/slub.c-3847-\t\tspin_lock_irqsave(\u0026n-\u003elist_lock, flags);\n--\nmm/slub.c=3893=static void *get_from_any_partial(struct kmem_cache *s, gfp_t gfp_flags,\n--\nmm/slub.c-3901-\tunsigned int cpuset_mems_cookie;\nmm/slub.c:3902:\tbool allow_spin = alloc_flags_allow_spinning(ac-\u003ealloc_flags);\nmm/slub.c-3903-\n--\nmm/slub.c-3932-\t\t */\nmm/slub.c:3933:\t\tif (allow_spin)\nmm/slub.c-3934-\t\t\tcpuset_mems_cookie = read_mems_allowed_begin();\n--\nmm/slub.c-3959-\t\t}\nmm/slub.c:3960:\t} while (allow_spin \u0026\u0026 read_mems_allowed_retry(cpuset_mems_cookie));\nmm/slub.c-3961-#endif\t/* CONFIG_NUMA */\n--\nmm/slub.c=4403=static unsigned int alloc_from_new_slab(struct kmem_cache *s, struct slab *slab,\nmm/slub.c:4404:\t\tvoid **p, unsigned int count, bool allow_spin)\nmm/slub.c-4405-{\n--\nmm/slub.c-4419-\nmm/slub.c:4420:\tinit_slab_obj_iter(s, slab, \u0026iter, allow_spin);\nmm/slub.c-4421-\n--\nmm/slub.c-4431-\nmm/slub.c:4432:\t\tif (allow_spin) {\nmm/slub.c-4433-\t\t\tspin_lock_irqsave(\u0026n-\u003elist_lock, flags);\n--\nmm/slub.c=4458=static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,\n--\nmm/slub.c-4460-{\nmm/slub.c:4461:\tbool allow_spin = alloc_flags_allow_spinning(ac-\u003ealloc_flags);\nmm/slub.c-4462-\tgfp_t trynode_flags;\n--\nmm/slub.c-4513-\t\t/* we don't need to check SLAB_STORE_USER here */\nmm/slub.c:4514:\t\tif (alloc_from_new_slab(s, slab, \u0026object, 1, allow_spin))\nmm/slub.c-4515-\t\t\treturn object;\n--\nmm/slub.c-4517-\nmm/slub.c:4518:\tif (allow_spin)\nmm/slub.c-4519-\t\tgoto new_objects;\n--\nmm/slub.c=4570=bool slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, size_t size,\n--\nmm/slub.c-4619-\nmm/slub.c:4620:\t\tif (alloc_flags_allow_spinning(ac-\u003ealloc_flags))\nmm/slub.c-4621-\t\t\tkmemleak_alloc_recursive(p[i], s-\u003eobject_size, 1,\n--\nmm/slub.c=4639=__pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,\n--\nmm/slub.c-4644-\tstruct node_barn *barn;\nmm/slub.c:4645:\tbool allow_spin;\nmm/slub.c-4646-\n--\nmm/slub.c-4665-\nmm/slub.c:4666:\tallow_spin = alloc_flags_allow_spinning(alloc_flags);\nmm/slub.c-4667-\nmm/slub.c:4668:\tfull = barn_replace_empty_sheaf(barn, pcs-\u003emain, allow_spin);\nmm/slub.c-4669-\n--\nmm/slub.c-4677-\nmm/slub.c:4678:\tif (allow_spin) {\nmm/slub.c-4679-\t\tif (pcs-\u003espare) {\n--\nmm/slub.c-4689-\nmm/slub.c:4690:\tif (!allow_spin)\nmm/slub.c-4691-\t\treturn NULL;\n--\nmm/slub.c=4805=unsigned int alloc_from_pcs_bulk(struct kmem_cache *s, size_t size, void **p)\n--\nmm/slub.c-4839-\t\tfull = barn_replace_empty_sheaf(barn, pcs-\u003emain,\nmm/slub.c:4840:\t\t\t\t\t\t/* allow_spin = */ true);\nmm/slub.c-4841-\n--\nmm/slub.c=5369=static void *__kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags,\n--\nmm/slub.c-5375-\nmm/slub.c:5376:\tVM_WARN_ON_ONCE(alloc_flags_allow_spinning(ac-\u003ealloc_flags));\nmm/slub.c-5377-\tVM_WARN_ON_ONCE(gfp_flags \u0026 ~(__GFP_ACCOUNT | __GFP_ZERO |\n--\nmm/slub.c=5523=void *__kmalloc_flags_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags,\n--\nmm/slub.c-5531-\nmm/slub.c:5532:\tif (alloc_flags_allow_spinning(alloc_flags)) {\nmm/slub.c-5533-\t\treturn __do_kmalloc_node(NULL, flags, node,\n--\nmm/slub.c=5814=__pcs_replace_full_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,\nmm/slub.c:5815:\t\t\tbool allow_spin)\nmm/slub.c-5816-{\n--\nmm/slub.c-5838-\tif (!pcs-\u003espare) {\nmm/slub.c:5839:\t\tempty = barn_get_empty_sheaf(barn, allow_spin);\nmm/slub.c-5840-\t\tif (empty) {\n--\nmm/slub.c-5852-\nmm/slub.c:5853:\tempty = barn_replace_full_sheaf(barn, pcs-\u003emain, allow_spin);\nmm/slub.c-5854-\n--\nmm/slub.c-5860-\nmm/slub.c:5861:\t/* sheaf_flush_unused() doesn't support !allow_spin */\nmm/slub.c:5862:\tif (PTR_ERR(empty) == -E2BIG \u0026\u0026 allow_spin) {\nmm/slub.c-5863-\t\t/* Since we got here, spare exists and is full */\n--\nmm/slub.c-5887-\t/*\nmm/slub.c:5888:\t * alloc_empty_sheaf() doesn't support !allow_spin and it's\nmm/slub.c-5889-\t * easier to fall back to freeing directly without sheaves\n--\nmm/slub.c-5891-\t */\nmm/slub.c:5892:\tif (!allow_spin)\nmm/slub.c-5893-\t\treturn NULL;\n--\nmm/slub.c=5936=static __fastpath_inline\nmm/slub.c:5937:bool free_to_pcs(struct kmem_cache *s, void *object, bool allow_spin)\nmm/slub.c-5938-{\n--\nmm/slub.c-5947-\nmm/slub.c:5948:\t\tpcs = __pcs_replace_full_main(s, pcs, allow_spin);\nmm/slub.c-5949-\t\tif (unlikely(!pcs))\n--\nmm/slub.c=7162=__refill_objects_node(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int min,\nmm/slub.c-7163-\t\t unsigned int max, struct kmem_cache_node *n,\nmm/slub.c:7164:\t\t bool allow_spin)\nmm/slub.c-7165-{\n--\nmm/slub.c-7175-\nmm/slub.c:7176:\tif (!get_partial_node_bulk(s, n, \u0026pc, allow_spin))\nmm/slub.c-7177-\t\treturn 0;\n--\nmm/slub.c=7238=__refill_objects_any(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int min,\n--\nmm/slub.c-7266-\t\t\tr = __refill_objects_node(s, p, gfp, min, max, n,\nmm/slub.c:7267:\t\t\t\t\t\t /* allow_spin = */ false);\nmm/slub.c-7268-\t\t\trefilled += r;\n--\nmm/slub.c=7297=refill_objects(struct kmem_cache *s, void **p, gfp_t gfp, unsigned int min,\n--\nmm/slub.c-7305-\t\t\t\t\t get_node(s, local_node),\nmm/slub.c:7306:\t\t\t\t\t /* allow_spin = */ true);\nmm/slub.c-7307-\tif (refilled \u003e= min)\n--\nmm/slub.c-7323-\trefilled += alloc_from_new_slab(s, slab, p + refilled, max - refilled,\nmm/slub.c:7324:\t\t\t\t\t/* allow_spin = */ true);\nmm/slub.c-7325-\n"
} |
| 21/2 | 2026/07/02 03:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 45456 output: 22 thoughts: 1902 Thoughts: **Fuzzing Strategy for Page Allocator Refactoring** Alright, let's break this down from a memory management expert's perspective. It appears we have a refactoring of the page allocator API that's introducing `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, and replacing some old flags with `ALLOC_NO_CODETAG` and `ALLOC_NOLOCK`. The goal here is to make the code more robust and flexible, but we need to ensure we're not introducing any regressions. The most critical aspect of this change is about non-blocking allocations and potential locking issues. First, let's identify the key areas to focus our fuzzing efforts. The code is touching core memory management files, and specifically, the changes revolve around how pages are allocated, particularly with respect to locking and profiling. This means we must check for lock related bugs and memory corruption bugs. The primary function of interest, after digging into this a bit, is definitely `alloc_frozen_pages_nolock_noprof`. It's a critical function for opportunistic reentrant allocation in the nolock context and is a strong candidate for fuzzing as it's been updated to use the new flags. Another function, `alloc_pages_node_noprof`, that's now an out-of-line function as part of this refactoring, warrants attention as well. The `ALLOC_NO_CODETAG` flag is interesting as it seems it adds profiling data to the allocations. This flag seems to be important, so we should enable `MEM_ALLOC_PROFILING`. So, here's the final list: **FocusSymbols:** * `alloc_frozen_pages_nolock_noprof` * `alloc_pages_node_noprof` **EnableConfigs:** * `MEM_ALLOC_PROFILING` The reasoning here is that by targeting these specific functions and configurations, we'll gain significant coverage of the page allocator API changes, paying specific attention to the refactored locking and profiling mechanisms, minimizing the risk of introducing regressions. |
| 22/2 | 2026/07/02 03:30 | tool | grepper |
0mArgs:{
"Expression": "config MEM_ALLOC_PROFILING"
}Results: {
"Output": "mm/Kconfig.debug=311=config PER_VMA_LOCK_STATS\n--\nmm/Kconfig.debug-323-\nmm/Kconfig.debug:324:config MEM_ALLOC_PROFILING\nmm/Kconfig.debug-325-\tbool \"Enable memory allocation profiling\"\n--\nmm/Kconfig.debug-337-\nmm/Kconfig.debug:338:config MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT\nmm/Kconfig.debug-339-\tbool \"Enable memory allocation profiling by default\"\n--\nmm/Kconfig.debug-342-\nmm/Kconfig.debug:343:config MEM_ALLOC_PROFILING_DEBUG\nmm/Kconfig.debug-344-\tbool \"Memory allocation profiler debugging\"\n"
} |
| 23/2 | 2026/07/02 03:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 48047 output: 198 thoughts: 150 Thoughts: **My Configuration Choices for Memory Allocation Profiling** Okay, so I'm honing in on the specific configurations needed to effectively profile these memory allocation changes related to `ALLOC_NO_CODETAG`. Right, the key is `MEM_ALLOC_PROFILING`. That's the one. I also need to ensure it's enabled by default, so I'll add `MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT` as well. Wait a second, the guidance is not to list generic configs. This is specific, however, as `MEM_ALLOC_PROFILING` directly addresses the modifications made with `ALLOC_NO_CODETAG`. Now, let me just double-check those FocusSymbols one more time. I see `alloc_frozen_pages_nolock_noprof` and `alloc_pages_node_noprof` are included in the changes, and are exactly what I need. Perfect. Alright, I'm confident in this, time to call `set-results`. |
| 24/2 | 2026/07/02 03:31 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MEM_ALLOC_PROFILING"
],
"FocusSymbols": [
"alloc_frozen_pages_nolock_noprof",
"alloc_pages_node_noprof"
],
"Reasoning": "The patch refactors the internal page allocator API by introducing `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, replacing `__GFP_NO_OBJ_EXT` and `ALLOC_TRYLOCK` with `ALLOC_NO_CODETAG` and `ALLOC_NOLOCK`. It also moves `alloc_pages_node_noprof` out-of-line. These are functional changes to core memory management code that should be fuzzed to ensure no regressions in page allocation, especially in non-blocking/nolock contexts and memory profiling.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MEM_ALLOC_PROFILING"
],
"FocusSymbols": [
"alloc_frozen_pages_nolock_noprof",
"alloc_pages_node_noprof"
],
"Reasoning": "The patch refactors the internal page allocator API by introducing `alloc_flags` to `__alloc_pages_noprof` and `__alloc_frozen_pages_noprof`, replacing `__GFP_NO_OBJ_EXT` and `ALLOC_TRYLOCK` with `ALLOC_NO_CODETAG` and `ALLOC_NOLOCK`. It also moves `alloc_pages_node_noprof` out-of-line. These are functional changes to core memory management code that should be fuzzed to ensure no regressions in page allocation, especially in non-blocking/nolock contexts and memory profiling.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|