18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 38c2ecf20Sopenharmony_ci#include <linux/mm.h> 48c2ecf20Sopenharmony_ci#include <linux/slab.h> 58c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 68c2ecf20Sopenharmony_ci#include <linux/memblock.h> 78c2ecf20Sopenharmony_ci#include <linux/stacktrace.h> 88c2ecf20Sopenharmony_ci#include <linux/page_owner.h> 98c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 108c2ecf20Sopenharmony_ci#include <linux/migrate.h> 118c2ecf20Sopenharmony_ci#include <linux/stackdepot.h> 128c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/clock.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "internal.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack) 198c2ecf20Sopenharmony_ci * to use off stack temporal storage 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#define PAGE_OWNER_STACK_DEPTH (16) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct page_owner { 248c2ecf20Sopenharmony_ci unsigned short order; 258c2ecf20Sopenharmony_ci short last_migrate_reason; 268c2ecf20Sopenharmony_ci gfp_t gfp_mask; 278c2ecf20Sopenharmony_ci depot_stack_handle_t handle; 288c2ecf20Sopenharmony_ci depot_stack_handle_t free_handle; 298c2ecf20Sopenharmony_ci u64 ts_nsec; 308c2ecf20Sopenharmony_ci u64 free_ts_nsec; 318c2ecf20Sopenharmony_ci pid_t pid; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic bool page_owner_enabled = false; 358c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(page_owner_inited); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic depot_stack_handle_t dummy_handle; 388c2ecf20Sopenharmony_cistatic depot_stack_handle_t failure_handle; 398c2ecf20Sopenharmony_cistatic depot_stack_handle_t early_handle; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void init_early_allocated_pages(void); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int __init early_page_owner_param(char *buf) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (!buf) 468c2ecf20Sopenharmony_ci return -EINVAL; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (strcmp(buf, "on") == 0) 498c2ecf20Sopenharmony_ci page_owner_enabled = true; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ciearly_param("page_owner", early_page_owner_param); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic bool need_page_owner(void) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return page_owner_enabled; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic __always_inline depot_stack_handle_t create_dummy_stack(void) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned long entries[4]; 638c2ecf20Sopenharmony_ci unsigned int nr_entries; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 0); 668c2ecf20Sopenharmony_ci return stack_depot_save(entries, nr_entries, GFP_KERNEL); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic noinline void register_dummy_stack(void) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci dummy_handle = create_dummy_stack(); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic noinline void register_failure_stack(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci failure_handle = create_dummy_stack(); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic noinline void register_early_stack(void) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci early_handle = create_dummy_stack(); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void init_page_owner(void) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci if (!page_owner_enabled) 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci register_dummy_stack(); 908c2ecf20Sopenharmony_ci register_failure_stack(); 918c2ecf20Sopenharmony_ci register_early_stack(); 928c2ecf20Sopenharmony_ci static_branch_enable(&page_owner_inited); 938c2ecf20Sopenharmony_ci init_early_allocated_pages(); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistruct page_ext_operations page_owner_ops = { 978c2ecf20Sopenharmony_ci .size = sizeof(struct page_owner), 988c2ecf20Sopenharmony_ci .need = need_page_owner, 998c2ecf20Sopenharmony_ci .init = init_page_owner, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline struct page_owner *get_page_owner(struct page_ext *page_ext) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return (void *)page_ext + page_owner_ops.offset; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline bool check_recursive_alloc(unsigned long *entries, 1088c2ecf20Sopenharmony_ci unsigned int nr_entries, 1098c2ecf20Sopenharmony_ci unsigned long ip) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned int i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci for (i = 0; i < nr_entries; i++) { 1148c2ecf20Sopenharmony_ci if (entries[i] == ip) 1158c2ecf20Sopenharmony_ci return true; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci return false; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic noinline depot_stack_handle_t save_stack(gfp_t flags) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned long entries[PAGE_OWNER_STACK_DEPTH]; 1238c2ecf20Sopenharmony_ci depot_stack_handle_t handle; 1248c2ecf20Sopenharmony_ci unsigned int nr_entries; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 2); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * We need to check recursion here because our request to 1308c2ecf20Sopenharmony_ci * stackdepot could trigger memory allocation to save new 1318c2ecf20Sopenharmony_ci * entry. New memory allocation would reach here and call 1328c2ecf20Sopenharmony_ci * stack_depot_save_entries() again if we don't catch it. There is 1338c2ecf20Sopenharmony_ci * still not enough memory in stackdepot so it would try to 1348c2ecf20Sopenharmony_ci * allocate memory again and loop forever. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci if (check_recursive_alloc(entries, nr_entries, _RET_IP_)) 1378c2ecf20Sopenharmony_ci return dummy_handle; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci handle = stack_depot_save(entries, nr_entries, flags); 1408c2ecf20Sopenharmony_ci if (!handle) 1418c2ecf20Sopenharmony_ci handle = failure_handle; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return handle; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_civoid __reset_page_owner(struct page *page, unsigned int order) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int i; 1498c2ecf20Sopenharmony_ci struct page_ext *page_ext; 1508c2ecf20Sopenharmony_ci depot_stack_handle_t handle = 0; 1518c2ecf20Sopenharmony_ci struct page_owner *page_owner; 1528c2ecf20Sopenharmony_ci u64 free_ts_nsec = local_clock(); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci handle = save_stack(GFP_NOWAIT | __GFP_NOWARN); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci page_ext = lookup_page_ext(page); 1578c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 1588c2ecf20Sopenharmony_ci return; 1598c2ecf20Sopenharmony_ci for (i = 0; i < (1 << order); i++) { 1608c2ecf20Sopenharmony_ci __clear_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags); 1618c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 1628c2ecf20Sopenharmony_ci page_owner->free_handle = handle; 1638c2ecf20Sopenharmony_ci page_owner->free_ts_nsec = free_ts_nsec; 1648c2ecf20Sopenharmony_ci page_ext = page_ext_next(page_ext); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline void __set_page_owner_handle(struct page *page, 1698c2ecf20Sopenharmony_ci struct page_ext *page_ext, depot_stack_handle_t handle, 1708c2ecf20Sopenharmony_ci unsigned int order, gfp_t gfp_mask) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct page_owner *page_owner; 1738c2ecf20Sopenharmony_ci int i; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci for (i = 0; i < (1 << order); i++) { 1768c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 1778c2ecf20Sopenharmony_ci page_owner->handle = handle; 1788c2ecf20Sopenharmony_ci page_owner->order = order; 1798c2ecf20Sopenharmony_ci page_owner->gfp_mask = gfp_mask; 1808c2ecf20Sopenharmony_ci page_owner->last_migrate_reason = -1; 1818c2ecf20Sopenharmony_ci page_owner->pid = current->pid; 1828c2ecf20Sopenharmony_ci page_owner->ts_nsec = local_clock(); 1838c2ecf20Sopenharmony_ci __set_bit(PAGE_EXT_OWNER, &page_ext->flags); 1848c2ecf20Sopenharmony_ci __set_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci page_ext = page_ext_next(page_ext); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cinoinline void __set_page_owner(struct page *page, unsigned int order, 1918c2ecf20Sopenharmony_ci gfp_t gfp_mask) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct page_ext *page_ext = lookup_page_ext(page); 1948c2ecf20Sopenharmony_ci depot_stack_handle_t handle; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 1978c2ecf20Sopenharmony_ci return; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci handle = save_stack(gfp_mask); 2008c2ecf20Sopenharmony_ci __set_page_owner_handle(page, page_ext, handle, order, gfp_mask); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_civoid __set_page_owner_migrate_reason(struct page *page, int reason) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct page_ext *page_ext = lookup_page_ext(page); 2068c2ecf20Sopenharmony_ci struct page_owner *page_owner; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 2098c2ecf20Sopenharmony_ci return; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 2128c2ecf20Sopenharmony_ci page_owner->last_migrate_reason = reason; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_civoid __split_page_owner(struct page *page, unsigned int nr) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci int i; 2188c2ecf20Sopenharmony_ci struct page_ext *page_ext = lookup_page_ext(page); 2198c2ecf20Sopenharmony_ci struct page_owner *page_owner; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 2228c2ecf20Sopenharmony_ci return; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 2258c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 2268c2ecf20Sopenharmony_ci page_owner->order = 0; 2278c2ecf20Sopenharmony_ci page_ext = page_ext_next(page_ext); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_civoid __copy_page_owner(struct page *oldpage, struct page *newpage) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct page_ext *old_ext = lookup_page_ext(oldpage); 2348c2ecf20Sopenharmony_ci struct page_ext *new_ext = lookup_page_ext(newpage); 2358c2ecf20Sopenharmony_ci struct page_owner *old_page_owner, *new_page_owner; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (unlikely(!old_ext || !new_ext)) 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci old_page_owner = get_page_owner(old_ext); 2418c2ecf20Sopenharmony_ci new_page_owner = get_page_owner(new_ext); 2428c2ecf20Sopenharmony_ci new_page_owner->order = old_page_owner->order; 2438c2ecf20Sopenharmony_ci new_page_owner->gfp_mask = old_page_owner->gfp_mask; 2448c2ecf20Sopenharmony_ci new_page_owner->last_migrate_reason = 2458c2ecf20Sopenharmony_ci old_page_owner->last_migrate_reason; 2468c2ecf20Sopenharmony_ci new_page_owner->handle = old_page_owner->handle; 2478c2ecf20Sopenharmony_ci new_page_owner->pid = old_page_owner->pid; 2488c2ecf20Sopenharmony_ci new_page_owner->ts_nsec = old_page_owner->ts_nsec; 2498c2ecf20Sopenharmony_ci new_page_owner->free_ts_nsec = old_page_owner->ts_nsec; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * We don't clear the bit on the oldpage as it's going to be freed 2538c2ecf20Sopenharmony_ci * after migration. Until then, the info can be useful in case of 2548c2ecf20Sopenharmony_ci * a bug, and the overal stats will be off a bit only temporarily. 2558c2ecf20Sopenharmony_ci * Also, migrate_misplaced_transhuge_page() can still fail the 2568c2ecf20Sopenharmony_ci * migration and then we want the oldpage to retain the info. But 2578c2ecf20Sopenharmony_ci * in that case we also don't need to explicitly clear the info from 2588c2ecf20Sopenharmony_ci * the new page, which will be freed. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci __set_bit(PAGE_EXT_OWNER, &new_ext->flags); 2618c2ecf20Sopenharmony_ci __set_bit(PAGE_EXT_OWNER_ALLOCATED, &new_ext->flags); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid pagetypeinfo_showmixedcount_print(struct seq_file *m, 2658c2ecf20Sopenharmony_ci pg_data_t *pgdat, struct zone *zone) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct page *page; 2688c2ecf20Sopenharmony_ci struct page_ext *page_ext; 2698c2ecf20Sopenharmony_ci struct page_owner *page_owner; 2708c2ecf20Sopenharmony_ci unsigned long pfn = zone->zone_start_pfn, block_end_pfn; 2718c2ecf20Sopenharmony_ci unsigned long end_pfn = pfn + zone->spanned_pages; 2728c2ecf20Sopenharmony_ci unsigned long count[MIGRATE_TYPES] = { 0, }; 2738c2ecf20Sopenharmony_ci int pageblock_mt, page_mt; 2748c2ecf20Sopenharmony_ci int i; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Scan block by block. First and last block may be incomplete */ 2778c2ecf20Sopenharmony_ci pfn = zone->zone_start_pfn; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * Walk the zone in pageblock_nr_pages steps. If a page block spans 2818c2ecf20Sopenharmony_ci * a zone boundary, it will be double counted between zones. This does 2828c2ecf20Sopenharmony_ci * not matter as the mixed block count will still be correct 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci for (; pfn < end_pfn; ) { 2858c2ecf20Sopenharmony_ci page = pfn_to_online_page(pfn); 2868c2ecf20Sopenharmony_ci if (!page) { 2878c2ecf20Sopenharmony_ci pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES); 2888c2ecf20Sopenharmony_ci continue; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); 2928c2ecf20Sopenharmony_ci block_end_pfn = min(block_end_pfn, end_pfn); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci pageblock_mt = get_pageblock_migratetype(page); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci for (; pfn < block_end_pfn; pfn++) { 2978c2ecf20Sopenharmony_ci if (!pfn_valid_within(pfn)) 2988c2ecf20Sopenharmony_ci continue; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* The pageblock is online, no need to recheck. */ 3018c2ecf20Sopenharmony_ci page = pfn_to_page(pfn); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (page_zone(page) != zone) 3048c2ecf20Sopenharmony_ci continue; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (PageBuddy(page)) { 3078c2ecf20Sopenharmony_ci unsigned long freepage_order; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci freepage_order = buddy_order_unsafe(page); 3108c2ecf20Sopenharmony_ci if (freepage_order < MAX_ORDER) 3118c2ecf20Sopenharmony_ci pfn += (1UL << freepage_order) - 1; 3128c2ecf20Sopenharmony_ci continue; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (PageReserved(page)) 3168c2ecf20Sopenharmony_ci continue; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci page_ext = lookup_page_ext(page); 3198c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 3208c2ecf20Sopenharmony_ci continue; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (!test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags)) 3238c2ecf20Sopenharmony_ci continue; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 3268c2ecf20Sopenharmony_ci page_mt = gfp_migratetype(page_owner->gfp_mask); 3278c2ecf20Sopenharmony_ci if (pageblock_mt != page_mt) { 3288c2ecf20Sopenharmony_ci if (is_migrate_cma(pageblock_mt)) 3298c2ecf20Sopenharmony_ci count[MIGRATE_MOVABLE]++; 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci count[pageblock_mt]++; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pfn = block_end_pfn; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci pfn += (1UL << page_owner->order) - 1; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Print counts */ 3418c2ecf20Sopenharmony_ci seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); 3428c2ecf20Sopenharmony_ci for (i = 0; i < MIGRATE_TYPES; i++) 3438c2ecf20Sopenharmony_ci seq_printf(m, "%12lu ", count[i]); 3448c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic ssize_t 3488c2ecf20Sopenharmony_ciprint_page_owner(char __user *buf, size_t count, unsigned long pfn, 3498c2ecf20Sopenharmony_ci struct page *page, struct page_owner *page_owner, 3508c2ecf20Sopenharmony_ci depot_stack_handle_t handle) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int ret, pageblock_mt, page_mt; 3538c2ecf20Sopenharmony_ci unsigned long *entries; 3548c2ecf20Sopenharmony_ci unsigned int nr_entries; 3558c2ecf20Sopenharmony_ci char *kbuf; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci count = min_t(size_t, count, PAGE_SIZE); 3588c2ecf20Sopenharmony_ci kbuf = kmalloc(count, GFP_KERNEL); 3598c2ecf20Sopenharmony_ci if (!kbuf) 3608c2ecf20Sopenharmony_ci return -ENOMEM; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ret = snprintf(kbuf, count, 3638c2ecf20Sopenharmony_ci "Page allocated via order %u, mask %#x(%pGg), pid %d, ts %llu ns, free_ts %llu ns\n", 3648c2ecf20Sopenharmony_ci page_owner->order, page_owner->gfp_mask, 3658c2ecf20Sopenharmony_ci &page_owner->gfp_mask, page_owner->pid, 3668c2ecf20Sopenharmony_ci page_owner->ts_nsec, page_owner->free_ts_nsec); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (ret >= count) 3698c2ecf20Sopenharmony_ci goto err; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Print information relevant to grouping pages by mobility */ 3728c2ecf20Sopenharmony_ci pageblock_mt = get_pageblock_migratetype(page); 3738c2ecf20Sopenharmony_ci page_mt = gfp_migratetype(page_owner->gfp_mask); 3748c2ecf20Sopenharmony_ci ret += snprintf(kbuf + ret, count - ret, 3758c2ecf20Sopenharmony_ci "PFN %lu type %s Block %lu type %s Flags %#lx(%pGp)\n", 3768c2ecf20Sopenharmony_ci pfn, 3778c2ecf20Sopenharmony_ci migratetype_names[page_mt], 3788c2ecf20Sopenharmony_ci pfn >> pageblock_order, 3798c2ecf20Sopenharmony_ci migratetype_names[pageblock_mt], 3808c2ecf20Sopenharmony_ci page->flags, &page->flags); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (ret >= count) 3838c2ecf20Sopenharmony_ci goto err; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci nr_entries = stack_depot_fetch(handle, &entries); 3868c2ecf20Sopenharmony_ci ret += stack_trace_snprint(kbuf + ret, count - ret, entries, nr_entries, 0); 3878c2ecf20Sopenharmony_ci if (ret >= count) 3888c2ecf20Sopenharmony_ci goto err; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (page_owner->last_migrate_reason != -1) { 3918c2ecf20Sopenharmony_ci ret += snprintf(kbuf + ret, count - ret, 3928c2ecf20Sopenharmony_ci "Page has been migrated, last migrate reason: %s\n", 3938c2ecf20Sopenharmony_ci migrate_reason_names[page_owner->last_migrate_reason]); 3948c2ecf20Sopenharmony_ci if (ret >= count) 3958c2ecf20Sopenharmony_ci goto err; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret += snprintf(kbuf + ret, count - ret, "\n"); 3998c2ecf20Sopenharmony_ci if (ret >= count) 4008c2ecf20Sopenharmony_ci goto err; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (copy_to_user(buf, kbuf, ret)) 4038c2ecf20Sopenharmony_ci ret = -EFAULT; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci kfree(kbuf); 4068c2ecf20Sopenharmony_ci return ret; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cierr: 4098c2ecf20Sopenharmony_ci kfree(kbuf); 4108c2ecf20Sopenharmony_ci return -ENOMEM; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_civoid __dump_page_owner(struct page *page) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct page_ext *page_ext = lookup_page_ext(page); 4168c2ecf20Sopenharmony_ci struct page_owner *page_owner; 4178c2ecf20Sopenharmony_ci depot_stack_handle_t handle; 4188c2ecf20Sopenharmony_ci unsigned long *entries; 4198c2ecf20Sopenharmony_ci unsigned int nr_entries; 4208c2ecf20Sopenharmony_ci gfp_t gfp_mask; 4218c2ecf20Sopenharmony_ci int mt; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) { 4248c2ecf20Sopenharmony_ci pr_alert("There is not page extension available.\n"); 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 4298c2ecf20Sopenharmony_ci gfp_mask = page_owner->gfp_mask; 4308c2ecf20Sopenharmony_ci mt = gfp_migratetype(gfp_mask); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) { 4338c2ecf20Sopenharmony_ci pr_alert("page_owner info is not present (never set?)\n"); 4348c2ecf20Sopenharmony_ci return; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags)) 4388c2ecf20Sopenharmony_ci pr_alert("page_owner tracks the page as allocated\n"); 4398c2ecf20Sopenharmony_ci else 4408c2ecf20Sopenharmony_ci pr_alert("page_owner tracks the page as freed\n"); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci pr_alert("page last allocated via order %u, migratetype %s, gfp_mask %#x(%pGg), pid %d, ts %llu, free_ts %llu\n", 4438c2ecf20Sopenharmony_ci page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask, 4448c2ecf20Sopenharmony_ci page_owner->pid, page_owner->ts_nsec, page_owner->free_ts_nsec); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci handle = READ_ONCE(page_owner->handle); 4478c2ecf20Sopenharmony_ci if (!handle) { 4488c2ecf20Sopenharmony_ci pr_alert("page_owner allocation stack trace missing\n"); 4498c2ecf20Sopenharmony_ci } else { 4508c2ecf20Sopenharmony_ci nr_entries = stack_depot_fetch(handle, &entries); 4518c2ecf20Sopenharmony_ci stack_trace_print(entries, nr_entries, 0); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci handle = READ_ONCE(page_owner->free_handle); 4558c2ecf20Sopenharmony_ci if (!handle) { 4568c2ecf20Sopenharmony_ci pr_alert("page_owner free stack trace missing\n"); 4578c2ecf20Sopenharmony_ci } else { 4588c2ecf20Sopenharmony_ci nr_entries = stack_depot_fetch(handle, &entries); 4598c2ecf20Sopenharmony_ci pr_alert("page last free stack trace:\n"); 4608c2ecf20Sopenharmony_ci stack_trace_print(entries, nr_entries, 0); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (page_owner->last_migrate_reason != -1) 4648c2ecf20Sopenharmony_ci pr_alert("page has been migrated, last migrate reason: %s\n", 4658c2ecf20Sopenharmony_ci migrate_reason_names[page_owner->last_migrate_reason]); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic ssize_t 4698c2ecf20Sopenharmony_ciread_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci unsigned long pfn; 4728c2ecf20Sopenharmony_ci struct page *page; 4738c2ecf20Sopenharmony_ci struct page_ext *page_ext; 4748c2ecf20Sopenharmony_ci struct page_owner *page_owner; 4758c2ecf20Sopenharmony_ci depot_stack_handle_t handle; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!static_branch_unlikely(&page_owner_inited)) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci page = NULL; 4818c2ecf20Sopenharmony_ci pfn = min_low_pfn + *ppos; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area */ 4848c2ecf20Sopenharmony_ci while (!pfn_valid(pfn) && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) 4858c2ecf20Sopenharmony_ci pfn++; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci drain_all_pages(NULL); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Find an allocated page */ 4908c2ecf20Sopenharmony_ci for (; pfn < max_pfn; pfn++) { 4918c2ecf20Sopenharmony_ci /* 4928c2ecf20Sopenharmony_ci * If the new page is in a new MAX_ORDER_NR_PAGES area, 4938c2ecf20Sopenharmony_ci * validate the area as existing, skip it if not 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ci if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0 && !pfn_valid(pfn)) { 4968c2ecf20Sopenharmony_ci pfn += MAX_ORDER_NR_PAGES - 1; 4978c2ecf20Sopenharmony_ci continue; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Check for holes within a MAX_ORDER area */ 5018c2ecf20Sopenharmony_ci if (!pfn_valid_within(pfn)) 5028c2ecf20Sopenharmony_ci continue; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci page = pfn_to_page(pfn); 5058c2ecf20Sopenharmony_ci if (PageBuddy(page)) { 5068c2ecf20Sopenharmony_ci unsigned long freepage_order = buddy_order_unsafe(page); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (freepage_order < MAX_ORDER) 5098c2ecf20Sopenharmony_ci pfn += (1UL << freepage_order) - 1; 5108c2ecf20Sopenharmony_ci continue; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci page_ext = lookup_page_ext(page); 5148c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 5158c2ecf20Sopenharmony_ci continue; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * Some pages could be missed by concurrent allocation or free, 5198c2ecf20Sopenharmony_ci * because we don't hold the zone lock. 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) 5228c2ecf20Sopenharmony_ci continue; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* 5258c2ecf20Sopenharmony_ci * Although we do have the info about past allocation of free 5268c2ecf20Sopenharmony_ci * pages, it's not relevant for current memory usage. 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_ci if (!test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags)) 5298c2ecf20Sopenharmony_ci continue; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci page_owner = get_page_owner(page_ext); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * Don't print "tail" pages of high-order allocations as that 5358c2ecf20Sopenharmony_ci * would inflate the stats. 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci if (!IS_ALIGNED(pfn, 1 << page_owner->order)) 5388c2ecf20Sopenharmony_ci continue; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* 5418c2ecf20Sopenharmony_ci * Access to page_ext->handle isn't synchronous so we should 5428c2ecf20Sopenharmony_ci * be careful to access it. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci handle = READ_ONCE(page_owner->handle); 5458c2ecf20Sopenharmony_ci if (!handle) 5468c2ecf20Sopenharmony_ci continue; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Record the next PFN to read in the file offset */ 5498c2ecf20Sopenharmony_ci *ppos = (pfn - min_low_pfn) + 1; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return print_page_owner(buf, count, pfn, page, 5528c2ecf20Sopenharmony_ci page_owner, handle); 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci unsigned long pfn = zone->zone_start_pfn; 5618c2ecf20Sopenharmony_ci unsigned long end_pfn = zone_end_pfn(zone); 5628c2ecf20Sopenharmony_ci unsigned long count = 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* 5658c2ecf20Sopenharmony_ci * Walk the zone in pageblock_nr_pages steps. If a page block spans 5668c2ecf20Sopenharmony_ci * a zone boundary, it will be double counted between zones. This does 5678c2ecf20Sopenharmony_ci * not matter as the mixed block count will still be correct 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci for (; pfn < end_pfn; ) { 5708c2ecf20Sopenharmony_ci unsigned long block_end_pfn; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (!pfn_valid(pfn)) { 5738c2ecf20Sopenharmony_ci pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES); 5748c2ecf20Sopenharmony_ci continue; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages); 5788c2ecf20Sopenharmony_ci block_end_pfn = min(block_end_pfn, end_pfn); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci for (; pfn < block_end_pfn; pfn++) { 5818c2ecf20Sopenharmony_ci struct page *page; 5828c2ecf20Sopenharmony_ci struct page_ext *page_ext; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!pfn_valid_within(pfn)) 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci page = pfn_to_page(pfn); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (page_zone(page) != zone) 5908c2ecf20Sopenharmony_ci continue; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * To avoid having to grab zone->lock, be a little 5948c2ecf20Sopenharmony_ci * careful when reading buddy page order. The only 5958c2ecf20Sopenharmony_ci * danger is that we skip too much and potentially miss 5968c2ecf20Sopenharmony_ci * some early allocated pages, which is better than 5978c2ecf20Sopenharmony_ci * heavy lock contention. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci if (PageBuddy(page)) { 6008c2ecf20Sopenharmony_ci unsigned long order = buddy_order_unsafe(page); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (order > 0 && order < MAX_ORDER) 6038c2ecf20Sopenharmony_ci pfn += (1UL << order) - 1; 6048c2ecf20Sopenharmony_ci continue; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (PageReserved(page)) 6088c2ecf20Sopenharmony_ci continue; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci page_ext = lookup_page_ext(page); 6118c2ecf20Sopenharmony_ci if (unlikely(!page_ext)) 6128c2ecf20Sopenharmony_ci continue; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Maybe overlapping zone */ 6158c2ecf20Sopenharmony_ci if (test_bit(PAGE_EXT_OWNER, &page_ext->flags)) 6168c2ecf20Sopenharmony_ci continue; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* Found early allocated page */ 6198c2ecf20Sopenharmony_ci __set_page_owner_handle(page, page_ext, early_handle, 6208c2ecf20Sopenharmony_ci 0, 0); 6218c2ecf20Sopenharmony_ci count++; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci cond_resched(); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci pr_info("Node %d, zone %8s: page owner found early allocated %lu pages\n", 6278c2ecf20Sopenharmony_ci pgdat->node_id, zone->name, count); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic void init_zones_in_node(pg_data_t *pgdat) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct zone *zone; 6338c2ecf20Sopenharmony_ci struct zone *node_zones = pgdat->node_zones; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { 6368c2ecf20Sopenharmony_ci if (!populated_zone(zone)) 6378c2ecf20Sopenharmony_ci continue; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci init_pages_in_zone(pgdat, zone); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void init_early_allocated_pages(void) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci pg_data_t *pgdat; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci for_each_online_pgdat(pgdat) 6488c2ecf20Sopenharmony_ci init_zones_in_node(pgdat); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic const struct file_operations proc_page_owner_operations = { 6528c2ecf20Sopenharmony_ci .read = read_page_owner, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int __init pageowner_init(void) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci if (!static_branch_unlikely(&page_owner_inited)) { 6588c2ecf20Sopenharmony_ci pr_info("page_owner is disabled\n"); 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci debugfs_create_file("page_owner", 0400, NULL, NULL, 6638c2ecf20Sopenharmony_ci &proc_page_owner_operations); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return 0; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_cilate_initcall(pageowner_init) 668