162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/debugfs.h>
362306a36Sopenharmony_ci#include <linux/mm.h>
462306a36Sopenharmony_ci#include <linux/slab.h>
562306a36Sopenharmony_ci#include <linux/uaccess.h>
662306a36Sopenharmony_ci#include <linux/memblock.h>
762306a36Sopenharmony_ci#include <linux/stacktrace.h>
862306a36Sopenharmony_ci#include <linux/page_owner.h>
962306a36Sopenharmony_ci#include <linux/jump_label.h>
1062306a36Sopenharmony_ci#include <linux/migrate.h>
1162306a36Sopenharmony_ci#include <linux/stackdepot.h>
1262306a36Sopenharmony_ci#include <linux/seq_file.h>
1362306a36Sopenharmony_ci#include <linux/memcontrol.h>
1462306a36Sopenharmony_ci#include <linux/sched/clock.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "internal.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * TODO: teach PAGE_OWNER_STACK_DEPTH (__dump_page_owner and save_stack)
2062306a36Sopenharmony_ci * to use off stack temporal storage
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#define PAGE_OWNER_STACK_DEPTH (16)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct page_owner {
2562306a36Sopenharmony_ci	unsigned short order;
2662306a36Sopenharmony_ci	short last_migrate_reason;
2762306a36Sopenharmony_ci	gfp_t gfp_mask;
2862306a36Sopenharmony_ci	depot_stack_handle_t handle;
2962306a36Sopenharmony_ci	depot_stack_handle_t free_handle;
3062306a36Sopenharmony_ci	u64 ts_nsec;
3162306a36Sopenharmony_ci	u64 free_ts_nsec;
3262306a36Sopenharmony_ci	char comm[TASK_COMM_LEN];
3362306a36Sopenharmony_ci	pid_t pid;
3462306a36Sopenharmony_ci	pid_t tgid;
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic bool page_owner_enabled __initdata;
3862306a36Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(page_owner_inited);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic depot_stack_handle_t dummy_handle;
4162306a36Sopenharmony_cistatic depot_stack_handle_t failure_handle;
4262306a36Sopenharmony_cistatic depot_stack_handle_t early_handle;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic void init_early_allocated_pages(void);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int __init early_page_owner_param(char *buf)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int ret = kstrtobool(buf, &page_owner_enabled);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (page_owner_enabled)
5162306a36Sopenharmony_ci		stack_depot_request_early_init();
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return ret;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ciearly_param("page_owner", early_page_owner_param);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic __init bool need_page_owner(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return page_owner_enabled;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic __always_inline depot_stack_handle_t create_dummy_stack(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned long entries[4];
6562306a36Sopenharmony_ci	unsigned int nr_entries;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 0);
6862306a36Sopenharmony_ci	return stack_depot_save(entries, nr_entries, GFP_KERNEL);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic noinline void register_dummy_stack(void)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	dummy_handle = create_dummy_stack();
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic noinline void register_failure_stack(void)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	failure_handle = create_dummy_stack();
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic noinline void register_early_stack(void)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	early_handle = create_dummy_stack();
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic __init void init_page_owner(void)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	if (!page_owner_enabled)
8962306a36Sopenharmony_ci		return;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	register_dummy_stack();
9262306a36Sopenharmony_ci	register_failure_stack();
9362306a36Sopenharmony_ci	register_early_stack();
9462306a36Sopenharmony_ci	static_branch_enable(&page_owner_inited);
9562306a36Sopenharmony_ci	init_early_allocated_pages();
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct page_ext_operations page_owner_ops = {
9962306a36Sopenharmony_ci	.size = sizeof(struct page_owner),
10062306a36Sopenharmony_ci	.need = need_page_owner,
10162306a36Sopenharmony_ci	.init = init_page_owner,
10262306a36Sopenharmony_ci	.need_shared_flags = true,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline struct page_owner *get_page_owner(struct page_ext *page_ext)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	return page_ext_data(page_ext, &page_owner_ops);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic noinline depot_stack_handle_t save_stack(gfp_t flags)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	unsigned long entries[PAGE_OWNER_STACK_DEPTH];
11362306a36Sopenharmony_ci	depot_stack_handle_t handle;
11462306a36Sopenharmony_ci	unsigned int nr_entries;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/*
11762306a36Sopenharmony_ci	 * Avoid recursion.
11862306a36Sopenharmony_ci	 *
11962306a36Sopenharmony_ci	 * Sometimes page metadata allocation tracking requires more
12062306a36Sopenharmony_ci	 * memory to be allocated:
12162306a36Sopenharmony_ci	 * - when new stack trace is saved to stack depot
12262306a36Sopenharmony_ci	 * - when backtrace itself is calculated (ia64)
12362306a36Sopenharmony_ci	 */
12462306a36Sopenharmony_ci	if (current->in_page_owner)
12562306a36Sopenharmony_ci		return dummy_handle;
12662306a36Sopenharmony_ci	current->in_page_owner = 1;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 2);
12962306a36Sopenharmony_ci	handle = stack_depot_save(entries, nr_entries, flags);
13062306a36Sopenharmony_ci	if (!handle)
13162306a36Sopenharmony_ci		handle = failure_handle;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	current->in_page_owner = 0;
13462306a36Sopenharmony_ci	return handle;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_civoid __reset_page_owner(struct page *page, unsigned short order)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	int i;
14062306a36Sopenharmony_ci	struct page_ext *page_ext;
14162306a36Sopenharmony_ci	depot_stack_handle_t handle;
14262306a36Sopenharmony_ci	struct page_owner *page_owner;
14362306a36Sopenharmony_ci	u64 free_ts_nsec = local_clock();
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	page_ext = page_ext_get(page);
14662306a36Sopenharmony_ci	if (unlikely(!page_ext))
14762306a36Sopenharmony_ci		return;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	handle = save_stack(GFP_NOWAIT | __GFP_NOWARN);
15062306a36Sopenharmony_ci	for (i = 0; i < (1 << order); i++) {
15162306a36Sopenharmony_ci		__clear_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags);
15262306a36Sopenharmony_ci		page_owner = get_page_owner(page_ext);
15362306a36Sopenharmony_ci		page_owner->free_handle = handle;
15462306a36Sopenharmony_ci		page_owner->free_ts_nsec = free_ts_nsec;
15562306a36Sopenharmony_ci		page_ext = page_ext_next(page_ext);
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci	page_ext_put(page_ext);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline void __set_page_owner_handle(struct page_ext *page_ext,
16162306a36Sopenharmony_ci					depot_stack_handle_t handle,
16262306a36Sopenharmony_ci					unsigned short order, gfp_t gfp_mask)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct page_owner *page_owner;
16562306a36Sopenharmony_ci	int i;
16662306a36Sopenharmony_ci	u64 ts_nsec = local_clock();
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	for (i = 0; i < (1 << order); i++) {
16962306a36Sopenharmony_ci		page_owner = get_page_owner(page_ext);
17062306a36Sopenharmony_ci		page_owner->handle = handle;
17162306a36Sopenharmony_ci		page_owner->order = order;
17262306a36Sopenharmony_ci		page_owner->gfp_mask = gfp_mask;
17362306a36Sopenharmony_ci		page_owner->last_migrate_reason = -1;
17462306a36Sopenharmony_ci		page_owner->pid = current->pid;
17562306a36Sopenharmony_ci		page_owner->tgid = current->tgid;
17662306a36Sopenharmony_ci		page_owner->ts_nsec = ts_nsec;
17762306a36Sopenharmony_ci		strscpy(page_owner->comm, current->comm,
17862306a36Sopenharmony_ci			sizeof(page_owner->comm));
17962306a36Sopenharmony_ci		__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
18062306a36Sopenharmony_ci		__set_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		page_ext = page_ext_next(page_ext);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cinoinline void __set_page_owner(struct page *page, unsigned short order,
18762306a36Sopenharmony_ci					gfp_t gfp_mask)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct page_ext *page_ext;
19062306a36Sopenharmony_ci	depot_stack_handle_t handle;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	handle = save_stack(gfp_mask);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	page_ext = page_ext_get(page);
19562306a36Sopenharmony_ci	if (unlikely(!page_ext))
19662306a36Sopenharmony_ci		return;
19762306a36Sopenharmony_ci	__set_page_owner_handle(page_ext, handle, order, gfp_mask);
19862306a36Sopenharmony_ci	page_ext_put(page_ext);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_civoid __set_page_owner_migrate_reason(struct page *page, int reason)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct page_ext *page_ext = page_ext_get(page);
20462306a36Sopenharmony_ci	struct page_owner *page_owner;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (unlikely(!page_ext))
20762306a36Sopenharmony_ci		return;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	page_owner = get_page_owner(page_ext);
21062306a36Sopenharmony_ci	page_owner->last_migrate_reason = reason;
21162306a36Sopenharmony_ci	page_ext_put(page_ext);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_civoid __split_page_owner(struct page *page, unsigned int nr)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int i;
21762306a36Sopenharmony_ci	struct page_ext *page_ext = page_ext_get(page);
21862306a36Sopenharmony_ci	struct page_owner *page_owner;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (unlikely(!page_ext))
22162306a36Sopenharmony_ci		return;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
22462306a36Sopenharmony_ci		page_owner = get_page_owner(page_ext);
22562306a36Sopenharmony_ci		page_owner->order = 0;
22662306a36Sopenharmony_ci		page_ext = page_ext_next(page_ext);
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci	page_ext_put(page_ext);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_civoid __folio_copy_owner(struct folio *newfolio, struct folio *old)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct page_ext *old_ext;
23462306a36Sopenharmony_ci	struct page_ext *new_ext;
23562306a36Sopenharmony_ci	struct page_owner *old_page_owner, *new_page_owner;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	old_ext = page_ext_get(&old->page);
23862306a36Sopenharmony_ci	if (unlikely(!old_ext))
23962306a36Sopenharmony_ci		return;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	new_ext = page_ext_get(&newfolio->page);
24262306a36Sopenharmony_ci	if (unlikely(!new_ext)) {
24362306a36Sopenharmony_ci		page_ext_put(old_ext);
24462306a36Sopenharmony_ci		return;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	old_page_owner = get_page_owner(old_ext);
24862306a36Sopenharmony_ci	new_page_owner = get_page_owner(new_ext);
24962306a36Sopenharmony_ci	new_page_owner->order = old_page_owner->order;
25062306a36Sopenharmony_ci	new_page_owner->gfp_mask = old_page_owner->gfp_mask;
25162306a36Sopenharmony_ci	new_page_owner->last_migrate_reason =
25262306a36Sopenharmony_ci		old_page_owner->last_migrate_reason;
25362306a36Sopenharmony_ci	new_page_owner->handle = old_page_owner->handle;
25462306a36Sopenharmony_ci	new_page_owner->pid = old_page_owner->pid;
25562306a36Sopenharmony_ci	new_page_owner->tgid = old_page_owner->tgid;
25662306a36Sopenharmony_ci	new_page_owner->ts_nsec = old_page_owner->ts_nsec;
25762306a36Sopenharmony_ci	new_page_owner->free_ts_nsec = old_page_owner->ts_nsec;
25862306a36Sopenharmony_ci	strcpy(new_page_owner->comm, old_page_owner->comm);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * We don't clear the bit on the old folio as it's going to be freed
26262306a36Sopenharmony_ci	 * after migration. Until then, the info can be useful in case of
26362306a36Sopenharmony_ci	 * a bug, and the overall stats will be off a bit only temporarily.
26462306a36Sopenharmony_ci	 * Also, migrate_misplaced_transhuge_page() can still fail the
26562306a36Sopenharmony_ci	 * migration and then we want the old folio to retain the info. But
26662306a36Sopenharmony_ci	 * in that case we also don't need to explicitly clear the info from
26762306a36Sopenharmony_ci	 * the new page, which will be freed.
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
27062306a36Sopenharmony_ci	__set_bit(PAGE_EXT_OWNER_ALLOCATED, &new_ext->flags);
27162306a36Sopenharmony_ci	page_ext_put(new_ext);
27262306a36Sopenharmony_ci	page_ext_put(old_ext);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_civoid pagetypeinfo_showmixedcount_print(struct seq_file *m,
27662306a36Sopenharmony_ci				       pg_data_t *pgdat, struct zone *zone)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct page *page;
27962306a36Sopenharmony_ci	struct page_ext *page_ext;
28062306a36Sopenharmony_ci	struct page_owner *page_owner;
28162306a36Sopenharmony_ci	unsigned long pfn, block_end_pfn;
28262306a36Sopenharmony_ci	unsigned long end_pfn = zone_end_pfn(zone);
28362306a36Sopenharmony_ci	unsigned long count[MIGRATE_TYPES] = { 0, };
28462306a36Sopenharmony_ci	int pageblock_mt, page_mt;
28562306a36Sopenharmony_ci	int i;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Scan block by block. First and last block may be incomplete */
28862306a36Sopenharmony_ci	pfn = zone->zone_start_pfn;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/*
29162306a36Sopenharmony_ci	 * Walk the zone in pageblock_nr_pages steps. If a page block spans
29262306a36Sopenharmony_ci	 * a zone boundary, it will be double counted between zones. This does
29362306a36Sopenharmony_ci	 * not matter as the mixed block count will still be correct
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	for (; pfn < end_pfn; ) {
29662306a36Sopenharmony_ci		page = pfn_to_online_page(pfn);
29762306a36Sopenharmony_ci		if (!page) {
29862306a36Sopenharmony_ci			pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
29962306a36Sopenharmony_ci			continue;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		block_end_pfn = pageblock_end_pfn(pfn);
30362306a36Sopenharmony_ci		block_end_pfn = min(block_end_pfn, end_pfn);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		pageblock_mt = get_pageblock_migratetype(page);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		for (; pfn < block_end_pfn; pfn++) {
30862306a36Sopenharmony_ci			/* The pageblock is online, no need to recheck. */
30962306a36Sopenharmony_ci			page = pfn_to_page(pfn);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci			if (page_zone(page) != zone)
31262306a36Sopenharmony_ci				continue;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci			if (PageBuddy(page)) {
31562306a36Sopenharmony_ci				unsigned long freepage_order;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci				freepage_order = buddy_order_unsafe(page);
31862306a36Sopenharmony_ci				if (freepage_order <= MAX_ORDER)
31962306a36Sopenharmony_ci					pfn += (1UL << freepage_order) - 1;
32062306a36Sopenharmony_ci				continue;
32162306a36Sopenharmony_ci			}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci			if (PageReserved(page))
32462306a36Sopenharmony_ci				continue;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci			page_ext = page_ext_get(page);
32762306a36Sopenharmony_ci			if (unlikely(!page_ext))
32862306a36Sopenharmony_ci				continue;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci			if (!test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags))
33162306a36Sopenharmony_ci				goto ext_put_continue;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci			page_owner = get_page_owner(page_ext);
33462306a36Sopenharmony_ci			page_mt = gfp_migratetype(page_owner->gfp_mask);
33562306a36Sopenharmony_ci			if (pageblock_mt != page_mt) {
33662306a36Sopenharmony_ci				if (is_migrate_cma(pageblock_mt))
33762306a36Sopenharmony_ci					count[MIGRATE_MOVABLE]++;
33862306a36Sopenharmony_ci				else
33962306a36Sopenharmony_ci					count[pageblock_mt]++;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci				pfn = block_end_pfn;
34262306a36Sopenharmony_ci				page_ext_put(page_ext);
34362306a36Sopenharmony_ci				break;
34462306a36Sopenharmony_ci			}
34562306a36Sopenharmony_ci			pfn += (1UL << page_owner->order) - 1;
34662306a36Sopenharmony_ciext_put_continue:
34762306a36Sopenharmony_ci			page_ext_put(page_ext);
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Print counts */
35262306a36Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
35362306a36Sopenharmony_ci	for (i = 0; i < MIGRATE_TYPES; i++)
35462306a36Sopenharmony_ci		seq_printf(m, "%12lu ", count[i]);
35562306a36Sopenharmony_ci	seq_putc(m, '\n');
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/*
35962306a36Sopenharmony_ci * Looking for memcg information and print it out
36062306a36Sopenharmony_ci */
36162306a36Sopenharmony_cistatic inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
36262306a36Sopenharmony_ci					 struct page *page)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci#ifdef CONFIG_MEMCG
36562306a36Sopenharmony_ci	unsigned long memcg_data;
36662306a36Sopenharmony_ci	struct mem_cgroup *memcg;
36762306a36Sopenharmony_ci	bool online;
36862306a36Sopenharmony_ci	char name[80];
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	rcu_read_lock();
37162306a36Sopenharmony_ci	memcg_data = READ_ONCE(page->memcg_data);
37262306a36Sopenharmony_ci	if (!memcg_data)
37362306a36Sopenharmony_ci		goto out_unlock;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (memcg_data & MEMCG_DATA_OBJCGS)
37662306a36Sopenharmony_ci		ret += scnprintf(kbuf + ret, count - ret,
37762306a36Sopenharmony_ci				"Slab cache page\n");
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	memcg = page_memcg_check(page);
38062306a36Sopenharmony_ci	if (!memcg)
38162306a36Sopenharmony_ci		goto out_unlock;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	online = (memcg->css.flags & CSS_ONLINE);
38462306a36Sopenharmony_ci	cgroup_name(memcg->css.cgroup, name, sizeof(name));
38562306a36Sopenharmony_ci	ret += scnprintf(kbuf + ret, count - ret,
38662306a36Sopenharmony_ci			"Charged %sto %smemcg %s\n",
38762306a36Sopenharmony_ci			PageMemcgKmem(page) ? "(via objcg) " : "",
38862306a36Sopenharmony_ci			online ? "" : "offline ",
38962306a36Sopenharmony_ci			name);
39062306a36Sopenharmony_ciout_unlock:
39162306a36Sopenharmony_ci	rcu_read_unlock();
39262306a36Sopenharmony_ci#endif /* CONFIG_MEMCG */
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return ret;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic ssize_t
39862306a36Sopenharmony_ciprint_page_owner(char __user *buf, size_t count, unsigned long pfn,
39962306a36Sopenharmony_ci		struct page *page, struct page_owner *page_owner,
40062306a36Sopenharmony_ci		depot_stack_handle_t handle)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	int ret, pageblock_mt, page_mt;
40362306a36Sopenharmony_ci	char *kbuf;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	count = min_t(size_t, count, PAGE_SIZE);
40662306a36Sopenharmony_ci	kbuf = kmalloc(count, GFP_KERNEL);
40762306a36Sopenharmony_ci	if (!kbuf)
40862306a36Sopenharmony_ci		return -ENOMEM;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	ret = scnprintf(kbuf, count,
41162306a36Sopenharmony_ci			"Page allocated via order %u, mask %#x(%pGg), pid %d, tgid %d (%s), ts %llu ns, free_ts %llu ns\n",
41262306a36Sopenharmony_ci			page_owner->order, page_owner->gfp_mask,
41362306a36Sopenharmony_ci			&page_owner->gfp_mask, page_owner->pid,
41462306a36Sopenharmony_ci			page_owner->tgid, page_owner->comm,
41562306a36Sopenharmony_ci			page_owner->ts_nsec, page_owner->free_ts_nsec);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Print information relevant to grouping pages by mobility */
41862306a36Sopenharmony_ci	pageblock_mt = get_pageblock_migratetype(page);
41962306a36Sopenharmony_ci	page_mt  = gfp_migratetype(page_owner->gfp_mask);
42062306a36Sopenharmony_ci	ret += scnprintf(kbuf + ret, count - ret,
42162306a36Sopenharmony_ci			"PFN 0x%lx type %s Block %lu type %s Flags %pGp\n",
42262306a36Sopenharmony_ci			pfn,
42362306a36Sopenharmony_ci			migratetype_names[page_mt],
42462306a36Sopenharmony_ci			pfn >> pageblock_order,
42562306a36Sopenharmony_ci			migratetype_names[pageblock_mt],
42662306a36Sopenharmony_ci			&page->flags);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	ret += stack_depot_snprint(handle, kbuf + ret, count - ret, 0);
42962306a36Sopenharmony_ci	if (ret >= count)
43062306a36Sopenharmony_ci		goto err;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (page_owner->last_migrate_reason != -1) {
43362306a36Sopenharmony_ci		ret += scnprintf(kbuf + ret, count - ret,
43462306a36Sopenharmony_ci			"Page has been migrated, last migrate reason: %s\n",
43562306a36Sopenharmony_ci			migrate_reason_names[page_owner->last_migrate_reason]);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = print_page_owner_memcg(kbuf, count, ret, page);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret += snprintf(kbuf + ret, count - ret, "\n");
44162306a36Sopenharmony_ci	if (ret >= count)
44262306a36Sopenharmony_ci		goto err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (copy_to_user(buf, kbuf, ret))
44562306a36Sopenharmony_ci		ret = -EFAULT;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	kfree(kbuf);
44862306a36Sopenharmony_ci	return ret;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cierr:
45162306a36Sopenharmony_ci	kfree(kbuf);
45262306a36Sopenharmony_ci	return -ENOMEM;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_civoid __dump_page_owner(const struct page *page)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct page_ext *page_ext = page_ext_get((void *)page);
45862306a36Sopenharmony_ci	struct page_owner *page_owner;
45962306a36Sopenharmony_ci	depot_stack_handle_t handle;
46062306a36Sopenharmony_ci	gfp_t gfp_mask;
46162306a36Sopenharmony_ci	int mt;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (unlikely(!page_ext)) {
46462306a36Sopenharmony_ci		pr_alert("There is not page extension available.\n");
46562306a36Sopenharmony_ci		return;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	page_owner = get_page_owner(page_ext);
46962306a36Sopenharmony_ci	gfp_mask = page_owner->gfp_mask;
47062306a36Sopenharmony_ci	mt = gfp_migratetype(gfp_mask);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) {
47362306a36Sopenharmony_ci		pr_alert("page_owner info is not present (never set?)\n");
47462306a36Sopenharmony_ci		page_ext_put(page_ext);
47562306a36Sopenharmony_ci		return;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags))
47962306a36Sopenharmony_ci		pr_alert("page_owner tracks the page as allocated\n");
48062306a36Sopenharmony_ci	else
48162306a36Sopenharmony_ci		pr_alert("page_owner tracks the page as freed\n");
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	pr_alert("page last allocated via order %u, migratetype %s, gfp_mask %#x(%pGg), pid %d, tgid %d (%s), ts %llu, free_ts %llu\n",
48462306a36Sopenharmony_ci		 page_owner->order, migratetype_names[mt], gfp_mask, &gfp_mask,
48562306a36Sopenharmony_ci		 page_owner->pid, page_owner->tgid, page_owner->comm,
48662306a36Sopenharmony_ci		 page_owner->ts_nsec, page_owner->free_ts_nsec);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	handle = READ_ONCE(page_owner->handle);
48962306a36Sopenharmony_ci	if (!handle)
49062306a36Sopenharmony_ci		pr_alert("page_owner allocation stack trace missing\n");
49162306a36Sopenharmony_ci	else
49262306a36Sopenharmony_ci		stack_depot_print(handle);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	handle = READ_ONCE(page_owner->free_handle);
49562306a36Sopenharmony_ci	if (!handle) {
49662306a36Sopenharmony_ci		pr_alert("page_owner free stack trace missing\n");
49762306a36Sopenharmony_ci	} else {
49862306a36Sopenharmony_ci		pr_alert("page last free stack trace:\n");
49962306a36Sopenharmony_ci		stack_depot_print(handle);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (page_owner->last_migrate_reason != -1)
50362306a36Sopenharmony_ci		pr_alert("page has been migrated, last migrate reason: %s\n",
50462306a36Sopenharmony_ci			migrate_reason_names[page_owner->last_migrate_reason]);
50562306a36Sopenharmony_ci	page_ext_put(page_ext);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic ssize_t
50962306a36Sopenharmony_ciread_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	unsigned long pfn;
51262306a36Sopenharmony_ci	struct page *page;
51362306a36Sopenharmony_ci	struct page_ext *page_ext;
51462306a36Sopenharmony_ci	struct page_owner *page_owner;
51562306a36Sopenharmony_ci	depot_stack_handle_t handle;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (!static_branch_unlikely(&page_owner_inited))
51862306a36Sopenharmony_ci		return -EINVAL;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	page = NULL;
52162306a36Sopenharmony_ci	if (*ppos == 0)
52262306a36Sopenharmony_ci		pfn = min_low_pfn;
52362306a36Sopenharmony_ci	else
52462306a36Sopenharmony_ci		pfn = *ppos;
52562306a36Sopenharmony_ci	/* Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area */
52662306a36Sopenharmony_ci	while (!pfn_valid(pfn) && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0)
52762306a36Sopenharmony_ci		pfn++;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* Find an allocated page */
53062306a36Sopenharmony_ci	for (; pfn < max_pfn; pfn++) {
53162306a36Sopenharmony_ci		/*
53262306a36Sopenharmony_ci		 * This temporary page_owner is required so
53362306a36Sopenharmony_ci		 * that we can avoid the context switches while holding
53462306a36Sopenharmony_ci		 * the rcu lock and copying the page owner information to
53562306a36Sopenharmony_ci		 * user through copy_to_user() or GFP_KERNEL allocations.
53662306a36Sopenharmony_ci		 */
53762306a36Sopenharmony_ci		struct page_owner page_owner_tmp;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		/*
54062306a36Sopenharmony_ci		 * If the new page is in a new MAX_ORDER_NR_PAGES area,
54162306a36Sopenharmony_ci		 * validate the area as existing, skip it if not
54262306a36Sopenharmony_ci		 */
54362306a36Sopenharmony_ci		if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0 && !pfn_valid(pfn)) {
54462306a36Sopenharmony_ci			pfn += MAX_ORDER_NR_PAGES - 1;
54562306a36Sopenharmony_ci			continue;
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		page = pfn_to_page(pfn);
54962306a36Sopenharmony_ci		if (PageBuddy(page)) {
55062306a36Sopenharmony_ci			unsigned long freepage_order = buddy_order_unsafe(page);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci			if (freepage_order <= MAX_ORDER)
55362306a36Sopenharmony_ci				pfn += (1UL << freepage_order) - 1;
55462306a36Sopenharmony_ci			continue;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		page_ext = page_ext_get(page);
55862306a36Sopenharmony_ci		if (unlikely(!page_ext))
55962306a36Sopenharmony_ci			continue;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		/*
56262306a36Sopenharmony_ci		 * Some pages could be missed by concurrent allocation or free,
56362306a36Sopenharmony_ci		 * because we don't hold the zone lock.
56462306a36Sopenharmony_ci		 */
56562306a36Sopenharmony_ci		if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags))
56662306a36Sopenharmony_ci			goto ext_put_continue;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		/*
56962306a36Sopenharmony_ci		 * Although we do have the info about past allocation of free
57062306a36Sopenharmony_ci		 * pages, it's not relevant for current memory usage.
57162306a36Sopenharmony_ci		 */
57262306a36Sopenharmony_ci		if (!test_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags))
57362306a36Sopenharmony_ci			goto ext_put_continue;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		page_owner = get_page_owner(page_ext);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		/*
57862306a36Sopenharmony_ci		 * Don't print "tail" pages of high-order allocations as that
57962306a36Sopenharmony_ci		 * would inflate the stats.
58062306a36Sopenharmony_ci		 */
58162306a36Sopenharmony_ci		if (!IS_ALIGNED(pfn, 1 << page_owner->order))
58262306a36Sopenharmony_ci			goto ext_put_continue;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		/*
58562306a36Sopenharmony_ci		 * Access to page_ext->handle isn't synchronous so we should
58662306a36Sopenharmony_ci		 * be careful to access it.
58762306a36Sopenharmony_ci		 */
58862306a36Sopenharmony_ci		handle = READ_ONCE(page_owner->handle);
58962306a36Sopenharmony_ci		if (!handle)
59062306a36Sopenharmony_ci			goto ext_put_continue;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		/* Record the next PFN to read in the file offset */
59362306a36Sopenharmony_ci		*ppos = pfn + 1;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		page_owner_tmp = *page_owner;
59662306a36Sopenharmony_ci		page_ext_put(page_ext);
59762306a36Sopenharmony_ci		return print_page_owner(buf, count, pfn, page,
59862306a36Sopenharmony_ci				&page_owner_tmp, handle);
59962306a36Sopenharmony_ciext_put_continue:
60062306a36Sopenharmony_ci		page_ext_put(page_ext);
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return 0;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic loff_t lseek_page_owner(struct file *file, loff_t offset, int orig)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	switch (orig) {
60962306a36Sopenharmony_ci	case SEEK_SET:
61062306a36Sopenharmony_ci		file->f_pos = offset;
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	case SEEK_CUR:
61362306a36Sopenharmony_ci		file->f_pos += offset;
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	default:
61662306a36Sopenharmony_ci		return -EINVAL;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	return file->f_pos;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	unsigned long pfn = zone->zone_start_pfn;
62462306a36Sopenharmony_ci	unsigned long end_pfn = zone_end_pfn(zone);
62562306a36Sopenharmony_ci	unsigned long count = 0;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/*
62862306a36Sopenharmony_ci	 * Walk the zone in pageblock_nr_pages steps. If a page block spans
62962306a36Sopenharmony_ci	 * a zone boundary, it will be double counted between zones. This does
63062306a36Sopenharmony_ci	 * not matter as the mixed block count will still be correct
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	for (; pfn < end_pfn; ) {
63362306a36Sopenharmony_ci		unsigned long block_end_pfn;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		if (!pfn_valid(pfn)) {
63662306a36Sopenharmony_ci			pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
63762306a36Sopenharmony_ci			continue;
63862306a36Sopenharmony_ci		}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		block_end_pfn = pageblock_end_pfn(pfn);
64162306a36Sopenharmony_ci		block_end_pfn = min(block_end_pfn, end_pfn);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		for (; pfn < block_end_pfn; pfn++) {
64462306a36Sopenharmony_ci			struct page *page = pfn_to_page(pfn);
64562306a36Sopenharmony_ci			struct page_ext *page_ext;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci			if (page_zone(page) != zone)
64862306a36Sopenharmony_ci				continue;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci			/*
65162306a36Sopenharmony_ci			 * To avoid having to grab zone->lock, be a little
65262306a36Sopenharmony_ci			 * careful when reading buddy page order. The only
65362306a36Sopenharmony_ci			 * danger is that we skip too much and potentially miss
65462306a36Sopenharmony_ci			 * some early allocated pages, which is better than
65562306a36Sopenharmony_ci			 * heavy lock contention.
65662306a36Sopenharmony_ci			 */
65762306a36Sopenharmony_ci			if (PageBuddy(page)) {
65862306a36Sopenharmony_ci				unsigned long order = buddy_order_unsafe(page);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci				if (order > 0 && order <= MAX_ORDER)
66162306a36Sopenharmony_ci					pfn += (1UL << order) - 1;
66262306a36Sopenharmony_ci				continue;
66362306a36Sopenharmony_ci			}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci			if (PageReserved(page))
66662306a36Sopenharmony_ci				continue;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci			page_ext = page_ext_get(page);
66962306a36Sopenharmony_ci			if (unlikely(!page_ext))
67062306a36Sopenharmony_ci				continue;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci			/* Maybe overlapping zone */
67362306a36Sopenharmony_ci			if (test_bit(PAGE_EXT_OWNER, &page_ext->flags))
67462306a36Sopenharmony_ci				goto ext_put_continue;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci			/* Found early allocated page */
67762306a36Sopenharmony_ci			__set_page_owner_handle(page_ext, early_handle,
67862306a36Sopenharmony_ci						0, 0);
67962306a36Sopenharmony_ci			count++;
68062306a36Sopenharmony_ciext_put_continue:
68162306a36Sopenharmony_ci			page_ext_put(page_ext);
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci		cond_resched();
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	pr_info("Node %d, zone %8s: page owner found early allocated %lu pages\n",
68762306a36Sopenharmony_ci		pgdat->node_id, zone->name, count);
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic void init_zones_in_node(pg_data_t *pgdat)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	struct zone *zone;
69362306a36Sopenharmony_ci	struct zone *node_zones = pgdat->node_zones;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
69662306a36Sopenharmony_ci		if (!populated_zone(zone))
69762306a36Sopenharmony_ci			continue;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		init_pages_in_zone(pgdat, zone);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic void init_early_allocated_pages(void)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	pg_data_t *pgdat;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	for_each_online_pgdat(pgdat)
70862306a36Sopenharmony_ci		init_zones_in_node(pgdat);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic const struct file_operations proc_page_owner_operations = {
71262306a36Sopenharmony_ci	.read		= read_page_owner,
71362306a36Sopenharmony_ci	.llseek		= lseek_page_owner,
71462306a36Sopenharmony_ci};
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int __init pageowner_init(void)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	if (!static_branch_unlikely(&page_owner_inited)) {
71962306a36Sopenharmony_ci		pr_info("page_owner is disabled\n");
72062306a36Sopenharmony_ci		return 0;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	debugfs_create_file("page_owner", 0400, NULL, NULL,
72462306a36Sopenharmony_ci			    &proc_page_owner_operations);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	return 0;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_cilate_initcall(pageowner_init)
729