18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/mm/vmstat.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Manages VM statistics
68c2ecf20Sopenharmony_ci *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  zoned VM statistics
98c2ecf20Sopenharmony_ci *  Copyright (C) 2006 Silicon Graphics, Inc.,
108c2ecf20Sopenharmony_ci *		Christoph Lameter <christoph@lameter.com>
118c2ecf20Sopenharmony_ci *  Copyright (C) 2008-2014 Christoph Lameter
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include <linux/fs.h>
148c2ecf20Sopenharmony_ci#include <linux/mm.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/cpu.h>
198c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
208c2ecf20Sopenharmony_ci#include <linux/vmstat.h>
218c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
228c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
238c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
248c2ecf20Sopenharmony_ci#include <linux/sched.h>
258c2ecf20Sopenharmony_ci#include <linux/math64.h>
268c2ecf20Sopenharmony_ci#include <linux/writeback.h>
278c2ecf20Sopenharmony_ci#include <linux/compaction.h>
288c2ecf20Sopenharmony_ci#include <linux/mm_inline.h>
298c2ecf20Sopenharmony_ci#include <linux/page_ext.h>
308c2ecf20Sopenharmony_ci#include <linux/page_owner.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "internal.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define NUMA_STATS_THRESHOLD (U16_MAX - 2)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
378c2ecf20Sopenharmony_ciint sysctl_vm_numa_stat = ENABLE_NUMA_STAT;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* zero numa counters within a zone */
408c2ecf20Sopenharmony_cistatic void zero_zone_numa_counters(struct zone *zone)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	int item, cpu;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++) {
458c2ecf20Sopenharmony_ci		atomic_long_set(&zone->vm_numa_stat[item], 0);
468c2ecf20Sopenharmony_ci		for_each_online_cpu(cpu)
478c2ecf20Sopenharmony_ci			per_cpu_ptr(zone->pageset, cpu)->vm_numa_stat_diff[item]
488c2ecf20Sopenharmony_ci						= 0;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* zero numa counters of all the populated zones */
538c2ecf20Sopenharmony_cistatic void zero_zones_numa_counters(void)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct zone *zone;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	for_each_populated_zone(zone)
588c2ecf20Sopenharmony_ci		zero_zone_numa_counters(zone);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* zero global numa counters */
628c2ecf20Sopenharmony_cistatic void zero_global_numa_counters(void)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	int item;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++)
678c2ecf20Sopenharmony_ci		atomic_long_set(&vm_numa_stat[item], 0);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void invalid_numa_statistics(void)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	zero_zones_numa_counters();
738c2ecf20Sopenharmony_ci	zero_global_numa_counters();
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(vm_numa_stat_lock);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciint sysctl_vm_numa_stat_handler(struct ctl_table *table, int write,
798c2ecf20Sopenharmony_ci		void *buffer, size_t *length, loff_t *ppos)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	int ret, oldval;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	mutex_lock(&vm_numa_stat_lock);
848c2ecf20Sopenharmony_ci	if (write)
858c2ecf20Sopenharmony_ci		oldval = sysctl_vm_numa_stat;
868c2ecf20Sopenharmony_ci	ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
878c2ecf20Sopenharmony_ci	if (ret || !write)
888c2ecf20Sopenharmony_ci		goto out;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (oldval == sysctl_vm_numa_stat)
918c2ecf20Sopenharmony_ci		goto out;
928c2ecf20Sopenharmony_ci	else if (sysctl_vm_numa_stat == ENABLE_NUMA_STAT) {
938c2ecf20Sopenharmony_ci		static_branch_enable(&vm_numa_stat_key);
948c2ecf20Sopenharmony_ci		pr_info("enable numa statistics\n");
958c2ecf20Sopenharmony_ci	} else {
968c2ecf20Sopenharmony_ci		static_branch_disable(&vm_numa_stat_key);
978c2ecf20Sopenharmony_ci		invalid_numa_statistics();
988c2ecf20Sopenharmony_ci		pr_info("disable numa statistics, and clear numa counters\n");
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ciout:
1028c2ecf20Sopenharmony_ci	mutex_unlock(&vm_numa_stat_lock);
1038c2ecf20Sopenharmony_ci	return ret;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci#endif
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#ifdef CONFIG_VM_EVENT_COUNTERS
1088c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
1098c2ecf20Sopenharmony_ciEXPORT_PER_CPU_SYMBOL(vm_event_states);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void sum_vm_events(unsigned long *ret)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	int cpu;
1148c2ecf20Sopenharmony_ci	int i;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	for_each_online_cpu(cpu) {
1198c2ecf20Sopenharmony_ci		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
1228c2ecf20Sopenharmony_ci			ret[i] += this->event[i];
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/*
1278c2ecf20Sopenharmony_ci * Accumulate the vm event counters across all CPUs.
1288c2ecf20Sopenharmony_ci * The result is unavoidably approximate - it can change
1298c2ecf20Sopenharmony_ci * during and after execution of this function.
1308c2ecf20Sopenharmony_ci*/
1318c2ecf20Sopenharmony_civoid all_vm_events(unsigned long *ret)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	get_online_cpus();
1348c2ecf20Sopenharmony_ci	sum_vm_events(ret);
1358c2ecf20Sopenharmony_ci	put_online_cpus();
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(all_vm_events);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/*
1408c2ecf20Sopenharmony_ci * Fold the foreign cpu events into our own.
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * This is adding to the events on one processor
1438c2ecf20Sopenharmony_ci * but keeps the global counts constant.
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_civoid vm_events_fold_cpu(int cpu)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
1488c2ecf20Sopenharmony_ci	int i;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
1518c2ecf20Sopenharmony_ci		count_vm_events(i, fold_state->event[i]);
1528c2ecf20Sopenharmony_ci		fold_state->event[i] = 0;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#endif /* CONFIG_VM_EVENT_COUNTERS */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/*
1598c2ecf20Sopenharmony_ci * Manage combined zone based / global counters
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * vm_stat contains the global counters
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_ciatomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
1648c2ecf20Sopenharmony_ciatomic_long_t vm_numa_stat[NR_VM_NUMA_STAT_ITEMS] __cacheline_aligned_in_smp;
1658c2ecf20Sopenharmony_ciatomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vm_zone_stat);
1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vm_numa_stat);
1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vm_node_stat);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciint calculate_pressure_threshold(struct zone *zone)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	int threshold;
1758c2ecf20Sopenharmony_ci	int watermark_distance;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/*
1788c2ecf20Sopenharmony_ci	 * As vmstats are not up to date, there is drift between the estimated
1798c2ecf20Sopenharmony_ci	 * and real values. For high thresholds and a high number of CPUs, it
1808c2ecf20Sopenharmony_ci	 * is possible for the min watermark to be breached while the estimated
1818c2ecf20Sopenharmony_ci	 * value looks fine. The pressure threshold is a reduced value such
1828c2ecf20Sopenharmony_ci	 * that even the maximum amount of drift will not accidentally breach
1838c2ecf20Sopenharmony_ci	 * the min watermark
1848c2ecf20Sopenharmony_ci	 */
1858c2ecf20Sopenharmony_ci	watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone);
1868c2ecf20Sopenharmony_ci	threshold = max(1, (int)(watermark_distance / num_online_cpus()));
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/*
1898c2ecf20Sopenharmony_ci	 * Maximum threshold is 125
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	threshold = min(125, threshold);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return threshold;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciint calculate_normal_threshold(struct zone *zone)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	int threshold;
1998c2ecf20Sopenharmony_ci	int mem;	/* memory in 128 MB units */
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/*
2028c2ecf20Sopenharmony_ci	 * The threshold scales with the number of processors and the amount
2038c2ecf20Sopenharmony_ci	 * of memory per zone. More memory means that we can defer updates for
2048c2ecf20Sopenharmony_ci	 * longer, more processors could lead to more contention.
2058c2ecf20Sopenharmony_ci 	 * fls() is used to have a cheap way of logarithmic scaling.
2068c2ecf20Sopenharmony_ci	 *
2078c2ecf20Sopenharmony_ci	 * Some sample thresholds:
2088c2ecf20Sopenharmony_ci	 *
2098c2ecf20Sopenharmony_ci	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
2108c2ecf20Sopenharmony_ci	 * ------------------------------------------------------------------
2118c2ecf20Sopenharmony_ci	 * 8		1		1	0.9-1 GB	4
2128c2ecf20Sopenharmony_ci	 * 16		2		2	0.9-1 GB	4
2138c2ecf20Sopenharmony_ci	 * 20 		2		2	1-2 GB		5
2148c2ecf20Sopenharmony_ci	 * 24		2		2	2-4 GB		6
2158c2ecf20Sopenharmony_ci	 * 28		2		2	4-8 GB		7
2168c2ecf20Sopenharmony_ci	 * 32		2		2	8-16 GB		8
2178c2ecf20Sopenharmony_ci	 * 4		2		2	<128M		1
2188c2ecf20Sopenharmony_ci	 * 30		4		3	2-4 GB		5
2198c2ecf20Sopenharmony_ci	 * 48		4		3	8-16 GB		8
2208c2ecf20Sopenharmony_ci	 * 32		8		4	1-2 GB		4
2218c2ecf20Sopenharmony_ci	 * 32		8		4	0.9-1GB		4
2228c2ecf20Sopenharmony_ci	 * 10		16		5	<128M		1
2238c2ecf20Sopenharmony_ci	 * 40		16		5	900M		4
2248c2ecf20Sopenharmony_ci	 * 70		64		7	2-4 GB		5
2258c2ecf20Sopenharmony_ci	 * 84		64		7	4-8 GB		6
2268c2ecf20Sopenharmony_ci	 * 108		512		9	4-8 GB		6
2278c2ecf20Sopenharmony_ci	 * 125		1024		10	8-16 GB		8
2288c2ecf20Sopenharmony_ci	 * 125		1024		10	16-32 GB	9
2298c2ecf20Sopenharmony_ci	 */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	mem = zone_managed_pages(zone) >> (27 - PAGE_SHIFT);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/*
2368c2ecf20Sopenharmony_ci	 * Maximum threshold is 125
2378c2ecf20Sopenharmony_ci	 */
2388c2ecf20Sopenharmony_ci	threshold = min(125, threshold);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return threshold;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/*
2448c2ecf20Sopenharmony_ci * Refresh the thresholds for each zone.
2458c2ecf20Sopenharmony_ci */
2468c2ecf20Sopenharmony_civoid refresh_zone_stat_thresholds(void)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;
2498c2ecf20Sopenharmony_ci	struct zone *zone;
2508c2ecf20Sopenharmony_ci	int cpu;
2518c2ecf20Sopenharmony_ci	int threshold;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* Zero current pgdat thresholds */
2548c2ecf20Sopenharmony_ci	for_each_online_pgdat(pgdat) {
2558c2ecf20Sopenharmony_ci		for_each_online_cpu(cpu) {
2568c2ecf20Sopenharmony_ci			per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	for_each_populated_zone(zone) {
2618c2ecf20Sopenharmony_ci		struct pglist_data *pgdat = zone->zone_pgdat;
2628c2ecf20Sopenharmony_ci		unsigned long max_drift, tolerate_drift;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		threshold = calculate_normal_threshold(zone);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci		for_each_online_cpu(cpu) {
2678c2ecf20Sopenharmony_ci			int pgdat_threshold;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci			per_cpu_ptr(zone->pageset, cpu)->stat_threshold
2708c2ecf20Sopenharmony_ci							= threshold;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci			/* Base nodestat threshold on the largest populated zone. */
2738c2ecf20Sopenharmony_ci			pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
2748c2ecf20Sopenharmony_ci			per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
2758c2ecf20Sopenharmony_ci				= max(threshold, pgdat_threshold);
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		/*
2798c2ecf20Sopenharmony_ci		 * Only set percpu_drift_mark if there is a danger that
2808c2ecf20Sopenharmony_ci		 * NR_FREE_PAGES reports the low watermark is ok when in fact
2818c2ecf20Sopenharmony_ci		 * the min watermark could be breached by an allocation
2828c2ecf20Sopenharmony_ci		 */
2838c2ecf20Sopenharmony_ci		tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone);
2848c2ecf20Sopenharmony_ci		max_drift = num_online_cpus() * threshold;
2858c2ecf20Sopenharmony_ci		if (max_drift > tolerate_drift)
2868c2ecf20Sopenharmony_ci			zone->percpu_drift_mark = high_wmark_pages(zone) +
2878c2ecf20Sopenharmony_ci					max_drift;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_civoid set_pgdat_percpu_threshold(pg_data_t *pgdat,
2928c2ecf20Sopenharmony_ci				int (*calculate_pressure)(struct zone *))
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct zone *zone;
2958c2ecf20Sopenharmony_ci	int cpu;
2968c2ecf20Sopenharmony_ci	int threshold;
2978c2ecf20Sopenharmony_ci	int i;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	for (i = 0; i < pgdat->nr_zones; i++) {
3008c2ecf20Sopenharmony_ci		zone = &pgdat->node_zones[i];
3018c2ecf20Sopenharmony_ci		if (!zone->percpu_drift_mark)
3028c2ecf20Sopenharmony_ci			continue;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		threshold = (*calculate_pressure)(zone);
3058c2ecf20Sopenharmony_ci		for_each_online_cpu(cpu)
3068c2ecf20Sopenharmony_ci			per_cpu_ptr(zone->pageset, cpu)->stat_threshold
3078c2ecf20Sopenharmony_ci							= threshold;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/*
3128c2ecf20Sopenharmony_ci * For use when we know that interrupts are disabled,
3138c2ecf20Sopenharmony_ci * or when we know that preemption is disabled and that
3148c2ecf20Sopenharmony_ci * particular counter cannot be updated from interrupt context.
3158c2ecf20Sopenharmony_ci */
3168c2ecf20Sopenharmony_civoid __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
3178c2ecf20Sopenharmony_ci			   long delta)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct per_cpu_pageset __percpu *pcp = zone->pageset;
3208c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_stat_diff + item;
3218c2ecf20Sopenharmony_ci	long x;
3228c2ecf20Sopenharmony_ci	long t;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	x = delta + __this_cpu_read(*p);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (unlikely(abs(x) > t)) {
3298c2ecf20Sopenharmony_ci		zone_page_state_add(x, zone, item);
3308c2ecf20Sopenharmony_ci		x = 0;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci	__this_cpu_write(*p, x);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mod_zone_page_state);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_civoid __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
3378c2ecf20Sopenharmony_ci				long delta)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
3408c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_node_stat_diff + item;
3418c2ecf20Sopenharmony_ci	long x;
3428c2ecf20Sopenharmony_ci	long t;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (vmstat_item_in_bytes(item)) {
3458c2ecf20Sopenharmony_ci		VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
3468c2ecf20Sopenharmony_ci		delta >>= PAGE_SHIFT;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	x = delta + __this_cpu_read(*p);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (unlikely(abs(x) > t)) {
3548c2ecf20Sopenharmony_ci		node_page_state_add(x, pgdat, item);
3558c2ecf20Sopenharmony_ci		x = 0;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	__this_cpu_write(*p, x);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mod_node_page_state);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/*
3628c2ecf20Sopenharmony_ci * Optimized increment and decrement functions.
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * These are only for a single page and therefore can take a struct page *
3658c2ecf20Sopenharmony_ci * argument instead of struct zone *. This allows the inclusion of the code
3668c2ecf20Sopenharmony_ci * generated for page_zone(page) into the optimized functions.
3678c2ecf20Sopenharmony_ci *
3688c2ecf20Sopenharmony_ci * No overflow check is necessary and therefore the differential can be
3698c2ecf20Sopenharmony_ci * incremented or decremented in place which may allow the compilers to
3708c2ecf20Sopenharmony_ci * generate better code.
3718c2ecf20Sopenharmony_ci * The increment or decrement is known and therefore one boundary check can
3728c2ecf20Sopenharmony_ci * be omitted.
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * NOTE: These functions are very performance sensitive. Change only
3758c2ecf20Sopenharmony_ci * with care.
3768c2ecf20Sopenharmony_ci *
3778c2ecf20Sopenharmony_ci * Some processors have inc/dec instructions that are atomic vs an interrupt.
3788c2ecf20Sopenharmony_ci * However, the code must first determine the differential location in a zone
3798c2ecf20Sopenharmony_ci * based on the processor number and then inc/dec the counter. There is no
3808c2ecf20Sopenharmony_ci * guarantee without disabling preemption that the processor will not change
3818c2ecf20Sopenharmony_ci * in between and therefore the atomicity vs. interrupt cannot be exploited
3828c2ecf20Sopenharmony_ci * in a useful way here.
3838c2ecf20Sopenharmony_ci */
3848c2ecf20Sopenharmony_civoid __inc_zone_state(struct zone *zone, enum zone_stat_item item)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct per_cpu_pageset __percpu *pcp = zone->pageset;
3878c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_stat_diff + item;
3888c2ecf20Sopenharmony_ci	s8 v, t;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	v = __this_cpu_inc_return(*p);
3918c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
3928c2ecf20Sopenharmony_ci	if (unlikely(v > t)) {
3938c2ecf20Sopenharmony_ci		s8 overstep = t >> 1;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		zone_page_state_add(v + overstep, zone, item);
3968c2ecf20Sopenharmony_ci		__this_cpu_write(*p, -overstep);
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_civoid __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
4038c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_node_stat_diff + item;
4048c2ecf20Sopenharmony_ci	s8 v, t;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	v = __this_cpu_inc_return(*p);
4098c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
4108c2ecf20Sopenharmony_ci	if (unlikely(v > t)) {
4118c2ecf20Sopenharmony_ci		s8 overstep = t >> 1;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci		node_page_state_add(v + overstep, pgdat, item);
4148c2ecf20Sopenharmony_ci		__this_cpu_write(*p, -overstep);
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_civoid __inc_zone_page_state(struct page *page, enum zone_stat_item item)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	__inc_zone_state(page_zone(page), item);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__inc_zone_page_state);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_civoid __inc_node_page_state(struct page *page, enum node_stat_item item)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	__inc_node_state(page_pgdat(page), item);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__inc_node_page_state);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_civoid __dec_zone_state(struct zone *zone, enum zone_stat_item item)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct per_cpu_pageset __percpu *pcp = zone->pageset;
4338c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_stat_diff + item;
4348c2ecf20Sopenharmony_ci	s8 v, t;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	v = __this_cpu_dec_return(*p);
4378c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
4388c2ecf20Sopenharmony_ci	if (unlikely(v < - t)) {
4398c2ecf20Sopenharmony_ci		s8 overstep = t >> 1;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		zone_page_state_add(v - overstep, zone, item);
4428c2ecf20Sopenharmony_ci		__this_cpu_write(*p, overstep);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_civoid __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
4498c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_node_stat_diff + item;
4508c2ecf20Sopenharmony_ci	s8 v, t;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	v = __this_cpu_dec_return(*p);
4558c2ecf20Sopenharmony_ci	t = __this_cpu_read(pcp->stat_threshold);
4568c2ecf20Sopenharmony_ci	if (unlikely(v < - t)) {
4578c2ecf20Sopenharmony_ci		s8 overstep = t >> 1;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		node_page_state_add(v - overstep, pgdat, item);
4608c2ecf20Sopenharmony_ci		__this_cpu_write(*p, overstep);
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_civoid __dec_zone_page_state(struct page *page, enum zone_stat_item item)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	__dec_zone_state(page_zone(page), item);
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__dec_zone_page_state);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_civoid __dec_node_page_state(struct page *page, enum node_stat_item item)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	__dec_node_state(page_pgdat(page), item);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__dec_node_page_state);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
4778c2ecf20Sopenharmony_ci/*
4788c2ecf20Sopenharmony_ci * If we have cmpxchg_local support then we do not need to incur the overhead
4798c2ecf20Sopenharmony_ci * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
4808c2ecf20Sopenharmony_ci *
4818c2ecf20Sopenharmony_ci * mod_state() modifies the zone counter state through atomic per cpu
4828c2ecf20Sopenharmony_ci * operations.
4838c2ecf20Sopenharmony_ci *
4848c2ecf20Sopenharmony_ci * Overstep mode specifies how overstep should handled:
4858c2ecf20Sopenharmony_ci *     0       No overstepping
4868c2ecf20Sopenharmony_ci *     1       Overstepping half of threshold
4878c2ecf20Sopenharmony_ci *     -1      Overstepping minus half of threshold
4888c2ecf20Sopenharmony_ci*/
4898c2ecf20Sopenharmony_cistatic inline void mod_zone_state(struct zone *zone,
4908c2ecf20Sopenharmony_ci       enum zone_stat_item item, long delta, int overstep_mode)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct per_cpu_pageset __percpu *pcp = zone->pageset;
4938c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_stat_diff + item;
4948c2ecf20Sopenharmony_ci	long o, n, t, z;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	do {
4978c2ecf20Sopenharmony_ci		z = 0;  /* overflow to zone counters */
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		/*
5008c2ecf20Sopenharmony_ci		 * The fetching of the stat_threshold is racy. We may apply
5018c2ecf20Sopenharmony_ci		 * a counter threshold to the wrong the cpu if we get
5028c2ecf20Sopenharmony_ci		 * rescheduled while executing here. However, the next
5038c2ecf20Sopenharmony_ci		 * counter update will apply the threshold again and
5048c2ecf20Sopenharmony_ci		 * therefore bring the counter under the threshold again.
5058c2ecf20Sopenharmony_ci		 *
5068c2ecf20Sopenharmony_ci		 * Most of the time the thresholds are the same anyways
5078c2ecf20Sopenharmony_ci		 * for all cpus in a zone.
5088c2ecf20Sopenharmony_ci		 */
5098c2ecf20Sopenharmony_ci		t = this_cpu_read(pcp->stat_threshold);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		o = this_cpu_read(*p);
5128c2ecf20Sopenharmony_ci		n = delta + o;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		if (abs(n) > t) {
5158c2ecf20Sopenharmony_ci			int os = overstep_mode * (t >> 1) ;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci			/* Overflow must be added to zone counters */
5188c2ecf20Sopenharmony_ci			z = n + os;
5198c2ecf20Sopenharmony_ci			n = -os;
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci	} while (this_cpu_cmpxchg(*p, o, n) != o);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (z)
5248c2ecf20Sopenharmony_ci		zone_page_state_add(z, zone, item);
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_civoid mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
5288c2ecf20Sopenharmony_ci			 long delta)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	mod_zone_state(zone, item, delta, 0);
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mod_zone_page_state);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_civoid inc_zone_page_state(struct page *page, enum zone_stat_item item)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	mod_zone_state(page_zone(page), item, 1, 1);
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inc_zone_page_state);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_civoid dec_zone_page_state(struct page *page, enum zone_stat_item item)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	mod_zone_state(page_zone(page), item, -1, -1);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dec_zone_page_state);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic inline void mod_node_state(struct pglist_data *pgdat,
5478c2ecf20Sopenharmony_ci       enum node_stat_item item, int delta, int overstep_mode)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
5508c2ecf20Sopenharmony_ci	s8 __percpu *p = pcp->vm_node_stat_diff + item;
5518c2ecf20Sopenharmony_ci	long o, n, t, z;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (vmstat_item_in_bytes(item)) {
5548c2ecf20Sopenharmony_ci		VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
5558c2ecf20Sopenharmony_ci		delta >>= PAGE_SHIFT;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	do {
5598c2ecf20Sopenharmony_ci		z = 0;  /* overflow to node counters */
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		/*
5628c2ecf20Sopenharmony_ci		 * The fetching of the stat_threshold is racy. We may apply
5638c2ecf20Sopenharmony_ci		 * a counter threshold to the wrong the cpu if we get
5648c2ecf20Sopenharmony_ci		 * rescheduled while executing here. However, the next
5658c2ecf20Sopenharmony_ci		 * counter update will apply the threshold again and
5668c2ecf20Sopenharmony_ci		 * therefore bring the counter under the threshold again.
5678c2ecf20Sopenharmony_ci		 *
5688c2ecf20Sopenharmony_ci		 * Most of the time the thresholds are the same anyways
5698c2ecf20Sopenharmony_ci		 * for all cpus in a node.
5708c2ecf20Sopenharmony_ci		 */
5718c2ecf20Sopenharmony_ci		t = this_cpu_read(pcp->stat_threshold);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		o = this_cpu_read(*p);
5748c2ecf20Sopenharmony_ci		n = delta + o;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		if (abs(n) > t) {
5778c2ecf20Sopenharmony_ci			int os = overstep_mode * (t >> 1) ;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci			/* Overflow must be added to node counters */
5808c2ecf20Sopenharmony_ci			z = n + os;
5818c2ecf20Sopenharmony_ci			n = -os;
5828c2ecf20Sopenharmony_ci		}
5838c2ecf20Sopenharmony_ci	} while (this_cpu_cmpxchg(*p, o, n) != o);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (z)
5868c2ecf20Sopenharmony_ci		node_page_state_add(z, pgdat, item);
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_civoid mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
5908c2ecf20Sopenharmony_ci					long delta)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	mod_node_state(pgdat, item, delta, 0);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mod_node_page_state);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_civoid inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	mod_node_state(pgdat, item, 1, 1);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_civoid inc_node_page_state(struct page *page, enum node_stat_item item)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	mod_node_state(page_pgdat(page), item, 1, 1);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inc_node_page_state);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_civoid dec_node_page_state(struct page *page, enum node_stat_item item)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	mod_node_state(page_pgdat(page), item, -1, -1);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dec_node_page_state);
6128c2ecf20Sopenharmony_ci#else
6138c2ecf20Sopenharmony_ci/*
6148c2ecf20Sopenharmony_ci * Use interrupt disable to serialize counter updates
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_civoid mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
6178c2ecf20Sopenharmony_ci			 long delta)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	unsigned long flags;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	local_irq_save(flags);
6228c2ecf20Sopenharmony_ci	__mod_zone_page_state(zone, item, delta);
6238c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mod_zone_page_state);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_civoid inc_zone_page_state(struct page *page, enum zone_stat_item item)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	unsigned long flags;
6308c2ecf20Sopenharmony_ci	struct zone *zone;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	zone = page_zone(page);
6338c2ecf20Sopenharmony_ci	local_irq_save(flags);
6348c2ecf20Sopenharmony_ci	__inc_zone_state(zone, item);
6358c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inc_zone_page_state);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_civoid dec_zone_page_state(struct page *page, enum zone_stat_item item)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	unsigned long flags;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	local_irq_save(flags);
6448c2ecf20Sopenharmony_ci	__dec_zone_page_state(page, item);
6458c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dec_zone_page_state);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_civoid inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	unsigned long flags;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	local_irq_save(flags);
6548c2ecf20Sopenharmony_ci	__inc_node_state(pgdat, item);
6558c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inc_node_state);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_civoid mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
6608c2ecf20Sopenharmony_ci					long delta)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	unsigned long flags;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	local_irq_save(flags);
6658c2ecf20Sopenharmony_ci	__mod_node_page_state(pgdat, item, delta);
6668c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mod_node_page_state);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_civoid inc_node_page_state(struct page *page, enum node_stat_item item)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	unsigned long flags;
6738c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	pgdat = page_pgdat(page);
6768c2ecf20Sopenharmony_ci	local_irq_save(flags);
6778c2ecf20Sopenharmony_ci	__inc_node_state(pgdat, item);
6788c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inc_node_page_state);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_civoid dec_node_page_state(struct page *page, enum node_stat_item item)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	unsigned long flags;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	local_irq_save(flags);
6878c2ecf20Sopenharmony_ci	__dec_node_page_state(page, item);
6888c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dec_node_page_state);
6918c2ecf20Sopenharmony_ci#endif
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci/*
6948c2ecf20Sopenharmony_ci * Fold a differential into the global counters.
6958c2ecf20Sopenharmony_ci * Returns the number of counters updated.
6968c2ecf20Sopenharmony_ci */
6978c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
6988c2ecf20Sopenharmony_cistatic int fold_diff(int *zone_diff, int *numa_diff, int *node_diff)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	int i;
7018c2ecf20Sopenharmony_ci	int changes = 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
7048c2ecf20Sopenharmony_ci		if (zone_diff[i]) {
7058c2ecf20Sopenharmony_ci			atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
7068c2ecf20Sopenharmony_ci			changes++;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
7108c2ecf20Sopenharmony_ci		if (numa_diff[i]) {
7118c2ecf20Sopenharmony_ci			atomic_long_add(numa_diff[i], &vm_numa_stat[i]);
7128c2ecf20Sopenharmony_ci			changes++;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
7168c2ecf20Sopenharmony_ci		if (node_diff[i]) {
7178c2ecf20Sopenharmony_ci			atomic_long_add(node_diff[i], &vm_node_stat[i]);
7188c2ecf20Sopenharmony_ci			changes++;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci	return changes;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci#else
7238c2ecf20Sopenharmony_cistatic int fold_diff(int *zone_diff, int *node_diff)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	int i;
7268c2ecf20Sopenharmony_ci	int changes = 0;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
7298c2ecf20Sopenharmony_ci		if (zone_diff[i]) {
7308c2ecf20Sopenharmony_ci			atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
7318c2ecf20Sopenharmony_ci			changes++;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
7358c2ecf20Sopenharmony_ci		if (node_diff[i]) {
7368c2ecf20Sopenharmony_ci			atomic_long_add(node_diff[i], &vm_node_stat[i]);
7378c2ecf20Sopenharmony_ci			changes++;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci	return changes;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci#endif /* CONFIG_NUMA */
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci/*
7448c2ecf20Sopenharmony_ci * Update the zone counters for the current cpu.
7458c2ecf20Sopenharmony_ci *
7468c2ecf20Sopenharmony_ci * Note that refresh_cpu_vm_stats strives to only access
7478c2ecf20Sopenharmony_ci * node local memory. The per cpu pagesets on remote zones are placed
7488c2ecf20Sopenharmony_ci * in the memory local to the processor using that pageset. So the
7498c2ecf20Sopenharmony_ci * loop over all zones will access a series of cachelines local to
7508c2ecf20Sopenharmony_ci * the processor.
7518c2ecf20Sopenharmony_ci *
7528c2ecf20Sopenharmony_ci * The call to zone_page_state_add updates the cachelines with the
7538c2ecf20Sopenharmony_ci * statistics in the remote zone struct as well as the global cachelines
7548c2ecf20Sopenharmony_ci * with the global counters. These could cause remote node cache line
7558c2ecf20Sopenharmony_ci * bouncing and will have to be only done when necessary.
7568c2ecf20Sopenharmony_ci *
7578c2ecf20Sopenharmony_ci * The function returns the number of global counters updated.
7588c2ecf20Sopenharmony_ci */
7598c2ecf20Sopenharmony_cistatic int refresh_cpu_vm_stats(bool do_pagesets)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;
7628c2ecf20Sopenharmony_ci	struct zone *zone;
7638c2ecf20Sopenharmony_ci	int i;
7648c2ecf20Sopenharmony_ci	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
7658c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
7668c2ecf20Sopenharmony_ci	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
7678c2ecf20Sopenharmony_ci#endif
7688c2ecf20Sopenharmony_ci	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
7698c2ecf20Sopenharmony_ci	int changes = 0;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	for_each_populated_zone(zone) {
7728c2ecf20Sopenharmony_ci		struct per_cpu_pageset __percpu *p = zone->pageset;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
7758c2ecf20Sopenharmony_ci			int v;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci			v = this_cpu_xchg(p->vm_stat_diff[i], 0);
7788c2ecf20Sopenharmony_ci			if (v) {
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci				atomic_long_add(v, &zone->vm_stat[i]);
7818c2ecf20Sopenharmony_ci				global_zone_diff[i] += v;
7828c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
7838c2ecf20Sopenharmony_ci				/* 3 seconds idle till flush */
7848c2ecf20Sopenharmony_ci				__this_cpu_write(p->expire, 3);
7858c2ecf20Sopenharmony_ci#endif
7868c2ecf20Sopenharmony_ci			}
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
7898c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
7908c2ecf20Sopenharmony_ci			int v;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci			v = this_cpu_xchg(p->vm_numa_stat_diff[i], 0);
7938c2ecf20Sopenharmony_ci			if (v) {
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci				atomic_long_add(v, &zone->vm_numa_stat[i]);
7968c2ecf20Sopenharmony_ci				global_numa_diff[i] += v;
7978c2ecf20Sopenharmony_ci				__this_cpu_write(p->expire, 3);
7988c2ecf20Sopenharmony_ci			}
7998c2ecf20Sopenharmony_ci		}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci		if (do_pagesets) {
8028c2ecf20Sopenharmony_ci			cond_resched();
8038c2ecf20Sopenharmony_ci			/*
8048c2ecf20Sopenharmony_ci			 * Deal with draining the remote pageset of this
8058c2ecf20Sopenharmony_ci			 * processor
8068c2ecf20Sopenharmony_ci			 *
8078c2ecf20Sopenharmony_ci			 * Check if there are pages remaining in this pageset
8088c2ecf20Sopenharmony_ci			 * if not then there is nothing to expire.
8098c2ecf20Sopenharmony_ci			 */
8108c2ecf20Sopenharmony_ci			if (!__this_cpu_read(p->expire) ||
8118c2ecf20Sopenharmony_ci			       !__this_cpu_read(p->pcp.count))
8128c2ecf20Sopenharmony_ci				continue;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci			/*
8158c2ecf20Sopenharmony_ci			 * We never drain zones local to this processor.
8168c2ecf20Sopenharmony_ci			 */
8178c2ecf20Sopenharmony_ci			if (zone_to_nid(zone) == numa_node_id()) {
8188c2ecf20Sopenharmony_ci				__this_cpu_write(p->expire, 0);
8198c2ecf20Sopenharmony_ci				continue;
8208c2ecf20Sopenharmony_ci			}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci			if (__this_cpu_dec_return(p->expire))
8238c2ecf20Sopenharmony_ci				continue;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci			if (__this_cpu_read(p->pcp.count)) {
8268c2ecf20Sopenharmony_ci				drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
8278c2ecf20Sopenharmony_ci				changes++;
8288c2ecf20Sopenharmony_ci			}
8298c2ecf20Sopenharmony_ci		}
8308c2ecf20Sopenharmony_ci#endif
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	for_each_online_pgdat(pgdat) {
8348c2ecf20Sopenharmony_ci		struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
8378c2ecf20Sopenharmony_ci			int v;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci			v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
8408c2ecf20Sopenharmony_ci			if (v) {
8418c2ecf20Sopenharmony_ci				atomic_long_add(v, &pgdat->vm_stat[i]);
8428c2ecf20Sopenharmony_ci				global_node_diff[i] += v;
8438c2ecf20Sopenharmony_ci			}
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
8488c2ecf20Sopenharmony_ci	changes += fold_diff(global_zone_diff, global_numa_diff,
8498c2ecf20Sopenharmony_ci			     global_node_diff);
8508c2ecf20Sopenharmony_ci#else
8518c2ecf20Sopenharmony_ci	changes += fold_diff(global_zone_diff, global_node_diff);
8528c2ecf20Sopenharmony_ci#endif
8538c2ecf20Sopenharmony_ci	return changes;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci/*
8578c2ecf20Sopenharmony_ci * Fold the data for an offline cpu into the global array.
8588c2ecf20Sopenharmony_ci * There cannot be any access by the offline cpu and therefore
8598c2ecf20Sopenharmony_ci * synchronization is simplified.
8608c2ecf20Sopenharmony_ci */
8618c2ecf20Sopenharmony_civoid cpu_vm_stats_fold(int cpu)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct pglist_data *pgdat;
8648c2ecf20Sopenharmony_ci	struct zone *zone;
8658c2ecf20Sopenharmony_ci	int i;
8668c2ecf20Sopenharmony_ci	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
8678c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
8688c2ecf20Sopenharmony_ci	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
8698c2ecf20Sopenharmony_ci#endif
8708c2ecf20Sopenharmony_ci	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	for_each_populated_zone(zone) {
8738c2ecf20Sopenharmony_ci		struct per_cpu_pageset *p;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		p = per_cpu_ptr(zone->pageset, cpu);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
8788c2ecf20Sopenharmony_ci			if (p->vm_stat_diff[i]) {
8798c2ecf20Sopenharmony_ci				int v;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci				v = p->vm_stat_diff[i];
8828c2ecf20Sopenharmony_ci				p->vm_stat_diff[i] = 0;
8838c2ecf20Sopenharmony_ci				atomic_long_add(v, &zone->vm_stat[i]);
8848c2ecf20Sopenharmony_ci				global_zone_diff[i] += v;
8858c2ecf20Sopenharmony_ci			}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
8888c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
8898c2ecf20Sopenharmony_ci			if (p->vm_numa_stat_diff[i]) {
8908c2ecf20Sopenharmony_ci				int v;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci				v = p->vm_numa_stat_diff[i];
8938c2ecf20Sopenharmony_ci				p->vm_numa_stat_diff[i] = 0;
8948c2ecf20Sopenharmony_ci				atomic_long_add(v, &zone->vm_numa_stat[i]);
8958c2ecf20Sopenharmony_ci				global_numa_diff[i] += v;
8968c2ecf20Sopenharmony_ci			}
8978c2ecf20Sopenharmony_ci#endif
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	for_each_online_pgdat(pgdat) {
9018c2ecf20Sopenharmony_ci		struct per_cpu_nodestat *p;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci		p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
9068c2ecf20Sopenharmony_ci			if (p->vm_node_stat_diff[i]) {
9078c2ecf20Sopenharmony_ci				int v;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci				v = p->vm_node_stat_diff[i];
9108c2ecf20Sopenharmony_ci				p->vm_node_stat_diff[i] = 0;
9118c2ecf20Sopenharmony_ci				atomic_long_add(v, &pgdat->vm_stat[i]);
9128c2ecf20Sopenharmony_ci				global_node_diff[i] += v;
9138c2ecf20Sopenharmony_ci			}
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
9178c2ecf20Sopenharmony_ci	fold_diff(global_zone_diff, global_numa_diff, global_node_diff);
9188c2ecf20Sopenharmony_ci#else
9198c2ecf20Sopenharmony_ci	fold_diff(global_zone_diff, global_node_diff);
9208c2ecf20Sopenharmony_ci#endif
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci/*
9248c2ecf20Sopenharmony_ci * this is only called if !populated_zone(zone), which implies no other users of
9258c2ecf20Sopenharmony_ci * pset->vm_stat_diff[] exsist.
9268c2ecf20Sopenharmony_ci */
9278c2ecf20Sopenharmony_civoid drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	int i;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
9328c2ecf20Sopenharmony_ci		if (pset->vm_stat_diff[i]) {
9338c2ecf20Sopenharmony_ci			int v = pset->vm_stat_diff[i];
9348c2ecf20Sopenharmony_ci			pset->vm_stat_diff[i] = 0;
9358c2ecf20Sopenharmony_ci			atomic_long_add(v, &zone->vm_stat[i]);
9368c2ecf20Sopenharmony_ci			atomic_long_add(v, &vm_zone_stat[i]);
9378c2ecf20Sopenharmony_ci		}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
9408c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
9418c2ecf20Sopenharmony_ci		if (pset->vm_numa_stat_diff[i]) {
9428c2ecf20Sopenharmony_ci			int v = pset->vm_numa_stat_diff[i];
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci			pset->vm_numa_stat_diff[i] = 0;
9458c2ecf20Sopenharmony_ci			atomic_long_add(v, &zone->vm_numa_stat[i]);
9468c2ecf20Sopenharmony_ci			atomic_long_add(v, &vm_numa_stat[i]);
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci#endif
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci#endif
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
9538c2ecf20Sopenharmony_civoid __inc_numa_state(struct zone *zone,
9548c2ecf20Sopenharmony_ci				 enum numa_stat_item item)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	struct per_cpu_pageset __percpu *pcp = zone->pageset;
9578c2ecf20Sopenharmony_ci	u16 __percpu *p = pcp->vm_numa_stat_diff + item;
9588c2ecf20Sopenharmony_ci	u16 v;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	v = __this_cpu_inc_return(*p);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	if (unlikely(v > NUMA_STATS_THRESHOLD)) {
9638c2ecf20Sopenharmony_ci		zone_numa_state_add(v, zone, item);
9648c2ecf20Sopenharmony_ci		__this_cpu_write(*p, 0);
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci/*
9698c2ecf20Sopenharmony_ci * Determine the per node value of a stat item. This function
9708c2ecf20Sopenharmony_ci * is called frequently in a NUMA machine, so try to be as
9718c2ecf20Sopenharmony_ci * frugal as possible.
9728c2ecf20Sopenharmony_ci */
9738c2ecf20Sopenharmony_ciunsigned long sum_zone_node_page_state(int node,
9748c2ecf20Sopenharmony_ci				 enum zone_stat_item item)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct zone *zones = NODE_DATA(node)->node_zones;
9778c2ecf20Sopenharmony_ci	int i;
9788c2ecf20Sopenharmony_ci	unsigned long count = 0;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_NR_ZONES; i++)
9818c2ecf20Sopenharmony_ci		count += zone_page_state(zones + i, item);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return count;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci/*
9878c2ecf20Sopenharmony_ci * Determine the per node value of a numa stat item. To avoid deviation,
9888c2ecf20Sopenharmony_ci * the per cpu stat number in vm_numa_stat_diff[] is also included.
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_ciunsigned long sum_zone_numa_state(int node,
9918c2ecf20Sopenharmony_ci				 enum numa_stat_item item)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct zone *zones = NODE_DATA(node)->node_zones;
9948c2ecf20Sopenharmony_ci	int i;
9958c2ecf20Sopenharmony_ci	unsigned long count = 0;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_NR_ZONES; i++)
9988c2ecf20Sopenharmony_ci		count += zone_numa_state_snapshot(zones + i, item);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	return count;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci/*
10048c2ecf20Sopenharmony_ci * Determine the per node value of a stat item.
10058c2ecf20Sopenharmony_ci */
10068c2ecf20Sopenharmony_ciunsigned long node_page_state_pages(struct pglist_data *pgdat,
10078c2ecf20Sopenharmony_ci				    enum node_stat_item item)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	long x = atomic_long_read(&pgdat->vm_stat[item]);
10108c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
10118c2ecf20Sopenharmony_ci	if (x < 0)
10128c2ecf20Sopenharmony_ci		x = 0;
10138c2ecf20Sopenharmony_ci#endif
10148c2ecf20Sopenharmony_ci	return x;
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ciunsigned long node_page_state(struct pglist_data *pgdat,
10188c2ecf20Sopenharmony_ci			      enum node_stat_item item)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	return node_page_state_pages(pgdat, item);
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci#endif
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPACTION
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistruct contig_page_info {
10298c2ecf20Sopenharmony_ci	unsigned long free_pages;
10308c2ecf20Sopenharmony_ci	unsigned long free_blocks_total;
10318c2ecf20Sopenharmony_ci	unsigned long free_blocks_suitable;
10328c2ecf20Sopenharmony_ci};
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci/*
10358c2ecf20Sopenharmony_ci * Calculate the number of free pages in a zone, how many contiguous
10368c2ecf20Sopenharmony_ci * pages are free and how many are large enough to satisfy an allocation of
10378c2ecf20Sopenharmony_ci * the target size. Note that this function makes no attempt to estimate
10388c2ecf20Sopenharmony_ci * how many suitable free blocks there *might* be if MOVABLE pages were
10398c2ecf20Sopenharmony_ci * migrated. Calculating that is possible, but expensive and can be
10408c2ecf20Sopenharmony_ci * figured out from userspace
10418c2ecf20Sopenharmony_ci */
10428c2ecf20Sopenharmony_cistatic void fill_contig_page_info(struct zone *zone,
10438c2ecf20Sopenharmony_ci				unsigned int suitable_order,
10448c2ecf20Sopenharmony_ci				struct contig_page_info *info)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	unsigned int order;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	info->free_pages = 0;
10498c2ecf20Sopenharmony_ci	info->free_blocks_total = 0;
10508c2ecf20Sopenharmony_ci	info->free_blocks_suitable = 0;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	for (order = 0; order < MAX_ORDER; order++) {
10538c2ecf20Sopenharmony_ci		unsigned long blocks;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci		/* Count number of free blocks */
10568c2ecf20Sopenharmony_ci		blocks = zone->free_area[order].nr_free;
10578c2ecf20Sopenharmony_ci		info->free_blocks_total += blocks;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci		/* Count free base pages */
10608c2ecf20Sopenharmony_ci		info->free_pages += blocks << order;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci		/* Count the suitable free blocks */
10638c2ecf20Sopenharmony_ci		if (order >= suitable_order)
10648c2ecf20Sopenharmony_ci			info->free_blocks_suitable += blocks <<
10658c2ecf20Sopenharmony_ci						(order - suitable_order);
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci/*
10708c2ecf20Sopenharmony_ci * A fragmentation index only makes sense if an allocation of a requested
10718c2ecf20Sopenharmony_ci * size would fail. If that is true, the fragmentation index indicates
10728c2ecf20Sopenharmony_ci * whether external fragmentation or a lack of memory was the problem.
10738c2ecf20Sopenharmony_ci * The value can be used to determine if page reclaim or compaction
10748c2ecf20Sopenharmony_ci * should be used
10758c2ecf20Sopenharmony_ci */
10768c2ecf20Sopenharmony_cistatic int __fragmentation_index(unsigned int order, struct contig_page_info *info)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	unsigned long requested = 1UL << order;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(order >= MAX_ORDER))
10818c2ecf20Sopenharmony_ci		return 0;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (!info->free_blocks_total)
10848c2ecf20Sopenharmony_ci		return 0;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	/* Fragmentation index only makes sense when a request would fail */
10878c2ecf20Sopenharmony_ci	if (info->free_blocks_suitable)
10888c2ecf20Sopenharmony_ci		return -1000;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	/*
10918c2ecf20Sopenharmony_ci	 * Index is between 0 and 1 so return within 3 decimal places
10928c2ecf20Sopenharmony_ci	 *
10938c2ecf20Sopenharmony_ci	 * 0 => allocation would fail due to lack of memory
10948c2ecf20Sopenharmony_ci	 * 1 => allocation would fail due to fragmentation
10958c2ecf20Sopenharmony_ci	 */
10968c2ecf20Sopenharmony_ci	return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci/*
11008c2ecf20Sopenharmony_ci * Calculates external fragmentation within a zone wrt the given order.
11018c2ecf20Sopenharmony_ci * It is defined as the percentage of pages found in blocks of size
11028c2ecf20Sopenharmony_ci * less than 1 << order. It returns values in range [0, 100].
11038c2ecf20Sopenharmony_ci */
11048c2ecf20Sopenharmony_ciunsigned int extfrag_for_order(struct zone *zone, unsigned int order)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	struct contig_page_info info;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	fill_contig_page_info(zone, order, &info);
11098c2ecf20Sopenharmony_ci	if (info.free_pages == 0)
11108c2ecf20Sopenharmony_ci		return 0;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	return div_u64((info.free_pages -
11138c2ecf20Sopenharmony_ci			(info.free_blocks_suitable << order)) * 100,
11148c2ecf20Sopenharmony_ci			info.free_pages);
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci/* Same as __fragmentation index but allocs contig_page_info on stack */
11188c2ecf20Sopenharmony_ciint fragmentation_index(struct zone *zone, unsigned int order)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct contig_page_info info;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	fill_contig_page_info(zone, order, &info);
11238c2ecf20Sopenharmony_ci	return __fragmentation_index(order, &info);
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci#endif
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
11288c2ecf20Sopenharmony_ci    defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
11298c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA
11308c2ecf20Sopenharmony_ci#define TEXT_FOR_DMA(xx) xx "_dma",
11318c2ecf20Sopenharmony_ci#else
11328c2ecf20Sopenharmony_ci#define TEXT_FOR_DMA(xx)
11338c2ecf20Sopenharmony_ci#endif
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32
11368c2ecf20Sopenharmony_ci#define TEXT_FOR_DMA32(xx) xx "_dma32",
11378c2ecf20Sopenharmony_ci#else
11388c2ecf20Sopenharmony_ci#define TEXT_FOR_DMA32(xx)
11398c2ecf20Sopenharmony_ci#endif
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM
11428c2ecf20Sopenharmony_ci#define TEXT_FOR_HIGHMEM(xx) xx "_high",
11438c2ecf20Sopenharmony_ci#else
11448c2ecf20Sopenharmony_ci#define TEXT_FOR_HIGHMEM(xx)
11458c2ecf20Sopenharmony_ci#endif
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
11488c2ecf20Sopenharmony_ci					TEXT_FOR_HIGHMEM(xx) xx "_movable",
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ciconst char * const vmstat_text[] = {
11518c2ecf20Sopenharmony_ci	/* enum zone_stat_item counters */
11528c2ecf20Sopenharmony_ci	"nr_free_pages",
11538c2ecf20Sopenharmony_ci	"nr_zone_inactive_anon",
11548c2ecf20Sopenharmony_ci	"nr_zone_active_anon",
11558c2ecf20Sopenharmony_ci	"nr_zone_inactive_file",
11568c2ecf20Sopenharmony_ci	"nr_zone_active_file",
11578c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_PURGEABLE
11588c2ecf20Sopenharmony_ci	"nr_zone_inactive_purgeable",
11598c2ecf20Sopenharmony_ci	"nr_zone_active_purgeable",
11608c2ecf20Sopenharmony_ci#endif
11618c2ecf20Sopenharmony_ci	"nr_zone_unevictable",
11628c2ecf20Sopenharmony_ci	"nr_zone_write_pending",
11638c2ecf20Sopenharmony_ci	"nr_mlock",
11648c2ecf20Sopenharmony_ci	"nr_page_table_pages",
11658c2ecf20Sopenharmony_ci	"nr_bounce",
11668c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_ZSMALLOC)
11678c2ecf20Sopenharmony_ci	"nr_zspages",
11688c2ecf20Sopenharmony_ci#endif
11698c2ecf20Sopenharmony_ci	"nr_free_cma",
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci#ifdef CONFIG_PAGE_TRACING
11728c2ecf20Sopenharmony_ci	"nr_skb_pages",
11738c2ecf20Sopenharmony_ci#endif
11748c2ecf20Sopenharmony_ci	/* enum numa_stat_item counters */
11758c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
11768c2ecf20Sopenharmony_ci	"numa_hit",
11778c2ecf20Sopenharmony_ci	"numa_miss",
11788c2ecf20Sopenharmony_ci	"numa_foreign",
11798c2ecf20Sopenharmony_ci	"numa_interleave",
11808c2ecf20Sopenharmony_ci	"numa_local",
11818c2ecf20Sopenharmony_ci	"numa_other",
11828c2ecf20Sopenharmony_ci#endif
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	/* enum node_stat_item counters */
11858c2ecf20Sopenharmony_ci	"nr_inactive_anon",
11868c2ecf20Sopenharmony_ci	"nr_active_anon",
11878c2ecf20Sopenharmony_ci	"nr_inactive_file",
11888c2ecf20Sopenharmony_ci	"nr_active_file",
11898c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_PURGEABLE
11908c2ecf20Sopenharmony_ci	"nr_inactive_purgeable",
11918c2ecf20Sopenharmony_ci	"nr_active_purgeable",
11928c2ecf20Sopenharmony_ci#endif
11938c2ecf20Sopenharmony_ci	"nr_unevictable",
11948c2ecf20Sopenharmony_ci	"nr_slab_reclaimable",
11958c2ecf20Sopenharmony_ci	"nr_slab_unreclaimable",
11968c2ecf20Sopenharmony_ci	"nr_isolated_anon",
11978c2ecf20Sopenharmony_ci	"nr_isolated_file",
11988c2ecf20Sopenharmony_ci	"workingset_nodes",
11998c2ecf20Sopenharmony_ci	"workingset_refault_anon",
12008c2ecf20Sopenharmony_ci	"workingset_refault_file",
12018c2ecf20Sopenharmony_ci	"workingset_activate_anon",
12028c2ecf20Sopenharmony_ci	"workingset_activate_file",
12038c2ecf20Sopenharmony_ci	"workingset_restore_anon",
12048c2ecf20Sopenharmony_ci	"workingset_restore_file",
12058c2ecf20Sopenharmony_ci	"workingset_nodereclaim",
12068c2ecf20Sopenharmony_ci	"nr_anon_pages",
12078c2ecf20Sopenharmony_ci	"nr_mapped",
12088c2ecf20Sopenharmony_ci	"nr_file_pages",
12098c2ecf20Sopenharmony_ci	"nr_dirty",
12108c2ecf20Sopenharmony_ci	"nr_writeback",
12118c2ecf20Sopenharmony_ci	"nr_writeback_temp",
12128c2ecf20Sopenharmony_ci	"nr_shmem",
12138c2ecf20Sopenharmony_ci	"nr_shmem_hugepages",
12148c2ecf20Sopenharmony_ci	"nr_shmem_pmdmapped",
12158c2ecf20Sopenharmony_ci	"nr_file_hugepages",
12168c2ecf20Sopenharmony_ci	"nr_file_pmdmapped",
12178c2ecf20Sopenharmony_ci	"nr_anon_transparent_hugepages",
12188c2ecf20Sopenharmony_ci	"nr_vmscan_write",
12198c2ecf20Sopenharmony_ci	"nr_vmscan_immediate_reclaim",
12208c2ecf20Sopenharmony_ci	"nr_dirtied",
12218c2ecf20Sopenharmony_ci	"nr_written",
12228c2ecf20Sopenharmony_ci	"nr_kernel_misc_reclaimable",
12238c2ecf20Sopenharmony_ci	"nr_foll_pin_acquired",
12248c2ecf20Sopenharmony_ci	"nr_foll_pin_released",
12258c2ecf20Sopenharmony_ci	"nr_kernel_stack",
12268c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
12278c2ecf20Sopenharmony_ci	"nr_shadow_call_stack",
12288c2ecf20Sopenharmony_ci#endif
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* enum writeback_stat_item counters */
12318c2ecf20Sopenharmony_ci	"nr_dirty_threshold",
12328c2ecf20Sopenharmony_ci	"nr_dirty_background_threshold",
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci#if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
12358c2ecf20Sopenharmony_ci	/* enum vm_event_item counters */
12368c2ecf20Sopenharmony_ci	"pgpgin",
12378c2ecf20Sopenharmony_ci	"pgpgout",
12388c2ecf20Sopenharmony_ci	"pswpin",
12398c2ecf20Sopenharmony_ci	"pswpout",
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	TEXTS_FOR_ZONES("pgalloc")
12428c2ecf20Sopenharmony_ci	TEXTS_FOR_ZONES("allocstall")
12438c2ecf20Sopenharmony_ci	TEXTS_FOR_ZONES("pgskip")
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	"pgfree",
12468c2ecf20Sopenharmony_ci	"pgactivate",
12478c2ecf20Sopenharmony_ci	"pgdeactivate",
12488c2ecf20Sopenharmony_ci	"pglazyfree",
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	"pgfault",
12518c2ecf20Sopenharmony_ci	"pgmajfault",
12528c2ecf20Sopenharmony_ci	"pglazyfreed",
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	"pgrefill",
12558c2ecf20Sopenharmony_ci	"pgreuse",
12568c2ecf20Sopenharmony_ci	"pgsteal_kswapd",
12578c2ecf20Sopenharmony_ci	"pgsteal_direct",
12588c2ecf20Sopenharmony_ci	"pgscan_kswapd",
12598c2ecf20Sopenharmony_ci	"pgscan_direct",
12608c2ecf20Sopenharmony_ci	"pgscan_direct_throttle",
12618c2ecf20Sopenharmony_ci	"pgscan_anon",
12628c2ecf20Sopenharmony_ci	"pgscan_file",
12638c2ecf20Sopenharmony_ci	"pgsteal_anon",
12648c2ecf20Sopenharmony_ci	"pgsteal_file",
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
12678c2ecf20Sopenharmony_ci	"zone_reclaim_failed",
12688c2ecf20Sopenharmony_ci#endif
12698c2ecf20Sopenharmony_ci	"pginodesteal",
12708c2ecf20Sopenharmony_ci	"slabs_scanned",
12718c2ecf20Sopenharmony_ci	"kswapd_inodesteal",
12728c2ecf20Sopenharmony_ci	"kswapd_low_wmark_hit_quickly",
12738c2ecf20Sopenharmony_ci	"kswapd_high_wmark_hit_quickly",
12748c2ecf20Sopenharmony_ci	"pageoutrun",
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	"pgrotated",
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	"drop_pagecache",
12798c2ecf20Sopenharmony_ci	"drop_slab",
12808c2ecf20Sopenharmony_ci	"oom_kill",
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING
12838c2ecf20Sopenharmony_ci	"numa_pte_updates",
12848c2ecf20Sopenharmony_ci	"numa_huge_pte_updates",
12858c2ecf20Sopenharmony_ci	"numa_hint_faults",
12868c2ecf20Sopenharmony_ci	"numa_hint_faults_local",
12878c2ecf20Sopenharmony_ci	"numa_pages_migrated",
12888c2ecf20Sopenharmony_ci#endif
12898c2ecf20Sopenharmony_ci#ifdef CONFIG_MIGRATION
12908c2ecf20Sopenharmony_ci	"pgmigrate_success",
12918c2ecf20Sopenharmony_ci	"pgmigrate_fail",
12928c2ecf20Sopenharmony_ci	"thp_migration_success",
12938c2ecf20Sopenharmony_ci	"thp_migration_fail",
12948c2ecf20Sopenharmony_ci	"thp_migration_split",
12958c2ecf20Sopenharmony_ci#endif
12968c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPACTION
12978c2ecf20Sopenharmony_ci	"compact_migrate_scanned",
12988c2ecf20Sopenharmony_ci	"compact_free_scanned",
12998c2ecf20Sopenharmony_ci	"compact_isolated",
13008c2ecf20Sopenharmony_ci	"compact_stall",
13018c2ecf20Sopenharmony_ci	"compact_fail",
13028c2ecf20Sopenharmony_ci	"compact_success",
13038c2ecf20Sopenharmony_ci	"compact_daemon_wake",
13048c2ecf20Sopenharmony_ci	"compact_daemon_migrate_scanned",
13058c2ecf20Sopenharmony_ci	"compact_daemon_free_scanned",
13068c2ecf20Sopenharmony_ci#endif
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE
13098c2ecf20Sopenharmony_ci	"htlb_buddy_alloc_success",
13108c2ecf20Sopenharmony_ci	"htlb_buddy_alloc_fail",
13118c2ecf20Sopenharmony_ci#endif
13128c2ecf20Sopenharmony_ci	"unevictable_pgs_culled",
13138c2ecf20Sopenharmony_ci	"unevictable_pgs_scanned",
13148c2ecf20Sopenharmony_ci	"unevictable_pgs_rescued",
13158c2ecf20Sopenharmony_ci	"unevictable_pgs_mlocked",
13168c2ecf20Sopenharmony_ci	"unevictable_pgs_munlocked",
13178c2ecf20Sopenharmony_ci	"unevictable_pgs_cleared",
13188c2ecf20Sopenharmony_ci	"unevictable_pgs_stranded",
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE
13218c2ecf20Sopenharmony_ci	"thp_fault_alloc",
13228c2ecf20Sopenharmony_ci	"thp_fault_fallback",
13238c2ecf20Sopenharmony_ci	"thp_fault_fallback_charge",
13248c2ecf20Sopenharmony_ci	"thp_collapse_alloc",
13258c2ecf20Sopenharmony_ci	"thp_collapse_alloc_failed",
13268c2ecf20Sopenharmony_ci	"thp_file_alloc",
13278c2ecf20Sopenharmony_ci	"thp_file_fallback",
13288c2ecf20Sopenharmony_ci	"thp_file_fallback_charge",
13298c2ecf20Sopenharmony_ci	"thp_file_mapped",
13308c2ecf20Sopenharmony_ci	"thp_split_page",
13318c2ecf20Sopenharmony_ci	"thp_split_page_failed",
13328c2ecf20Sopenharmony_ci	"thp_deferred_split_page",
13338c2ecf20Sopenharmony_ci	"thp_split_pmd",
13348c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
13358c2ecf20Sopenharmony_ci	"thp_split_pud",
13368c2ecf20Sopenharmony_ci#endif
13378c2ecf20Sopenharmony_ci	"thp_zero_page_alloc",
13388c2ecf20Sopenharmony_ci	"thp_zero_page_alloc_failed",
13398c2ecf20Sopenharmony_ci	"thp_swpout",
13408c2ecf20Sopenharmony_ci	"thp_swpout_fallback",
13418c2ecf20Sopenharmony_ci#endif
13428c2ecf20Sopenharmony_ci#ifdef CONFIG_MEMORY_BALLOON
13438c2ecf20Sopenharmony_ci	"balloon_inflate",
13448c2ecf20Sopenharmony_ci	"balloon_deflate",
13458c2ecf20Sopenharmony_ci#ifdef CONFIG_BALLOON_COMPACTION
13468c2ecf20Sopenharmony_ci	"balloon_migrate",
13478c2ecf20Sopenharmony_ci#endif
13488c2ecf20Sopenharmony_ci#endif /* CONFIG_MEMORY_BALLOON */
13498c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_TLBFLUSH
13508c2ecf20Sopenharmony_ci	"nr_tlb_remote_flush",
13518c2ecf20Sopenharmony_ci	"nr_tlb_remote_flush_received",
13528c2ecf20Sopenharmony_ci	"nr_tlb_local_flush_all",
13538c2ecf20Sopenharmony_ci	"nr_tlb_local_flush_one",
13548c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_TLBFLUSH */
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_VM_VMACACHE
13578c2ecf20Sopenharmony_ci	"vmacache_find_calls",
13588c2ecf20Sopenharmony_ci	"vmacache_find_hits",
13598c2ecf20Sopenharmony_ci#endif
13608c2ecf20Sopenharmony_ci#ifdef CONFIG_SWAP
13618c2ecf20Sopenharmony_ci	"swap_ra",
13628c2ecf20Sopenharmony_ci	"swap_ra_hit",
13638c2ecf20Sopenharmony_ci#endif
13648c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_ZSWAPD
13658c2ecf20Sopenharmony_ci	"zswapd_running",
13668c2ecf20Sopenharmony_ci	"zswapd_hit_refaults",
13678c2ecf20Sopenharmony_ci	"zswapd_medium_press",
13688c2ecf20Sopenharmony_ci	"zswapd_critical_press",
13698c2ecf20Sopenharmony_ci	"zswapd_memcg_ratio_skip",
13708c2ecf20Sopenharmony_ci	"zswapd_memcg_refault_skip",
13718c2ecf20Sopenharmony_ci	"zswapd_swapout",
13728c2ecf20Sopenharmony_ci	"zswapd_empty_round",
13738c2ecf20Sopenharmony_ci	"zswapd_empty_round_skip_times",
13748c2ecf20Sopenharmony_ci	"zswapd_snapshot_times",
13758c2ecf20Sopenharmony_ci	"zswapd_reclaimed",
13768c2ecf20Sopenharmony_ci	"zswapd_scanned",
13778c2ecf20Sopenharmony_ci#endif
13788c2ecf20Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_MEMCG
13798c2ecf20Sopenharmony_ci	"freeze_reclaimed",
13808c2ecf20Sopenharmony_ci	"freeze_reclaim_count",
13818c2ecf20Sopenharmony_ci#endif
13828c2ecf20Sopenharmony_ci#endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
13838c2ecf20Sopenharmony_ci};
13848c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA || CONFIG_MEMCG */
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
13878c2ecf20Sopenharmony_ci     defined(CONFIG_PROC_FS)
13888c2ecf20Sopenharmony_cistatic void *frag_start(struct seq_file *m, loff_t *pos)
13898c2ecf20Sopenharmony_ci{
13908c2ecf20Sopenharmony_ci	pg_data_t *pgdat;
13918c2ecf20Sopenharmony_ci	loff_t node = *pos;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	for (pgdat = first_online_pgdat();
13948c2ecf20Sopenharmony_ci	     pgdat && node;
13958c2ecf20Sopenharmony_ci	     pgdat = next_online_pgdat(pgdat))
13968c2ecf20Sopenharmony_ci		--node;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	return pgdat;
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	(*pos)++;
14068c2ecf20Sopenharmony_ci	return next_online_pgdat(pgdat);
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_cistatic void frag_stop(struct seq_file *m, void *arg)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci/*
14148c2ecf20Sopenharmony_ci * Walk zones in a node and print using a callback.
14158c2ecf20Sopenharmony_ci * If @assert_populated is true, only use callback for zones that are populated.
14168c2ecf20Sopenharmony_ci */
14178c2ecf20Sopenharmony_cistatic void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
14188c2ecf20Sopenharmony_ci		bool assert_populated, bool nolock,
14198c2ecf20Sopenharmony_ci		void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
14208c2ecf20Sopenharmony_ci{
14218c2ecf20Sopenharmony_ci	struct zone *zone;
14228c2ecf20Sopenharmony_ci	struct zone *node_zones = pgdat->node_zones;
14238c2ecf20Sopenharmony_ci	unsigned long flags;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
14268c2ecf20Sopenharmony_ci		if (assert_populated && !populated_zone(zone))
14278c2ecf20Sopenharmony_ci			continue;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		if (!nolock)
14308c2ecf20Sopenharmony_ci			spin_lock_irqsave(&zone->lock, flags);
14318c2ecf20Sopenharmony_ci		print(m, pgdat, zone);
14328c2ecf20Sopenharmony_ci		if (!nolock)
14338c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&zone->lock, flags);
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ci#endif
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
14398c2ecf20Sopenharmony_cistatic void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
14408c2ecf20Sopenharmony_ci						struct zone *zone)
14418c2ecf20Sopenharmony_ci{
14428c2ecf20Sopenharmony_ci	int order;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
14458c2ecf20Sopenharmony_ci	for (order = 0; order < MAX_ORDER; ++order)
14468c2ecf20Sopenharmony_ci		seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
14478c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci/*
14518c2ecf20Sopenharmony_ci * This walks the free areas for each zone.
14528c2ecf20Sopenharmony_ci */
14538c2ecf20Sopenharmony_cistatic int frag_show(struct seq_file *m, void *arg)
14548c2ecf20Sopenharmony_ci{
14558c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
14568c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, false, frag_show_print);
14578c2ecf20Sopenharmony_ci	return 0;
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic void pagetypeinfo_showfree_print(struct seq_file *m,
14618c2ecf20Sopenharmony_ci					pg_data_t *pgdat, struct zone *zone)
14628c2ecf20Sopenharmony_ci{
14638c2ecf20Sopenharmony_ci	int order, mtype;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
14668c2ecf20Sopenharmony_ci		seq_printf(m, "Node %4d, zone %8s, type %12s ",
14678c2ecf20Sopenharmony_ci					pgdat->node_id,
14688c2ecf20Sopenharmony_ci					zone->name,
14698c2ecf20Sopenharmony_ci					migratetype_names[mtype]);
14708c2ecf20Sopenharmony_ci		for (order = 0; order < MAX_ORDER; ++order) {
14718c2ecf20Sopenharmony_ci			unsigned long freecount = 0;
14728c2ecf20Sopenharmony_ci			struct free_area *area;
14738c2ecf20Sopenharmony_ci			struct list_head *curr;
14748c2ecf20Sopenharmony_ci			bool overflow = false;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci			area = &(zone->free_area[order]);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci			list_for_each(curr, &area->free_list[mtype]) {
14798c2ecf20Sopenharmony_ci				/*
14808c2ecf20Sopenharmony_ci				 * Cap the free_list iteration because it might
14818c2ecf20Sopenharmony_ci				 * be really large and we are under a spinlock
14828c2ecf20Sopenharmony_ci				 * so a long time spent here could trigger a
14838c2ecf20Sopenharmony_ci				 * hard lockup detector. Anyway this is a
14848c2ecf20Sopenharmony_ci				 * debugging tool so knowing there is a handful
14858c2ecf20Sopenharmony_ci				 * of pages of this order should be more than
14868c2ecf20Sopenharmony_ci				 * sufficient.
14878c2ecf20Sopenharmony_ci				 */
14888c2ecf20Sopenharmony_ci				if (++freecount >= 100000) {
14898c2ecf20Sopenharmony_ci					overflow = true;
14908c2ecf20Sopenharmony_ci					break;
14918c2ecf20Sopenharmony_ci				}
14928c2ecf20Sopenharmony_ci			}
14938c2ecf20Sopenharmony_ci			seq_printf(m, "%s%6lu ", overflow ? ">" : "", freecount);
14948c2ecf20Sopenharmony_ci			spin_unlock_irq(&zone->lock);
14958c2ecf20Sopenharmony_ci			cond_resched();
14968c2ecf20Sopenharmony_ci			spin_lock_irq(&zone->lock);
14978c2ecf20Sopenharmony_ci		}
14988c2ecf20Sopenharmony_ci		seq_putc(m, '\n');
14998c2ecf20Sopenharmony_ci	}
15008c2ecf20Sopenharmony_ci}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci/* Print out the free pages at each order for each migatetype */
15038c2ecf20Sopenharmony_cistatic int pagetypeinfo_showfree(struct seq_file *m, void *arg)
15048c2ecf20Sopenharmony_ci{
15058c2ecf20Sopenharmony_ci	int order;
15068c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	/* Print header */
15098c2ecf20Sopenharmony_ci	seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
15108c2ecf20Sopenharmony_ci	for (order = 0; order < MAX_ORDER; ++order)
15118c2ecf20Sopenharmony_ci		seq_printf(m, "%6d ", order);
15128c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	return 0;
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_cistatic void pagetypeinfo_showblockcount_print(struct seq_file *m,
15208c2ecf20Sopenharmony_ci					pg_data_t *pgdat, struct zone *zone)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	int mtype;
15238c2ecf20Sopenharmony_ci	unsigned long pfn;
15248c2ecf20Sopenharmony_ci	unsigned long start_pfn = zone->zone_start_pfn;
15258c2ecf20Sopenharmony_ci	unsigned long end_pfn = zone_end_pfn(zone);
15268c2ecf20Sopenharmony_ci	unsigned long count[MIGRATE_TYPES] = { 0, };
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
15298c2ecf20Sopenharmony_ci		struct page *page;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci		page = pfn_to_online_page(pfn);
15328c2ecf20Sopenharmony_ci		if (!page)
15338c2ecf20Sopenharmony_ci			continue;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci		if (page_zone(page) != zone)
15368c2ecf20Sopenharmony_ci			continue;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		mtype = get_pageblock_migratetype(page);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci		if (mtype < MIGRATE_TYPES)
15418c2ecf20Sopenharmony_ci			count[mtype]++;
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	/* Print counts */
15458c2ecf20Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
15468c2ecf20Sopenharmony_ci	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
15478c2ecf20Sopenharmony_ci		seq_printf(m, "%12lu ", count[mtype]);
15488c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
15498c2ecf20Sopenharmony_ci}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci/* Print out the number of pageblocks for each migratetype */
15528c2ecf20Sopenharmony_cistatic int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
15538c2ecf20Sopenharmony_ci{
15548c2ecf20Sopenharmony_ci	int mtype;
15558c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	seq_printf(m, "\n%-23s", "Number of blocks type ");
15588c2ecf20Sopenharmony_ci	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
15598c2ecf20Sopenharmony_ci		seq_printf(m, "%12s ", migratetype_names[mtype]);
15608c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
15618c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, false,
15628c2ecf20Sopenharmony_ci		pagetypeinfo_showblockcount_print);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	return 0;
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci/*
15688c2ecf20Sopenharmony_ci * Print out the number of pageblocks for each migratetype that contain pages
15698c2ecf20Sopenharmony_ci * of other types. This gives an indication of how well fallbacks are being
15708c2ecf20Sopenharmony_ci * contained by rmqueue_fallback(). It requires information from PAGE_OWNER
15718c2ecf20Sopenharmony_ci * to determine what is going on
15728c2ecf20Sopenharmony_ci */
15738c2ecf20Sopenharmony_cistatic void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci#ifdef CONFIG_PAGE_OWNER
15768c2ecf20Sopenharmony_ci	int mtype;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (!static_branch_unlikely(&page_owner_inited))
15798c2ecf20Sopenharmony_ci		return;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	drain_all_pages(NULL);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	seq_printf(m, "\n%-23s", "Number of mixed blocks ");
15848c2ecf20Sopenharmony_ci	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
15858c2ecf20Sopenharmony_ci		seq_printf(m, "%12s ", migratetype_names[mtype]);
15868c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, true,
15898c2ecf20Sopenharmony_ci		pagetypeinfo_showmixedcount_print);
15908c2ecf20Sopenharmony_ci#endif /* CONFIG_PAGE_OWNER */
15918c2ecf20Sopenharmony_ci}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci/*
15948c2ecf20Sopenharmony_ci * This prints out statistics in relation to grouping pages by mobility.
15958c2ecf20Sopenharmony_ci * It is expensive to collect so do not constantly read the file.
15968c2ecf20Sopenharmony_ci */
15978c2ecf20Sopenharmony_cistatic int pagetypeinfo_show(struct seq_file *m, void *arg)
15988c2ecf20Sopenharmony_ci{
15998c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	/* check memoryless node */
16028c2ecf20Sopenharmony_ci	if (!node_state(pgdat->node_id, N_MEMORY))
16038c2ecf20Sopenharmony_ci		return 0;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	seq_printf(m, "Page block order: %d\n", pageblock_order);
16068c2ecf20Sopenharmony_ci	seq_printf(m, "Pages per block:  %lu\n", pageblock_nr_pages);
16078c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
16088c2ecf20Sopenharmony_ci	pagetypeinfo_showfree(m, pgdat);
16098c2ecf20Sopenharmony_ci	pagetypeinfo_showblockcount(m, pgdat);
16108c2ecf20Sopenharmony_ci	pagetypeinfo_showmixedcount(m, pgdat);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	return 0;
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic const struct seq_operations fragmentation_op = {
16168c2ecf20Sopenharmony_ci	.start	= frag_start,
16178c2ecf20Sopenharmony_ci	.next	= frag_next,
16188c2ecf20Sopenharmony_ci	.stop	= frag_stop,
16198c2ecf20Sopenharmony_ci	.show	= frag_show,
16208c2ecf20Sopenharmony_ci};
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cistatic const struct seq_operations pagetypeinfo_op = {
16238c2ecf20Sopenharmony_ci	.start	= frag_start,
16248c2ecf20Sopenharmony_ci	.next	= frag_next,
16258c2ecf20Sopenharmony_ci	.stop	= frag_stop,
16268c2ecf20Sopenharmony_ci	.show	= pagetypeinfo_show,
16278c2ecf20Sopenharmony_ci};
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	int zid;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	for (zid = 0; zid < MAX_NR_ZONES; zid++) {
16348c2ecf20Sopenharmony_ci		struct zone *compare = &pgdat->node_zones[zid];
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci		if (populated_zone(compare))
16378c2ecf20Sopenharmony_ci			return zone == compare;
16388c2ecf20Sopenharmony_ci	}
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	return false;
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_cistatic void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
16448c2ecf20Sopenharmony_ci							struct zone *zone)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	int i;
16478c2ecf20Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
16488c2ecf20Sopenharmony_ci	if (is_zone_first_populated(pgdat, zone)) {
16498c2ecf20Sopenharmony_ci		seq_printf(m, "\n  per-node stats");
16508c2ecf20Sopenharmony_ci		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
16518c2ecf20Sopenharmony_ci			seq_printf(m, "\n      %-12s %lu", node_stat_name(i),
16528c2ecf20Sopenharmony_ci				   node_page_state_pages(pgdat, i));
16538c2ecf20Sopenharmony_ci		}
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci	seq_printf(m,
16568c2ecf20Sopenharmony_ci		   "\n  pages free     %lu"
16578c2ecf20Sopenharmony_ci		   "\n        min      %lu"
16588c2ecf20Sopenharmony_ci		   "\n        low      %lu"
16598c2ecf20Sopenharmony_ci		   "\n        high     %lu"
16608c2ecf20Sopenharmony_ci		   "\n        spanned  %lu"
16618c2ecf20Sopenharmony_ci		   "\n        present  %lu"
16628c2ecf20Sopenharmony_ci		   "\n        managed  %lu",
16638c2ecf20Sopenharmony_ci		   zone_page_state(zone, NR_FREE_PAGES),
16648c2ecf20Sopenharmony_ci		   min_wmark_pages(zone),
16658c2ecf20Sopenharmony_ci		   low_wmark_pages(zone),
16668c2ecf20Sopenharmony_ci		   high_wmark_pages(zone),
16678c2ecf20Sopenharmony_ci		   zone->spanned_pages,
16688c2ecf20Sopenharmony_ci		   zone->present_pages,
16698c2ecf20Sopenharmony_ci		   zone_managed_pages(zone));
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	seq_printf(m,
16728c2ecf20Sopenharmony_ci		   "\n        protection: (%ld",
16738c2ecf20Sopenharmony_ci		   zone->lowmem_reserve[0]);
16748c2ecf20Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
16758c2ecf20Sopenharmony_ci		seq_printf(m, ", %ld", zone->lowmem_reserve[i]);
16768c2ecf20Sopenharmony_ci	seq_putc(m, ')');
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	/* If unpopulated, no other information is useful */
16798c2ecf20Sopenharmony_ci	if (!populated_zone(zone)) {
16808c2ecf20Sopenharmony_ci		seq_putc(m, '\n');
16818c2ecf20Sopenharmony_ci		return;
16828c2ecf20Sopenharmony_ci	}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
16858c2ecf20Sopenharmony_ci		seq_printf(m, "\n      %-12s %lu", zone_stat_name(i),
16868c2ecf20Sopenharmony_ci			   zone_page_state(zone, i));
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
16898c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
16908c2ecf20Sopenharmony_ci		seq_printf(m, "\n      %-12s %lu", numa_stat_name(i),
16918c2ecf20Sopenharmony_ci			   zone_numa_state_snapshot(zone, i));
16928c2ecf20Sopenharmony_ci#endif
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	seq_printf(m, "\n  pagesets");
16958c2ecf20Sopenharmony_ci	for_each_online_cpu(i) {
16968c2ecf20Sopenharmony_ci		struct per_cpu_pageset *pageset;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci		pageset = per_cpu_ptr(zone->pageset, i);
16998c2ecf20Sopenharmony_ci		seq_printf(m,
17008c2ecf20Sopenharmony_ci			   "\n    cpu: %i"
17018c2ecf20Sopenharmony_ci			   "\n              count: %i"
17028c2ecf20Sopenharmony_ci			   "\n              high:  %i"
17038c2ecf20Sopenharmony_ci			   "\n              batch: %i",
17048c2ecf20Sopenharmony_ci			   i,
17058c2ecf20Sopenharmony_ci			   pageset->pcp.count,
17068c2ecf20Sopenharmony_ci			   pageset->pcp.high,
17078c2ecf20Sopenharmony_ci			   pageset->pcp.batch);
17088c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
17098c2ecf20Sopenharmony_ci		seq_printf(m, "\n  vm stats threshold: %d",
17108c2ecf20Sopenharmony_ci				pageset->stat_threshold);
17118c2ecf20Sopenharmony_ci#endif
17128c2ecf20Sopenharmony_ci	}
17138c2ecf20Sopenharmony_ci	seq_printf(m,
17148c2ecf20Sopenharmony_ci		   "\n  node_unreclaimable:  %u"
17158c2ecf20Sopenharmony_ci		   "\n  start_pfn:           %lu",
17168c2ecf20Sopenharmony_ci		   pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
17178c2ecf20Sopenharmony_ci		   zone->zone_start_pfn);
17188c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci/*
17228c2ecf20Sopenharmony_ci * Output information about zones in @pgdat.  All zones are printed regardless
17238c2ecf20Sopenharmony_ci * of whether they are populated or not: lowmem_reserve_ratio operates on the
17248c2ecf20Sopenharmony_ci * set of all zones and userspace would not be aware of such zones if they are
17258c2ecf20Sopenharmony_ci * suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio).
17268c2ecf20Sopenharmony_ci */
17278c2ecf20Sopenharmony_cistatic int zoneinfo_show(struct seq_file *m, void *arg)
17288c2ecf20Sopenharmony_ci{
17298c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
17308c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
17318c2ecf20Sopenharmony_ci	return 0;
17328c2ecf20Sopenharmony_ci}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_cistatic const struct seq_operations zoneinfo_op = {
17358c2ecf20Sopenharmony_ci	.start	= frag_start, /* iterate over all zones. The same as in
17368c2ecf20Sopenharmony_ci			       * fragmentation. */
17378c2ecf20Sopenharmony_ci	.next	= frag_next,
17388c2ecf20Sopenharmony_ci	.stop	= frag_stop,
17398c2ecf20Sopenharmony_ci	.show	= zoneinfo_show,
17408c2ecf20Sopenharmony_ci};
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci#define NR_VMSTAT_ITEMS (NR_VM_ZONE_STAT_ITEMS + \
17438c2ecf20Sopenharmony_ci			 NR_VM_NUMA_STAT_ITEMS + \
17448c2ecf20Sopenharmony_ci			 NR_VM_NODE_STAT_ITEMS + \
17458c2ecf20Sopenharmony_ci			 NR_VM_WRITEBACK_STAT_ITEMS + \
17468c2ecf20Sopenharmony_ci			 (IS_ENABLED(CONFIG_VM_EVENT_COUNTERS) ? \
17478c2ecf20Sopenharmony_ci			  NR_VM_EVENT_ITEMS : 0))
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_cistatic void *vmstat_start(struct seq_file *m, loff_t *pos)
17508c2ecf20Sopenharmony_ci{
17518c2ecf20Sopenharmony_ci	unsigned long *v;
17528c2ecf20Sopenharmony_ci	int i;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	if (*pos >= NR_VMSTAT_ITEMS)
17558c2ecf20Sopenharmony_ci		return NULL;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(vmstat_text) < NR_VMSTAT_ITEMS);
17588c2ecf20Sopenharmony_ci	v = kmalloc_array(NR_VMSTAT_ITEMS, sizeof(unsigned long), GFP_KERNEL);
17598c2ecf20Sopenharmony_ci	m->private = v;
17608c2ecf20Sopenharmony_ci	if (!v)
17618c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
17628c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
17638c2ecf20Sopenharmony_ci		v[i] = global_zone_page_state(i);
17648c2ecf20Sopenharmony_ci	v += NR_VM_ZONE_STAT_ITEMS;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
17678c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
17688c2ecf20Sopenharmony_ci		v[i] = global_numa_state(i);
17698c2ecf20Sopenharmony_ci	v += NR_VM_NUMA_STAT_ITEMS;
17708c2ecf20Sopenharmony_ci#endif
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
17738c2ecf20Sopenharmony_ci		v[i] = global_node_page_state_pages(i);
17748c2ecf20Sopenharmony_ci	v += NR_VM_NODE_STAT_ITEMS;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
17778c2ecf20Sopenharmony_ci			    v + NR_DIRTY_THRESHOLD);
17788c2ecf20Sopenharmony_ci	v += NR_VM_WRITEBACK_STAT_ITEMS;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci#ifdef CONFIG_VM_EVENT_COUNTERS
17818c2ecf20Sopenharmony_ci	all_vm_events(v);
17828c2ecf20Sopenharmony_ci	v[PGPGIN] /= 2;		/* sectors -> kbytes */
17838c2ecf20Sopenharmony_ci	v[PGPGOUT] /= 2;
17848c2ecf20Sopenharmony_ci#endif
17858c2ecf20Sopenharmony_ci	return (unsigned long *)m->private + *pos;
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_cistatic void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
17898c2ecf20Sopenharmony_ci{
17908c2ecf20Sopenharmony_ci	(*pos)++;
17918c2ecf20Sopenharmony_ci	if (*pos >= NR_VMSTAT_ITEMS)
17928c2ecf20Sopenharmony_ci		return NULL;
17938c2ecf20Sopenharmony_ci	return (unsigned long *)m->private + *pos;
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_cistatic int vmstat_show(struct seq_file *m, void *arg)
17978c2ecf20Sopenharmony_ci{
17988c2ecf20Sopenharmony_ci	unsigned long *l = arg;
17998c2ecf20Sopenharmony_ci	unsigned long off = l - (unsigned long *)m->private;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	seq_puts(m, vmstat_text[off]);
18028c2ecf20Sopenharmony_ci	seq_put_decimal_ull(m, " ", *l);
18038c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	if (off == NR_VMSTAT_ITEMS - 1) {
18068c2ecf20Sopenharmony_ci		/*
18078c2ecf20Sopenharmony_ci		 * We've come to the end - add any deprecated counters to avoid
18088c2ecf20Sopenharmony_ci		 * breaking userspace which might depend on them being present.
18098c2ecf20Sopenharmony_ci		 */
18108c2ecf20Sopenharmony_ci		seq_puts(m, "nr_unstable 0\n");
18118c2ecf20Sopenharmony_ci	}
18128c2ecf20Sopenharmony_ci	return 0;
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_cistatic void vmstat_stop(struct seq_file *m, void *arg)
18168c2ecf20Sopenharmony_ci{
18178c2ecf20Sopenharmony_ci	kfree(m->private);
18188c2ecf20Sopenharmony_ci	m->private = NULL;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_cistatic const struct seq_operations vmstat_op = {
18228c2ecf20Sopenharmony_ci	.start	= vmstat_start,
18238c2ecf20Sopenharmony_ci	.next	= vmstat_next,
18248c2ecf20Sopenharmony_ci	.stop	= vmstat_stop,
18258c2ecf20Sopenharmony_ci	.show	= vmstat_show,
18268c2ecf20Sopenharmony_ci};
18278c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
18308c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct delayed_work, vmstat_work);
18318c2ecf20Sopenharmony_ciint sysctl_stat_interval __read_mostly = HZ;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
18348c2ecf20Sopenharmony_cistatic void refresh_vm_stats(struct work_struct *work)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	refresh_cpu_vm_stats(true);
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ciint vmstat_refresh(struct ctl_table *table, int write,
18408c2ecf20Sopenharmony_ci		   void *buffer, size_t *lenp, loff_t *ppos)
18418c2ecf20Sopenharmony_ci{
18428c2ecf20Sopenharmony_ci	long val;
18438c2ecf20Sopenharmony_ci	int err;
18448c2ecf20Sopenharmony_ci	int i;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	/*
18478c2ecf20Sopenharmony_ci	 * The regular update, every sysctl_stat_interval, may come later
18488c2ecf20Sopenharmony_ci	 * than expected: leaving a significant amount in per_cpu buckets.
18498c2ecf20Sopenharmony_ci	 * This is particularly misleading when checking a quantity of HUGE
18508c2ecf20Sopenharmony_ci	 * pages, immediately after running a test.  /proc/sys/vm/stat_refresh,
18518c2ecf20Sopenharmony_ci	 * which can equally be echo'ed to or cat'ted from (by root),
18528c2ecf20Sopenharmony_ci	 * can be used to update the stats just before reading them.
18538c2ecf20Sopenharmony_ci	 *
18548c2ecf20Sopenharmony_ci	 * Oh, and since global_zone_page_state() etc. are so careful to hide
18558c2ecf20Sopenharmony_ci	 * transiently negative values, report an error here if any of
18568c2ecf20Sopenharmony_ci	 * the stats is negative, so we know to go looking for imbalance.
18578c2ecf20Sopenharmony_ci	 */
18588c2ecf20Sopenharmony_ci	err = schedule_on_each_cpu(refresh_vm_stats);
18598c2ecf20Sopenharmony_ci	if (err)
18608c2ecf20Sopenharmony_ci		return err;
18618c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
18628c2ecf20Sopenharmony_ci		val = atomic_long_read(&vm_zone_stat[i]);
18638c2ecf20Sopenharmony_ci		if (val < 0) {
18648c2ecf20Sopenharmony_ci			pr_warn("%s: %s %ld\n",
18658c2ecf20Sopenharmony_ci				__func__, zone_stat_name(i), val);
18668c2ecf20Sopenharmony_ci			err = -EINVAL;
18678c2ecf20Sopenharmony_ci		}
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
18708c2ecf20Sopenharmony_ci	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
18718c2ecf20Sopenharmony_ci		val = atomic_long_read(&vm_numa_stat[i]);
18728c2ecf20Sopenharmony_ci		if (val < 0) {
18738c2ecf20Sopenharmony_ci			pr_warn("%s: %s %ld\n",
18748c2ecf20Sopenharmony_ci				__func__, numa_stat_name(i), val);
18758c2ecf20Sopenharmony_ci			err = -EINVAL;
18768c2ecf20Sopenharmony_ci		}
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci#endif
18798c2ecf20Sopenharmony_ci	if (err)
18808c2ecf20Sopenharmony_ci		return err;
18818c2ecf20Sopenharmony_ci	if (write)
18828c2ecf20Sopenharmony_ci		*ppos += *lenp;
18838c2ecf20Sopenharmony_ci	else
18848c2ecf20Sopenharmony_ci		*lenp = 0;
18858c2ecf20Sopenharmony_ci	return 0;
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic void vmstat_update(struct work_struct *w)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	if (refresh_cpu_vm_stats(true) && !cpu_isolated(smp_processor_id())) {
18928c2ecf20Sopenharmony_ci		/*
18938c2ecf20Sopenharmony_ci		 * Counters were updated so we expect more updates
18948c2ecf20Sopenharmony_ci		 * to occur in the future. Keep on running the
18958c2ecf20Sopenharmony_ci		 * update worker thread.
18968c2ecf20Sopenharmony_ci		 */
18978c2ecf20Sopenharmony_ci		queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
18988c2ecf20Sopenharmony_ci				this_cpu_ptr(&vmstat_work),
18998c2ecf20Sopenharmony_ci				round_jiffies_relative(sysctl_stat_interval));
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci/*
19048c2ecf20Sopenharmony_ci * Switch off vmstat processing and then fold all the remaining differentials
19058c2ecf20Sopenharmony_ci * until the diffs stay at zero. The function is used by NOHZ and can only be
19068c2ecf20Sopenharmony_ci * invoked when tick processing is not active.
19078c2ecf20Sopenharmony_ci */
19088c2ecf20Sopenharmony_ci/*
19098c2ecf20Sopenharmony_ci * Check if the diffs for a certain cpu indicate that
19108c2ecf20Sopenharmony_ci * an update is needed.
19118c2ecf20Sopenharmony_ci */
19128c2ecf20Sopenharmony_cistatic bool need_update(int cpu)
19138c2ecf20Sopenharmony_ci{
19148c2ecf20Sopenharmony_ci	struct zone *zone;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	for_each_populated_zone(zone) {
19178c2ecf20Sopenharmony_ci		struct per_cpu_pageset *p = per_cpu_ptr(zone->pageset, cpu);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(p->vm_stat_diff[0]) != 1);
19208c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
19218c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(p->vm_numa_stat_diff[0]) != 2);
19228c2ecf20Sopenharmony_ci#endif
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci		/*
19258c2ecf20Sopenharmony_ci		 * The fast way of checking if there are any vmstat diffs.
19268c2ecf20Sopenharmony_ci		 */
19278c2ecf20Sopenharmony_ci		if (memchr_inv(p->vm_stat_diff, 0, NR_VM_ZONE_STAT_ITEMS *
19288c2ecf20Sopenharmony_ci			       sizeof(p->vm_stat_diff[0])))
19298c2ecf20Sopenharmony_ci			return true;
19308c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA
19318c2ecf20Sopenharmony_ci		if (memchr_inv(p->vm_numa_stat_diff, 0, NR_VM_NUMA_STAT_ITEMS *
19328c2ecf20Sopenharmony_ci			       sizeof(p->vm_numa_stat_diff[0])))
19338c2ecf20Sopenharmony_ci			return true;
19348c2ecf20Sopenharmony_ci#endif
19358c2ecf20Sopenharmony_ci	}
19368c2ecf20Sopenharmony_ci	return false;
19378c2ecf20Sopenharmony_ci}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci/*
19408c2ecf20Sopenharmony_ci * Switch off vmstat processing and then fold all the remaining differentials
19418c2ecf20Sopenharmony_ci * until the diffs stay at zero. The function is used by NOHZ and can only be
19428c2ecf20Sopenharmony_ci * invoked when tick processing is not active.
19438c2ecf20Sopenharmony_ci */
19448c2ecf20Sopenharmony_civoid quiet_vmstat(void)
19458c2ecf20Sopenharmony_ci{
19468c2ecf20Sopenharmony_ci	if (system_state != SYSTEM_RUNNING)
19478c2ecf20Sopenharmony_ci		return;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
19508c2ecf20Sopenharmony_ci		return;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	if (!need_update(smp_processor_id()))
19538c2ecf20Sopenharmony_ci		return;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	/*
19568c2ecf20Sopenharmony_ci	 * Just refresh counters and do not care about the pending delayed
19578c2ecf20Sopenharmony_ci	 * vmstat_update. It doesn't fire that often to matter and canceling
19588c2ecf20Sopenharmony_ci	 * it would be too expensive from this path.
19598c2ecf20Sopenharmony_ci	 * vmstat_shepherd will take care about that for us.
19608c2ecf20Sopenharmony_ci	 */
19618c2ecf20Sopenharmony_ci	refresh_cpu_vm_stats(false);
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci/*
19658c2ecf20Sopenharmony_ci * Shepherd worker thread that checks the
19668c2ecf20Sopenharmony_ci * differentials of processors that have their worker
19678c2ecf20Sopenharmony_ci * threads for vm statistics updates disabled because of
19688c2ecf20Sopenharmony_ci * inactivity.
19698c2ecf20Sopenharmony_ci */
19708c2ecf20Sopenharmony_cistatic void vmstat_shepherd(struct work_struct *w);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_cistatic DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_cistatic void vmstat_shepherd(struct work_struct *w)
19758c2ecf20Sopenharmony_ci{
19768c2ecf20Sopenharmony_ci	int cpu;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	get_online_cpus();
19798c2ecf20Sopenharmony_ci	/* Check processors whose vmstat worker threads have been disabled */
19808c2ecf20Sopenharmony_ci	for_each_online_cpu(cpu) {
19818c2ecf20Sopenharmony_ci		struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci		if (!delayed_work_pending(dw) && need_update(cpu) &&
19848c2ecf20Sopenharmony_ci			!cpu_isolated(cpu))
19858c2ecf20Sopenharmony_ci			queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
19868c2ecf20Sopenharmony_ci	}
19878c2ecf20Sopenharmony_ci	put_online_cpus();
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	schedule_delayed_work(&shepherd,
19908c2ecf20Sopenharmony_ci		round_jiffies_relative(sysctl_stat_interval));
19918c2ecf20Sopenharmony_ci}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_cistatic void __init start_shepherd_timer(void)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	int cpu;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu)
19988c2ecf20Sopenharmony_ci		INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
19998c2ecf20Sopenharmony_ci			vmstat_update);
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	schedule_delayed_work(&shepherd,
20028c2ecf20Sopenharmony_ci		round_jiffies_relative(sysctl_stat_interval));
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistatic void __init init_cpu_node_state(void)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	int node;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	for_each_online_node(node) {
20108c2ecf20Sopenharmony_ci		if (cpumask_weight(cpumask_of_node(node)) > 0)
20118c2ecf20Sopenharmony_ci			node_set_state(node, N_CPU);
20128c2ecf20Sopenharmony_ci	}
20138c2ecf20Sopenharmony_ci}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_cistatic int vmstat_cpu_online(unsigned int cpu)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	refresh_zone_stat_thresholds();
20188c2ecf20Sopenharmony_ci	node_set_state(cpu_to_node(cpu), N_CPU);
20198c2ecf20Sopenharmony_ci	return 0;
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic int vmstat_cpu_down_prep(unsigned int cpu)
20238c2ecf20Sopenharmony_ci{
20248c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
20258c2ecf20Sopenharmony_ci	return 0;
20268c2ecf20Sopenharmony_ci}
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic int vmstat_cpu_dead(unsigned int cpu)
20298c2ecf20Sopenharmony_ci{
20308c2ecf20Sopenharmony_ci	const struct cpumask *node_cpus;
20318c2ecf20Sopenharmony_ci	int node;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	node = cpu_to_node(cpu);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	refresh_zone_stat_thresholds();
20368c2ecf20Sopenharmony_ci	node_cpus = cpumask_of_node(node);
20378c2ecf20Sopenharmony_ci	if (cpumask_weight(node_cpus) > 0)
20388c2ecf20Sopenharmony_ci		return 0;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	node_clear_state(node, N_CPU);
20418c2ecf20Sopenharmony_ci	return 0;
20428c2ecf20Sopenharmony_ci}
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci#endif
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_cistruct workqueue_struct *mm_percpu_wq;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_civoid __init init_mm_internals(void)
20498c2ecf20Sopenharmony_ci{
20508c2ecf20Sopenharmony_ci	int ret __maybe_unused;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
20558c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead",
20568c2ecf20Sopenharmony_ci					NULL, vmstat_cpu_dead);
20578c2ecf20Sopenharmony_ci	if (ret < 0)
20588c2ecf20Sopenharmony_ci		pr_err("vmstat: failed to register 'dead' hotplug state\n");
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmstat:online",
20618c2ecf20Sopenharmony_ci					vmstat_cpu_online,
20628c2ecf20Sopenharmony_ci					vmstat_cpu_down_prep);
20638c2ecf20Sopenharmony_ci	if (ret < 0)
20648c2ecf20Sopenharmony_ci		pr_err("vmstat: failed to register 'online' hotplug state\n");
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	get_online_cpus();
20678c2ecf20Sopenharmony_ci	init_cpu_node_state();
20688c2ecf20Sopenharmony_ci	put_online_cpus();
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	start_shepherd_timer();
20718c2ecf20Sopenharmony_ci#endif
20728c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
20738c2ecf20Sopenharmony_ci	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
20748c2ecf20Sopenharmony_ci	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
20758c2ecf20Sopenharmony_ci	proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
20768c2ecf20Sopenharmony_ci	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
20778c2ecf20Sopenharmony_ci#endif
20788c2ecf20Sopenharmony_ci}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci/*
20838c2ecf20Sopenharmony_ci * Return an index indicating how much of the available free memory is
20848c2ecf20Sopenharmony_ci * unusable for an allocation of the requested size.
20858c2ecf20Sopenharmony_ci */
20868c2ecf20Sopenharmony_cistatic int unusable_free_index(unsigned int order,
20878c2ecf20Sopenharmony_ci				struct contig_page_info *info)
20888c2ecf20Sopenharmony_ci{
20898c2ecf20Sopenharmony_ci	/* No free memory is interpreted as all free memory is unusable */
20908c2ecf20Sopenharmony_ci	if (info->free_pages == 0)
20918c2ecf20Sopenharmony_ci		return 1000;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	/*
20948c2ecf20Sopenharmony_ci	 * Index should be a value between 0 and 1. Return a value to 3
20958c2ecf20Sopenharmony_ci	 * decimal places.
20968c2ecf20Sopenharmony_ci	 *
20978c2ecf20Sopenharmony_ci	 * 0 => no fragmentation
20988c2ecf20Sopenharmony_ci	 * 1 => high fragmentation
20998c2ecf20Sopenharmony_ci	 */
21008c2ecf20Sopenharmony_ci	return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_cistatic void unusable_show_print(struct seq_file *m,
21058c2ecf20Sopenharmony_ci					pg_data_t *pgdat, struct zone *zone)
21068c2ecf20Sopenharmony_ci{
21078c2ecf20Sopenharmony_ci	unsigned int order;
21088c2ecf20Sopenharmony_ci	int index;
21098c2ecf20Sopenharmony_ci	struct contig_page_info info;
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s ",
21128c2ecf20Sopenharmony_ci				pgdat->node_id,
21138c2ecf20Sopenharmony_ci				zone->name);
21148c2ecf20Sopenharmony_ci	for (order = 0; order < MAX_ORDER; ++order) {
21158c2ecf20Sopenharmony_ci		fill_contig_page_info(zone, order, &info);
21168c2ecf20Sopenharmony_ci		index = unusable_free_index(order, &info);
21178c2ecf20Sopenharmony_ci		seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
21218c2ecf20Sopenharmony_ci}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci/*
21248c2ecf20Sopenharmony_ci * Display unusable free space index
21258c2ecf20Sopenharmony_ci *
21268c2ecf20Sopenharmony_ci * The unusable free space index measures how much of the available free
21278c2ecf20Sopenharmony_ci * memory cannot be used to satisfy an allocation of a given size and is a
21288c2ecf20Sopenharmony_ci * value between 0 and 1. The higher the value, the more of free memory is
21298c2ecf20Sopenharmony_ci * unusable and by implication, the worse the external fragmentation is. This
21308c2ecf20Sopenharmony_ci * can be expressed as a percentage by multiplying by 100.
21318c2ecf20Sopenharmony_ci */
21328c2ecf20Sopenharmony_cistatic int unusable_show(struct seq_file *m, void *arg)
21338c2ecf20Sopenharmony_ci{
21348c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	/* check memoryless node */
21378c2ecf20Sopenharmony_ci	if (!node_state(pgdat->node_id, N_MEMORY))
21388c2ecf20Sopenharmony_ci		return 0;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	return 0;
21438c2ecf20Sopenharmony_ci}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_cistatic const struct seq_operations unusable_sops = {
21468c2ecf20Sopenharmony_ci	.start	= frag_start,
21478c2ecf20Sopenharmony_ci	.next	= frag_next,
21488c2ecf20Sopenharmony_ci	.stop	= frag_stop,
21498c2ecf20Sopenharmony_ci	.show	= unusable_show,
21508c2ecf20Sopenharmony_ci};
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(unusable);
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_cistatic void extfrag_show_print(struct seq_file *m,
21558c2ecf20Sopenharmony_ci					pg_data_t *pgdat, struct zone *zone)
21568c2ecf20Sopenharmony_ci{
21578c2ecf20Sopenharmony_ci	unsigned int order;
21588c2ecf20Sopenharmony_ci	int index;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/* Alloc on stack as interrupts are disabled for zone walk */
21618c2ecf20Sopenharmony_ci	struct contig_page_info info;
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	seq_printf(m, "Node %d, zone %8s ",
21648c2ecf20Sopenharmony_ci				pgdat->node_id,
21658c2ecf20Sopenharmony_ci				zone->name);
21668c2ecf20Sopenharmony_ci	for (order = 0; order < MAX_ORDER; ++order) {
21678c2ecf20Sopenharmony_ci		fill_contig_page_info(zone, order, &info);
21688c2ecf20Sopenharmony_ci		index = __fragmentation_index(order, &info);
21698c2ecf20Sopenharmony_ci		seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
21708c2ecf20Sopenharmony_ci	}
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
21738c2ecf20Sopenharmony_ci}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci/*
21768c2ecf20Sopenharmony_ci * Display fragmentation index for orders that allocations would fail for
21778c2ecf20Sopenharmony_ci */
21788c2ecf20Sopenharmony_cistatic int extfrag_show(struct seq_file *m, void *arg)
21798c2ecf20Sopenharmony_ci{
21808c2ecf20Sopenharmony_ci	pg_data_t *pgdat = (pg_data_t *)arg;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	return 0;
21858c2ecf20Sopenharmony_ci}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_cistatic const struct seq_operations extfrag_sops = {
21888c2ecf20Sopenharmony_ci	.start	= frag_start,
21898c2ecf20Sopenharmony_ci	.next	= frag_next,
21908c2ecf20Sopenharmony_ci	.stop	= frag_stop,
21918c2ecf20Sopenharmony_ci	.show	= extfrag_show,
21928c2ecf20Sopenharmony_ci};
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ciDEFINE_SEQ_ATTRIBUTE(extfrag);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic int __init extfrag_debug_init(void)
21978c2ecf20Sopenharmony_ci{
21988c2ecf20Sopenharmony_ci	struct dentry *extfrag_debug_root;
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	debugfs_create_file("unusable_index", 0444, extfrag_debug_root, NULL,
22038c2ecf20Sopenharmony_ci			    &unusable_fops);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	debugfs_create_file("extfrag_index", 0444, extfrag_debug_root, NULL,
22068c2ecf20Sopenharmony_ci			    &extfrag_fops);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	return 0;
22098c2ecf20Sopenharmony_ci}
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_cimodule_init(extfrag_debug_init);
22128c2ecf20Sopenharmony_ci#endif
2213