mm/page_owner: add filter infrastructure for print_mode and NUMA filtering
Subsystems (2)
v2 cover mm/page_owner: add filter infrastructure for print_mode and NUMA filtering
This patch series introduces filtering capabilities to the page_owner feature to address storage and performance challenges in production environments.
Changes from v1:
- Renamed 'compact' to 'print_mode' with enum type for better clarity
* PAGE_OWNER_PRINT_FULL_STACK (0): print full stack traces
* PAGE_OWNER_PRINT_STACK_HANDLE (1): print only stack handles
- Changed NUMA filter from single node to nodelist with bitmask support
* Uses nodelist_parse() to support "0", "0,2", "0-3", "0,2-4,7" formats
* Uses nodemask_t internally for efficient multi-node filtering
* Output uses %*pbl format (e.g., "0-2", "0,2-4,7")
- Improved memory handling in nid_filter_write using dynamic allocation
* Limit: (100 + 6 * MAX_NUMNODES) to handle worst-case input
These changes address feedback from v1 review:
- "compact" was too vague → use descriptive enum (PAGE_OWNER_PRINT_*)
- Single node filter was limiting → use nodelist_parse() for multi-node support
Problem Statement
=================
In production environments with large memory configurations (e.g., 250GB+), collecting page_owner information often results in files ranging from several gigabytes to over 10GB. This creates significant challenges:
1. Storage pressure on production systems
2. Difficulty transferring large files from production environments
3. Post-processing overhead with tools/mm/page_owner_sort.c
The primary contributor to file size is redundant stack trace information. While the kernel already deduplicates stacks via stackdepot, page_owner retrieves and stores full stack traces for each page, only to deduplicate them again during post-processing.
Additionally, in NUMA-aware environments (e.g., DPDK-based cloud deployments where QEMU processes are bound to specific NUMA nodes), OOM events are often node-specific rather than system-wide. Currently, page_owner cannot filter by NUMA node, forcing users to collect and analyze data for all nodes.
Solution
========
This patch series introduces a flexible filter infrastructure with two initial filters:
1. **Print Mode Filter**: Outputs only stack handles instead of full stack traces. The handle-to-stack mapping can be retrieved from the existing show_stacks_handles interface. This dramatically reduces output size while preserving all allocation metadata.
2. **NUMA Node Filter**: Allows filtering pages by specific NUMA node(s) using flexible nodelist format, enabling targeted analysis of memory issues in NUMA-aware deployments.
Implementation
==============
The series is structured as follows:
- Patch 1: Add filter infrastructure (data structures and debugfs directory)
- Patch 2: Implement print_mode filter
- Patch 3: Implement NUMA node filter with nodelist support
Usage Example
=============
Enable print_mode and filter for NUMA nodes 0,2-3:
# cd /sys/kernel/debug/page_owner_filter/
# echo 1 > print_mode
# echo "0,2-3" > nid
# cat /sys/kernel/debug/page_owner > page_owner.txtSample print_mode output (showing handles only):
Page allocated via order 0, mask 0x0(), pid 0, tgid 0 (swapper),
ts 0 ns PFN 0x40000 type Unmovable Block 512 type Unmovable
Flags 0x3fffe0000000000(node=0|zone=0|lastcpupid=0x1ffff)
handle: 1048577
Page allocated via order 0, mask 0x252000(__GFP_NOWARN|
__GFP_NORETRY|__GFP_COMP|__GFP_THISNODE), pid 0, tgid 0 (swapper),
ts 0 ns PFN 0x40002 type Unmovable Block 512 type Unmovable
Flags 0x23fffe0000000200(workingset|node=0|zone=0|lastcpupid=0x1ffff)
handle: 1048577Testing
=======
Tested on a system with multiple NUMA nodes. Verified that:
- Filters work independently and in combination
- Print_mode output correlates correctly with show_stacks_handles
- Default behavior (filters disabled) remains unchanged
- NUMA filter works with single node, multiple nodes, and ranges
Example test session:
# cat print_mode
0
# echo "0,1-2" > nid
# cat nid
0-2
# echo "0,2-3" > nid
# cat nid
0,2-3
# echo 1 > print_mode
# head -n 100 /sys/kernel/debug/page_owner
[Shows compact mode output with handles only]Future Enhancements
==================
The filter infrastructure is designed to be extensible. Potential future filters could include:
- PID/TGID filtering
- Time range filtering (allocation timestamp windows)
- GFP flag filtering
- Migration type filtering
---
Zhen Ni (3):
mm/page_owner: add filter infrastructure mm/page_owner: add print_mode filter mm/page_owner: add NUMA node filter with nodelist support
mm/page_owner.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-)
--
2.20.1
PATCH v2 1/3 mm/page_owner: add filter infrastructure
Add data structure for page_owner filtering functionality and create debugfs directory for filter controls.
This adds:
- enum page_owner_print_mode with values for full_stack and stack_handle
- struct page_owner_filter with print_mode and nid_mask fields
- Static owner_filter instance initialized with default values
- page_owner_filter debugfs directory
The filter infrastructure will be used to add print_mode and NUMA node filtering capabilities in subsequent commits.
---
Changes in v2:
- Use enum page_owner_print_mode instead of bool 'compact' for better clarity
- Use nodemask_t instead of int 'nid' to support multi-node filtering
--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
mm/page_owner.c +19 -1
@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);
@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );
@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |
Signature · 1 line
2.20.1
Zi Yan
reviewerRe: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>
Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
The patch can be folded into Patch 2. Otherwise, these new types are not used and page_owner_filter folder is just empty.
Quoted 48 lines
mm/page_owner.c +19
-1@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |Signature · 1 line
2.20.1
Best Regards,
Yan, Zi
Re: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
Quoted 26 lines · Zi Yan
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
Quoted 3 lines
The patch can be folded into Patch 2. Otherwise, these new types are not used and
page_owner_filterfolder is just empty.
Thanks for your review and suggestion.
I kept the 3-patch structure mainly for clear functional separation, which also makes review easier. Patch 1 adds the infrastructure, patch 2 adds print_mode filter, and patch 3 adds NUMA filter.
I discussed this with Andrew and he has already accepted the current 3-patch structure into mm-new for testing. Since he's okay with it and mentioned that bisection holes are acceptable in this case, I'll keep the current structure in v3.
Quoted 39 lines
Quoted 39 lines
mm/page_owner.c +16
-1@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }
Quoted 15 lines
Quoted 9 lines
mm/page_owner.c +3
-0debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |Signature · 1 line
2.20.1Best Regards,
Yan, Zi
Best regards,
Zhen
Zi Yan
reviewerRe: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
Quoted 32 lines · zhen.ni
Quoted 26 lines · Zi Yan
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)Quoted 3 lines
The patch can be folded into Patch 2. Otherwise, these new types are not used and
page_owner_filterfolder is just empty.
Quoted 4 lines
Thanks for your review and suggestion.
I kept the 3-patch structure mainly for clear functional separation, which also makes review easier. Patch 1 adds the infrastructure,
What is the point of adding unused code in a separate patch? Patch 1 has no functional addition and should be part of Patch 2.
Quoted 5 lines
patch 2 adds
print_modefilter, and patch 3 adds NUMA filter.I discussed this with Andrew and he has already accepted the current 3-patch structure into mm-new for testing. Since he's okay with it and mentioned that bisection holes are acceptable in this
The patches are still in mm-new, not mm-stable. It is totally acceptable to reorganize them.
Quoted 1 line
case, I'll keep the current structure in v3.
Please refrain from posting a new version when the discussion is still going on.
Quoted 55 lines
Quoted 40 lines
Quoted 40 lines
mm/page_owner.c +16
-1@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }Quoted 15 lines
Quoted 9 lines
mm/page_owner.c +3
-0debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |Signature · 1 line
2.20.1Best Regards,
Yan, Zi
Quoted 2 lines
Best regards,
Zhen
Best Regards,
Yan, Zi
Re: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
Quoted 34 lines · On Tue, 28 Apr 2026 09:13:03 -0400 Zi Yan <[email protected]> wrote:
Quoted 32 lines · zhen.ni
Quoted 29 lines · Zi Yan
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)The patch can be folded into Patch 2. Otherwise, these new types are not used and
page_owner_filterfolder is just empty.
Quoted 7 lines
Quoted 4 lines
Thanks for your review and suggestion.
I kept the 3-patch structure mainly for clear functional separation, which also makes review easier. Patch 1 adds the infrastructure,
What is the point of adding unused code in a separate patch? Patch 1 has no functional addition and should be part of Patch 2.
I agree.
While I was reviewing the v3 of this series, I had to move between the patch 2 and patch 1 to check the value of the print_mode enum. Having those on single patch will be easier to read for people like me.
Thanks,
SJ
[...]
Re: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
In reply to Zi YanQuoted 111 lines · Zi Yan
Quoted 32 lines · zhen.ni
Quoted 26 lines · Zi Yan
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)Quoted 3 lines
The patch can be folded into Patch 2. Otherwise, these new types are not used and
page_owner_filterfolder is just empty.Quoted 4 lines
Thanks for your review and suggestion.
I kept the 3-patch structure mainly for clear functional separation, which also makes review easier. Patch 1 adds the infrastructure,
What is the point of adding unused code in a separate patch? Patch 1 has no functional addition and should be part of Patch 2.
Quoted 5 lines
patch 2 adds
print_modefilter, and patch 3 adds NUMA filter.I discussed this with Andrew and he has already accepted the current 3-patch structure into mm-new for testing. Since he's okay with it and mentioned that bisection holes are acceptable in this
The patches are still in mm-new, not mm-stable. It is totally acceptable to reorganize them.
Quoted 1 line
case, I'll keep the current structure in v3.
Please refrain from posting a new version when the discussion is still going on.
Quoted 55 lines
Quoted 55 lines
Quoted 49 lines
mm/page_owner.c +19
-1@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |Signature · 1 line
2.20.1Best Regards,
Yan, Zi
Quoted 8 lines
Quoted 2 lines
Best regards,
ZhenBest Regards,
Yan, Zi
Regarding your suggestion to fold patch 1 into patch 2:
I understand your point that patch 1 adds unused code and creates
an empty page_owner_filter folder. While a single patch should not have unused variables, in a patch series it's sometimes acceptable to have preparatory patches that add infrastructure for subsequent patches to use.
I found many examples in the kernel where "prepare" or "preparatory" patches add code that is only fully utilized in later patches
If you and other reviewers strongly prefer merging patches 1 and 2 to follow the guidance more strictly, I can do that in v4. I'm open to this change if the community feels it's the better approach.
Best regards,
Zhen
Zi Yan
reviewerRe: [PATCH v2 1/3] mm/page_owner: add filter infrastructure
Quoted 120 lines · zhen.ni
Quoted 111 lines · Zi Yan
Quoted 32 lines · zhen.ni
Quoted 26 lines · Zi Yan
Quoted 15 lines · Zhen Ni
Add data structure for
page_ownerfiltering functionality and create debugfs directory for filter controls.This adds:
- enumpage_owner_print_modewith values forfull_stackandstack_handle
- structpage_owner_filterwithprint_modeandnid_maskfields
- Staticowner_filterinstance initialized with default values
-page_owner_filterdebugfs directoryThe filter infrastructure will be used to add
print_modeand NUMA node filtering capabilities in subsequent commits.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>Quoted 8 lines
---
Changes in v2:
- Use enumpage_owner_print_modeinstead of bool 'compact' for better clarity
- Usenodemask_tinstead of int 'nid' to support multi-node filtering--- mm/page_owner.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)Quoted 3 lines
The patch can be folded into Patch 2. Otherwise, these new types are not used and
page_owner_filterfolder is just empty.Quoted 4 lines
Thanks for your review and suggestion.
I kept the 3-patch structure mainly for clear functional separation, which also makes review easier. Patch 1 adds the infrastructure,
What is the point of adding unused code in a separate patch? Patch 1 has no functional addition and should be part of Patch 2.
Quoted 5 lines
patch 2 adds
print_modefilter, and patch 3 adds NUMA filter.I discussed this with Andrew and he has already accepted the current 3-patch structure into mm-new for testing. Since he's okay with it and mentioned that bisection holes are acceptable in this
The patches are still in mm-new, not mm-stable. It is totally acceptable to reorganize them.
Quoted 1 line
case, I'll keep the current structure in v3.
Please refrain from posting a new version when the discussion is still going on.
Quoted 55 lines
Quoted 55 lines
Quoted 49 lines
mm/page_owner.c +19
-1@@ -54,6 +54,21 @@ struct stack_print_ctx {u8 flags; }; +enum page_owner_print_mode { +PAGE_OWNER_PRINT_FULL_STACK , +PAGE_OWNER_PRINT_STACK_HANDLE , +}; + +struct page_owner_filter { +enum page_owner_print_mode print_mode; +nodemask_t nid_mask; +}; + +static struct page_owner_filter owner_filter = { + .print_mode =PAGE_OWNER_PRINT_FULL_STACK , + .nid_mask =NODE_MASK_NONE , +}; +static bool page_owner_enabled__initdata ;DEFINE_STATIC_KEY_FALSE (page_owner_inited);@@ -973,7 +988,7 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_threshold_fops, &page_owner_threshold_get,static int __init pageowner_init (void ) { -struct dentry *dir; +struct dentry *dir, *filter_dir;if (!static_branch_unlikely (&page_owner_inited)) {pr_info ("page_owner is disabled\n" );@@ -981,6 +996,9 @@ static int __init pageowner_init(void) }debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); + + filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); + dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir, (void *)(STACK_PRINT_FLAG_STACK |Signature · 1 line
2.20.1Best Regards,
Yan, ZiQuoted 8 lines
Quoted 2 lines
Best regards,
ZhenBest Regards,
Yan, Zi
Quoted 6 lines
Regarding your suggestion to fold patch 1 into patch 2:
I understand your point that patch 1 adds unused code and creates
an emptypage_owner_filterfolder. While a single patch should not have unused variables, in a patch series it's sometimes acceptable to have preparatory patches that add infrastructure for subsequent patches to use.I found many examples in the kernel where "prepare" or "preparatory" patches add code that is only fully utilized in later patches
Those preparatory patches usually add actual functions, not just types. This patch also adds a user visible folder that has no function. I do not see any reason this standalone patch is necessary.
Quoted 2 lines
If you and other reviewers strongly prefer merging patches 1 and 2 to follow the guidance more strictly, I can do that in v4. I'm open to this change if the community feels it's the better approach.
Best Regards,
Yan, Zi
PATCH v2 2/3 mm/page_owner: add print_mode filter
In reply to Zhen NiAdd print_mode functionality to reduce page_owner output size by printing only the stack handle instead of the full stack trace.
Example output with print_mode enabled:
Page allocated via order 0, mask 0x42800(GFP_NOWAIT|__GFP_COMP), pid 1, tgid 1 (systemd), ts 349667370 ns
PFN 0xa00a2 type Unmovable Block 1280 type Unmovable
Flags 0x33fffe0000004124(referenced|lru|active|private|node=3|zone=0|
lastcpupid=0x1ffff)
handle: 17432583
Charged to memcg /
Print mode significantly reduces output size while preserving all other page allocation information. The correspondence between handles and stack traces can be obtained through the show_stacks_handles interface.
---
Changes in v2:
- Renamed from 'compact mode' to 'print_mode' for better clarity
- Use enum values (0=full_stack, 1=stack_handle) instead of boolean
- Update debugfs filename from 'compact' to 'print_mode'
--- mm/page_owner.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
mm/page_owner.c +27 -1
@@ -590,7 +590,13 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, migratetype_names[pageblock_mt], &page->flags); - ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); +/* Print mode: full stack or stack handle */ +if (READ_ONCE (owner_filter.print_mode) ==PAGE_OWNER_PRINT_STACK_HANDLE ) { + ret +=scnprintf (kbuf + ret, count - ret, +"handle: %d\n" , handle); + }else { + ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); + }if (ret >= count) goto err;
@@ -985,6 +991,24 @@ static int page_owner_threshold_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (page_owner_threshold_fops, &page_owner_threshold_get, &page_owner_threshold_set,"%llu" ); +static int page_owner_print_mode_get (void *data,u64 *val) +{ + *val =READ_ONCE (owner_filter.print_mode); +return 0 ; +} + +static int page_owner_print_mode_set (void *data,u64 val) +{ +if (val >PAGE_OWNER_PRINT_STACK_HANDLE ) +return -EINVAL ; +WRITE_ONCE (owner_filter.print_mode, val); +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (page_owner_print_mode_fops, + &page_owner_print_mode_get, + &page_owner_print_mode_set,"%lld" ); +static int __init pageowner_init (void ) {
@@ -998,6 +1022,8 @@ static int __init pageowner_init(void)debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); +debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , + &page_owner_print_mode_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,
Signature · 1 line
2.20.1
Zi Yan
reviewerRe: [PATCH v2 2/3] mm/page_owner: add print_mode filter
Quoted 84 lines · Zhen Ni
Add
print_modefunctionality to reducepage_owneroutput size by printing only the stack handle instead of the full stack trace.Example output with
print_modeenabled:
Page allocated via order 0, mask 0x42800(GFP_NOWAIT|__GFP_COMP), pid 1, tgid 1 (systemd), ts 349667370 ns
PFN0xa00a2type Unmovable Block 1280 type Unmovable
Flags 0x33fffe0000004124(referenced|lru|active|private|node=3|zone=0|
lastcpupid=0x1ffff)
handle: 17432583
Charged to memcg /Print mode significantly reduces output size while preserving all other page allocation information. The correspondence between handles and stack traces can be obtained through the
show_stacks_handlesinterface.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>---
Changes in v2:
- Renamed from 'compact mode' to 'print_mode' for better clarity
- Use enum values (0=full_stack, 1=stack_handle) instead of boolean
- Update debugfs filename from 'compact' to 'print_mode'--- mm/page_owner.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)mm/page_owner.c +27
-1@@ -590,7 +590,13 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, migratetype_names[pageblock_mt], &page->flags); - ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); +/* Print mode: full stack or stack handle */ +if (READ_ONCE (owner_filter.print_mode) ==PAGE_OWNER_PRINT_STACK_HANDLE ) { + ret +=scnprintf (kbuf + ret, count - ret, +"handle: %d\n" , handle); + }else { + ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); + }if (ret >= count) goto err;@@ -985,6 +991,24 @@ static int page_owner_threshold_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (page_owner_threshold_fops, &page_owner_threshold_get, &page_owner_threshold_set,"%llu" ); +static int page_owner_print_mode_get (void *data,u64 *val) +{ + *val =READ_ONCE (owner_filter.print_mode); +return 0 ; +} + +static int page_owner_print_mode_set (void *data,u64 val) +{ +if (val >PAGE_OWNER_PRINT_STACK_HANDLE ) +return -EINVAL ; +WRITE_ONCE (owner_filter.print_mode, val); +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (page_owner_print_mode_fops, + &page_owner_print_mode_get, + &page_owner_print_mode_set,"%lld" ); +static int __init pageowner_init (void ) {@@ -998,6 +1022,8 @@ static int __init pageowner_init(void)debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); +debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , + &page_owner_print_mode_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,Signature · 1 line
2.20.1
I think it is more user-friendly to use “full_stack” and “stack_handle” instead of 0 and 1. You can refer to [1] to sysfs_match_string() to do that. I was testing the interface, but needed to look at your code to know which print_mode I am using. ;)
Best Regards,
Yan, Zi
Re: [PATCH v2 2/3] mm/page_owner: add print_mode filter
Quoted 93 lines · Zi Yan
Quoted 84 lines · Zhen Ni
Add
print_modefunctionality to reducepage_owneroutput size by printing only the stack handle instead of the full stack trace.Example output with
print_modeenabled:
Page allocated via order 0, mask 0x42800(GFP_NOWAIT|__GFP_COMP), pid 1, tgid 1 (systemd), ts 349667370 ns
PFN0xa00a2type Unmovable Block 1280 type Unmovable Flags 0x33fffe0000004124(referenced|lru|active|private|node=3|zone=0|
lastcpupid=0x1ffff)
handle: 17432583
Charged to memcg /Print mode significantly reduces output size while preserving all other page allocation information. The correspondence between handles and stack traces can be obtained through the
show_stacks_handlesinterface.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>---
Changes in v2:
- Renamed from 'compact mode' to 'print_mode' for better clarity
- Use enum values (0=full_stack, 1=stack_handle) instead of boolean
- Update debugfs filename from 'compact' to 'print_mode'--- mm/page_owner.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)mm/page_owner.c +27
-1@@ -590,7 +590,13 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, migratetype_names[pageblock_mt], &page->flags); - ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); +/* Print mode: full stack or stack handle */ +if (READ_ONCE (owner_filter.print_mode) ==PAGE_OWNER_PRINT_STACK_HANDLE ) { + ret +=scnprintf (kbuf + ret, count - ret, +"handle: %d\n" , handle); + }else { + ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); + }if (ret >= count) goto err;@@ -985,6 +991,24 @@ static int page_owner_threshold_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (page_owner_threshold_fops, &page_owner_threshold_get, &page_owner_threshold_set,"%llu" ); +static int page_owner_print_mode_get (void *data,u64 *val) +{ + *val =READ_ONCE (owner_filter.print_mode); +return 0 ; +} + +static int page_owner_print_mode_set (void *data,u64 val) +{ +if (val >PAGE_OWNER_PRINT_STACK_HANDLE ) +return -EINVAL ; +WRITE_ONCE (owner_filter.print_mode, val); +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (page_owner_print_mode_fops, + &page_owner_print_mode_get, + &page_owner_print_mode_set,"%lld" ); +static int __init pageowner_init (void ) {@@ -998,6 +1022,8 @@ static int __init pageowner_init(void)debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); +debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , + &page_owner_print_mode_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,Signature · 1 line
2.20.1I think it is more user-friendly to use “full_stack” and “stack_handle” instead of 0 and 1. You can refer to [1] to
sysfs_match_string()to do that. I was testing the interface, but needed to look at your code to know whichprint_modeI am using. ;)
Quoted 3 lines
Thanks for the suggestion!
I considered using "full_stack" and "stack_handle" strings, but I think the numeric values (0/1) are more concise and easier to type for users.
The v3 documentation will clarify the meaning:
- 0 (default): Print full stack traces
- 1: Print only stack handles
Do you think this is sufficient, or would you still prefer using string values instead?
Quoted 4 lines
Best Regards,
Yan, Zi
Best regards,
Zhen
Zi Yan
reviewerRe: [PATCH v2 2/3] mm/page_owner: add print_mode filter
Quoted 98 lines · zhen.ni
Quoted 93 lines · Zi Yan
Quoted 84 lines · Zhen Ni
Add
print_modefunctionality to reducepage_owneroutput size by printing only the stack handle instead of the full stack trace.Example output with
print_modeenabled:
Page allocated via order 0, mask 0x42800(GFP_NOWAIT|__GFP_COMP), pid 1, tgid 1 (systemd), ts 349667370 ns
PFN0xa00a2type Unmovable Block 1280 type Unmovable Flags 0x33fffe0000004124(referenced|lru|active|private|node=3|zone=0|
lastcpupid=0x1ffff)
handle: 17432583
Charged to memcg /Print mode significantly reduces output size while preserving all other page allocation information. The correspondence between handles and stack traces can be obtained through the
show_stacks_handlesinterface.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>---
Changes in v2:
- Renamed from 'compact mode' to 'print_mode' for better clarity
- Use enum values (0=full_stack, 1=stack_handle) instead of boolean
- Update debugfs filename from 'compact' to 'print_mode'--- mm/page_owner.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)mm/page_owner.c +27
-1@@ -590,7 +590,13 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, migratetype_names[pageblock_mt], &page->flags); - ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); +/* Print mode: full stack or stack handle */ +if (READ_ONCE (owner_filter.print_mode) ==PAGE_OWNER_PRINT_STACK_HANDLE ) { + ret +=scnprintf (kbuf + ret, count - ret, +"handle: %d\n" , handle); + }else { + ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); + }if (ret >= count) goto err;@@ -985,6 +991,24 @@ static int page_owner_threshold_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (page_owner_threshold_fops, &page_owner_threshold_get, &page_owner_threshold_set,"%llu" ); +static int page_owner_print_mode_get (void *data,u64 *val) +{ + *val =READ_ONCE (owner_filter.print_mode); +return 0 ; +} + +static int page_owner_print_mode_set (void *data,u64 val) +{ +if (val >PAGE_OWNER_PRINT_STACK_HANDLE ) +return -EINVAL ; +WRITE_ONCE (owner_filter.print_mode, val); +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (page_owner_print_mode_fops, + &page_owner_print_mode_get, + &page_owner_print_mode_set,"%lld" ); +static int __init pageowner_init (void ) {@@ -998,6 +1022,8 @@ static int __init pageowner_init(void)debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); +debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , + &page_owner_print_mode_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,Signature · 1 line
2.20.1I think it is more user-friendly to use “full_stack” and “stack_handle” instead of 0 and 1. You can refer to [1] to
sysfs_match_string()to do that. I was testing the interface, but needed to look at your code to know whichprint_modeI am using. ;)
Quoted 5 lines
Thanks for the suggestion!
I considered using "
full_stack" and "stack_handle" strings, but I think the numeric values (0/1) are more concise and easier to type for users.
I disagree. It is hard for user to know what the current print mode is and what available modes are. 0 or 1 is usually for boolean input.
Something like:
[full_stack] stack_handlefull_stack [stack_handle]
is much easier for user to read and use.
Quoted 9 lines
The v3 documentation will clarify the meaning:
- 0 (default): Print full stack traces
- 1: Print only stack handlesDo you think this is sufficient, or would you still prefer using string values instead?
Quoted 6 lines
Quoted 4 lines
Best Regards,
Yan, ZiBest regards,
Zhen
Best Regards,
Yan, Zi
Re: [PATCH v2 2/3] mm/page_owner: add print_mode filter
Quoted 106 lines · Zi Yan
Quoted 98 lines · zhen.ni
Quoted 93 lines · Zi Yan
Quoted 84 lines · Zhen Ni
Add
print_modefunctionality to reducepage_owneroutput size by printing only the stack handle instead of the full stack trace.Example output with
print_modeenabled:Page allocated via order 0, mask 0x42800(GFP_NOWAIT|__GFP_COMP), pid 1, tgid 1 (systemd), ts 349667370 ns PFN 0xa00a2 type Unmovable Block 1280 type Unmovable Flags 0x33fffe0000004124(referenced|lru|active|private|node=3|zone=0|lastcpupid=0x1ffff)
handle: 17432583
Charged to memcg /Print mode significantly reduces output size while preserving all other page allocation information. The correspondence between handles and stack traces can be obtained through the
show_stacks_handlesinterface.Suggested-by Zi Yan <[email protected]>Signed-off-by Zhen Ni <[email protected]>---
Changes in v2:
- Renamed from 'compact mode' to 'print_mode' for better clarity
- Use enum values (0=full_stack, 1=stack_handle) instead of boolean
- Update debugfs filename from 'compact' to 'print_mode'--- mm/page_owner.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)mm/page_owner.c +27
-1@@ -590,7 +590,13 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn, migratetype_names[pageblock_mt], &page->flags); - ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); +/* Print mode: full stack or stack handle */ +if (READ_ONCE (owner_filter.print_mode) ==PAGE_OWNER_PRINT_STACK_HANDLE ) { + ret +=scnprintf (kbuf + ret, count - ret, +"handle: %d\n" , handle); + }else { + ret +=stack_depot_snprint (handle, kbuf + ret, count - ret,0 ); + }if (ret >= count) goto err;@@ -985,6 +991,24 @@ static int page_owner_threshold_set(void *data, u64 val)DEFINE_SIMPLE_ATTRIBUTE (page_owner_threshold_fops, &page_owner_threshold_get, &page_owner_threshold_set,"%llu" ); +static int page_owner_print_mode_get (void *data,u64 *val) +{ + *val =READ_ONCE (owner_filter.print_mode); +return 0 ; +} + +static int page_owner_print_mode_set (void *data,u64 val) +{ +if (val >PAGE_OWNER_PRINT_STACK_HANDLE ) +return -EINVAL ; +WRITE_ONCE (owner_filter.print_mode, val); +return 0 ; +} + +DEFINE_SIMPLE_ATTRIBUTE (page_owner_print_mode_fops, + &page_owner_print_mode_get, + &page_owner_print_mode_set,"%lld" ); +static int __init pageowner_init (void ) {@@ -998,6 +1022,8 @@ static int __init pageowner_init(void)debugfs_create_file ("page_owner" ,0400 ,NULL ,NULL , &page_owner_fops); filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL ); +debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , + &page_owner_print_mode_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,Signature · 1 line
2.20.1I think it is more user-friendly to use “full_stack” and “stack_handle” instead of 0 and 1. You can refer to [1] to
sysfs_match_string()to do that. I was testing the interface, but needed to look at your code to know whichprint_modeI am using. ;)Quoted 5 lines
Thanks for the suggestion!
I considered using "
full_stack" and "stack_handle" strings, but I think the numeric values (0/1) are more concise and easier to type for users.
Quoted 9 lines
I disagree. It is hard for user to know what the current print mode is and what available modes are. 0 or 1 is usually for boolean input.
Something like:
[full_stack]stack_handlefull_stack[stack_handle]is much easier for user to read and use.
The string-based interface is more user-friendly
I'll switch to using string values "full_stack" and "stack_handle" with sysfs_match_string() in v4, implementing the show function to
display them with [] brackets around the current selection.
Quoted 13 lines
Quoted 13 lines
The v3 documentation will clarify the meaning:
- 0 (default): Print full stack traces
- 1: Print only stack handlesDo you think this is sufficient, or would you still prefer using string values instead?
Quoted 4 lines
Best Regards,
Yan, Zi
Quoted 8 lines
Quoted 2 lines
Best regards,
ZhenBest Regards,
Yan, Zi
Best regards,
Zhen
PATCH v2 3/3 mm/page_owner: add NUMA node filter with nodelist support
In reply to Zhen NiAdd NUMA node filtering functionality to page_owner to allow filtering pages by specific NUMA node(s) using nodelist format.
The filter allows users to focus on pages from specific NUMA nodes, which is useful for NUMA-aware memory allocation analysis and debugging.
Supported input formats:
- Single node: echo "2" > nid
- Multiple nodes: echo "0,2,3" > nid
- Node range: echo "0-3" > nid
- Mixed format: echo "0,2-4,7" > nid
- Disable filter: echo "-1" > nid
---
Changes in v2:
- Use nodemask_t instead of int to support multiple nodes
- Implement nodelist_parse() to support flexible input formats
* Single node: "0", "2"
* Multiple nodes: "0,2,3"
* Ranges: "0-3"
* Mixed: "0,2-4,7"
- Use %*pbl format for output (e.g., "0-2", "0,2-4,7")
- Use dynamic memory allocation (kmalloc) to handle variable-length input
- Follow cpuset's max_write_len pattern: (100 + 6 * MAX_NUMNODES)
--- mm/page_owner.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
mm/page_owner.c +76 -0
@@ -707,6 +707,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)* user through copy_to_user() or GFP_KERNEL allocations. */ struct page_owner page_owner_tmp; +nodemask_t mask;/* * If the new page is in a new MAX_ORDER_NR_PAGES area,
@@ -730,6 +731,15 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)if (unlikely (!page_ext))continue ; +/* NUMA node filter using bitmask */ + mask =READ_ONCE (owner_filter.nid_mask); +if (!nodes_empty (mask)) { +int nid =page_to_nid (page); + +if (!node_isset (nid, mask)) + goto ext_put_continue; + } +/* * Some pages could be missed by concurrent allocation or free, * because we don't hold the zone lock.
@@ -1009,6 +1019,70 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_print_mode_fops, &page_owner_print_mode_get, &page_owner_print_mode_set, "%lld"); +static ssize_t nid_filter_write (struct file *file, +const char __user *buf, +size_t count,loff_t *ppos) +{ +char *kbuf; +nodemask_t mask; +int ret; + +/* Limit input size to handle worst-case nodelist (all nodes) */ +if (count > (100 +6 *MAX_NUMNODES )) +return -EINVAL ; + + kbuf =kmalloc (count +1 ,GFP_KERNEL ); +if (!kbuf) +return -ENOMEM ; + +if (copy_from_user (kbuf, buf, count)) { + ret = -EFAULT ; + goto out_free; + } + kbuf[count] ='\0' ; + +/* Support: "-1" to clear, or nodelist format like "0", "0,2", "0-3" */ +if (strcmp (kbuf,"-1\n" ) ==0 ||strcmp (kbuf,"-1" ) ==0 ) +nodes_clear (mask); +else if (nodelist_parse (kbuf, mask)) { + ret = -EINVAL ; + goto out_free; + } + +WRITE_ONCE (owner_filter.nid_mask, mask); + ret = count; + +out_free: +kfree (kbuf); +return ret; +} + +static int nid_filter_show (struct seq_file *m,void *v) +{ +nodemask_t mask =READ_ONCE (owner_filter.nid_mask); + +if (nodes_empty (mask)) +seq_puts (m,"-1\n" ); +else +seq_printf (m,"%*pbl\n" ,nodemask_pr_args (&mask)); + +return 0 ; +} + +static int nid_filter_open (struct inode *inode,struct file *file) +{ +return single_open (file, nid_filter_show,NULL ); +} + +static const struct file_operations nid_filter_fops = { + .owner =THIS_MODULE , + .open = nid_filter_open, + .read = seq_read, + .llseek = seq_lseek, + .write = nid_filter_write, + .release = single_release, +}; +static int __init pageowner_init (void ) {
@@ -1024,6 +1098,8 @@ static int __init pageowner_init(void) filter_dir =debugfs_create_dir ("page_owner_filter" ,NULL );debugfs_create_file ("print_mode" ,0600 , filter_dir,NULL , &page_owner_print_mode_fops); +debugfs_create_file ("nid" ,0600 , filter_dir,NULL , + &nid_filter_fops); dir =debugfs_create_dir ("page_owner_stacks" ,NULL ); debugfs_create_file("show_stacks", 0400, dir,
Signature · 1 line
2.20.1
Andrew Morton
maintainerRe: [PATCH v2 3/3] mm/page_owner: add NUMA node filter with nodelist support
Quoted 46 lines · On Sun, 19 Apr 2026 23:55:40 +0800 Zhen Ni <[email protected]> wrote:
Add NUMA node filtering functionality to
page_ownerto allow filtering pages by specific NUMA node(s) using nodelist format.The filter allows users to focus on pages from specific NUMA nodes, which is useful for NUMA-aware memory allocation analysis and debugging.
Supported input formats:
- Single node: echo "2" > nid
- Multiple nodes: echo "0,2,3" > nid
- Node range: echo "0-3" > nid
- Mixed format: echo "0,2-4,7" > nid
- Disable filter: echo "-1" > nid...
mm/page_owner.c +11
-0@@ -707,6 +707,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)* user through copy_to_user() or GFP_KERNEL allocations. */ struct page_owner page_owner_tmp; +nodemask_t mask;/* * If the new page is in a new MAX_ORDER_NR_PAGES area, @@ -730,6 +731,15 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)if (unlikely (!page_ext))continue ; +/* NUMA node filter using bitmask */ + mask =READ_ONCE (owner_filter.nid_mask); +if (!nodes_empty (mask)) { +int nid =page_to_nid (page); + +if (!node_isset (nid, mask)) + goto ext_put_continue; + } +/* * Some pages could be missed by concurrent allocation or free, * because we don't hold the zone lock. @@ -1009,6 +1019,70 @@ DEFINE_SIMPLE_ATTRIBUTE(page_owner_print_mode_fops, &page_owner_print_mode_get, &page_owner_print_mode_set, "%lld"); +static ssize_t nid_filter_write(struct file *file,
mm/page_owner.c DEFINE_SIMPLE_ATTRIBUTE(page_owner_print_mode_fops, · line 1032
Quoted 10 lines
mm/page_owner.c +10
-0+const char __user *buf, + size_t count, loff_t *ppos) +{ + char *kbuf; +nodemask_t mask; +int ret; + +/* Limit input size to handle worst-case nodelist (all nodes) */ +if (count > (100 +6 *MAX_NUMNODES )) +return -EINVAL ;
I'm wondering how that expression was arrived at ;) Perhaps a little comment explaining? Or can we simply use strnlen_user() here?
mm/page_owner.c DEFINE_SIMPLE_ATTRIBUTE(page_owner_print_mode_fops, · line 1042
Quoted 9 lines
mm/page_owner.c +9
-0+ kbuf =kmalloc (count +1 ,GFP_KERNEL ); +if (!kbuf) +return -ENOMEM ; + +if (copy_from_user (kbuf, buf, count)) { + ret = -EFAULT ; + goto out_free; + } + kbuf[count] ='\0' ;
Can we use strncpy_from_user() here?
In fact I thought that we had a strdup_from_user() thing which does the kmalloc also, but maybe I dreamed it.
And memdup_user_nul() could perhaps be used in here.
Nothing really fits. We need a
char *strdup_user(const void __user *src);
(Probably it's OK to assume GFP_KERNEL)
(Maybe needs a size_t max_len arg)
mm/page_owner.c DEFINE_SIMPLE_ATTRIBUTE(page_owner_print_mode_fops, · line 1045
Quoted 2 lines
mm/page_owner.c +2
-0+/* Support: "-1" to clear, or nodelist format like "0", "0,2", "0-3" */ +if (strcmp (kbuf,"-1\n" ) ==0 ||strcmp (kbuf,"-1" ) ==0 )
Maybe
if (kstrtoll(kbuf) == -1)
(we have lots of goodies in /lib!)
Andrew Morton
maintainerRe: [PATCH v2 3/3] mm/page_owner: add NUMA node filter with nodelist support
In reply to Zhen NiQuoted 5 lines · On Sun, 19 Apr 2026 23:55:40 +0800 Zhen Ni <[email protected]> wrote:
Add NUMA node filtering functionality to
page_ownerto allow filtering pages by specific NUMA node(s) using nodelist format.The filter allows users to focus on pages from specific NUMA nodes, which is useful for NUMA-aware memory allocation analysis and debugging.
AI review
(https://sashiko.dev/#/patchset/[email protected])
wonders if it's legitimate to use READ_ONCE/WRITE_ONCE against a nodemask_t. And indeed, my x86_64 allmodconfig hit compile time asserts over this.
So I took them out:
mm/page_owner.c renamed from mm/page_owner.c~mm-page_owner-add-numa-node-filter-with-nodelist-support-fix +3 -3
@@ -732,7 +732,7 @@ read_page_owner(struct file *file, charcontinue ;/* NUMA node filter using bitmask */ - mask =READ_ONCE (owner_filter.nid_mask); + mask = owner_filter.nid_mask;if (!nodes_empty (mask)) {int nid =page_to_nid (page);
@@ -1049,7 +1049,7 @@ static ssize_t nid_filter_write(struct f goto out_free; } -WRITE_ONCE (owner_filter.nid_mask, mask); + owner_filter.nid_mask = mask; ret = count; out_free:
@@ -1059,7 +1059,7 @@ out_free:static int nid_filter_show (struct seq_file *m,void *v) { -nodemask_t mask =READ_ONCE (owner_filter.nid_mask); +nodemask_t mask = owner_filter.nid_mask;if (nodes_empty (mask))seq_puts (m,"-1\n" );
_
Andrew Morton
maintainerQuoted 3 lines · On Sun, 19 Apr 2026 23:55:37 +0800 Zhen Ni <[email protected]> wrote:
This patch series introduces filtering capabilities to the
page_ownerfeature to address storage and performance challenges in production environments.
Nice patchset, thanks. I'm glad to hear that page_owner is being useful in such environments.
I'll add this to mm.git for some testing and review. Meanwhile...
Quoted 2 lines
mm/page_owner.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-)
Could you please add appropriate updates toDocumentation/mm/page_owner.rst?
Andrew Morton
maintainerQuoted 3 lines · On Sun, 19 Apr 2026 23:55:37 +0800 Zhen Ni <[email protected]> wrote:
This patch series introduces filtering capabilities to the
page_ownerfeature to address storage and performance challenges in production environments.
AI review asks some good questions:
https://sashiko.dev/#/patchset/[email protected]
(I'd be OK with ignoring the bisection hole issues)