Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
mm, page_owner: keep owner info when freeing the page
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
tehcaster authored and torvalds committed Sep 24, 2019
1 parent 7e2f2a0 commit 3738916
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
1 change: 1 addition & 0 deletions include/linux/page_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct page_ext_operations {

enum page_ext_flags {
PAGE_EXT_OWNER,
PAGE_EXT_OWNER_ACTIVE,
#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT)
PAGE_EXT_YOUNG,
PAGE_EXT_IDLE,
Expand Down
34 changes: 24 additions & 10 deletions mm/page_owner.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ void __reset_page_owner(struct page *page, unsigned int order)
page_ext = lookup_page_ext(page + i);
if (unlikely(!page_ext))
continue;
__clear_bit(PAGE_EXT_OWNER, &page_ext->flags);
__clear_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags);
}
}

Expand Down Expand Up @@ -168,6 +168,7 @@ static inline void __set_page_owner_handle(struct page *page,
page_owner->gfp_mask = gfp_mask;
page_owner->last_migrate_reason = -1;
__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
__set_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags);

page_ext = lookup_page_ext(page + i);
}
Expand Down Expand Up @@ -243,6 +244,7 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage)
* the new page, which will be freed.
*/
__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
__set_bit(PAGE_EXT_OWNER_ACTIVE, &new_ext->flags);
}

void pagetypeinfo_showmixedcount_print(struct seq_file *m,
Expand Down Expand Up @@ -302,7 +304,7 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
if (unlikely(!page_ext))
continue;

if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
if (!test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
continue;

page_owner = get_page_owner(page_ext);
Expand Down Expand Up @@ -413,21 +415,26 @@ void __dump_page_owner(struct page *page)
mt = gfpflags_to_migratetype(gfp_mask);

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

if (test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
pr_alert("page_owner tracks the page as allocated\n");
else
pr_alert("page_owner tracks the page as freed\n");

pr_alert("page last allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);

handle = READ_ONCE(page_owner->handle);
if (!handle) {
pr_alert("page_owner info is not active (free page?)\n");
return;
pr_alert("page_owner allocation stack trace missing\n");
} else {
nr_entries = stack_depot_fetch(handle, &entries);
stack_trace_print(entries, nr_entries, 0);
}

nr_entries = stack_depot_fetch(handle, &entries);
pr_alert("page allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask);
stack_trace_print(entries, nr_entries, 0);

if (page_owner->last_migrate_reason != -1)
pr_alert("page has been migrated, last migrate reason: %s\n",
migrate_reason_names[page_owner->last_migrate_reason]);
Expand Down Expand Up @@ -489,6 +496,13 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
continue;

/*
* Although we do have the info about past allocation of free
* pages, it's not relevant for current memory usage.
*/
if (!test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags))
continue;

page_owner = get_page_owner(page_ext);

/*
Expand Down

0 comments on commit 3738916

Please sign in to comment.