Skip to content

Commit 3738916

Browse files
tehcastertorvalds
authored andcommitted
mm, page_owner: keep owner info when freeing the page
For debugging purposes it might be useful to keep the owner info even after page has been freed, and include it in e.g. dump_page() when detecting a bad page state. For that, change the PAGE_EXT_OWNER flag meaning to "page owner info has been set at least once" and add new PAGE_EXT_OWNER_ACTIVE for tracking whether page is supposed to be currently tracked allocated or free. Adjust dump_page() accordingly, distinguishing free and allocated pages. In the page_owner debugfs file, keep printing only allocated pages so that existing scripts are not confused, and also because free pages are irrelevant for the memory statistics or leak detection that's the typical use case of the file, anyway. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Vlastimil Babka <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Michal Hocko <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 7e2f2a0 commit 3738916

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

include/linux/page_ext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct page_ext_operations {
1818

1919
enum page_ext_flags {
2020
PAGE_EXT_OWNER,
21+
PAGE_EXT_OWNER_ACTIVE,
2122
#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT)
2223
PAGE_EXT_YOUNG,
2324
PAGE_EXT_IDLE,

mm/page_owner.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ void __reset_page_owner(struct page *page, unsigned int order)
111111
page_ext = lookup_page_ext(page + i);
112112
if (unlikely(!page_ext))
113113
continue;
114-
__clear_bit(PAGE_EXT_OWNER, &page_ext->flags);
114+
__clear_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags);
115115
}
116116
}
117117

@@ -168,6 +168,7 @@ static inline void __set_page_owner_handle(struct page *page,
168168
page_owner->gfp_mask = gfp_mask;
169169
page_owner->last_migrate_reason = -1;
170170
__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
171+
__set_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags);
171172

172173
page_ext = lookup_page_ext(page + i);
173174
}
@@ -243,6 +244,7 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage)
243244
* the new page, which will be freed.
244245
*/
245246
__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
247+
__set_bit(PAGE_EXT_OWNER_ACTIVE, &new_ext->flags);
246248
}
247249

248250
void pagetypeinfo_showmixedcount_print(struct seq_file *m,
@@ -302,7 +304,7 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
302304
if (unlikely(!page_ext))
303305
continue;
304306

305-
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
307+
if (!test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
306308
continue;
307309

308310
page_owner = get_page_owner(page_ext);
@@ -413,21 +415,26 @@ void __dump_page_owner(struct page *page)
413415
mt = gfpflags_to_migratetype(gfp_mask);
414416

415417
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) {
416-
pr_alert("page_owner info is not active (free page?)\n");
418+
pr_alert("page_owner info is not present (never set?)\n");
417419
return;
418420
}
419421

422+
if (test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
423+
pr_alert("page_owner tracks the page as allocated\n");
424+
else
425+
pr_alert("page_owner tracks the page as freed\n");
426+
427+
pr_alert("page last allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
428+
page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);
429+
420430
handle = READ_ONCE(page_owner->handle);
421431
if (!handle) {
422-
pr_alert("page_owner info is not active (free page?)\n");
423-
return;
432+
pr_alert("page_owner allocation stack trace missing\n");
433+
} else {
434+
nr_entries = stack_depot_fetch(handle, &entries);
435+
stack_trace_print(entries, nr_entries, 0);
424436
}
425437

426-
nr_entries = stack_depot_fetch(handle, &entries);
427-
pr_alert("page allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
428-
page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);
429-
stack_trace_print(entries, nr_entries, 0);
430-
431438
if (page_owner->last_migrate_reason != -1)
432439
pr_alert("page has been migrated, last migrate reason: %s\n",
433440
migrate_reason_names[page_owner->last_migrate_reason]);
@@ -489,6 +496,13 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
489496
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
490497
continue;
491498

499+
/*
500+
* Although we do have the info about past allocation of free
501+
* pages, it's not relevant for current memory usage.
502+
*/
503+
if (!test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
504+
continue;
505+
492506
page_owner = get_page_owner(page_ext);
493507

494508
/*

0 commit comments

Comments
 (0)