xref: /linux/mm/page_owner.c (revision 0b423ca22f95a867f789aab1fe57ee4e378df43b)
148c96a36SJoonsoo Kim #include <linux/debugfs.h>
248c96a36SJoonsoo Kim #include <linux/mm.h>
348c96a36SJoonsoo Kim #include <linux/slab.h>
448c96a36SJoonsoo Kim #include <linux/uaccess.h>
548c96a36SJoonsoo Kim #include <linux/bootmem.h>
648c96a36SJoonsoo Kim #include <linux/stacktrace.h>
748c96a36SJoonsoo Kim #include <linux/page_owner.h>
87dd80b8aSVlastimil Babka #include <linux/jump_label.h>
97cd12b4aSVlastimil Babka #include <linux/migrate.h>
1048c96a36SJoonsoo Kim #include "internal.h"
1148c96a36SJoonsoo Kim 
1248c96a36SJoonsoo Kim static bool page_owner_disabled = true;
137dd80b8aSVlastimil Babka DEFINE_STATIC_KEY_FALSE(page_owner_inited);
1448c96a36SJoonsoo Kim 
1561cf5febSJoonsoo Kim static void init_early_allocated_pages(void);
1661cf5febSJoonsoo Kim 
1748c96a36SJoonsoo Kim static int early_page_owner_param(char *buf)
1848c96a36SJoonsoo Kim {
1948c96a36SJoonsoo Kim 	if (!buf)
2048c96a36SJoonsoo Kim 		return -EINVAL;
2148c96a36SJoonsoo Kim 
2248c96a36SJoonsoo Kim 	if (strcmp(buf, "on") == 0)
2348c96a36SJoonsoo Kim 		page_owner_disabled = false;
2448c96a36SJoonsoo Kim 
2548c96a36SJoonsoo Kim 	return 0;
2648c96a36SJoonsoo Kim }
2748c96a36SJoonsoo Kim early_param("page_owner", early_page_owner_param);
2848c96a36SJoonsoo Kim 
2948c96a36SJoonsoo Kim static bool need_page_owner(void)
3048c96a36SJoonsoo Kim {
3148c96a36SJoonsoo Kim 	if (page_owner_disabled)
3248c96a36SJoonsoo Kim 		return false;
3348c96a36SJoonsoo Kim 
3448c96a36SJoonsoo Kim 	return true;
3548c96a36SJoonsoo Kim }
3648c96a36SJoonsoo Kim 
3748c96a36SJoonsoo Kim static void init_page_owner(void)
3848c96a36SJoonsoo Kim {
3948c96a36SJoonsoo Kim 	if (page_owner_disabled)
4048c96a36SJoonsoo Kim 		return;
4148c96a36SJoonsoo Kim 
427dd80b8aSVlastimil Babka 	static_branch_enable(&page_owner_inited);
4361cf5febSJoonsoo Kim 	init_early_allocated_pages();
4448c96a36SJoonsoo Kim }
4548c96a36SJoonsoo Kim 
4648c96a36SJoonsoo Kim struct page_ext_operations page_owner_ops = {
4748c96a36SJoonsoo Kim 	.need = need_page_owner,
4848c96a36SJoonsoo Kim 	.init = init_page_owner,
4948c96a36SJoonsoo Kim };
5048c96a36SJoonsoo Kim 
5148c96a36SJoonsoo Kim void __reset_page_owner(struct page *page, unsigned int order)
5248c96a36SJoonsoo Kim {
5348c96a36SJoonsoo Kim 	int i;
5448c96a36SJoonsoo Kim 	struct page_ext *page_ext;
5548c96a36SJoonsoo Kim 
5648c96a36SJoonsoo Kim 	for (i = 0; i < (1 << order); i++) {
5748c96a36SJoonsoo Kim 		page_ext = lookup_page_ext(page + i);
5848c96a36SJoonsoo Kim 		__clear_bit(PAGE_EXT_OWNER, &page_ext->flags);
5948c96a36SJoonsoo Kim 	}
6048c96a36SJoonsoo Kim }
6148c96a36SJoonsoo Kim 
6248c96a36SJoonsoo Kim void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
6348c96a36SJoonsoo Kim {
6494f759d6SSergei Rogachev 	struct page_ext *page_ext = lookup_page_ext(page);
6594f759d6SSergei Rogachev 	struct stack_trace trace = {
6694f759d6SSergei Rogachev 		.nr_entries = 0,
6794f759d6SSergei Rogachev 		.max_entries = ARRAY_SIZE(page_ext->trace_entries),
6894f759d6SSergei Rogachev 		.entries = &page_ext->trace_entries[0],
6994f759d6SSergei Rogachev 		.skip = 3,
7094f759d6SSergei Rogachev 	};
7148c96a36SJoonsoo Kim 
7294f759d6SSergei Rogachev 	save_stack_trace(&trace);
7348c96a36SJoonsoo Kim 
7448c96a36SJoonsoo Kim 	page_ext->order = order;
7548c96a36SJoonsoo Kim 	page_ext->gfp_mask = gfp_mask;
7694f759d6SSergei Rogachev 	page_ext->nr_entries = trace.nr_entries;
777cd12b4aSVlastimil Babka 	page_ext->last_migrate_reason = -1;
7848c96a36SJoonsoo Kim 
7948c96a36SJoonsoo Kim 	__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
8048c96a36SJoonsoo Kim }
8148c96a36SJoonsoo Kim 
827cd12b4aSVlastimil Babka void __set_page_owner_migrate_reason(struct page *page, int reason)
837cd12b4aSVlastimil Babka {
847cd12b4aSVlastimil Babka 	struct page_ext *page_ext = lookup_page_ext(page);
857cd12b4aSVlastimil Babka 
867cd12b4aSVlastimil Babka 	page_ext->last_migrate_reason = reason;
877cd12b4aSVlastimil Babka }
887cd12b4aSVlastimil Babka 
89e2cfc911SJoonsoo Kim gfp_t __get_page_owner_gfp(struct page *page)
90e2cfc911SJoonsoo Kim {
91e2cfc911SJoonsoo Kim 	struct page_ext *page_ext = lookup_page_ext(page);
92e2cfc911SJoonsoo Kim 
93e2cfc911SJoonsoo Kim 	return page_ext->gfp_mask;
94e2cfc911SJoonsoo Kim }
95e2cfc911SJoonsoo Kim 
96d435edcaSVlastimil Babka void __copy_page_owner(struct page *oldpage, struct page *newpage)
97d435edcaSVlastimil Babka {
98d435edcaSVlastimil Babka 	struct page_ext *old_ext = lookup_page_ext(oldpage);
99d435edcaSVlastimil Babka 	struct page_ext *new_ext = lookup_page_ext(newpage);
100d435edcaSVlastimil Babka 	int i;
101d435edcaSVlastimil Babka 
102d435edcaSVlastimil Babka 	new_ext->order = old_ext->order;
103d435edcaSVlastimil Babka 	new_ext->gfp_mask = old_ext->gfp_mask;
104d435edcaSVlastimil Babka 	new_ext->nr_entries = old_ext->nr_entries;
105d435edcaSVlastimil Babka 
106d435edcaSVlastimil Babka 	for (i = 0; i < ARRAY_SIZE(new_ext->trace_entries); i++)
107d435edcaSVlastimil Babka 		new_ext->trace_entries[i] = old_ext->trace_entries[i];
108d435edcaSVlastimil Babka 
109d435edcaSVlastimil Babka 	/*
110d435edcaSVlastimil Babka 	 * We don't clear the bit on the oldpage as it's going to be freed
111d435edcaSVlastimil Babka 	 * after migration. Until then, the info can be useful in case of
112d435edcaSVlastimil Babka 	 * a bug, and the overal stats will be off a bit only temporarily.
113d435edcaSVlastimil Babka 	 * Also, migrate_misplaced_transhuge_page() can still fail the
114d435edcaSVlastimil Babka 	 * migration and then we want the oldpage to retain the info. But
115d435edcaSVlastimil Babka 	 * in that case we also don't need to explicitly clear the info from
116d435edcaSVlastimil Babka 	 * the new page, which will be freed.
117d435edcaSVlastimil Babka 	 */
118d435edcaSVlastimil Babka 	__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
119d435edcaSVlastimil Babka }
120d435edcaSVlastimil Babka 
12148c96a36SJoonsoo Kim static ssize_t
12248c96a36SJoonsoo Kim print_page_owner(char __user *buf, size_t count, unsigned long pfn,
12348c96a36SJoonsoo Kim 		struct page *page, struct page_ext *page_ext)
12448c96a36SJoonsoo Kim {
12548c96a36SJoonsoo Kim 	int ret;
12648c96a36SJoonsoo Kim 	int pageblock_mt, page_mt;
12748c96a36SJoonsoo Kim 	char *kbuf;
12894f759d6SSergei Rogachev 	struct stack_trace trace = {
12994f759d6SSergei Rogachev 		.nr_entries = page_ext->nr_entries,
13094f759d6SSergei Rogachev 		.entries = &page_ext->trace_entries[0],
13194f759d6SSergei Rogachev 	};
13248c96a36SJoonsoo Kim 
13348c96a36SJoonsoo Kim 	kbuf = kmalloc(count, GFP_KERNEL);
13448c96a36SJoonsoo Kim 	if (!kbuf)
13548c96a36SJoonsoo Kim 		return -ENOMEM;
13648c96a36SJoonsoo Kim 
13748c96a36SJoonsoo Kim 	ret = snprintf(kbuf, count,
13860f30350SVlastimil Babka 			"Page allocated via order %u, mask %#x(%pGg)\n",
13960f30350SVlastimil Babka 			page_ext->order, page_ext->gfp_mask,
14060f30350SVlastimil Babka 			&page_ext->gfp_mask);
14148c96a36SJoonsoo Kim 
14248c96a36SJoonsoo Kim 	if (ret >= count)
14348c96a36SJoonsoo Kim 		goto err;
14448c96a36SJoonsoo Kim 
14548c96a36SJoonsoo Kim 	/* Print information relevant to grouping pages by mobility */
146*0b423ca2SMel Gorman 	pageblock_mt = get_pageblock_migratetype(page);
14748c96a36SJoonsoo Kim 	page_mt  = gfpflags_to_migratetype(page_ext->gfp_mask);
14848c96a36SJoonsoo Kim 	ret += snprintf(kbuf + ret, count - ret,
14960f30350SVlastimil Babka 			"PFN %lu type %s Block %lu type %s Flags %#lx(%pGp)\n",
15048c96a36SJoonsoo Kim 			pfn,
15160f30350SVlastimil Babka 			migratetype_names[page_mt],
15248c96a36SJoonsoo Kim 			pfn >> pageblock_order,
15360f30350SVlastimil Babka 			migratetype_names[pageblock_mt],
15460f30350SVlastimil Babka 			page->flags, &page->flags);
15548c96a36SJoonsoo Kim 
15648c96a36SJoonsoo Kim 	if (ret >= count)
15748c96a36SJoonsoo Kim 		goto err;
15848c96a36SJoonsoo Kim 
15994f759d6SSergei Rogachev 	ret += snprint_stack_trace(kbuf + ret, count - ret, &trace, 0);
16048c96a36SJoonsoo Kim 	if (ret >= count)
16148c96a36SJoonsoo Kim 		goto err;
16248c96a36SJoonsoo Kim 
1637cd12b4aSVlastimil Babka 	if (page_ext->last_migrate_reason != -1) {
1647cd12b4aSVlastimil Babka 		ret += snprintf(kbuf + ret, count - ret,
1657cd12b4aSVlastimil Babka 			"Page has been migrated, last migrate reason: %s\n",
1667cd12b4aSVlastimil Babka 			migrate_reason_names[page_ext->last_migrate_reason]);
1677cd12b4aSVlastimil Babka 		if (ret >= count)
1687cd12b4aSVlastimil Babka 			goto err;
1697cd12b4aSVlastimil Babka 	}
1707cd12b4aSVlastimil Babka 
17148c96a36SJoonsoo Kim 	ret += snprintf(kbuf + ret, count - ret, "\n");
17248c96a36SJoonsoo Kim 	if (ret >= count)
17348c96a36SJoonsoo Kim 		goto err;
17448c96a36SJoonsoo Kim 
17548c96a36SJoonsoo Kim 	if (copy_to_user(buf, kbuf, ret))
17648c96a36SJoonsoo Kim 		ret = -EFAULT;
17748c96a36SJoonsoo Kim 
17848c96a36SJoonsoo Kim 	kfree(kbuf);
17948c96a36SJoonsoo Kim 	return ret;
18048c96a36SJoonsoo Kim 
18148c96a36SJoonsoo Kim err:
18248c96a36SJoonsoo Kim 	kfree(kbuf);
18348c96a36SJoonsoo Kim 	return -ENOMEM;
18448c96a36SJoonsoo Kim }
18548c96a36SJoonsoo Kim 
1864e462112SVlastimil Babka void __dump_page_owner(struct page *page)
1874e462112SVlastimil Babka {
1884e462112SVlastimil Babka 	struct page_ext *page_ext = lookup_page_ext(page);
1894e462112SVlastimil Babka 	struct stack_trace trace = {
1904e462112SVlastimil Babka 		.nr_entries = page_ext->nr_entries,
1914e462112SVlastimil Babka 		.entries = &page_ext->trace_entries[0],
1924e462112SVlastimil Babka 	};
1934e462112SVlastimil Babka 	gfp_t gfp_mask = page_ext->gfp_mask;
1944e462112SVlastimil Babka 	int mt = gfpflags_to_migratetype(gfp_mask);
1954e462112SVlastimil Babka 
1964e462112SVlastimil Babka 	if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) {
1974e462112SVlastimil Babka 		pr_alert("page_owner info is not active (free page?)\n");
1984e462112SVlastimil Babka 		return;
1994e462112SVlastimil Babka 	}
2004e462112SVlastimil Babka 
201756a025fSJoe Perches 	pr_alert("page allocated via order %u, migratetype %s, gfp_mask %#x(%pGg)\n",
202756a025fSJoe Perches 		 page_ext->order, migratetype_names[mt], gfp_mask, &gfp_mask);
2034e462112SVlastimil Babka 	print_stack_trace(&trace, 0);
2044e462112SVlastimil Babka 
2054e462112SVlastimil Babka 	if (page_ext->last_migrate_reason != -1)
2064e462112SVlastimil Babka 		pr_alert("page has been migrated, last migrate reason: %s\n",
2074e462112SVlastimil Babka 			migrate_reason_names[page_ext->last_migrate_reason]);
2084e462112SVlastimil Babka }
2094e462112SVlastimil Babka 
21048c96a36SJoonsoo Kim static ssize_t
21148c96a36SJoonsoo Kim read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
21248c96a36SJoonsoo Kim {
21348c96a36SJoonsoo Kim 	unsigned long pfn;
21448c96a36SJoonsoo Kim 	struct page *page;
21548c96a36SJoonsoo Kim 	struct page_ext *page_ext;
21648c96a36SJoonsoo Kim 
2177dd80b8aSVlastimil Babka 	if (!static_branch_unlikely(&page_owner_inited))
21848c96a36SJoonsoo Kim 		return -EINVAL;
21948c96a36SJoonsoo Kim 
22048c96a36SJoonsoo Kim 	page = NULL;
22148c96a36SJoonsoo Kim 	pfn = min_low_pfn + *ppos;
22248c96a36SJoonsoo Kim 
22348c96a36SJoonsoo Kim 	/* Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area */
22448c96a36SJoonsoo Kim 	while (!pfn_valid(pfn) && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0)
22548c96a36SJoonsoo Kim 		pfn++;
22648c96a36SJoonsoo Kim 
22748c96a36SJoonsoo Kim 	drain_all_pages(NULL);
22848c96a36SJoonsoo Kim 
22948c96a36SJoonsoo Kim 	/* Find an allocated page */
23048c96a36SJoonsoo Kim 	for (; pfn < max_pfn; pfn++) {
23148c96a36SJoonsoo Kim 		/*
23248c96a36SJoonsoo Kim 		 * If the new page is in a new MAX_ORDER_NR_PAGES area,
23348c96a36SJoonsoo Kim 		 * validate the area as existing, skip it if not
23448c96a36SJoonsoo Kim 		 */
23548c96a36SJoonsoo Kim 		if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0 && !pfn_valid(pfn)) {
23648c96a36SJoonsoo Kim 			pfn += MAX_ORDER_NR_PAGES - 1;
23748c96a36SJoonsoo Kim 			continue;
23848c96a36SJoonsoo Kim 		}
23948c96a36SJoonsoo Kim 
24048c96a36SJoonsoo Kim 		/* Check for holes within a MAX_ORDER area */
24148c96a36SJoonsoo Kim 		if (!pfn_valid_within(pfn))
24248c96a36SJoonsoo Kim 			continue;
24348c96a36SJoonsoo Kim 
24448c96a36SJoonsoo Kim 		page = pfn_to_page(pfn);
24548c96a36SJoonsoo Kim 		if (PageBuddy(page)) {
24648c96a36SJoonsoo Kim 			unsigned long freepage_order = page_order_unsafe(page);
24748c96a36SJoonsoo Kim 
24848c96a36SJoonsoo Kim 			if (freepage_order < MAX_ORDER)
24948c96a36SJoonsoo Kim 				pfn += (1UL << freepage_order) - 1;
25048c96a36SJoonsoo Kim 			continue;
25148c96a36SJoonsoo Kim 		}
25248c96a36SJoonsoo Kim 
25348c96a36SJoonsoo Kim 		page_ext = lookup_page_ext(page);
25448c96a36SJoonsoo Kim 
25548c96a36SJoonsoo Kim 		/*
25661cf5febSJoonsoo Kim 		 * Some pages could be missed by concurrent allocation or free,
25761cf5febSJoonsoo Kim 		 * because we don't hold the zone lock.
25848c96a36SJoonsoo Kim 		 */
25948c96a36SJoonsoo Kim 		if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
26048c96a36SJoonsoo Kim 			continue;
26148c96a36SJoonsoo Kim 
26248c96a36SJoonsoo Kim 		/* Record the next PFN to read in the file offset */
26348c96a36SJoonsoo Kim 		*ppos = (pfn - min_low_pfn) + 1;
26448c96a36SJoonsoo Kim 
26548c96a36SJoonsoo Kim 		return print_page_owner(buf, count, pfn, page, page_ext);
26648c96a36SJoonsoo Kim 	}
26748c96a36SJoonsoo Kim 
26848c96a36SJoonsoo Kim 	return 0;
26948c96a36SJoonsoo Kim }
27048c96a36SJoonsoo Kim 
27161cf5febSJoonsoo Kim static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone)
27261cf5febSJoonsoo Kim {
27361cf5febSJoonsoo Kim 	struct page *page;
27461cf5febSJoonsoo Kim 	struct page_ext *page_ext;
27561cf5febSJoonsoo Kim 	unsigned long pfn = zone->zone_start_pfn, block_end_pfn;
27661cf5febSJoonsoo Kim 	unsigned long end_pfn = pfn + zone->spanned_pages;
27761cf5febSJoonsoo Kim 	unsigned long count = 0;
27861cf5febSJoonsoo Kim 
27961cf5febSJoonsoo Kim 	/* Scan block by block. First and last block may be incomplete */
28061cf5febSJoonsoo Kim 	pfn = zone->zone_start_pfn;
28161cf5febSJoonsoo Kim 
28261cf5febSJoonsoo Kim 	/*
28361cf5febSJoonsoo Kim 	 * Walk the zone in pageblock_nr_pages steps. If a page block spans
28461cf5febSJoonsoo Kim 	 * a zone boundary, it will be double counted between zones. This does
28561cf5febSJoonsoo Kim 	 * not matter as the mixed block count will still be correct
28661cf5febSJoonsoo Kim 	 */
28761cf5febSJoonsoo Kim 	for (; pfn < end_pfn; ) {
28861cf5febSJoonsoo Kim 		if (!pfn_valid(pfn)) {
28961cf5febSJoonsoo Kim 			pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
29061cf5febSJoonsoo Kim 			continue;
29161cf5febSJoonsoo Kim 		}
29261cf5febSJoonsoo Kim 
29361cf5febSJoonsoo Kim 		block_end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
29461cf5febSJoonsoo Kim 		block_end_pfn = min(block_end_pfn, end_pfn);
29561cf5febSJoonsoo Kim 
29661cf5febSJoonsoo Kim 		page = pfn_to_page(pfn);
29761cf5febSJoonsoo Kim 
29861cf5febSJoonsoo Kim 		for (; pfn < block_end_pfn; pfn++) {
29961cf5febSJoonsoo Kim 			if (!pfn_valid_within(pfn))
30061cf5febSJoonsoo Kim 				continue;
30161cf5febSJoonsoo Kim 
30261cf5febSJoonsoo Kim 			page = pfn_to_page(pfn);
30361cf5febSJoonsoo Kim 
3049d43f5aeSJoonsoo Kim 			if (page_zone(page) != zone)
3059d43f5aeSJoonsoo Kim 				continue;
3069d43f5aeSJoonsoo Kim 
30761cf5febSJoonsoo Kim 			/*
30861cf5febSJoonsoo Kim 			 * We are safe to check buddy flag and order, because
30961cf5febSJoonsoo Kim 			 * this is init stage and only single thread runs.
31061cf5febSJoonsoo Kim 			 */
31161cf5febSJoonsoo Kim 			if (PageBuddy(page)) {
31261cf5febSJoonsoo Kim 				pfn += (1UL << page_order(page)) - 1;
31361cf5febSJoonsoo Kim 				continue;
31461cf5febSJoonsoo Kim 			}
31561cf5febSJoonsoo Kim 
31661cf5febSJoonsoo Kim 			if (PageReserved(page))
31761cf5febSJoonsoo Kim 				continue;
31861cf5febSJoonsoo Kim 
31961cf5febSJoonsoo Kim 			page_ext = lookup_page_ext(page);
32061cf5febSJoonsoo Kim 
32161cf5febSJoonsoo Kim 			/* Maybe overraping zone */
32261cf5febSJoonsoo Kim 			if (test_bit(PAGE_EXT_OWNER, &page_ext->flags))
32361cf5febSJoonsoo Kim 				continue;
32461cf5febSJoonsoo Kim 
32561cf5febSJoonsoo Kim 			/* Found early allocated page */
32661cf5febSJoonsoo Kim 			set_page_owner(page, 0, 0);
32761cf5febSJoonsoo Kim 			count++;
32861cf5febSJoonsoo Kim 		}
32961cf5febSJoonsoo Kim 	}
33061cf5febSJoonsoo Kim 
33161cf5febSJoonsoo Kim 	pr_info("Node %d, zone %8s: page owner found early allocated %lu pages\n",
33261cf5febSJoonsoo Kim 		pgdat->node_id, zone->name, count);
33361cf5febSJoonsoo Kim }
33461cf5febSJoonsoo Kim 
33561cf5febSJoonsoo Kim static void init_zones_in_node(pg_data_t *pgdat)
33661cf5febSJoonsoo Kim {
33761cf5febSJoonsoo Kim 	struct zone *zone;
33861cf5febSJoonsoo Kim 	struct zone *node_zones = pgdat->node_zones;
33961cf5febSJoonsoo Kim 	unsigned long flags;
34061cf5febSJoonsoo Kim 
34161cf5febSJoonsoo Kim 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
34261cf5febSJoonsoo Kim 		if (!populated_zone(zone))
34361cf5febSJoonsoo Kim 			continue;
34461cf5febSJoonsoo Kim 
34561cf5febSJoonsoo Kim 		spin_lock_irqsave(&zone->lock, flags);
34661cf5febSJoonsoo Kim 		init_pages_in_zone(pgdat, zone);
34761cf5febSJoonsoo Kim 		spin_unlock_irqrestore(&zone->lock, flags);
34861cf5febSJoonsoo Kim 	}
34961cf5febSJoonsoo Kim }
35061cf5febSJoonsoo Kim 
35161cf5febSJoonsoo Kim static void init_early_allocated_pages(void)
35261cf5febSJoonsoo Kim {
35361cf5febSJoonsoo Kim 	pg_data_t *pgdat;
35461cf5febSJoonsoo Kim 
35561cf5febSJoonsoo Kim 	drain_all_pages(NULL);
35661cf5febSJoonsoo Kim 	for_each_online_pgdat(pgdat)
35761cf5febSJoonsoo Kim 		init_zones_in_node(pgdat);
35861cf5febSJoonsoo Kim }
35961cf5febSJoonsoo Kim 
36048c96a36SJoonsoo Kim static const struct file_operations proc_page_owner_operations = {
36148c96a36SJoonsoo Kim 	.read		= read_page_owner,
36248c96a36SJoonsoo Kim };
36348c96a36SJoonsoo Kim 
36448c96a36SJoonsoo Kim static int __init pageowner_init(void)
36548c96a36SJoonsoo Kim {
36648c96a36SJoonsoo Kim 	struct dentry *dentry;
36748c96a36SJoonsoo Kim 
3687dd80b8aSVlastimil Babka 	if (!static_branch_unlikely(&page_owner_inited)) {
36948c96a36SJoonsoo Kim 		pr_info("page_owner is disabled\n");
37048c96a36SJoonsoo Kim 		return 0;
37148c96a36SJoonsoo Kim 	}
37248c96a36SJoonsoo Kim 
37348c96a36SJoonsoo Kim 	dentry = debugfs_create_file("page_owner", S_IRUSR, NULL,
37448c96a36SJoonsoo Kim 			NULL, &proc_page_owner_operations);
37548c96a36SJoonsoo Kim 	if (IS_ERR(dentry))
37648c96a36SJoonsoo Kim 		return PTR_ERR(dentry);
37748c96a36SJoonsoo Kim 
37848c96a36SJoonsoo Kim 	return 0;
37948c96a36SJoonsoo Kim }
38044c5af96SPaul Gortmaker late_initcall(pageowner_init)
381