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.
Unified · Split
| @@ -18,6 +18,7 @@ struct page_ext_operations { · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | enum page_ext_flags { | 19 | enum page_ext_flags { |
| 20 | PAGE_EXT_OWNER, | 20 | PAGE_EXT_OWNER, |
| 21 | PAGE_EXT_OWNER_ACTIVE, | ||
| 21 | #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) | 22 | #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) |
| 22 | PAGE_EXT_YOUNG, | 23 | PAGE_EXT_YOUNG, |
| 23 | PAGE_EXT_IDLE, | 24 | PAGE_EXT_IDLE, |
| @@ -111,7 +111,7 @@ void __reset_page_owner(struct page *page, unsigned int order) · 110 unmodified lines | |||
| 111 | page_ext = lookup_page_ext(page + i); | 111 | page_ext = lookup_page_ext(page + i); |
| 112 | if (unlikely(!page_ext)) | 112 | if (unlikely(!page_ext)) |
| 113 | continue; | 113 | continue; |
| 114 | __clear_bit(PAGE_EXT_OWNER, &page_ext->flags); | 114 | __clear_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags); |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | 117 | ||
| @@ -168,6 +168,7 @@ static inline void __set_page_owner_handle(struct page *page, · 50 unmodified lines | |||
| 168 | page_owner->gfp_mask = gfp_mask; | 168 | page_owner->gfp_mask = gfp_mask; |
| 169 | page_owner->last_migrate_reason = -1; | 169 | page_owner->last_migrate_reason = -1; |
| 170 | __set_bit(PAGE_EXT_OWNER, &page_ext->flags); | 170 | __set_bit(PAGE_EXT_OWNER, &page_ext->flags); |
| 171 | __set_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags); | ||
| 171 | 172 | ||
| 172 | page_ext = lookup_page_ext(page + i); | 173 | page_ext = lookup_page_ext(page + i); |
| 173 | } | 174 | } |
| @@ -243,6 +244,7 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage) · 69 unmodified lines | |||
| 243 | * the new page, which will be freed. | 244 | * the new page, which will be freed. |
| 244 | */ | 245 | */ |
| 245 | __set_bit(PAGE_EXT_OWNER, &new_ext->flags); | 246 | __set_bit(PAGE_EXT_OWNER, &new_ext->flags); |
| 247 | __set_bit(PAGE_EXT_OWNER_ACTIVE, &new_ext->flags); | ||
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | void pagetypeinfo_showmixedcount_print(struct seq_file *m, | 250 | void pagetypeinfo_showmixedcount_print(struct seq_file *m, |
| @@ -302,7 +304,7 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m, · 53 unmodified lines | |||
| 302 | if (unlikely(!page_ext)) | 304 | if (unlikely(!page_ext)) |
| 303 | continue; | 305 | continue; |
| 304 | 306 | ||
| 305 | if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) | 307 | if (!test_bit(PAGE_EXT_OWNER_ACTIVE, &page_ext->flags)) |
| 306 | continue; | 308 | continue; |
| 307 | 309 | ||
| 308 | page_owner = get_page_owner(page_ext); | 310 | page_owner = get_page_owner(page_ext); |
| @@ -413,21 +415,26 @@ void __dump_page_owner(struct page *page) · 104 unmodified lines | |||
| 413 | mt = gfpflags_to_migratetype(gfp_mask); | 415 | mt = gfpflags_to_migratetype(gfp_mask); |
| 414 | 416 | ||
| 415 | if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) { | 417 | 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"); |
| 417 | return; | 419 | return; |
| 418 | } | 420 | } |
| 419 | 421 | ||
| 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 | |||
| 420 | handle = READ_ONCE(page_owner->handle); | 430 | handle = READ_ONCE(page_owner->handle); |
| 421 | if (!handle) { | 431 | if (!handle) { |
| 422 | pr_alert("page_owner info is not active (free page?)\n"); | 432 | pr_alert("page_owner allocation stack trace missing\n"); |
| 423 | return; | 433 | } else { |
| 434 | nr_entries = stack_depot_fetch(handle, &entries); | ||
| 435 | stack_trace_print(entries, nr_entries, 0); | ||
| 424 | } | 436 | } |
| 425 | 437 | ||
| 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 | |||
| 431 | if (page_owner->last_migrate_reason != -1) | 438 | if (page_owner->last_migrate_reason != -1) |
| 432 | pr_alert("page has been migrated, last migrate reason: %s\n", | 439 | pr_alert("page has been migrated, last migrate reason: %s\n", |
| 433 | migrate_reason_names[page_owner->last_migrate_reason]); | 440 | 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 | |||
| 489 | if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) | 496 | if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) |
| 490 | continue; | 497 | continue; |
| 491 | 498 | ||
| 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 | |||
| 492 | page_owner = get_page_owner(page_ext); | 506 | page_owner = get_page_owner(page_ext); |
| 493 | 507 | ||
| 494 | /* | 508 | /* |