* [RFC PATCH 01/16] mm: Page Alloc Hogger module
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 02/16] mm: Define structs for allocation requests and store allocations Juan Yescas
` (15 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This patch contains the skeleton for the Pagei Alloc Hogger. It creates the
"mm" dir that will be the base directory that will contain the "free" file
and the "node-<x>" dirs.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/Kconfig.debug | 12 +++++
mm/Makefile | 1 +
mm/page_alloc_hogger.c | 115 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 128 insertions(+)
create mode 100644 mm/page_alloc_hogger.c
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 7638d75b27db..c8fcecdca6ac 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -309,3 +309,15 @@ config PER_VMA_LOCK_STATS
overhead in the page fault path.
If in doubt, say N.
+
+config PAGEALLOC_HOGGER
+ bool "Alloc pages from different nodes, zones, migrate types and orders"
+ depends on DEBUG_FS
+ help
+ Say Y to alloc pages from different nodes, zones, migrate type and
+ orders using the debug fs filesystem. This helps to generate memory
+ pressure easily. This is useful to debug memory reclaims issues,
+ OOM triggers, page migration issues, etc.
+
+ If in doubt, say N.
+
diff --git a/mm/Makefile b/mm/Makefile
index 2d0570a16e5b..b48f2ac6ee80 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
obj-$(CONFIG_DEBUG_PAGEALLOC) += debug_page_alloc.o
obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o
obj-$(CONFIG_DAMON) += damon/
+obj-$(CONFIG_PAGEALLOC_HOGGER) += page_alloc_hogger.o
obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o
obj-$(CONFIG_ZONE_DEVICE) += memremap.o
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
new file mode 100644
index 000000000000..dfdc2ee2eafe
--- /dev/null
+++ b/mm/page_alloc_hogger.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Page allocator DebugFS Interface
+ * Author: Juan Yescas <jyescas@google.com>
+ *
+ * This module allows to make page allocs per node, zone, migrate type
+ * and order using the DebugFS filesystem.
+ *
+ * When this module is installed and the debugfs is mounted, the "mm" directory
+ " will be created in <debugfs mount point>/mm" directory. Under this directory,
+ * there will be subdirs to select the nodes, zones, orders and migrate type.
+ *
+ * For example:
+ *
+ * /sys/kernel/debug/mm/
+ * |-- free
+ * `-- node-0
+ * |-- zone-DMA
+ * | |-- order-0
+ * | | |-- migrate-HighAtomic
+ * | | | `-- nr_pages_allocs
+ * | | |-- migrate-Movable
+ * | | | `-- nr_pages_allocs
+ * | | |-- migrate-Reclaimable
+ * | | | `-- nr_pages_allocs
+ * | | `-- migrate-Unmovable
+ * | | `-- nr_pages_allocs
+ * | |-- ...
+ * | |
+ * | `-- order-9
+ * | |-- migrate-HighAtomic
+ * | | `-- nr_pages_allocs
+ * | |-- migrate-Movable
+ * | | `-- nr_pages_allocs
+ * | |-- migrate-Reclaimable
+ * | | `-- nr_pages_allocs
+ * | `-- migrate-Unmovable
+ * | `-- nr_pages_allocs
+ * `-- zone-Normal
+ * |-- order-0
+ * | |-- migrate-HighAtomic
+ * | | `-- nr_pages_allocs
+ * | |-- migrate-Movable
+ * | | `-- nr_pages_allocs
+ * | |-- migrate-Reclaimable
+ * | | `-- nr_pages_allocs
+ * | `-- migrate-Unmovable
+ * | `-- nr_pages_allocs
+ * |-- ....
+ * |
+ * `-- order-9
+ * |-- migrate-HighAtomic
+ * | `-- nr_pages_allocs
+ * |-- migrate-Movable
+ * | `-- nr_pages_allocs
+ * |-- migrate-Reclaimable
+ * | `-- nr_pages_allocs
+ * `-- migrate-Unmovable
+ * `-- nr_pages_allocs
+ *
+ * Usage:
+ *
+ * 1. To trigger the allocation, navigate to the debugfs path corresponding
+ * to your target node, memory zone, allocation order, and migration type,
+ * then write the requested allocation count to nr_pages_allocs.
+ *
+ * For example, to make 3 allocs of order 9, Migrate Type Movable,
+ * Zone Normal and Node 0, run:
+ *
+ * $ echo 3 > /sys/kernel/debug/mm/node-0/zone-Normal/order-9/migrate-Movable/nr_pages_allocs
+ *
+ * 2. For each allocation created, a corresponding file named sequentially
+ * (1, 2, n) will appear in that directory.
+ *
+ * $ ls /sys/kernel/debug/mm/node-0/zone-Normal/order-9/migrate-Movable/
+ * 1 2 3 nr_pages_allocs
+ *
+ * 3. To free the allocation, write the allocation file name in /sys/kernel/debug/mm/free.
+ * For example, to release the 2nd allocation run:
+ *
+ * $ echo 2 > /sys/kernel/debug/mm/free
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+
+struct dentry *mmdir;
+
+static int __init page_alloc_hogger_debugfs_init(void)
+{
+ mmdir = debugfs_create_dir("mm", NULL);
+ if (IS_ERR(mmdir)) {
+ pr_err("Unable to create mm directory");
+ return PTR_ERR(mmdir);
+ }
+
+ return 0;
+}
+
+static void __exit page_alloc_hogger_debugfs_exit(void)
+{
+ debugfs_remove_recursive(mmdir);
+}
+
+module_init(page_alloc_hogger_debugfs_init);
+module_exit(page_alloc_hogger_debugfs_exit);
+
+MODULE_AUTHOR("Juan Yescas");
+MODULE_DESCRIPTION("Module to alloc pages to generate memory pressure");
+MODULE_LICENSE("GPL");
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 02/16] mm: Define structs for allocation requests and store allocations
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 01/16] mm: Page Alloc Hogger module Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 03/16] mm: Define the caches for the structs req_alloc and page_alloc Juan Yescas
` (14 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change introduces the next structs:
- struct req_alloc to keep the request info for the allocation.
- struct page_alloc to store a pointer to the page that was
allocated, the request info and the file that represents this
allocation. This file will be used to free the allocation when
it is not longer needed.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index dfdc2ee2eafe..47b08d056978 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -91,6 +91,34 @@
struct dentry *mmdir;
+/**
+ * struct req_alloc - Represents the requested allocation
+ * @node_idx: The Node index to allocate from.
+ * @zone_idx: The Zone index to allocate from.
+ * @order: The Order of pages to allocate.
+ * @migrate_type: The Migrate type to allocate from.
+ * @parentdir: The parent dir where the file representing the alloc was created.
+ */
+struct req_alloc {
+ int node_idx;
+ int zone_idx;
+ int order;
+ int migrate_type;
+ struct dentry *parentdir;
+};
+
+/*
+ * struct page_alloc - Represents the page allocation.
+ * @page: The pointer to the page(s) allocated.
+ * @req_alloc: The details of the allocation.
+ * @alloc_dentry: The pointer to the file that represents the allocation.
+ */
+struct page_alloc {
+ struct page *page;
+ struct req_alloc *req_alloc;
+ struct dentry *alloc_dentry;
+};
+
static int __init page_alloc_hogger_debugfs_init(void)
{
mmdir = debugfs_create_dir("mm", NULL);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 03/16] mm: Define the caches for the structs req_alloc and page_alloc
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 01/16] mm: Page Alloc Hogger module Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 02/16] mm: Define structs for allocation requests and store allocations Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 04/16] mm: Define function to create a dir for each online node Juan Yescas
` (13 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change defines and initializes the caches for the structs req_alloc
and page_alloc.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 42 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 47b08d056978..52ccc6e99eb5 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -85,9 +85,12 @@
#include <linux/errno.h>
#include <linux/debugfs.h>
+#include <linux/gfp.h>
+#include <linux/gfp_types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/printk.h>
+#include <linux/slab.h>
struct dentry *mmdir;
@@ -119,20 +122,55 @@ struct page_alloc {
struct dentry *alloc_dentry;
};
+struct kmem_cache *req_alloc_cache;
+struct kmem_cache *page_alloc_cache;
+
static int __init page_alloc_hogger_debugfs_init(void)
{
+ int ret;
+
+ req_alloc_cache = kmem_cache_create(
+ "req_alloc_cache", sizeof(struct req_alloc), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!req_alloc_cache) {
+ pr_err("The req_alloc_cache couldn't be created");
+ ret = -ENOMEM;
+ goto error_exit;
+ }
+
+ page_alloc_cache = kmem_cache_create(
+ "page_alloc_cache", sizeof(struct page_alloc), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!page_alloc_cache) {
+ pr_err("The page_alloc_cache couldn't be created");
+ ret = -ENOMEM;
+ goto clean_req_alloc_cache;
+ }
+
mmdir = debugfs_create_dir("mm", NULL);
if (IS_ERR(mmdir)) {
pr_err("Unable to create mm directory");
- return PTR_ERR(mmdir);
+ ret = PTR_ERR(mmdir);
+ goto clean_page_alloc_cache;
}
return 0;
-}
+
+clean_page_alloc_cache:
+ kmem_cache_destroy(page_alloc_cache);
+
+clean_req_alloc_cache:
+ kmem_cache_destroy(req_alloc_cache);
+
+error_exit:
+ return ret;
+}
static void __exit page_alloc_hogger_debugfs_exit(void)
{
debugfs_remove_recursive(mmdir);
+ kmem_cache_destroy(req_alloc_cache);
+ kmem_cache_destroy(page_alloc_cache);
}
module_init(page_alloc_hogger_debugfs_init);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 04/16] mm: Define function to create a dir for each online node
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (2 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 03/16] mm: Define the caches for the structs req_alloc and page_alloc Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 05/16] mm: Define function to create a dir for populated zone Juan Yescas
` (12 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates a directory for each online node
in the system.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 52ccc6e99eb5..880de1a6e9ea 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -89,6 +89,7 @@
#include <linux/gfp_types.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/nodemask.h>
#include <linux/printk.h>
#include <linux/slab.h>
@@ -125,6 +126,27 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+/**
+ * create_nodes_subdirs() - Creates a directory for each online node in the
+ * system. Once that the node directory is created, it creates a directory for
+ * each zone in the node.
+ */
+static inline int create_nodes_subdirs(struct dentry *mmdir)
+{
+ struct dentry *nodedir;
+ int node_idx;
+ char dirname[12];
+
+ for_each_online_node(node_idx) {
+ snprintf(dirname, sizeof(dirname), "node-%d", node_idx);
+ nodedir = debugfs_create_dir(dirname, mmdir);
+ if (IS_ERR(nodedir))
+ return PTR_ERR(nodedir);
+ }
+
+ return 0;
+}
+
static int __init page_alloc_hogger_debugfs_init(void)
{
int ret;
@@ -154,8 +176,14 @@ static int __init page_alloc_hogger_debugfs_init(void)
goto clean_page_alloc_cache;
}
+ ret = create_nodes_subdirs(mmdir);
+ if (ret)
+ goto clean_dir;
+
return 0;
+clean_dir:
+ debugfs_remove_recursive(mmdir);
clean_page_alloc_cache:
kmem_cache_destroy(page_alloc_cache);
@@ -166,6 +194,7 @@ static int __init page_alloc_hogger_debugfs_init(void)
error_exit:
return ret;
}
+
static void __exit page_alloc_hogger_debugfs_exit(void)
{
debugfs_remove_recursive(mmdir);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 05/16] mm: Define function to create a dir for populated zone
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (3 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 04/16] mm: Define function to create a dir for each online node Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 06/16] mm: Define function to create a dir for each page order Juan Yescas
` (11 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates a directory for each populated zone
in the node.
Note: ZONE_DEVICE pages won't be exposed in this driver
due they are not managed by the Buddy Allocator.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 43 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 880de1a6e9ea..1cec9ec5e35e 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -88,6 +88,7 @@
#include <linux/gfp.h>
#include <linux/gfp_types.h>
#include <linux/kernel.h>
+#include <linux/mmzone.h>
#include <linux/module.h>
#include <linux/nodemask.h>
#include <linux/printk.h>
@@ -126,6 +127,41 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+/**
+ * create_zones_subdirs() - Creates a directory for each populated zone in the
+ * node. Once that the zone directory is created, it creates a directory for
+ * each order supported.
+ *
+ * Note: ZONE_DEVICE pages won't be allocated using this driver. The main reason
+ * is because they are not managed by the Buddy Allocator or CMA allocator.
+ */
+static inline int create_zones_subdirs(struct dentry *nodedir, int node_idx,
+ struct pglist_data *pgdata)
+{
+ struct dentry *zonedir;
+ struct zone *zone;
+ struct zone *node_zones = pgdata->node_zones;
+ int zone_idx;
+ char dirname[24];
+
+ for (zone = node_zones, zone_idx = 0; zone - node_zones < MAX_NR_ZONES;
+ ++zone, ++zone_idx) {
+ if (!populated_zone(zone))
+ continue;
+
+ /* ZONE_DEVICE pages won't be allocated using this driver. */
+ if (zone_is_zone_device(zone))
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "zone-%s", zone->name);
+ zonedir = debugfs_create_dir(dirname, nodedir);
+ if (IS_ERR(zonedir))
+ return PTR_ERR(zonedir);
+ }
+
+ return 0;
+}
+
/**
* create_nodes_subdirs() - Creates a directory for each online node in the
* system. Once that the node directory is created, it creates a directory for
@@ -136,12 +172,19 @@ static inline int create_nodes_subdirs(struct dentry *mmdir)
struct dentry *nodedir;
int node_idx;
char dirname[12];
+ int ret;
for_each_online_node(node_idx) {
+ struct pglist_data *pgdata = NODE_DATA(node_idx);
+
snprintf(dirname, sizeof(dirname), "node-%d", node_idx);
nodedir = debugfs_create_dir(dirname, mmdir);
if (IS_ERR(nodedir))
return PTR_ERR(nodedir);
+
+ ret = create_zones_subdirs(nodedir, node_idx, pgdata);
+ if (ret)
+ return ret;
}
return 0;
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 06/16] mm: Define function to create a dir for each page order
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (4 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 05/16] mm: Define function to create a dir for populated zone Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 07/16] mm: Define function to create a dir for each migrate type Juan Yescas
` (10 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates a directory for each page order inside
the zone directory.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 1cec9ec5e35e..de86b8526338 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -127,6 +127,28 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+/**
+ * create_page_orders_subdirs() - Creates a directory for each page order inside
+ * the zone directory. Once that the page order directory is created, it creates
+ * a directory for each migrate type.
+ */
+static inline int create_page_orders_subdirs(struct dentry *zonedir,
+ int node_idx, int zone_idx,
+ struct zone *zone)
+{
+ struct dentry *orderdir;
+ char dirname[12];
+
+ for (int order = 0; order < NR_PAGE_ORDERS; order++) {
+ snprintf(dirname, sizeof(dirname), "order-%d", order);
+ orderdir = debugfs_create_dir(dirname, zonedir);
+ if (IS_ERR(orderdir))
+ return PTR_ERR(orderdir);
+ }
+
+ return 0;
+}
+
/**
* create_zones_subdirs() - Creates a directory for each populated zone in the
* node. Once that the zone directory is created, it creates a directory for
@@ -143,6 +165,7 @@ static inline int create_zones_subdirs(struct dentry *nodedir, int node_idx,
struct zone *node_zones = pgdata->node_zones;
int zone_idx;
char dirname[24];
+ int ret;
for (zone = node_zones, zone_idx = 0; zone - node_zones < MAX_NR_ZONES;
++zone, ++zone_idx) {
@@ -157,6 +180,11 @@ static inline int create_zones_subdirs(struct dentry *nodedir, int node_idx,
zonedir = debugfs_create_dir(dirname, nodedir);
if (IS_ERR(zonedir))
return PTR_ERR(zonedir);
+
+ ret = create_page_orders_subdirs(zonedir, node_idx, zone_idx,
+ zone);
+ if (ret)
+ return ret;
}
return 0;
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 07/16] mm: Define function to create a dir for each migrate type
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (5 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 06/16] mm: Define function to create a dir for each page order Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 08/16] mm: Define function that creates the "nr_pages_allocs" file Juan Yescas
` (9 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates a directory for each migrate type inside
the order directory.
This function won't create a directory for MIGRATE_ISOLATE due
they can't be allocated using the Buddy Allocator.
Note: The MIGRATE_CMA directory won't be created yet. It will
be supported in the future.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index de86b8526338..a727c4f48ffb 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -127,6 +127,37 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+/**
+ * create_migrate_type_subdirs() - Creates a directory for each migrate type
+ * inside the order directory. Once the migrate type directory is created, it
+ * creates the "nr_allocs" file and the "free" file.
+ */
+static inline int create_migrate_type_subdirs(struct dentry *orderdir,
+ int node_idx, int zone_idx,
+ int order)
+{
+ struct dentry *migratedir;
+ char dirname[24];
+
+ for (int mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
+#ifdef CONFIG_CMA
+ if (mtype == MIGRATE_CMA) /* CMA allocs are not supported yet*/
+ continue;
+#endif
+#ifdef CONFIG_MEMORY_ISOLATION
+ if (mtype == MIGRATE_ISOLATE) /* can't allocate from here */
+ continue;
+#endif
+ snprintf(dirname, sizeof(dirname), "migrate-%s",
+ migratetype_names[mtype]);
+ migratedir = debugfs_create_dir(dirname, orderdir);
+ if (IS_ERR(migratedir))
+ return PTR_ERR(migratedir);
+ }
+
+ return 0;
+}
+
/**
* create_page_orders_subdirs() - Creates a directory for each page order inside
* the zone directory. Once that the page order directory is created, it creates
@@ -138,12 +169,18 @@ static inline int create_page_orders_subdirs(struct dentry *zonedir,
{
struct dentry *orderdir;
char dirname[12];
+ int ret;
for (int order = 0; order < NR_PAGE_ORDERS; order++) {
snprintf(dirname, sizeof(dirname), "order-%d", order);
orderdir = debugfs_create_dir(dirname, zonedir);
if (IS_ERR(orderdir))
return PTR_ERR(orderdir);
+
+ ret = create_migrate_type_subdirs(orderdir, node_idx, zone_idx,
+ order);
+ if (ret)
+ return ret;
}
return 0;
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 08/16] mm: Define function that creates the "nr_pages_allocs" file
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (6 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 07/16] mm: Define function to create a dir for each migrate type Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 09/16] mm: Read the nr_pages_allocs value given by user Juan Yescas
` (8 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change implements the function that creates the
"nr_pages_allocs". This file will be used to make the allocations.
When the user wants to make an allocation, it will write
the number of allocations to this file. For example, if want
to make 56 allocations of order 9 in the Node 0, Normal Zone and Migrate
type Movable, we execute this command:
echo 56 > <sysfs>/mm/node-0/zone-Normal/order-9/migrate-Movable/nr_pages_allocs
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 58 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index a727c4f48ffb..3ffad74a0bdf 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -127,6 +127,58 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+
+/**
+ * req_page_alloc_write() - Allocates the pages on the requested node, zone,
+ * order and migrate type. Once the allocation is performed, a file is created
+ * to free the allocation later.
+ */
+static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return cnt;
+}
+
+static const struct file_operations req_page_alloc_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = req_page_alloc_write,
+};
+
+/**
+ * create_nr_pages_allocs_file() - Creates the file "nr_pages_allocs".
+ *
+ * The "nr_pages_allocs" file will be used to write the number of allocations
+ * that will be performed. When the allocations are performed, a new file for
+ * each allocation will be created in @migratedir.
+ */
+static inline int create_nr_pages_allocs_file(struct dentry *migratedir,
+ int node_idx, int zone_idx,
+ int order, int mtype)
+{
+ struct req_alloc *req;
+ struct dentry *nr_pages;
+
+ req = kmem_cache_alloc(req_alloc_cache, GFP_KERNEL);
+ if (!req) {
+ pr_err("Failed to create nr_pages_allocs_info");
+ return -ENOMEM;
+ }
+
+ req->node_idx = node_idx;
+ req->zone_idx = zone_idx;
+ req->order = order;
+ req->migrate_type = mtype;
+ req->parentdir = migratedir;
+
+ nr_pages = debugfs_create_file("nr_pages_allocs", 0644, migratedir, req,
+ &req_page_alloc_fops);
+ if (IS_ERR(nr_pages))
+ return PTR_ERR(nr_pages);
+
+ return 0;
+}
+
/**
* create_migrate_type_subdirs() - Creates a directory for each migrate type
* inside the order directory. Once the migrate type directory is created, it
@@ -138,6 +190,7 @@ static inline int create_migrate_type_subdirs(struct dentry *orderdir,
{
struct dentry *migratedir;
char dirname[24];
+ int ret;
for (int mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
#ifdef CONFIG_CMA
@@ -153,6 +206,11 @@ static inline int create_migrate_type_subdirs(struct dentry *orderdir,
migratedir = debugfs_create_dir(dirname, orderdir);
if (IS_ERR(migratedir))
return PTR_ERR(migratedir);
+
+ ret = create_nr_pages_allocs_file(migratedir, node_idx,
+ zone_idx, order, mtype);
+ if (ret)
+ return ret;
}
return 0;
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 09/16] mm: Read the nr_pages_allocs value given by user
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (7 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 08/16] mm: Define function that creates the "nr_pages_allocs" file Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 10/16] mm: Set the selected zone in gfp_t flags Juan Yescas
` (7 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change reads the nr_page_allocs value given by the user and
validates that is an unsigned long.
If the input is valid, it will allocate an array of nr_page_allocs
size. This array will store the allocation ids. These allocation ids
will be used to free the allocations.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 3ffad74a0bdf..60dfddf6b441 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -136,6 +136,19 @@ struct kmem_cache *page_alloc_cache;
static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
+ unsigned long nr_pages_allocs;
+ unsigned long *allocs_ids;
+ int ret;
+
+ ret = kstrtoul_from_user(ubuf, cnt, 10, &nr_pages_allocs);
+ if (ret)
+ return ret;
+
+ allocs_ids = kmalloc_array(nr_pages_allocs, sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!allocs_ids)
+ return -ENOMEM;
+
return cnt;
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 10/16] mm: Set the selected zone in gfp_t flags
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (8 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 09/16] mm: Read the nr_pages_allocs value given by user Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 11/16] mm: Sets the migrate type " Juan Yescas
` (6 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change sets the selected zone in gfp_t flags.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 60dfddf6b441..5c00e9134a66 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -87,6 +87,7 @@
#include <linux/debugfs.h>
#include <linux/gfp.h>
#include <linux/gfp_types.h>
+#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/mmzone.h>
#include <linux/module.h>
@@ -127,6 +128,33 @@ struct page_alloc {
struct kmem_cache *req_alloc_cache;
struct kmem_cache *page_alloc_cache;
+inline void set_zone_to_alloc_from(int zone_idx, gfp_t *flags_ptr)
+{
+ switch (zone_idx) {
+#ifdef CONFIG_ZONE_DMA
+ case ZONE_DMA:
+ *flags_ptr |= __GFP_DMA;
+ break;
+#endif
+#ifdef CONFIG_ZONE_DMA32
+ case ZONE_DMA32:
+ *flags_ptr |= __GFP_DMA32;
+ break;
+#endif
+#ifdef CONFIG_HIGHMEM
+ case ZONE_HIGHMEM:
+ *flags_ptr |= __GFP_HIGHMEM;
+ break;
+#endif
+ case ZONE_MOVABLE:
+ *flags_ptr |= __GFP_MOVABLE;
+ break;
+ case ZONE_NORMAL:
+ default:
+ *flags_ptr |= 0;
+ break;
+ }
+}
/**
* req_page_alloc_write() - Allocates the pages on the requested node, zone,
@@ -136,8 +164,10 @@ struct kmem_cache *page_alloc_cache;
static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
+ struct req_alloc *req = file->private_data;
unsigned long nr_pages_allocs;
unsigned long *allocs_ids;
+ gfp_t flags = 0;
int ret;
ret = kstrtoul_from_user(ubuf, cnt, 10, &nr_pages_allocs);
@@ -149,6 +179,8 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
if (!allocs_ids)
return -ENOMEM;
+ set_zone_to_alloc_from(req->zone_idx, &flags);
+
return cnt;
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 11/16] mm: Sets the migrate type in gfp_t flags
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (9 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 10/16] mm: Set the selected zone in gfp_t flags Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 12/16] mm: Define the make_alloc() function Juan Yescas
` (5 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change sets the selected migrate type in gfp_t flags.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 5c00e9134a66..d91f49880f8d 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -156,6 +156,24 @@ inline void set_zone_to_alloc_from(int zone_idx, gfp_t *flags_ptr)
}
}
+inline void set_migrate_type_to_alloc_from(int migrate_type, gfp_t *flags_ptr)
+{
+ switch (migrate_type) {
+ case MIGRATE_UNMOVABLE:
+ *flags_ptr &= ~(__GFP_RECLAIMABLE | __GFP_MOVABLE);
+ break;
+ case MIGRATE_RECLAIMABLE:
+ *flags_ptr |= __GFP_RECLAIMABLE;
+ break;
+ case MIGRATE_HIGHATOMIC:
+ *flags_ptr |= __GFP_HIGH;
+ break;
+ case MIGRATE_MOVABLE: default:
+ *flags_ptr |= __GFP_MOVABLE;
+ break;
+ }
+}
+
/**
* req_page_alloc_write() - Allocates the pages on the requested node, zone,
* order and migrate type. Once the allocation is performed, a file is created
@@ -180,6 +198,7 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
return -ENOMEM;
set_zone_to_alloc_from(req->zone_idx, &flags);
+ set_migrate_type_to_alloc_from(req->migrate_type, &flags);
return cnt;
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 12/16] mm: Define the make_alloc() function
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (10 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 11/16] mm: Sets the migrate type " Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 13/16] mm: Create the file asociated with an allocation Juan Yescas
` (4 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
The make_alloc() is the core function that performs the allocation.
The tasks of this function are:
- Call the Buddy allocator to make the allocation.
- Store the details of the allocation in struct page_alloc.
- Insert the struct page_alloc in an xarray using the allocation id
as key.
If something fails during the allocation, the pages and cache
will be freed.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 71 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index d91f49880f8d..7f6eebdd5197 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -97,6 +97,18 @@
struct dentry *mmdir;
+/**
+ * atomic_long_t allocs_file_seq - Represents the naming sequence used for
+ * allocation files.
+ */
+atomic_long_t allocs_file_seq = ATOMIC_INIT(0);
+
+/**
+ * allocs_xa - Represent the xarray that contains the actual allocations perform
+ * by this driver.
+ */
+static DEFINE_XARRAY(allocs_xa);
+
/**
* struct req_alloc - Represents the requested allocation
* @node_idx: The Node index to allocate from.
@@ -174,6 +186,47 @@ inline void set_migrate_type_to_alloc_from(int migrate_type, gfp_t *flags_ptr)
}
}
+static int make_alloc(struct req_alloc *req,
+ gfp_t flags, unsigned long *alloc_id)
+{
+ struct page_alloc *pa;
+ struct page *page;
+ char new_alloc_name[12];
+ int ret;
+
+ page = alloc_pages_node_noprof(req->node_idx, flags, req->order);
+ if (page) {
+ pa = kmem_cache_alloc(page_alloc_cache, GFP_KERNEL);
+ if (!pa) {
+ ret = -ENOMEM;
+ goto free_pages;
+ }
+
+ *alloc_id = atomic_long_inc_return(&allocs_file_seq);
+ ret = xa_insert(&allocs_xa, *alloc_id, pa, GFP_KERNEL);
+ if (ret)
+ goto free_page_alloc;
+
+ snprintf(new_alloc_name, sizeof(new_alloc_name), "%lu",
+ *alloc_id);
+
+ pa->req_alloc = req;
+ pa->page = page;
+ } else {
+ return -ENOMEM;
+ }
+
+ return 0;
+
+free_page_alloc:
+ kmem_cache_free(page_alloc_cache, pa);
+
+free_pages:
+ __free_pages(page, pa->req_alloc->order);
+
+ return ret;
+}
+
/**
* req_page_alloc_write() - Allocates the pages on the requested node, zone,
* order and migrate type. Once the allocation is performed, a file is created
@@ -183,10 +236,12 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct req_alloc *req = file->private_data;
+ unsigned long alloc_id;
unsigned long nr_pages_allocs;
unsigned long *allocs_ids;
gfp_t flags = 0;
int ret;
+ int i;
ret = kstrtoul_from_user(ubuf, cnt, 10, &nr_pages_allocs);
if (ret)
@@ -200,7 +255,23 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
set_zone_to_alloc_from(req->zone_idx, &flags);
set_migrate_type_to_alloc_from(req->migrate_type, &flags);
+ for (i = 0; i < nr_pages_allocs; i++) {
+ ret = make_alloc(req, flags, &alloc_id);
+ if (ret)
+ goto free_allocs;
+
+ allocs_ids[i] = alloc_id;
+ }
+
+ kfree(allocs_ids);
+
return cnt;
+
+free_allocs:
+
+ kfree(allocs_ids);
+
+ return ret;
}
static const struct file_operations req_page_alloc_fops = {
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 13/16] mm: Create the file asociated with an allocation
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (11 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 12/16] mm: Define the make_alloc() function Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 14/16] mm: Free pages, remove files and clean cache when one alloc fails Juan Yescas
` (3 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates the file asociated with an allocation. The
name of the file will be given by incrementing the atomic
long "allocs_file_seq".
This file will be used to free the alocation when the user
requests it.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 7f6eebdd5197..203b71a25e64 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -186,12 +186,26 @@ inline void set_migrate_type_to_alloc_from(int migrate_type, gfp_t *flags_ptr)
}
}
+static ssize_t page_alloc_read(struct file *file, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ /* Which information should be print about the page or allocation? */
+ return 0;
+}
+
+static const struct file_operations page_alloc_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = page_alloc_read,
+};
+
static int make_alloc(struct req_alloc *req,
gfp_t flags, unsigned long *alloc_id)
{
struct page_alloc *pa;
struct page *page;
char new_alloc_name[12];
+ struct dentry *new_alloc_dentry;
int ret;
page = alloc_pages_node_noprof(req->node_idx, flags, req->order);
@@ -210,14 +224,26 @@ static int make_alloc(struct req_alloc *req,
snprintf(new_alloc_name, sizeof(new_alloc_name), "%lu",
*alloc_id);
+ new_alloc_dentry = debugfs_create_file(
+ new_alloc_name, 0644, req->parentdir,
+ pa, &page_alloc_fops);
+ if (IS_ERR(new_alloc_dentry)) {
+ ret = PTR_ERR(new_alloc_dentry);
+ goto erase_xa_entry;
+ }
+
pa->req_alloc = req;
pa->page = page;
+ pa->alloc_dentry = new_alloc_dentry;
} else {
return -ENOMEM;
}
return 0;
+erase_xa_entry:
+ xa_erase(&allocs_xa, *alloc_id);
+
free_page_alloc:
kmem_cache_free(page_alloc_cache, pa);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 14/16] mm: Free pages, remove files and clean cache when one alloc fails
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (12 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 13/16] mm: Create the file asociated with an allocation Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 15/16] mm: Create the "free" file to release the previously allocated pages Juan Yescas
` (2 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
When one of the requested allocations failed, do
- free the pages that were previously allocated as part of the request.
- remove the files that were created as part of the request.
- clean the kmem cache.
- Erase the struct page_alloc objects from the xarray that were inserted
as part of the request.
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 203b71a25e64..e65aac881ec7 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -253,6 +253,23 @@ static int make_alloc(struct req_alloc *req,
return ret;
}
+static int free_alloc_helper(unsigned long alloc_id)
+{
+ struct page_alloc *pa;
+
+ pa = xa_erase(&allocs_xa, alloc_id);
+ if (!pa) {
+ pr_err("The alloc_id %lu was not found!", alloc_id);
+ return -EINVAL;
+ }
+
+ __free_pages(pa->page, pa->req_alloc->order);
+ debugfs_remove(pa->alloc_dentry);
+ kmem_cache_free(page_alloc_cache, pa);
+
+ return 0;
+}
+
/**
* req_page_alloc_write() - Allocates the pages on the requested node, zone,
* order and migrate type. Once the allocation is performed, a file is created
@@ -294,6 +311,14 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
return cnt;
free_allocs:
+ /* Free all the pages previously allocated. */
+ for (int j = 0; j < i; j++) {
+ int ret2 = free_alloc_helper(allocs_ids[j]);
+
+ if (ret2)
+ pr_err("Unable to free pages associated with file %lu",
+ allocs_ids[j]);
+ }
kfree(allocs_ids);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 15/16] mm: Create the "free" file to release the previously allocated pages
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (13 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 14/16] mm: Free pages, remove files and clean cache when one alloc fails Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-23 7:47 ` [RFC PATCH 16/16] mm: Release resources when the page alloc hogger module exits Juan Yescas
2026-07-28 19:29 ` [RFC PATCH 00/16] Page Alloc Hogger David Hildenbrand (Arm)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
This change creates the "free" file and defines its file_operations
to release the previously allocated pages. To release an allocation,
the user will run:
echo <file name> > /sys/kernel/debug/mm/free
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index e65aac881ec7..5fe9c545e884 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -83,6 +83,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/debugfs.h>
#include <linux/gfp.h>
@@ -94,6 +95,7 @@
#include <linux/nodemask.h>
#include <linux/printk.h>
#include <linux/slab.h>
+#include <linux/xarray.h>
struct dentry *mmdir;
@@ -331,6 +333,37 @@ static const struct file_operations req_page_alloc_fops = {
.write = req_page_alloc_write,
};
+/**
+ * free_page_alloc_write() - free the previously allocated pages.
+ * @file: File where the user is writing.
+ * @ubuf: Contains the name of the file the user wants to delete and have the
+ * memory associated with that file freed.
+ * @cnt: Size of @ubuf.
+ * @ppos: Current position in the file.
+ */
+static ssize_t free_page_alloc_write(struct file *file,
+ const char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+ int ret;
+ unsigned long alloc_id;
+
+ ret = kstrtoul_from_user(ubuf, cnt, 10, &alloc_id);
+ if (ret)
+ return ret;
+
+ ret = free_alloc_helper(alloc_id);
+ if (ret)
+ return ret;
+
+ return cnt;
+}
+
+static const struct file_operations free_page_alloc_fops = {
+ .owner = THIS_MODULE,
+ .write = free_page_alloc_write,
+};
+
/**
* create_nr_pages_allocs_file() - Creates the file "nr_pages_allocs".
*
@@ -501,6 +534,7 @@ static inline int create_nodes_subdirs(struct dentry *mmdir)
static int __init page_alloc_hogger_debugfs_init(void)
{
+ struct dentry *free_file;
int ret;
req_alloc_cache = kmem_cache_create(
@@ -532,6 +566,13 @@ static int __init page_alloc_hogger_debugfs_init(void)
if (ret)
goto clean_dir;
+ free_file = debugfs_create_file("free", 0644, mmdir, NULL,
+ &free_page_alloc_fops);
+ if (IS_ERR(free_file)) {
+ ret = PTR_ERR(free_file);
+ goto clean_dir;
+ }
+
return 0;
clean_dir:
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC PATCH 16/16] mm: Release resources when the page alloc hogger module exits
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (14 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 15/16] mm: Create the "free" file to release the previously allocated pages Juan Yescas
@ 2026-07-23 7:47 ` Juan Yescas
2026-07-28 19:29 ` [RFC PATCH 00/16] Page Alloc Hogger David Hildenbrand (Arm)
16 siblings, 0 replies; 20+ messages in thread
From: Juan Yescas @ 2026-07-23 7:47 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE
Cc: jyescas, android-mm, fvdl, tkjos, minchan, dskiba, open list,
open list:MEMORY MANAGEMENT - CORE
When the page alloc hogger module exits:
- free all the previously allocated pages
- Erase all the entries from the xarray
Signed-off-by: Juan Yescas <jyescas@google.com>
---
mm/page_alloc_hogger.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 5fe9c545e884..f554bbb4afa7 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -590,6 +590,14 @@ static int __init page_alloc_hogger_debugfs_init(void)
static void __exit page_alloc_hogger_debugfs_exit(void)
{
+ struct page_alloc *pa;
+ unsigned long idx;
+
+ xa_for_each(&allocs_xa, idx, pa) {
+ __free_pages(pa->page, pa->req_alloc->order);
+ xa_erase(&allocs_xa, idx);
+ }
+
debugfs_remove_recursive(mmdir);
kmem_cache_destroy(req_alloc_cache);
kmem_cache_destroy(page_alloc_cache);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [RFC PATCH 00/16] Page Alloc Hogger
2026-07-23 7:47 [RFC PATCH 00/16] Page Alloc Hogger Juan Yescas
` (15 preceding siblings ...)
2026-07-23 7:47 ` [RFC PATCH 16/16] mm: Release resources when the page alloc hogger module exits Juan Yescas
@ 2026-07-28 19:29 ` David Hildenbrand (Arm)
2026-07-29 0:36 ` Juan Yescas
16 siblings, 1 reply; 20+ messages in thread
From: David Hildenbrand (Arm) @ 2026-07-28 19:29 UTC (permalink / raw)
To: Juan Yescas, Andrew Morton, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
open list, open list:MEMORY MANAGEMENT - CORE
Cc: android-mm, fvdl, tkjos, minchan, dskiba
On 7/23/26 09:47, Juan Yescas wrote:
> This patch series introduces the Page Alloc Hogger. The Page Alloc Hogger
> allows you to allocate memory pages from specific nodes, zones, migration
> types, and orders directly via debugfs. This provides key benefits for
> testing and debugging:
Would it be feasible to carry this as an OOT debugging module? Would a lot of
symbols be missing to achieve that?
--
Cheers,
David
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC PATCH 00/16] Page Alloc Hogger
2026-07-28 19:29 ` [RFC PATCH 00/16] Page Alloc Hogger David Hildenbrand (Arm)
@ 2026-07-29 0:36 ` Juan Yescas
2026-07-30 7:50 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 20+ messages in thread
From: Juan Yescas @ 2026-07-29 0:36 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Andrew Morton, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE, android-mm, fvdl, tkjos,
minchan, dskiba, Lorenzo Stoakes (Oracle)
On Tue, Jul 28, 2026 at 12:29 PM David Hildenbrand (Arm)
<david@kernel.org> wrote:
>
> On 7/23/26 09:47, Juan Yescas wrote:
> > This patch series introduces the Page Alloc Hogger. The Page Alloc Hogger
> > allows you to allocate memory pages from specific nodes, zones, migration
> > types, and orders directly via debugfs. This provides key benefits for
> > testing and debugging:
>
> Would it be feasible to carry this as an OOT debugging module? Would a lot of
> symbols be missing to achieve that?
>
Thanks David for the comment.
The only symbol that would be needed to have this module as OOT is
"migratetype_names".
However, although this module was originally designed to debug CMA
issues, it can be
easily used to debug issues in kswapd, direct reclaims, OOM killer,
etc. We could even
use this module to add kunit test cases.
Let's take for example this case. We want to allocate Unmovable memory and check
that the allocation came from Movable, as per the buddy allocator
fallback mechanism.
How can we do that in user space?
$ cat /proc/pagetypeinfo
Page block order: 9
Pages per block: 512
Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10
Node 0, zone DMA, type Unmovable 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone DMA, type Movable 1 1 1 0 1 1 2 2 1 3 732
Node 0, zone DMA, type Reclaimable 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone DMA, type HighAtomic 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone DMA, type CMA 0 0 0 0 0 0 0 0 0 1 7
Node 0, zone DMA, type Isolate 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone Normal, type Unmovable 13 7 0 1 0 0 1 0 1 0 0
Node 0, zone Normal, type Movable 1 1 1 1 1 1 1 0 1 1 1221
Node 0, zone Normal, type Reclaimable 1 0 0 0 0 0 1 0 0 1 0
Node 0, zone Normal, type HighAtomic 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone Normal, type CMA 0 0 0 0 0 0 0 0 0 1 7
Node 0, zone Normal, type Isolate 0 0 0 0 0 0 0 0 0 0 0
// Allocate Unmovable memory (note that there are NO Unmovable pages,
so the allocation will fall back from Movable)
$ echo 1221 > /sys/kernel/debug/mm/node-0/zone-Normal/order-10/migrate-Unmovable/nr_pages_allocs
$ cat /proc/pagetypeinfo
Page block order: 9
Pages per block: 512
Free pages count per migrate type at order 0 1 2
3 4 5 6 7 8 9 10
Node 0, zone DMA, type Unmovable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone DMA, type Movable 1 1 1
0 1 1 2 2 1 3 701
Node 0, zone DMA, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone DMA, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone DMA, type CMA 0 0 0
0 0 0 0 0 0 1 31
Node 0, zone DMA, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Unmovable 1 0 0
1 1 1 1 1 1 0 0
Node 0, zone Normal, type Movable 1 0 1
1 1 1 1 1 1 1 7
Node 0, zone Normal, type Reclaimable 0 1 0
0 1 0 0 0 1 0 0
Node 0, zone Normal, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type CMA 0 0 0
0 0 0 0 0 0 1 7
Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Number of blocks type Unmovable Movable Reclaimable
HighAtomic CMA Isolate
Node 0, zone DMA 14 1458 0
0 64 0
Node 0, zone Normal 2440 102 2
0 16 0
// Now we want to test that Reclaimable memory allocations fall back
from ZONE_DMA and Migrate Movable
$ echo 600 > /sys/kernel/debug/mm/node-0/zone-Normal/order-10/migrate-Reclaimable/nr_pages_allocs
# cat /proc/pagetypeinfo
Page block order: 9
Pages per block: 512
Free pages count per migrate type at order 0 1 2
3 4 5 6 7 8 9 10
Node 0, zone DMA, type Unmovable 0 0 0
0 0 1 1 0 0 1 0
Node 0, zone DMA, type Movable 1 1 1
0 1 1 2 2 1 3 99
Node 0, zone DMA, type Reclaimable 1 0 0
1 0 0 1 0 1 1 0
Node 0, zone DMA, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone DMA, type CMA 0 0 0
0 0 0 0 0 0 1 31
Node 0, zone DMA, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Unmovable 1 0 0
1 1 1 1 1 1 0 0
Node 0, zone Normal, type Movable 0 0 0
1 0 0 1 0 1 0 7
Node 0, zone Normal, type Reclaimable 0 1 0
0 1 0 0 0 1 0 0
Node 0, zone Normal, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type CMA 0 0 0
0 0 0 0 0 0 1 7
Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Number of blocks type Unmovable Movable Reclaimable
HighAtomic CMA Isolate
Node 0, zone DMA 16 254 1202
0 64 0
Node 0, zone Normal 2440 102 2
0 16 0
// Now, we want to free all the MIGRATE_UNMOVABLE allocations and
sleep 1 second for every
// allocation and see how the pages return to the MIGRATE_UNMOVABLE bucket:
for i in `seq 1 1221`; do echo $i > /sys/kernel/debug/mm/free; sleep 10; done
// in another console
watch cat /proc/pagetypeinfo
2026-07-29 00:28:49
Page block order: 9
Pages per block: 512
Free pages count per migrate type at order 0 1 2
3 4 5 6 7 8 9 10
Node 0, zone DMA, type Unmovable 0 0 0
0 0 1 1 0 0 1 0
Node 0, zone DMA, type Movable 1 1 1
0 1 1 2 2 1 3 99
Node 0, zone DMA, type Reclaimable 1 0 0
1 0 0 1 0 1 1 0
Node 0, zone DMA, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone DMA, type CMA 0 0 0
0 0 0 0 0 0 1 31
Node 0, zone DMA, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Unmovable 1 0 0
1 1 1 1 1 1 0 698
Node 0, zone Normal, type Movable 1 0 0
1 0 0 0 0 1 0 7
Node 0, zone Normal, type Reclaimable 0 1 0
0 1 0 0 0 1 0 0
Node 0, zone Normal, type HighAtomic 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type CMA 0 0 0
0 0 0 0 0 0 1 7
Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Number of blocks type Unmovable Movable Reclaimable
HighAtomic CMA Isolate
Node 0, zone DMA 16 254 1202
0 64 0
Node 0, zone Normal 2440 102 2
0 16 0
Achieving the same result in a user program is not as straightforward.
The Page Alloc Hogger gives us the flexibility to allocate from any
valid memory we desire.
As I mentioned before, it allows us to test/check/analyze/generate:
- kwapd triggers
- direct reclaims
- OOM killer
- generate page fragmentation using simple scripts instead of complex programs
Greetigns
Juan
> --
> Cheers,
>
> David
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [RFC PATCH 00/16] Page Alloc Hogger
2026-07-29 0:36 ` Juan Yescas
@ 2026-07-30 7:50 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 20+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-07-30 7:50 UTC (permalink / raw)
To: Juan Yescas
Cc: David Hildenbrand (Arm), Andrew Morton, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, open list,
open list:MEMORY MANAGEMENT - CORE, android-mm, fvdl, tkjos,
minchan, dskiba
On Tue, Jul 28, 2026 at 05:36:03PM -0700, Juan Yescas wrote:
> On Tue, Jul 28, 2026 at 12:29 PM David Hildenbrand (Arm)
> <david@kernel.org> wrote:
> >
> > On 7/23/26 09:47, Juan Yescas wrote:
> > > This patch series introduces the Page Alloc Hogger. The Page Alloc Hogger
> > > allows you to allocate memory pages from specific nodes, zones, migration
> > > types, and orders directly via debugfs. This provides key benefits for
> > > testing and debugging:
> >
> > Would it be feasible to carry this as an OOT debugging module? Would a lot of
> > symbols be missing to achieve that?
> >
>
> Thanks David for the comment.
>
> The only symbol that would be needed to have this module as OOT is
> "migratetype_names".
I mean you could hardcode these and be pretty safe :) I don't we're going
to add any time soon and if we did you'd probably need to change the module
code anyway?
I feel this debug module should be a noop in core.
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 20+ messages in thread