History

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.

Vlastimil Babka committed 7 years ago

Commit 37389161 parent 7e2f2a02 files · +25 −10Browse files

Unified · Split

2 files
  1. include/linux/page_ext.h +1 −0
  2. mm/page_owner.c +24 −10
include/linux/page_ext.h+1−0
@@ -18,6 +18,7 @@ struct page_ext_operations { · 17 unmodified lines
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+24−10
@@ -111,7 +111,7 @@ void __reset_page_owner(struct page *page, unsigned int order) · 110 unmodified lines
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, · 50 unmodified lines
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) · 69 unmodified lines
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, · 53 unmodified lines
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) · 104 unmodified lines
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) · 55 unmodified lines
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 /*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t