[PATCH v2 2/2] mm,page_owner: Fix accounting of pages when migrating

From: Oscar Salvador
Date: Tue Mar 19 2024 - 14:31:19 EST


Upon migration, new allocated pages are being given the handle of the old
pages. This is problematic because it means that for the stack which
allocated the old page, we will be substracting the old page + the new one
when that page is freed, creating an accounting imbalance.

Fix this by adding a new migrate_handle in the page_owner struct, and
record the handle that allocated the new page in __folio_copy_owner().
Upon freeing, we check whether we have a migrate_handle, and if we do,
we use migrate_handle for dec_stack_record_count(), which will
subtract those pages from its right handle.

Fixes: 217b2119b9e2 ("mm,page_owner: implement the tracking of the stacks count")
Signed-off-by: Oscar Salvador <osalvador@xxxxxxx>
---
mm/page_owner.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/mm/page_owner.c b/mm/page_owner.c
index 2613805cb665..1a7d0d1dc640 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -27,6 +27,7 @@ struct page_owner {
gfp_t gfp_mask;
depot_stack_handle_t handle;
depot_stack_handle_t free_handle;
+ depot_stack_handle_t migrate_handle;
u64 ts_nsec;
u64 free_ts_nsec;
char comm[TASK_COMM_LEN];
@@ -240,7 +241,15 @@ void __reset_page_owner(struct page *page, unsigned short order)
return;

page_owner = get_page_owner(page_ext);
- alloc_handle = page_owner->handle;
+ /*
+ * If this page was allocated for migration purposes, its handle doesn't
+ * reference the stack it was allocated from, so make sure to use the
+ * migrate_handle in order to subtract it from the right stack.
+ */
+ if (!page_owner->migrate_handle)
+ alloc_handle = page_owner->handle;
+ else
+ alloc_handle = page_owner->migrate_handle;

handle = save_stack(GFP_NOWAIT | __GFP_NOWARN);
for (i = 0; i < (1 << order); i++) {
@@ -277,6 +286,7 @@ static inline void __set_page_owner_handle(struct page_ext *page_ext,
page_owner->handle = handle;
page_owner->order = order;
page_owner->gfp_mask = gfp_mask;
+ page_owner->migrate_handle = 0;
page_owner->last_migrate_reason = -1;
page_owner->pid = current->pid;
page_owner->tgid = current->tgid;
@@ -358,6 +368,7 @@ void __folio_copy_owner(struct folio *newfolio, struct folio *old)
new_page_owner->gfp_mask = old_page_owner->gfp_mask;
new_page_owner->last_migrate_reason =
old_page_owner->last_migrate_reason;
+ new_page_owner->migrate_handle = new_page_owner->handle;
new_page_owner->handle = old_page_owner->handle;
new_page_owner->pid = old_page_owner->pid;
new_page_owner->tgid = old_page_owner->tgid;
--
2.44.0