1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f6ac2354SChristoph Lameter /*
3f6ac2354SChristoph Lameter * linux/mm/vmstat.c
4f6ac2354SChristoph Lameter *
5f6ac2354SChristoph Lameter * Manages VM statistics
6f6ac2354SChristoph Lameter * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
72244b95aSChristoph Lameter *
82244b95aSChristoph Lameter * zoned VM statistics
92244b95aSChristoph Lameter * Copyright (C) 2006 Silicon Graphics, Inc.,
102244b95aSChristoph Lameter * Christoph Lameter <christoph@lameter.com>
117cc36bbdSChristoph Lameter * Copyright (C) 2008-2014 Christoph Lameter
12f6ac2354SChristoph Lameter */
138f32f7e5SAlexey Dobriyan #include <linux/fs.h>
14f6ac2354SChristoph Lameter #include <linux/mm.h>
154e950f6fSAlexey Dobriyan #include <linux/err.h>
162244b95aSChristoph Lameter #include <linux/module.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18df9ecabaSChristoph Lameter #include <linux/cpu.h>
197cc36bbdSChristoph Lameter #include <linux/cpumask.h>
20c748e134SAdrian Bunk #include <linux/vmstat.h>
213c486871SAndrew Morton #include <linux/proc_fs.h>
223c486871SAndrew Morton #include <linux/seq_file.h>
233c486871SAndrew Morton #include <linux/debugfs.h>
24e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
25f1a5ab12SMel Gorman #include <linux/math64.h>
2679da826aSMichael Rubin #include <linux/writeback.h>
2736deb0beSNamhyung Kim #include <linux/compaction.h>
286e543d57SLisa Du #include <linux/mm_inline.h>
2948c96a36SJoonsoo Kim #include <linux/page_owner.h>
30be5e015dSMarcelo Tosatti #include <linux/sched/isolation.h>
316e543d57SLisa Du
326e543d57SLisa Du #include "internal.h"
33f6ac2354SChristoph Lameter
344518085eSKemi Wang #ifdef CONFIG_NUMA
354518085eSKemi Wang int sysctl_vm_numa_stat = ENABLE_NUMA_STAT;
364518085eSKemi Wang
374518085eSKemi Wang /* zero numa counters within a zone */
zero_zone_numa_counters(struct zone * zone)384518085eSKemi Wang static void zero_zone_numa_counters(struct zone *zone)
394518085eSKemi Wang {
404518085eSKemi Wang int item, cpu;
414518085eSKemi Wang
42f19298b9SMel Gorman for (item = 0; item < NR_VM_NUMA_EVENT_ITEMS; item++) {
43f19298b9SMel Gorman atomic_long_set(&zone->vm_numa_event[item], 0);
44f19298b9SMel Gorman for_each_online_cpu(cpu) {
45f19298b9SMel Gorman per_cpu_ptr(zone->per_cpu_zonestats, cpu)->vm_numa_event[item]
464518085eSKemi Wang = 0;
474518085eSKemi Wang }
484518085eSKemi Wang }
49f19298b9SMel Gorman }
504518085eSKemi Wang
514518085eSKemi Wang /* zero numa counters of all the populated zones */
zero_zones_numa_counters(void)524518085eSKemi Wang static void zero_zones_numa_counters(void)
534518085eSKemi Wang {
544518085eSKemi Wang struct zone *zone;
554518085eSKemi Wang
564518085eSKemi Wang for_each_populated_zone(zone)
574518085eSKemi Wang zero_zone_numa_counters(zone);
584518085eSKemi Wang }
594518085eSKemi Wang
604518085eSKemi Wang /* zero global numa counters */
zero_global_numa_counters(void)614518085eSKemi Wang static void zero_global_numa_counters(void)
624518085eSKemi Wang {
634518085eSKemi Wang int item;
644518085eSKemi Wang
65f19298b9SMel Gorman for (item = 0; item < NR_VM_NUMA_EVENT_ITEMS; item++)
66f19298b9SMel Gorman atomic_long_set(&vm_numa_event[item], 0);
674518085eSKemi Wang }
684518085eSKemi Wang
invalid_numa_statistics(void)694518085eSKemi Wang static void invalid_numa_statistics(void)
704518085eSKemi Wang {
714518085eSKemi Wang zero_zones_numa_counters();
724518085eSKemi Wang zero_global_numa_counters();
734518085eSKemi Wang }
744518085eSKemi Wang
754518085eSKemi Wang static DEFINE_MUTEX(vm_numa_stat_lock);
764518085eSKemi Wang
sysctl_vm_numa_stat_handler(struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos)774518085eSKemi Wang int sysctl_vm_numa_stat_handler(struct ctl_table *table, int write,
7832927393SChristoph Hellwig void *buffer, size_t *length, loff_t *ppos)
794518085eSKemi Wang {
804518085eSKemi Wang int ret, oldval;
814518085eSKemi Wang
824518085eSKemi Wang mutex_lock(&vm_numa_stat_lock);
834518085eSKemi Wang if (write)
844518085eSKemi Wang oldval = sysctl_vm_numa_stat;
854518085eSKemi Wang ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
864518085eSKemi Wang if (ret || !write)
874518085eSKemi Wang goto out;
884518085eSKemi Wang
894518085eSKemi Wang if (oldval == sysctl_vm_numa_stat)
904518085eSKemi Wang goto out;
914518085eSKemi Wang else if (sysctl_vm_numa_stat == ENABLE_NUMA_STAT) {
924518085eSKemi Wang static_branch_enable(&vm_numa_stat_key);
934518085eSKemi Wang pr_info("enable numa statistics\n");
944518085eSKemi Wang } else {
954518085eSKemi Wang static_branch_disable(&vm_numa_stat_key);
964518085eSKemi Wang invalid_numa_statistics();
974518085eSKemi Wang pr_info("disable numa statistics, and clear numa counters\n");
984518085eSKemi Wang }
994518085eSKemi Wang
1004518085eSKemi Wang out:
1014518085eSKemi Wang mutex_unlock(&vm_numa_stat_lock);
1024518085eSKemi Wang return ret;
1034518085eSKemi Wang }
1044518085eSKemi Wang #endif
1054518085eSKemi Wang
106f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
107f8891e5eSChristoph Lameter DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
108f8891e5eSChristoph Lameter EXPORT_PER_CPU_SYMBOL(vm_event_states);
109f8891e5eSChristoph Lameter
sum_vm_events(unsigned long * ret)11031f961a8SMinchan Kim static void sum_vm_events(unsigned long *ret)
111f8891e5eSChristoph Lameter {
1129eccf2a8SChristoph Lameter int cpu;
113f8891e5eSChristoph Lameter int i;
114f8891e5eSChristoph Lameter
115f8891e5eSChristoph Lameter memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
116f8891e5eSChristoph Lameter
11731f961a8SMinchan Kim for_each_online_cpu(cpu) {
118f8891e5eSChristoph Lameter struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
119f8891e5eSChristoph Lameter
120f8891e5eSChristoph Lameter for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
121f8891e5eSChristoph Lameter ret[i] += this->event[i];
122f8891e5eSChristoph Lameter }
123f8891e5eSChristoph Lameter }
124f8891e5eSChristoph Lameter
125f8891e5eSChristoph Lameter /*
126f8891e5eSChristoph Lameter * Accumulate the vm event counters across all CPUs.
127f8891e5eSChristoph Lameter * The result is unavoidably approximate - it can change
128f8891e5eSChristoph Lameter * during and after execution of this function.
129f8891e5eSChristoph Lameter */
all_vm_events(unsigned long * ret)130f8891e5eSChristoph Lameter void all_vm_events(unsigned long *ret)
131f8891e5eSChristoph Lameter {
1327625eccdSSebastian Andrzej Siewior cpus_read_lock();
13331f961a8SMinchan Kim sum_vm_events(ret);
1347625eccdSSebastian Andrzej Siewior cpus_read_unlock();
135f8891e5eSChristoph Lameter }
13632dd66fcSHeiko Carstens EXPORT_SYMBOL_GPL(all_vm_events);
137f8891e5eSChristoph Lameter
138f8891e5eSChristoph Lameter /*
139f8891e5eSChristoph Lameter * Fold the foreign cpu events into our own.
140f8891e5eSChristoph Lameter *
141f8891e5eSChristoph Lameter * This is adding to the events on one processor
142f8891e5eSChristoph Lameter * but keeps the global counts constant.
143f8891e5eSChristoph Lameter */
vm_events_fold_cpu(int cpu)144f8891e5eSChristoph Lameter void vm_events_fold_cpu(int cpu)
145f8891e5eSChristoph Lameter {
146f8891e5eSChristoph Lameter struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
147f8891e5eSChristoph Lameter int i;
148f8891e5eSChristoph Lameter
149f8891e5eSChristoph Lameter for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
150f8891e5eSChristoph Lameter count_vm_events(i, fold_state->event[i]);
151f8891e5eSChristoph Lameter fold_state->event[i] = 0;
152f8891e5eSChristoph Lameter }
153f8891e5eSChristoph Lameter }
154f8891e5eSChristoph Lameter
155f8891e5eSChristoph Lameter #endif /* CONFIG_VM_EVENT_COUNTERS */
156f8891e5eSChristoph Lameter
1572244b95aSChristoph Lameter /*
1582244b95aSChristoph Lameter * Manage combined zone based / global counters
1592244b95aSChristoph Lameter *
1602244b95aSChristoph Lameter * vm_stat contains the global counters
1612244b95aSChristoph Lameter */
16275ef7184SMel Gorman atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
16375ef7184SMel Gorman atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
164f19298b9SMel Gorman atomic_long_t vm_numa_event[NR_VM_NUMA_EVENT_ITEMS] __cacheline_aligned_in_smp;
16575ef7184SMel Gorman EXPORT_SYMBOL(vm_zone_stat);
16675ef7184SMel Gorman EXPORT_SYMBOL(vm_node_stat);
1672244b95aSChristoph Lameter
168ebeac3eaSGeert Uytterhoeven #ifdef CONFIG_NUMA
fold_vm_zone_numa_events(struct zone * zone)169ebeac3eaSGeert Uytterhoeven static void fold_vm_zone_numa_events(struct zone *zone)
170ebeac3eaSGeert Uytterhoeven {
171ebeac3eaSGeert Uytterhoeven unsigned long zone_numa_events[NR_VM_NUMA_EVENT_ITEMS] = { 0, };
172ebeac3eaSGeert Uytterhoeven int cpu;
173ebeac3eaSGeert Uytterhoeven enum numa_stat_item item;
174ebeac3eaSGeert Uytterhoeven
175ebeac3eaSGeert Uytterhoeven for_each_online_cpu(cpu) {
176ebeac3eaSGeert Uytterhoeven struct per_cpu_zonestat *pzstats;
177ebeac3eaSGeert Uytterhoeven
178ebeac3eaSGeert Uytterhoeven pzstats = per_cpu_ptr(zone->per_cpu_zonestats, cpu);
179ebeac3eaSGeert Uytterhoeven for (item = 0; item < NR_VM_NUMA_EVENT_ITEMS; item++)
180ebeac3eaSGeert Uytterhoeven zone_numa_events[item] += xchg(&pzstats->vm_numa_event[item], 0);
181ebeac3eaSGeert Uytterhoeven }
182ebeac3eaSGeert Uytterhoeven
183ebeac3eaSGeert Uytterhoeven for (item = 0; item < NR_VM_NUMA_EVENT_ITEMS; item++)
184ebeac3eaSGeert Uytterhoeven zone_numa_event_add(zone_numa_events[item], zone, item);
185ebeac3eaSGeert Uytterhoeven }
186ebeac3eaSGeert Uytterhoeven
fold_vm_numa_events(void)187ebeac3eaSGeert Uytterhoeven void fold_vm_numa_events(void)
188ebeac3eaSGeert Uytterhoeven {
189ebeac3eaSGeert Uytterhoeven struct zone *zone;
190ebeac3eaSGeert Uytterhoeven
191ebeac3eaSGeert Uytterhoeven for_each_populated_zone(zone)
192ebeac3eaSGeert Uytterhoeven fold_vm_zone_numa_events(zone);
193ebeac3eaSGeert Uytterhoeven }
194ebeac3eaSGeert Uytterhoeven #endif
195ebeac3eaSGeert Uytterhoeven
1962244b95aSChristoph Lameter #ifdef CONFIG_SMP
1972244b95aSChristoph Lameter
calculate_pressure_threshold(struct zone * zone)198b44129b3SMel Gorman int calculate_pressure_threshold(struct zone *zone)
19988f5acf8SMel Gorman {
20088f5acf8SMel Gorman int threshold;
20188f5acf8SMel Gorman int watermark_distance;
20288f5acf8SMel Gorman
20388f5acf8SMel Gorman /*
20488f5acf8SMel Gorman * As vmstats are not up to date, there is drift between the estimated
20588f5acf8SMel Gorman * and real values. For high thresholds and a high number of CPUs, it
20688f5acf8SMel Gorman * is possible for the min watermark to be breached while the estimated
20788f5acf8SMel Gorman * value looks fine. The pressure threshold is a reduced value such
20888f5acf8SMel Gorman * that even the maximum amount of drift will not accidentally breach
20988f5acf8SMel Gorman * the min watermark
21088f5acf8SMel Gorman */
21188f5acf8SMel Gorman watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone);
21288f5acf8SMel Gorman threshold = max(1, (int)(watermark_distance / num_online_cpus()));
21388f5acf8SMel Gorman
21488f5acf8SMel Gorman /*
21588f5acf8SMel Gorman * Maximum threshold is 125
21688f5acf8SMel Gorman */
21788f5acf8SMel Gorman threshold = min(125, threshold);
21888f5acf8SMel Gorman
21988f5acf8SMel Gorman return threshold;
22088f5acf8SMel Gorman }
22188f5acf8SMel Gorman
calculate_normal_threshold(struct zone * zone)222b44129b3SMel Gorman int calculate_normal_threshold(struct zone *zone)
223df9ecabaSChristoph Lameter {
224df9ecabaSChristoph Lameter int threshold;
225df9ecabaSChristoph Lameter int mem; /* memory in 128 MB units */
2262244b95aSChristoph Lameter
2272244b95aSChristoph Lameter /*
228df9ecabaSChristoph Lameter * The threshold scales with the number of processors and the amount
229df9ecabaSChristoph Lameter * of memory per zone. More memory means that we can defer updates for
230df9ecabaSChristoph Lameter * longer, more processors could lead to more contention.
231df9ecabaSChristoph Lameter * fls() is used to have a cheap way of logarithmic scaling.
2322244b95aSChristoph Lameter *
233df9ecabaSChristoph Lameter * Some sample thresholds:
234df9ecabaSChristoph Lameter *
235ea15ba17SMiaohe Lin * Threshold Processors (fls) Zonesize fls(mem)+1
236df9ecabaSChristoph Lameter * ------------------------------------------------------------------
237df9ecabaSChristoph Lameter * 8 1 1 0.9-1 GB 4
238df9ecabaSChristoph Lameter * 16 2 2 0.9-1 GB 4
239df9ecabaSChristoph Lameter * 20 2 2 1-2 GB 5
240df9ecabaSChristoph Lameter * 24 2 2 2-4 GB 6
241df9ecabaSChristoph Lameter * 28 2 2 4-8 GB 7
242df9ecabaSChristoph Lameter * 32 2 2 8-16 GB 8
243df9ecabaSChristoph Lameter * 4 2 2 <128M 1
244df9ecabaSChristoph Lameter * 30 4 3 2-4 GB 5
245df9ecabaSChristoph Lameter * 48 4 3 8-16 GB 8
246df9ecabaSChristoph Lameter * 32 8 4 1-2 GB 4
247df9ecabaSChristoph Lameter * 32 8 4 0.9-1GB 4
248df9ecabaSChristoph Lameter * 10 16 5 <128M 1
249df9ecabaSChristoph Lameter * 40 16 5 900M 4
250df9ecabaSChristoph Lameter * 70 64 7 2-4 GB 5
251df9ecabaSChristoph Lameter * 84 64 7 4-8 GB 6
252df9ecabaSChristoph Lameter * 108 512 9 4-8 GB 6
253df9ecabaSChristoph Lameter * 125 1024 10 8-16 GB 8
254df9ecabaSChristoph Lameter * 125 1024 10 16-32 GB 9
2552244b95aSChristoph Lameter */
256df9ecabaSChristoph Lameter
2579705bea5SArun KS mem = zone_managed_pages(zone) >> (27 - PAGE_SHIFT);
258df9ecabaSChristoph Lameter
259df9ecabaSChristoph Lameter threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
260df9ecabaSChristoph Lameter
261df9ecabaSChristoph Lameter /*
262df9ecabaSChristoph Lameter * Maximum threshold is 125
263df9ecabaSChristoph Lameter */
264df9ecabaSChristoph Lameter threshold = min(125, threshold);
265df9ecabaSChristoph Lameter
266df9ecabaSChristoph Lameter return threshold;
267df9ecabaSChristoph Lameter }
268df9ecabaSChristoph Lameter
269df9ecabaSChristoph Lameter /*
270df9ecabaSChristoph Lameter * Refresh the thresholds for each zone.
271df9ecabaSChristoph Lameter */
refresh_zone_stat_thresholds(void)272a6cccdc3SKOSAKI Motohiro void refresh_zone_stat_thresholds(void)
2732244b95aSChristoph Lameter {
27475ef7184SMel Gorman struct pglist_data *pgdat;
275df9ecabaSChristoph Lameter struct zone *zone;
276df9ecabaSChristoph Lameter int cpu;
277df9ecabaSChristoph Lameter int threshold;
278df9ecabaSChristoph Lameter
27975ef7184SMel Gorman /* Zero current pgdat thresholds */
28075ef7184SMel Gorman for_each_online_pgdat(pgdat) {
28175ef7184SMel Gorman for_each_online_cpu(cpu) {
28275ef7184SMel Gorman per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
28375ef7184SMel Gorman }
28475ef7184SMel Gorman }
28575ef7184SMel Gorman
286ee99c71cSKOSAKI Motohiro for_each_populated_zone(zone) {
28775ef7184SMel Gorman struct pglist_data *pgdat = zone->zone_pgdat;
288aa454840SChristoph Lameter unsigned long max_drift, tolerate_drift;
289aa454840SChristoph Lameter
290b44129b3SMel Gorman threshold = calculate_normal_threshold(zone);
291df9ecabaSChristoph Lameter
29275ef7184SMel Gorman for_each_online_cpu(cpu) {
29375ef7184SMel Gorman int pgdat_threshold;
29475ef7184SMel Gorman
29528f836b6SMel Gorman per_cpu_ptr(zone->per_cpu_zonestats, cpu)->stat_threshold
29699dcc3e5SChristoph Lameter = threshold;
2971d90ca89SKemi Wang
29875ef7184SMel Gorman /* Base nodestat threshold on the largest populated zone. */
29975ef7184SMel Gorman pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
30075ef7184SMel Gorman per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
30175ef7184SMel Gorman = max(threshold, pgdat_threshold);
30275ef7184SMel Gorman }
30375ef7184SMel Gorman
304aa454840SChristoph Lameter /*
305aa454840SChristoph Lameter * Only set percpu_drift_mark if there is a danger that
306aa454840SChristoph Lameter * NR_FREE_PAGES reports the low watermark is ok when in fact
307aa454840SChristoph Lameter * the min watermark could be breached by an allocation
308aa454840SChristoph Lameter */
309aa454840SChristoph Lameter tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone);
310aa454840SChristoph Lameter max_drift = num_online_cpus() * threshold;
311aa454840SChristoph Lameter if (max_drift > tolerate_drift)
312aa454840SChristoph Lameter zone->percpu_drift_mark = high_wmark_pages(zone) +
313aa454840SChristoph Lameter max_drift;
314df9ecabaSChristoph Lameter }
3152244b95aSChristoph Lameter }
3162244b95aSChristoph Lameter
set_pgdat_percpu_threshold(pg_data_t * pgdat,int (* calculate_pressure)(struct zone *))317b44129b3SMel Gorman void set_pgdat_percpu_threshold(pg_data_t *pgdat,
318b44129b3SMel Gorman int (*calculate_pressure)(struct zone *))
31988f5acf8SMel Gorman {
32088f5acf8SMel Gorman struct zone *zone;
32188f5acf8SMel Gorman int cpu;
32288f5acf8SMel Gorman int threshold;
32388f5acf8SMel Gorman int i;
32488f5acf8SMel Gorman
32588f5acf8SMel Gorman for (i = 0; i < pgdat->nr_zones; i++) {
32688f5acf8SMel Gorman zone = &pgdat->node_zones[i];
32788f5acf8SMel Gorman if (!zone->percpu_drift_mark)
32888f5acf8SMel Gorman continue;
32988f5acf8SMel Gorman
330b44129b3SMel Gorman threshold = (*calculate_pressure)(zone);
3311d90ca89SKemi Wang for_each_online_cpu(cpu)
33228f836b6SMel Gorman per_cpu_ptr(zone->per_cpu_zonestats, cpu)->stat_threshold
33388f5acf8SMel Gorman = threshold;
33488f5acf8SMel Gorman }
33588f5acf8SMel Gorman }
33688f5acf8SMel Gorman
3372244b95aSChristoph Lameter /*
338bea04b07SJianyu Zhan * For use when we know that interrupts are disabled,
339bea04b07SJianyu Zhan * or when we know that preemption is disabled and that
340bea04b07SJianyu Zhan * particular counter cannot be updated from interrupt context.
3412244b95aSChristoph Lameter */
__mod_zone_page_state(struct zone * zone,enum zone_stat_item item,long delta)3422244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
3436cdb18adSHeiko Carstens long delta)
3442244b95aSChristoph Lameter {
34528f836b6SMel Gorman struct per_cpu_zonestat __percpu *pcp = zone->per_cpu_zonestats;
34612938a92SChristoph Lameter s8 __percpu *p = pcp->vm_stat_diff + item;
3472244b95aSChristoph Lameter long x;
34812938a92SChristoph Lameter long t;
3492244b95aSChristoph Lameter
350c68ed794SIngo Molnar /*
351c68ed794SIngo Molnar * Accurate vmstat updates require a RMW. On !PREEMPT_RT kernels,
352c68ed794SIngo Molnar * atomicity is provided by IRQs being disabled -- either explicitly
353c68ed794SIngo Molnar * or via local_lock_irq. On PREEMPT_RT, local_lock_irq only disables
354c68ed794SIngo Molnar * CPU migrations and preemption potentially corrupts a counter so
355c68ed794SIngo Molnar * disable preemption.
356c68ed794SIngo Molnar */
3577a025e91SThomas Gleixner preempt_disable_nested();
358c68ed794SIngo Molnar
35912938a92SChristoph Lameter x = delta + __this_cpu_read(*p);
3602244b95aSChristoph Lameter
36112938a92SChristoph Lameter t = __this_cpu_read(pcp->stat_threshold);
36212938a92SChristoph Lameter
36340610076SMiaohe Lin if (unlikely(abs(x) > t)) {
3642244b95aSChristoph Lameter zone_page_state_add(x, zone, item);
3652244b95aSChristoph Lameter x = 0;
3662244b95aSChristoph Lameter }
36712938a92SChristoph Lameter __this_cpu_write(*p, x);
368c68ed794SIngo Molnar
3697a025e91SThomas Gleixner preempt_enable_nested();
3702244b95aSChristoph Lameter }
3712244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
3722244b95aSChristoph Lameter
__mod_node_page_state(struct pglist_data * pgdat,enum node_stat_item item,long delta)37375ef7184SMel Gorman void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
37475ef7184SMel Gorman long delta)
37575ef7184SMel Gorman {
37675ef7184SMel Gorman struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
37775ef7184SMel Gorman s8 __percpu *p = pcp->vm_node_stat_diff + item;
37875ef7184SMel Gorman long x;
37975ef7184SMel Gorman long t;
38075ef7184SMel Gorman
381ea426c2aSRoman Gushchin if (vmstat_item_in_bytes(item)) {
382629484aeSJohannes Weiner /*
383629484aeSJohannes Weiner * Only cgroups use subpage accounting right now; at
384629484aeSJohannes Weiner * the global level, these items still change in
385629484aeSJohannes Weiner * multiples of whole pages. Store them as pages
386629484aeSJohannes Weiner * internally to keep the per-cpu counters compact.
387629484aeSJohannes Weiner */
388ea426c2aSRoman Gushchin VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
389ea426c2aSRoman Gushchin delta >>= PAGE_SHIFT;
390ea426c2aSRoman Gushchin }
391ea426c2aSRoman Gushchin
392c68ed794SIngo Molnar /* See __mod_node_page_state */
3937a025e91SThomas Gleixner preempt_disable_nested();
394c68ed794SIngo Molnar
39575ef7184SMel Gorman x = delta + __this_cpu_read(*p);
39675ef7184SMel Gorman
39775ef7184SMel Gorman t = __this_cpu_read(pcp->stat_threshold);
39875ef7184SMel Gorman
39940610076SMiaohe Lin if (unlikely(abs(x) > t)) {
40075ef7184SMel Gorman node_page_state_add(x, pgdat, item);
40175ef7184SMel Gorman x = 0;
40275ef7184SMel Gorman }
40375ef7184SMel Gorman __this_cpu_write(*p, x);
404c68ed794SIngo Molnar
4057a025e91SThomas Gleixner preempt_enable_nested();
40675ef7184SMel Gorman }
40775ef7184SMel Gorman EXPORT_SYMBOL(__mod_node_page_state);
40875ef7184SMel Gorman
4092244b95aSChristoph Lameter /*
4102244b95aSChristoph Lameter * Optimized increment and decrement functions.
4112244b95aSChristoph Lameter *
4122244b95aSChristoph Lameter * These are only for a single page and therefore can take a struct page *
4132244b95aSChristoph Lameter * argument instead of struct zone *. This allows the inclusion of the code
4142244b95aSChristoph Lameter * generated for page_zone(page) into the optimized functions.
4152244b95aSChristoph Lameter *
4162244b95aSChristoph Lameter * No overflow check is necessary and therefore the differential can be
4172244b95aSChristoph Lameter * incremented or decremented in place which may allow the compilers to
4182244b95aSChristoph Lameter * generate better code.
4192244b95aSChristoph Lameter * The increment or decrement is known and therefore one boundary check can
4202244b95aSChristoph Lameter * be omitted.
4212244b95aSChristoph Lameter *
422df9ecabaSChristoph Lameter * NOTE: These functions are very performance sensitive. Change only
423df9ecabaSChristoph Lameter * with care.
424df9ecabaSChristoph Lameter *
4252244b95aSChristoph Lameter * Some processors have inc/dec instructions that are atomic vs an interrupt.
4262244b95aSChristoph Lameter * However, the code must first determine the differential location in a zone
4272244b95aSChristoph Lameter * based on the processor number and then inc/dec the counter. There is no
4282244b95aSChristoph Lameter * guarantee without disabling preemption that the processor will not change
4292244b95aSChristoph Lameter * in between and therefore the atomicity vs. interrupt cannot be exploited
4302244b95aSChristoph Lameter * in a useful way here.
4312244b95aSChristoph Lameter */
__inc_zone_state(struct zone * zone,enum zone_stat_item item)432c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
4332244b95aSChristoph Lameter {
43428f836b6SMel Gorman struct per_cpu_zonestat __percpu *pcp = zone->per_cpu_zonestats;
43512938a92SChristoph Lameter s8 __percpu *p = pcp->vm_stat_diff + item;
43612938a92SChristoph Lameter s8 v, t;
4372244b95aSChristoph Lameter
438c68ed794SIngo Molnar /* See __mod_node_page_state */
4397a025e91SThomas Gleixner preempt_disable_nested();
440c68ed794SIngo Molnar
441908ee0f1SChristoph Lameter v = __this_cpu_inc_return(*p);
44212938a92SChristoph Lameter t = __this_cpu_read(pcp->stat_threshold);
44312938a92SChristoph Lameter if (unlikely(v > t)) {
44412938a92SChristoph Lameter s8 overstep = t >> 1;
4452244b95aSChristoph Lameter
44612938a92SChristoph Lameter zone_page_state_add(v + overstep, zone, item);
44712938a92SChristoph Lameter __this_cpu_write(*p, -overstep);
4482244b95aSChristoph Lameter }
449c68ed794SIngo Molnar
4507a025e91SThomas Gleixner preempt_enable_nested();
4512244b95aSChristoph Lameter }
452ca889e6cSChristoph Lameter
__inc_node_state(struct pglist_data * pgdat,enum node_stat_item item)45375ef7184SMel Gorman void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
45475ef7184SMel Gorman {
45575ef7184SMel Gorman struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
45675ef7184SMel Gorman s8 __percpu *p = pcp->vm_node_stat_diff + item;
45775ef7184SMel Gorman s8 v, t;
45875ef7184SMel Gorman
459ea426c2aSRoman Gushchin VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
460ea426c2aSRoman Gushchin
461c68ed794SIngo Molnar /* See __mod_node_page_state */
4627a025e91SThomas Gleixner preempt_disable_nested();
463c68ed794SIngo Molnar
46475ef7184SMel Gorman v = __this_cpu_inc_return(*p);
46575ef7184SMel Gorman t = __this_cpu_read(pcp->stat_threshold);
46675ef7184SMel Gorman if (unlikely(v > t)) {
46775ef7184SMel Gorman s8 overstep = t >> 1;
46875ef7184SMel Gorman
46975ef7184SMel Gorman node_page_state_add(v + overstep, pgdat, item);
47075ef7184SMel Gorman __this_cpu_write(*p, -overstep);
47175ef7184SMel Gorman }
472c68ed794SIngo Molnar
4737a025e91SThomas Gleixner preempt_enable_nested();
47475ef7184SMel Gorman }
47575ef7184SMel Gorman
__inc_zone_page_state(struct page * page,enum zone_stat_item item)476ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
477ca889e6cSChristoph Lameter {
478ca889e6cSChristoph Lameter __inc_zone_state(page_zone(page), item);
479ca889e6cSChristoph Lameter }
4802244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
4812244b95aSChristoph Lameter
__inc_node_page_state(struct page * page,enum node_stat_item item)48275ef7184SMel Gorman void __inc_node_page_state(struct page *page, enum node_stat_item item)
48375ef7184SMel Gorman {
48475ef7184SMel Gorman __inc_node_state(page_pgdat(page), item);
48575ef7184SMel Gorman }
48675ef7184SMel Gorman EXPORT_SYMBOL(__inc_node_page_state);
48775ef7184SMel Gorman
__dec_zone_state(struct zone * zone,enum zone_stat_item item)488c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
4892244b95aSChristoph Lameter {
49028f836b6SMel Gorman struct per_cpu_zonestat __percpu *pcp = zone->per_cpu_zonestats;
49112938a92SChristoph Lameter s8 __percpu *p = pcp->vm_stat_diff + item;
49212938a92SChristoph Lameter s8 v, t;
4932244b95aSChristoph Lameter
494c68ed794SIngo Molnar /* See __mod_node_page_state */
4957a025e91SThomas Gleixner preempt_disable_nested();
496c68ed794SIngo Molnar
497908ee0f1SChristoph Lameter v = __this_cpu_dec_return(*p);
49812938a92SChristoph Lameter t = __this_cpu_read(pcp->stat_threshold);
49912938a92SChristoph Lameter if (unlikely(v < - t)) {
50012938a92SChristoph Lameter s8 overstep = t >> 1;
5012244b95aSChristoph Lameter
50212938a92SChristoph Lameter zone_page_state_add(v - overstep, zone, item);
50312938a92SChristoph Lameter __this_cpu_write(*p, overstep);
5042244b95aSChristoph Lameter }
505c68ed794SIngo Molnar
5067a025e91SThomas Gleixner preempt_enable_nested();
5072244b95aSChristoph Lameter }
508c8785385SChristoph Lameter
__dec_node_state(struct pglist_data * pgdat,enum node_stat_item item)50975ef7184SMel Gorman void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
51075ef7184SMel Gorman {
51175ef7184SMel Gorman struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
51275ef7184SMel Gorman s8 __percpu *p = pcp->vm_node_stat_diff + item;
51375ef7184SMel Gorman s8 v, t;
51475ef7184SMel Gorman
515ea426c2aSRoman Gushchin VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
516ea426c2aSRoman Gushchin
517c68ed794SIngo Molnar /* See __mod_node_page_state */
5187a025e91SThomas Gleixner preempt_disable_nested();
519c68ed794SIngo Molnar
52075ef7184SMel Gorman v = __this_cpu_dec_return(*p);
52175ef7184SMel Gorman t = __this_cpu_read(pcp->stat_threshold);
52275ef7184SMel Gorman if (unlikely(v < - t)) {
52375ef7184SMel Gorman s8 overstep = t >> 1;
52475ef7184SMel Gorman
52575ef7184SMel Gorman node_page_state_add(v - overstep, pgdat, item);
52675ef7184SMel Gorman __this_cpu_write(*p, overstep);
52775ef7184SMel Gorman }
528c68ed794SIngo Molnar
5297a025e91SThomas Gleixner preempt_enable_nested();
53075ef7184SMel Gorman }
53175ef7184SMel Gorman
__dec_zone_page_state(struct page * page,enum zone_stat_item item)532c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
533c8785385SChristoph Lameter {
534c8785385SChristoph Lameter __dec_zone_state(page_zone(page), item);
535c8785385SChristoph Lameter }
5362244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
5372244b95aSChristoph Lameter
__dec_node_page_state(struct page * page,enum node_stat_item item)53875ef7184SMel Gorman void __dec_node_page_state(struct page *page, enum node_stat_item item)
53975ef7184SMel Gorman {
54075ef7184SMel Gorman __dec_node_state(page_pgdat(page), item);
54175ef7184SMel Gorman }
54275ef7184SMel Gorman EXPORT_SYMBOL(__dec_node_page_state);
54375ef7184SMel Gorman
5444156153cSHeiko Carstens #ifdef CONFIG_HAVE_CMPXCHG_LOCAL
5457c839120SChristoph Lameter /*
5467c839120SChristoph Lameter * If we have cmpxchg_local support then we do not need to incur the overhead
5477c839120SChristoph Lameter * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
5487c839120SChristoph Lameter *
5497c839120SChristoph Lameter * mod_state() modifies the zone counter state through atomic per cpu
5507c839120SChristoph Lameter * operations.
5517c839120SChristoph Lameter *
5527c839120SChristoph Lameter * Overstep mode specifies how overstep should handled:
5537c839120SChristoph Lameter * 0 No overstepping
5547c839120SChristoph Lameter * 1 Overstepping half of threshold
5557c839120SChristoph Lameter * -1 Overstepping minus half of threshold
5567c839120SChristoph Lameter */
mod_zone_state(struct zone * zone,enum zone_stat_item item,long delta,int overstep_mode)55775ef7184SMel Gorman static inline void mod_zone_state(struct zone *zone,
55875ef7184SMel Gorman enum zone_stat_item item, long delta, int overstep_mode)
5597c839120SChristoph Lameter {
56028f836b6SMel Gorman struct per_cpu_zonestat __percpu *pcp = zone->per_cpu_zonestats;
5617c839120SChristoph Lameter s8 __percpu *p = pcp->vm_stat_diff + item;
5627c839120SChristoph Lameter long o, n, t, z;
5637c839120SChristoph Lameter
5647c839120SChristoph Lameter do {
5657c839120SChristoph Lameter z = 0; /* overflow to zone counters */
5667c839120SChristoph Lameter
5677c839120SChristoph Lameter /*
5687c839120SChristoph Lameter * The fetching of the stat_threshold is racy. We may apply
5697c839120SChristoph Lameter * a counter threshold to the wrong the cpu if we get
570d3bc2367SChristoph Lameter * rescheduled while executing here. However, the next
571d3bc2367SChristoph Lameter * counter update will apply the threshold again and
572d3bc2367SChristoph Lameter * therefore bring the counter under the threshold again.
573d3bc2367SChristoph Lameter *
574d3bc2367SChristoph Lameter * Most of the time the thresholds are the same anyways
575d3bc2367SChristoph Lameter * for all cpus in a zone.
5767c839120SChristoph Lameter */
5777c839120SChristoph Lameter t = this_cpu_read(pcp->stat_threshold);
5787c839120SChristoph Lameter
5797c839120SChristoph Lameter o = this_cpu_read(*p);
5807c839120SChristoph Lameter n = delta + o;
5817c839120SChristoph Lameter
58240610076SMiaohe Lin if (abs(n) > t) {
5837c839120SChristoph Lameter int os = overstep_mode * (t >> 1) ;
5847c839120SChristoph Lameter
5857c839120SChristoph Lameter /* Overflow must be added to zone counters */
5867c839120SChristoph Lameter z = n + os;
5877c839120SChristoph Lameter n = -os;
5887c839120SChristoph Lameter }
5897c839120SChristoph Lameter } while (this_cpu_cmpxchg(*p, o, n) != o);
5907c839120SChristoph Lameter
5917c839120SChristoph Lameter if (z)
5927c839120SChristoph Lameter zone_page_state_add(z, zone, item);
5937c839120SChristoph Lameter }
5947c839120SChristoph Lameter
mod_zone_page_state(struct zone * zone,enum zone_stat_item item,long delta)5957c839120SChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
5966cdb18adSHeiko Carstens long delta)
5977c839120SChristoph Lameter {
59875ef7184SMel Gorman mod_zone_state(zone, item, delta, 0);
5997c839120SChristoph Lameter }
6007c839120SChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
6017c839120SChristoph Lameter
inc_zone_page_state(struct page * page,enum zone_stat_item item)6027c839120SChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
6037c839120SChristoph Lameter {
60475ef7184SMel Gorman mod_zone_state(page_zone(page), item, 1, 1);
6057c839120SChristoph Lameter }
6067c839120SChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
6077c839120SChristoph Lameter
dec_zone_page_state(struct page * page,enum zone_stat_item item)6087c839120SChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
6097c839120SChristoph Lameter {
61075ef7184SMel Gorman mod_zone_state(page_zone(page), item, -1, -1);
6117c839120SChristoph Lameter }
6127c839120SChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
61375ef7184SMel Gorman
mod_node_state(struct pglist_data * pgdat,enum node_stat_item item,int delta,int overstep_mode)61475ef7184SMel Gorman static inline void mod_node_state(struct pglist_data *pgdat,
61575ef7184SMel Gorman enum node_stat_item item, int delta, int overstep_mode)
61675ef7184SMel Gorman {
61775ef7184SMel Gorman struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
61875ef7184SMel Gorman s8 __percpu *p = pcp->vm_node_stat_diff + item;
61975ef7184SMel Gorman long o, n, t, z;
62075ef7184SMel Gorman
621ea426c2aSRoman Gushchin if (vmstat_item_in_bytes(item)) {
622629484aeSJohannes Weiner /*
623629484aeSJohannes Weiner * Only cgroups use subpage accounting right now; at
624629484aeSJohannes Weiner * the global level, these items still change in
625629484aeSJohannes Weiner * multiples of whole pages. Store them as pages
626629484aeSJohannes Weiner * internally to keep the per-cpu counters compact.
627629484aeSJohannes Weiner */
628ea426c2aSRoman Gushchin VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
629ea426c2aSRoman Gushchin delta >>= PAGE_SHIFT;
630ea426c2aSRoman Gushchin }
631ea426c2aSRoman Gushchin
63275ef7184SMel Gorman do {
63375ef7184SMel Gorman z = 0; /* overflow to node counters */
63475ef7184SMel Gorman
63575ef7184SMel Gorman /*
63675ef7184SMel Gorman * The fetching of the stat_threshold is racy. We may apply
63775ef7184SMel Gorman * a counter threshold to the wrong the cpu if we get
63875ef7184SMel Gorman * rescheduled while executing here. However, the next
63975ef7184SMel Gorman * counter update will apply the threshold again and
64075ef7184SMel Gorman * therefore bring the counter under the threshold again.
64175ef7184SMel Gorman *
64275ef7184SMel Gorman * Most of the time the thresholds are the same anyways
64375ef7184SMel Gorman * for all cpus in a node.
64475ef7184SMel Gorman */
64575ef7184SMel Gorman t = this_cpu_read(pcp->stat_threshold);
64675ef7184SMel Gorman
64775ef7184SMel Gorman o = this_cpu_read(*p);
64875ef7184SMel Gorman n = delta + o;
64975ef7184SMel Gorman
65040610076SMiaohe Lin if (abs(n) > t) {
65175ef7184SMel Gorman int os = overstep_mode * (t >> 1) ;
65275ef7184SMel Gorman
65375ef7184SMel Gorman /* Overflow must be added to node counters */
65475ef7184SMel Gorman z = n + os;
65575ef7184SMel Gorman n = -os;
65675ef7184SMel Gorman }
65775ef7184SMel Gorman } while (this_cpu_cmpxchg(*p, o, n) != o);
65875ef7184SMel Gorman
65975ef7184SMel Gorman if (z)
66075ef7184SMel Gorman node_page_state_add(z, pgdat, item);
66175ef7184SMel Gorman }
66275ef7184SMel Gorman
mod_node_page_state(struct pglist_data * pgdat,enum node_stat_item item,long delta)66375ef7184SMel Gorman void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
66475ef7184SMel Gorman long delta)
66575ef7184SMel Gorman {
66675ef7184SMel Gorman mod_node_state(pgdat, item, delta, 0);
66775ef7184SMel Gorman }
66875ef7184SMel Gorman EXPORT_SYMBOL(mod_node_page_state);
66975ef7184SMel Gorman
inc_node_state(struct pglist_data * pgdat,enum node_stat_item item)67075ef7184SMel Gorman void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
67175ef7184SMel Gorman {
67275ef7184SMel Gorman mod_node_state(pgdat, item, 1, 1);
67375ef7184SMel Gorman }
67475ef7184SMel Gorman
inc_node_page_state(struct page * page,enum node_stat_item item)67575ef7184SMel Gorman void inc_node_page_state(struct page *page, enum node_stat_item item)
67675ef7184SMel Gorman {
67775ef7184SMel Gorman mod_node_state(page_pgdat(page), item, 1, 1);
67875ef7184SMel Gorman }
67975ef7184SMel Gorman EXPORT_SYMBOL(inc_node_page_state);
68075ef7184SMel Gorman
dec_node_page_state(struct page * page,enum node_stat_item item)68175ef7184SMel Gorman void dec_node_page_state(struct page *page, enum node_stat_item item)
68275ef7184SMel Gorman {
68375ef7184SMel Gorman mod_node_state(page_pgdat(page), item, -1, -1);
68475ef7184SMel Gorman }
68575ef7184SMel Gorman EXPORT_SYMBOL(dec_node_page_state);
6867c839120SChristoph Lameter #else
6877c839120SChristoph Lameter /*
6887c839120SChristoph Lameter * Use interrupt disable to serialize counter updates
6897c839120SChristoph Lameter */
mod_zone_page_state(struct zone * zone,enum zone_stat_item item,long delta)6907c839120SChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
6916cdb18adSHeiko Carstens long delta)
6927c839120SChristoph Lameter {
6937c839120SChristoph Lameter unsigned long flags;
6947c839120SChristoph Lameter
6957c839120SChristoph Lameter local_irq_save(flags);
6967c839120SChristoph Lameter __mod_zone_page_state(zone, item, delta);
6977c839120SChristoph Lameter local_irq_restore(flags);
6987c839120SChristoph Lameter }
6997c839120SChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
7007c839120SChristoph Lameter
inc_zone_page_state(struct page * page,enum zone_stat_item item)7012244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
7022244b95aSChristoph Lameter {
7032244b95aSChristoph Lameter unsigned long flags;
7042244b95aSChristoph Lameter struct zone *zone;
7052244b95aSChristoph Lameter
7062244b95aSChristoph Lameter zone = page_zone(page);
7072244b95aSChristoph Lameter local_irq_save(flags);
708ca889e6cSChristoph Lameter __inc_zone_state(zone, item);
7092244b95aSChristoph Lameter local_irq_restore(flags);
7102244b95aSChristoph Lameter }
7112244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
7122244b95aSChristoph Lameter
dec_zone_page_state(struct page * page,enum zone_stat_item item)7132244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
7142244b95aSChristoph Lameter {
7152244b95aSChristoph Lameter unsigned long flags;
7162244b95aSChristoph Lameter
7172244b95aSChristoph Lameter local_irq_save(flags);
718a302eb4eSChristoph Lameter __dec_zone_page_state(page, item);
7192244b95aSChristoph Lameter local_irq_restore(flags);
7202244b95aSChristoph Lameter }
7212244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
7222244b95aSChristoph Lameter
inc_node_state(struct pglist_data * pgdat,enum node_stat_item item)72375ef7184SMel Gorman void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
72475ef7184SMel Gorman {
72575ef7184SMel Gorman unsigned long flags;
72675ef7184SMel Gorman
72775ef7184SMel Gorman local_irq_save(flags);
72875ef7184SMel Gorman __inc_node_state(pgdat, item);
72975ef7184SMel Gorman local_irq_restore(flags);
73075ef7184SMel Gorman }
73175ef7184SMel Gorman EXPORT_SYMBOL(inc_node_state);
73275ef7184SMel Gorman
mod_node_page_state(struct pglist_data * pgdat,enum node_stat_item item,long delta)73375ef7184SMel Gorman void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
73475ef7184SMel Gorman long delta)
73575ef7184SMel Gorman {
73675ef7184SMel Gorman unsigned long flags;
73775ef7184SMel Gorman
73875ef7184SMel Gorman local_irq_save(flags);
73975ef7184SMel Gorman __mod_node_page_state(pgdat, item, delta);
74075ef7184SMel Gorman local_irq_restore(flags);
74175ef7184SMel Gorman }
74275ef7184SMel Gorman EXPORT_SYMBOL(mod_node_page_state);
74375ef7184SMel Gorman
inc_node_page_state(struct page * page,enum node_stat_item item)74475ef7184SMel Gorman void inc_node_page_state(struct page *page, enum node_stat_item item)
74575ef7184SMel Gorman {
74675ef7184SMel Gorman unsigned long flags;
74775ef7184SMel Gorman struct pglist_data *pgdat;
74875ef7184SMel Gorman
74975ef7184SMel Gorman pgdat = page_pgdat(page);
75075ef7184SMel Gorman local_irq_save(flags);
75175ef7184SMel Gorman __inc_node_state(pgdat, item);
75275ef7184SMel Gorman local_irq_restore(flags);
75375ef7184SMel Gorman }
75475ef7184SMel Gorman EXPORT_SYMBOL(inc_node_page_state);
75575ef7184SMel Gorman
dec_node_page_state(struct page * page,enum node_stat_item item)75675ef7184SMel Gorman void dec_node_page_state(struct page *page, enum node_stat_item item)
75775ef7184SMel Gorman {
75875ef7184SMel Gorman unsigned long flags;
75975ef7184SMel Gorman
76075ef7184SMel Gorman local_irq_save(flags);
76175ef7184SMel Gorman __dec_node_page_state(page, item);
76275ef7184SMel Gorman local_irq_restore(flags);
76375ef7184SMel Gorman }
76475ef7184SMel Gorman EXPORT_SYMBOL(dec_node_page_state);
76575ef7184SMel Gorman #endif
7667cc36bbdSChristoph Lameter
7677cc36bbdSChristoph Lameter /*
7687cc36bbdSChristoph Lameter * Fold a differential into the global counters.
7697cc36bbdSChristoph Lameter * Returns the number of counters updated.
7707cc36bbdSChristoph Lameter */
fold_diff(int * zone_diff,int * node_diff)77175ef7184SMel Gorman static int fold_diff(int *zone_diff, int *node_diff)
7724edb0748SChristoph Lameter {
7734edb0748SChristoph Lameter int i;
7747cc36bbdSChristoph Lameter int changes = 0;
7754edb0748SChristoph Lameter
7764edb0748SChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
77775ef7184SMel Gorman if (zone_diff[i]) {
77875ef7184SMel Gorman atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
77975ef7184SMel Gorman changes++;
78075ef7184SMel Gorman }
78175ef7184SMel Gorman
78275ef7184SMel Gorman for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
78375ef7184SMel Gorman if (node_diff[i]) {
78475ef7184SMel Gorman atomic_long_add(node_diff[i], &vm_node_stat[i]);
7857cc36bbdSChristoph Lameter changes++;
7867cc36bbdSChristoph Lameter }
7877cc36bbdSChristoph Lameter return changes;
7884edb0748SChristoph Lameter }
789f19298b9SMel Gorman
7902244b95aSChristoph Lameter /*
7912bb921e5SChristoph Lameter * Update the zone counters for the current cpu.
792a7f75e25SChristoph Lameter *
7934037d452SChristoph Lameter * Note that refresh_cpu_vm_stats strives to only access
7944037d452SChristoph Lameter * node local memory. The per cpu pagesets on remote zones are placed
7954037d452SChristoph Lameter * in the memory local to the processor using that pageset. So the
7964037d452SChristoph Lameter * loop over all zones will access a series of cachelines local to
7974037d452SChristoph Lameter * the processor.
7984037d452SChristoph Lameter *
7994037d452SChristoph Lameter * The call to zone_page_state_add updates the cachelines with the
8004037d452SChristoph Lameter * statistics in the remote zone struct as well as the global cachelines
8014037d452SChristoph Lameter * with the global counters. These could cause remote node cache line
8024037d452SChristoph Lameter * bouncing and will have to be only done when necessary.
8037cc36bbdSChristoph Lameter *
8047cc36bbdSChristoph Lameter * The function returns the number of global counters updated.
8052244b95aSChristoph Lameter */
refresh_cpu_vm_stats(bool do_pagesets)8060eb77e98SChristoph Lameter static int refresh_cpu_vm_stats(bool do_pagesets)
8072244b95aSChristoph Lameter {
80875ef7184SMel Gorman struct pglist_data *pgdat;
8092244b95aSChristoph Lameter struct zone *zone;
8102244b95aSChristoph Lameter int i;
81175ef7184SMel Gorman int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
81275ef7184SMel Gorman int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
8137cc36bbdSChristoph Lameter int changes = 0;
8142244b95aSChristoph Lameter
815ee99c71cSKOSAKI Motohiro for_each_populated_zone(zone) {
81628f836b6SMel Gorman struct per_cpu_zonestat __percpu *pzstats = zone->per_cpu_zonestats;
81728f836b6SMel Gorman #ifdef CONFIG_NUMA
81828f836b6SMel Gorman struct per_cpu_pages __percpu *pcp = zone->per_cpu_pageset;
81928f836b6SMel Gorman #endif
8202244b95aSChristoph Lameter
821fbc2edb0SChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
822a7f75e25SChristoph Lameter int v;
823a7f75e25SChristoph Lameter
82428f836b6SMel Gorman v = this_cpu_xchg(pzstats->vm_stat_diff[i], 0);
825fbc2edb0SChristoph Lameter if (v) {
826fbc2edb0SChristoph Lameter
827a7f75e25SChristoph Lameter atomic_long_add(v, &zone->vm_stat[i]);
82875ef7184SMel Gorman global_zone_diff[i] += v;
8294037d452SChristoph Lameter #ifdef CONFIG_NUMA
8304037d452SChristoph Lameter /* 3 seconds idle till flush */
83128f836b6SMel Gorman __this_cpu_write(pcp->expire, 3);
8324037d452SChristoph Lameter #endif
8332244b95aSChristoph Lameter }
834fbc2edb0SChristoph Lameter }
8354037d452SChristoph Lameter #ifdef CONFIG_NUMA
8363a321d2aSKemi Wang
8370eb77e98SChristoph Lameter if (do_pagesets) {
8380eb77e98SChristoph Lameter cond_resched();
8394037d452SChristoph Lameter /*
8404037d452SChristoph Lameter * Deal with draining the remote pageset of this
8414037d452SChristoph Lameter * processor
8424037d452SChristoph Lameter *
8434037d452SChristoph Lameter * Check if there are pages remaining in this pageset
8444037d452SChristoph Lameter * if not then there is nothing to expire.
8454037d452SChristoph Lameter */
84628f836b6SMel Gorman if (!__this_cpu_read(pcp->expire) ||
84728f836b6SMel Gorman !__this_cpu_read(pcp->count))
8484037d452SChristoph Lameter continue;
8494037d452SChristoph Lameter
8504037d452SChristoph Lameter /*
8514037d452SChristoph Lameter * We never drain zones local to this processor.
8524037d452SChristoph Lameter */
8534037d452SChristoph Lameter if (zone_to_nid(zone) == numa_node_id()) {
85428f836b6SMel Gorman __this_cpu_write(pcp->expire, 0);
8554037d452SChristoph Lameter continue;
8564037d452SChristoph Lameter }
8574037d452SChristoph Lameter
85828f836b6SMel Gorman if (__this_cpu_dec_return(pcp->expire))
8594037d452SChristoph Lameter continue;
8604037d452SChristoph Lameter
86128f836b6SMel Gorman if (__this_cpu_read(pcp->count)) {
86228f836b6SMel Gorman drain_zone_pages(zone, this_cpu_ptr(pcp));
8637cc36bbdSChristoph Lameter changes++;
8647cc36bbdSChristoph Lameter }
8650eb77e98SChristoph Lameter }
8664037d452SChristoph Lameter #endif
8672244b95aSChristoph Lameter }
86875ef7184SMel Gorman
86975ef7184SMel Gorman for_each_online_pgdat(pgdat) {
87075ef7184SMel Gorman struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
87175ef7184SMel Gorman
87275ef7184SMel Gorman for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
87375ef7184SMel Gorman int v;
87475ef7184SMel Gorman
87575ef7184SMel Gorman v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
87675ef7184SMel Gorman if (v) {
87775ef7184SMel Gorman atomic_long_add(v, &pgdat->vm_stat[i]);
87875ef7184SMel Gorman global_node_diff[i] += v;
87975ef7184SMel Gorman }
88075ef7184SMel Gorman }
88175ef7184SMel Gorman }
88275ef7184SMel Gorman
88375ef7184SMel Gorman changes += fold_diff(global_zone_diff, global_node_diff);
8847cc36bbdSChristoph Lameter return changes;
8852244b95aSChristoph Lameter }
8862244b95aSChristoph Lameter
88740f4b1eaSCody P Schafer /*
8882bb921e5SChristoph Lameter * Fold the data for an offline cpu into the global array.
8892bb921e5SChristoph Lameter * There cannot be any access by the offline cpu and therefore
8902bb921e5SChristoph Lameter * synchronization is simplified.
8912bb921e5SChristoph Lameter */
cpu_vm_stats_fold(int cpu)8922bb921e5SChristoph Lameter void cpu_vm_stats_fold(int cpu)
8932bb921e5SChristoph Lameter {
89475ef7184SMel Gorman struct pglist_data *pgdat;
8952bb921e5SChristoph Lameter struct zone *zone;
8962bb921e5SChristoph Lameter int i;
89775ef7184SMel Gorman int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
89875ef7184SMel Gorman int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
8992bb921e5SChristoph Lameter
9002bb921e5SChristoph Lameter for_each_populated_zone(zone) {
90128f836b6SMel Gorman struct per_cpu_zonestat *pzstats;
9022bb921e5SChristoph Lameter
90328f836b6SMel Gorman pzstats = per_cpu_ptr(zone->per_cpu_zonestats, cpu);
9042bb921e5SChristoph Lameter
905f19298b9SMel Gorman for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
90628f836b6SMel Gorman if (pzstats->vm_stat_diff[i]) {
9072bb921e5SChristoph Lameter int v;
9082bb921e5SChristoph Lameter
90928f836b6SMel Gorman v = pzstats->vm_stat_diff[i];
91028f836b6SMel Gorman pzstats->vm_stat_diff[i] = 0;
9112bb921e5SChristoph Lameter atomic_long_add(v, &zone->vm_stat[i]);
91275ef7184SMel Gorman global_zone_diff[i] += v;
9132bb921e5SChristoph Lameter }
914f19298b9SMel Gorman }
9153a321d2aSKemi Wang #ifdef CONFIG_NUMA
916f19298b9SMel Gorman for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++) {
917f19298b9SMel Gorman if (pzstats->vm_numa_event[i]) {
918f19298b9SMel Gorman unsigned long v;
9193a321d2aSKemi Wang
920f19298b9SMel Gorman v = pzstats->vm_numa_event[i];
921f19298b9SMel Gorman pzstats->vm_numa_event[i] = 0;
922f19298b9SMel Gorman zone_numa_event_add(v, zone, i);
923f19298b9SMel Gorman }
9243a321d2aSKemi Wang }
9253a321d2aSKemi Wang #endif
9262bb921e5SChristoph Lameter }
9272bb921e5SChristoph Lameter
92875ef7184SMel Gorman for_each_online_pgdat(pgdat) {
92975ef7184SMel Gorman struct per_cpu_nodestat *p;
93075ef7184SMel Gorman
93175ef7184SMel Gorman p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
93275ef7184SMel Gorman
93375ef7184SMel Gorman for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
93475ef7184SMel Gorman if (p->vm_node_stat_diff[i]) {
93575ef7184SMel Gorman int v;
93675ef7184SMel Gorman
93775ef7184SMel Gorman v = p->vm_node_stat_diff[i];
93875ef7184SMel Gorman p->vm_node_stat_diff[i] = 0;
93975ef7184SMel Gorman atomic_long_add(v, &pgdat->vm_stat[i]);
94075ef7184SMel Gorman global_node_diff[i] += v;
94175ef7184SMel Gorman }
94275ef7184SMel Gorman }
94375ef7184SMel Gorman
94475ef7184SMel Gorman fold_diff(global_zone_diff, global_node_diff);
9452bb921e5SChristoph Lameter }
9462bb921e5SChristoph Lameter
9472bb921e5SChristoph Lameter /*
94840f4b1eaSCody P Schafer * this is only called if !populated_zone(zone), which implies no other users of
949f0953a1bSIngo Molnar * pset->vm_stat_diff[] exist.
95040f4b1eaSCody P Schafer */
drain_zonestat(struct zone * zone,struct per_cpu_zonestat * pzstats)95128f836b6SMel Gorman void drain_zonestat(struct zone *zone, struct per_cpu_zonestat *pzstats)
9525a883813SMinchan Kim {
953f19298b9SMel Gorman unsigned long v;
9545a883813SMinchan Kim int i;
9555a883813SMinchan Kim
956f19298b9SMel Gorman for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
95728f836b6SMel Gorman if (pzstats->vm_stat_diff[i]) {
958f19298b9SMel Gorman v = pzstats->vm_stat_diff[i];
95928f836b6SMel Gorman pzstats->vm_stat_diff[i] = 0;
960f19298b9SMel Gorman zone_page_state_add(v, zone, i);
961f19298b9SMel Gorman }
9625a883813SMinchan Kim }
9633a321d2aSKemi Wang
9643a321d2aSKemi Wang #ifdef CONFIG_NUMA
965f19298b9SMel Gorman for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++) {
966f19298b9SMel Gorman if (pzstats->vm_numa_event[i]) {
967f19298b9SMel Gorman v = pzstats->vm_numa_event[i];
968f19298b9SMel Gorman pzstats->vm_numa_event[i] = 0;
969f19298b9SMel Gorman zone_numa_event_add(v, zone, i);
970f19298b9SMel Gorman }
9713a321d2aSKemi Wang }
9723a321d2aSKemi Wang #endif
9735a883813SMinchan Kim }
9742244b95aSChristoph Lameter #endif
9752244b95aSChristoph Lameter
976ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
977ca889e6cSChristoph Lameter /*
97875ef7184SMel Gorman * Determine the per node value of a stat item. This function
97975ef7184SMel Gorman * is called frequently in a NUMA machine, so try to be as
98075ef7184SMel Gorman * frugal as possible.
981c2d42c16SAndrew Morton */
sum_zone_node_page_state(int node,enum zone_stat_item item)98275ef7184SMel Gorman unsigned long sum_zone_node_page_state(int node,
98375ef7184SMel Gorman enum zone_stat_item item)
984c2d42c16SAndrew Morton {
985c2d42c16SAndrew Morton struct zone *zones = NODE_DATA(node)->node_zones;
986e87d59f7SJoonsoo Kim int i;
987e87d59f7SJoonsoo Kim unsigned long count = 0;
988c2d42c16SAndrew Morton
989e87d59f7SJoonsoo Kim for (i = 0; i < MAX_NR_ZONES; i++)
990e87d59f7SJoonsoo Kim count += zone_page_state(zones + i, item);
991e87d59f7SJoonsoo Kim
992e87d59f7SJoonsoo Kim return count;
993c2d42c16SAndrew Morton }
994c2d42c16SAndrew Morton
995f19298b9SMel Gorman /* Determine the per node value of a numa stat item. */
sum_zone_numa_event_state(int node,enum numa_stat_item item)996f19298b9SMel Gorman unsigned long sum_zone_numa_event_state(int node,
9973a321d2aSKemi Wang enum numa_stat_item item)
9983a321d2aSKemi Wang {
9993a321d2aSKemi Wang struct zone *zones = NODE_DATA(node)->node_zones;
10003a321d2aSKemi Wang unsigned long count = 0;
1001f19298b9SMel Gorman int i;
10023a321d2aSKemi Wang
10033a321d2aSKemi Wang for (i = 0; i < MAX_NR_ZONES; i++)
1004f19298b9SMel Gorman count += zone_numa_event_state(zones + i, item);
10053a321d2aSKemi Wang
10063a321d2aSKemi Wang return count;
10073a321d2aSKemi Wang }
10083a321d2aSKemi Wang
100975ef7184SMel Gorman /*
101075ef7184SMel Gorman * Determine the per node value of a stat item.
101175ef7184SMel Gorman */
node_page_state_pages(struct pglist_data * pgdat,enum node_stat_item item)1012ea426c2aSRoman Gushchin unsigned long node_page_state_pages(struct pglist_data *pgdat,
101375ef7184SMel Gorman enum node_stat_item item)
101475ef7184SMel Gorman {
101575ef7184SMel Gorman long x = atomic_long_read(&pgdat->vm_stat[item]);
101675ef7184SMel Gorman #ifdef CONFIG_SMP
101775ef7184SMel Gorman if (x < 0)
101875ef7184SMel Gorman x = 0;
101975ef7184SMel Gorman #endif
102075ef7184SMel Gorman return x;
102175ef7184SMel Gorman }
1022ea426c2aSRoman Gushchin
node_page_state(struct pglist_data * pgdat,enum node_stat_item item)1023ea426c2aSRoman Gushchin unsigned long node_page_state(struct pglist_data *pgdat,
1024ea426c2aSRoman Gushchin enum node_stat_item item)
1025ea426c2aSRoman Gushchin {
1026ea426c2aSRoman Gushchin VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
1027ea426c2aSRoman Gushchin
1028ea426c2aSRoman Gushchin return node_page_state_pages(pgdat, item);
1029ea426c2aSRoman Gushchin }
1030ca889e6cSChristoph Lameter #endif
1031ca889e6cSChristoph Lameter
1032d7a5752cSMel Gorman #ifdef CONFIG_COMPACTION
103336deb0beSNamhyung Kim
1034d7a5752cSMel Gorman struct contig_page_info {
1035d7a5752cSMel Gorman unsigned long free_pages;
1036d7a5752cSMel Gorman unsigned long free_blocks_total;
1037d7a5752cSMel Gorman unsigned long free_blocks_suitable;
1038d7a5752cSMel Gorman };
1039d7a5752cSMel Gorman
1040d7a5752cSMel Gorman /*
1041d7a5752cSMel Gorman * Calculate the number of free pages in a zone, how many contiguous
1042d7a5752cSMel Gorman * pages are free and how many are large enough to satisfy an allocation of
1043d7a5752cSMel Gorman * the target size. Note that this function makes no attempt to estimate
1044d7a5752cSMel Gorman * how many suitable free blocks there *might* be if MOVABLE pages were
1045d7a5752cSMel Gorman * migrated. Calculating that is possible, but expensive and can be
1046d7a5752cSMel Gorman * figured out from userspace
1047d7a5752cSMel Gorman */
fill_contig_page_info(struct zone * zone,unsigned int suitable_order,struct contig_page_info * info)1048d7a5752cSMel Gorman static void fill_contig_page_info(struct zone *zone,
1049d7a5752cSMel Gorman unsigned int suitable_order,
1050d7a5752cSMel Gorman struct contig_page_info *info)
1051d7a5752cSMel Gorman {
1052d7a5752cSMel Gorman unsigned int order;
1053d7a5752cSMel Gorman
1054d7a5752cSMel Gorman info->free_pages = 0;
1055d7a5752cSMel Gorman info->free_blocks_total = 0;
1056d7a5752cSMel Gorman info->free_blocks_suitable = 0;
1057d7a5752cSMel Gorman
1058ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; order++) {
1059d7a5752cSMel Gorman unsigned long blocks;
1060d7a5752cSMel Gorman
1061af1c31acSLiu Shixin /*
1062af1c31acSLiu Shixin * Count number of free blocks.
1063af1c31acSLiu Shixin *
1064af1c31acSLiu Shixin * Access to nr_free is lockless as nr_free is used only for
1065af1c31acSLiu Shixin * diagnostic purposes. Use data_race to avoid KCSAN warning.
1066af1c31acSLiu Shixin */
1067af1c31acSLiu Shixin blocks = data_race(zone->free_area[order].nr_free);
1068d7a5752cSMel Gorman info->free_blocks_total += blocks;
1069d7a5752cSMel Gorman
1070d7a5752cSMel Gorman /* Count free base pages */
1071d7a5752cSMel Gorman info->free_pages += blocks << order;
1072d7a5752cSMel Gorman
1073d7a5752cSMel Gorman /* Count the suitable free blocks */
1074d7a5752cSMel Gorman if (order >= suitable_order)
1075d7a5752cSMel Gorman info->free_blocks_suitable += blocks <<
1076d7a5752cSMel Gorman (order - suitable_order);
1077d7a5752cSMel Gorman }
1078d7a5752cSMel Gorman }
1079f1a5ab12SMel Gorman
1080f1a5ab12SMel Gorman /*
1081f1a5ab12SMel Gorman * A fragmentation index only makes sense if an allocation of a requested
1082f1a5ab12SMel Gorman * size would fail. If that is true, the fragmentation index indicates
1083f1a5ab12SMel Gorman * whether external fragmentation or a lack of memory was the problem.
1084f1a5ab12SMel Gorman * The value can be used to determine if page reclaim or compaction
1085f1a5ab12SMel Gorman * should be used
1086f1a5ab12SMel Gorman */
__fragmentation_index(unsigned int order,struct contig_page_info * info)108756de7263SMel Gorman static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
1088f1a5ab12SMel Gorman {
1089f1a5ab12SMel Gorman unsigned long requested = 1UL << order;
1090f1a5ab12SMel Gorman
109123baf831SKirill A. Shutemov if (WARN_ON_ONCE(order > MAX_ORDER))
109288d6ac40SWen Yang return 0;
109388d6ac40SWen Yang
1094f1a5ab12SMel Gorman if (!info->free_blocks_total)
1095f1a5ab12SMel Gorman return 0;
1096f1a5ab12SMel Gorman
1097f1a5ab12SMel Gorman /* Fragmentation index only makes sense when a request would fail */
1098f1a5ab12SMel Gorman if (info->free_blocks_suitable)
1099f1a5ab12SMel Gorman return -1000;
1100f1a5ab12SMel Gorman
1101f1a5ab12SMel Gorman /*
1102f1a5ab12SMel Gorman * Index is between 0 and 1 so return within 3 decimal places
1103f1a5ab12SMel Gorman *
1104f1a5ab12SMel Gorman * 0 => allocation would fail due to lack of memory
1105f1a5ab12SMel Gorman * 1 => allocation would fail due to fragmentation
1106f1a5ab12SMel Gorman */
1107f1a5ab12SMel Gorman return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
1108f1a5ab12SMel Gorman }
110956de7263SMel Gorman
1110facdaa91SNitin Gupta /*
1111facdaa91SNitin Gupta * Calculates external fragmentation within a zone wrt the given order.
1112facdaa91SNitin Gupta * It is defined as the percentage of pages found in blocks of size
1113facdaa91SNitin Gupta * less than 1 << order. It returns values in range [0, 100].
1114facdaa91SNitin Gupta */
extfrag_for_order(struct zone * zone,unsigned int order)1115d34c0a75SNitin Gupta unsigned int extfrag_for_order(struct zone *zone, unsigned int order)
1116facdaa91SNitin Gupta {
1117facdaa91SNitin Gupta struct contig_page_info info;
1118facdaa91SNitin Gupta
1119facdaa91SNitin Gupta fill_contig_page_info(zone, order, &info);
1120facdaa91SNitin Gupta if (info.free_pages == 0)
1121facdaa91SNitin Gupta return 0;
1122facdaa91SNitin Gupta
1123facdaa91SNitin Gupta return div_u64((info.free_pages -
1124facdaa91SNitin Gupta (info.free_blocks_suitable << order)) * 100,
1125facdaa91SNitin Gupta info.free_pages);
1126facdaa91SNitin Gupta }
1127facdaa91SNitin Gupta
112856de7263SMel Gorman /* Same as __fragmentation index but allocs contig_page_info on stack */
fragmentation_index(struct zone * zone,unsigned int order)112956de7263SMel Gorman int fragmentation_index(struct zone *zone, unsigned int order)
113056de7263SMel Gorman {
113156de7263SMel Gorman struct contig_page_info info;
113256de7263SMel Gorman
113356de7263SMel Gorman fill_contig_page_info(zone, order, &info);
113456de7263SMel Gorman return __fragmentation_index(order, &info);
113556de7263SMel Gorman }
1136d7a5752cSMel Gorman #endif
1137d7a5752cSMel Gorman
1138ebc5d83dSKonstantin Khlebnikov #if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
1139ebc5d83dSKonstantin Khlebnikov defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
1140fa25c503SKOSAKI Motohiro #ifdef CONFIG_ZONE_DMA
1141fa25c503SKOSAKI Motohiro #define TEXT_FOR_DMA(xx) xx "_dma",
1142fa25c503SKOSAKI Motohiro #else
1143fa25c503SKOSAKI Motohiro #define TEXT_FOR_DMA(xx)
1144fa25c503SKOSAKI Motohiro #endif
1145fa25c503SKOSAKI Motohiro
1146fa25c503SKOSAKI Motohiro #ifdef CONFIG_ZONE_DMA32
1147fa25c503SKOSAKI Motohiro #define TEXT_FOR_DMA32(xx) xx "_dma32",
1148fa25c503SKOSAKI Motohiro #else
1149fa25c503SKOSAKI Motohiro #define TEXT_FOR_DMA32(xx)
1150fa25c503SKOSAKI Motohiro #endif
1151fa25c503SKOSAKI Motohiro
1152fa25c503SKOSAKI Motohiro #ifdef CONFIG_HIGHMEM
1153fa25c503SKOSAKI Motohiro #define TEXT_FOR_HIGHMEM(xx) xx "_high",
1154fa25c503SKOSAKI Motohiro #else
1155fa25c503SKOSAKI Motohiro #define TEXT_FOR_HIGHMEM(xx)
1156fa25c503SKOSAKI Motohiro #endif
1157fa25c503SKOSAKI Motohiro
1158a39c5d3cSHao Lee #ifdef CONFIG_ZONE_DEVICE
1159a39c5d3cSHao Lee #define TEXT_FOR_DEVICE(xx) xx "_device",
1160a39c5d3cSHao Lee #else
1161a39c5d3cSHao Lee #define TEXT_FOR_DEVICE(xx)
1162a39c5d3cSHao Lee #endif
1163a39c5d3cSHao Lee
1164fa25c503SKOSAKI Motohiro #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
1165a39c5d3cSHao Lee TEXT_FOR_HIGHMEM(xx) xx "_movable", \
1166a39c5d3cSHao Lee TEXT_FOR_DEVICE(xx)
1167fa25c503SKOSAKI Motohiro
1168fa25c503SKOSAKI Motohiro const char * const vmstat_text[] = {
11698d92890bSNeilBrown /* enum zone_stat_item counters */
1170fa25c503SKOSAKI Motohiro "nr_free_pages",
117171c799f4SMinchan Kim "nr_zone_inactive_anon",
117271c799f4SMinchan Kim "nr_zone_active_anon",
117371c799f4SMinchan Kim "nr_zone_inactive_file",
117471c799f4SMinchan Kim "nr_zone_active_file",
117571c799f4SMinchan Kim "nr_zone_unevictable",
11765a1c84b4SMel Gorman "nr_zone_write_pending",
1177fa25c503SKOSAKI Motohiro "nr_mlock",
1178fa25c503SKOSAKI Motohiro "nr_bounce",
117991537feeSMinchan Kim #if IS_ENABLED(CONFIG_ZSMALLOC)
118091537feeSMinchan Kim "nr_zspages",
118191537feeSMinchan Kim #endif
11823a321d2aSKemi Wang "nr_free_cma",
1183dcdfdd40SKirill A. Shutemov #ifdef CONFIG_UNACCEPTED_MEMORY
1184dcdfdd40SKirill A. Shutemov "nr_unaccepted",
1185dcdfdd40SKirill A. Shutemov #endif
11863a321d2aSKemi Wang
11873a321d2aSKemi Wang /* enum numa_stat_item counters */
1188fa25c503SKOSAKI Motohiro #ifdef CONFIG_NUMA
1189fa25c503SKOSAKI Motohiro "numa_hit",
1190fa25c503SKOSAKI Motohiro "numa_miss",
1191fa25c503SKOSAKI Motohiro "numa_foreign",
1192fa25c503SKOSAKI Motohiro "numa_interleave",
1193fa25c503SKOSAKI Motohiro "numa_local",
1194fa25c503SKOSAKI Motohiro "numa_other",
1195fa25c503SKOSAKI Motohiro #endif
119609316c09SKonstantin Khlebnikov
11979d7ea9a2SKonstantin Khlebnikov /* enum node_stat_item counters */
1198599d0c95SMel Gorman "nr_inactive_anon",
1199599d0c95SMel Gorman "nr_active_anon",
1200599d0c95SMel Gorman "nr_inactive_file",
1201599d0c95SMel Gorman "nr_active_file",
1202599d0c95SMel Gorman "nr_unevictable",
1203385386cfSJohannes Weiner "nr_slab_reclaimable",
1204385386cfSJohannes Weiner "nr_slab_unreclaimable",
1205599d0c95SMel Gorman "nr_isolated_anon",
1206599d0c95SMel Gorman "nr_isolated_file",
120768d48e6aSJohannes Weiner "workingset_nodes",
1208170b04b7SJoonsoo Kim "workingset_refault_anon",
1209170b04b7SJoonsoo Kim "workingset_refault_file",
1210170b04b7SJoonsoo Kim "workingset_activate_anon",
1211170b04b7SJoonsoo Kim "workingset_activate_file",
1212170b04b7SJoonsoo Kim "workingset_restore_anon",
1213170b04b7SJoonsoo Kim "workingset_restore_file",
12141e6b1085SMel Gorman "workingset_nodereclaim",
121550658e2eSMel Gorman "nr_anon_pages",
121650658e2eSMel Gorman "nr_mapped",
121711fb9989SMel Gorman "nr_file_pages",
121811fb9989SMel Gorman "nr_dirty",
121911fb9989SMel Gorman "nr_writeback",
122011fb9989SMel Gorman "nr_writeback_temp",
122111fb9989SMel Gorman "nr_shmem",
122211fb9989SMel Gorman "nr_shmem_hugepages",
122311fb9989SMel Gorman "nr_shmem_pmdmapped",
122460fbf0abSSong Liu "nr_file_hugepages",
122560fbf0abSSong Liu "nr_file_pmdmapped",
122611fb9989SMel Gorman "nr_anon_transparent_hugepages",
1227c4a25635SMel Gorman "nr_vmscan_write",
1228c4a25635SMel Gorman "nr_vmscan_immediate_reclaim",
1229c4a25635SMel Gorman "nr_dirtied",
1230c4a25635SMel Gorman "nr_written",
12318cd7c588SMel Gorman "nr_throttled_written",
1232b29940c1SVlastimil Babka "nr_kernel_misc_reclaimable",
12331970dc6fSJohn Hubbard "nr_foll_pin_acquired",
12341970dc6fSJohn Hubbard "nr_foll_pin_released",
1235991e7673SShakeel Butt "nr_kernel_stack",
1236991e7673SShakeel Butt #if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
1237991e7673SShakeel Butt "nr_shadow_call_stack",
1238991e7673SShakeel Butt #endif
1239f0c0c115SShakeel Butt "nr_page_table_pages",
1240ebc97a52SYosry Ahmed "nr_sec_page_table_pages",
1241b6038942SShakeel Butt #ifdef CONFIG_SWAP
1242b6038942SShakeel Butt "nr_swapcached",
1243b6038942SShakeel Butt #endif
1244e39bb6beSHuang Ying #ifdef CONFIG_NUMA_BALANCING
1245e39bb6beSHuang Ying "pgpromote_success",
1246c6833e10SHuang Ying "pgpromote_candidate",
1247e39bb6beSHuang Ying #endif
1248599d0c95SMel Gorman
124909316c09SKonstantin Khlebnikov /* enum writeback_stat_item counters */
1250fa25c503SKOSAKI Motohiro "nr_dirty_threshold",
1251fa25c503SKOSAKI Motohiro "nr_dirty_background_threshold",
1252fa25c503SKOSAKI Motohiro
1253ebc5d83dSKonstantin Khlebnikov #if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
125409316c09SKonstantin Khlebnikov /* enum vm_event_item counters */
1255fa25c503SKOSAKI Motohiro "pgpgin",
1256fa25c503SKOSAKI Motohiro "pgpgout",
1257fa25c503SKOSAKI Motohiro "pswpin",
1258fa25c503SKOSAKI Motohiro "pswpout",
1259fa25c503SKOSAKI Motohiro
1260fa25c503SKOSAKI Motohiro TEXTS_FOR_ZONES("pgalloc")
12617cc30fcfSMel Gorman TEXTS_FOR_ZONES("allocstall")
12627cc30fcfSMel Gorman TEXTS_FOR_ZONES("pgskip")
1263fa25c503SKOSAKI Motohiro
1264fa25c503SKOSAKI Motohiro "pgfree",
1265fa25c503SKOSAKI Motohiro "pgactivate",
1266fa25c503SKOSAKI Motohiro "pgdeactivate",
1267f7ad2a6cSShaohua Li "pglazyfree",
1268fa25c503SKOSAKI Motohiro
1269fa25c503SKOSAKI Motohiro "pgfault",
1270fa25c503SKOSAKI Motohiro "pgmajfault",
1271854e9ed0SMinchan Kim "pglazyfreed",
1272fa25c503SKOSAKI Motohiro
1273599d0c95SMel Gorman "pgrefill",
1274798a6b87SPeter Xu "pgreuse",
1275599d0c95SMel Gorman "pgsteal_kswapd",
1276599d0c95SMel Gorman "pgsteal_direct",
127757e9cc50SJohannes Weiner "pgsteal_khugepaged",
1278668e4147SYang Shi "pgdemote_kswapd",
1279668e4147SYang Shi "pgdemote_direct",
128057e9cc50SJohannes Weiner "pgdemote_khugepaged",
1281599d0c95SMel Gorman "pgscan_kswapd",
1282599d0c95SMel Gorman "pgscan_direct",
128357e9cc50SJohannes Weiner "pgscan_khugepaged",
128468243e76SMel Gorman "pgscan_direct_throttle",
1285497a6c1bSJohannes Weiner "pgscan_anon",
1286497a6c1bSJohannes Weiner "pgscan_file",
1287497a6c1bSJohannes Weiner "pgsteal_anon",
1288497a6c1bSJohannes Weiner "pgsteal_file",
1289fa25c503SKOSAKI Motohiro
1290fa25c503SKOSAKI Motohiro #ifdef CONFIG_NUMA
1291fa25c503SKOSAKI Motohiro "zone_reclaim_failed",
1292fa25c503SKOSAKI Motohiro #endif
1293fa25c503SKOSAKI Motohiro "pginodesteal",
1294fa25c503SKOSAKI Motohiro "slabs_scanned",
1295fa25c503SKOSAKI Motohiro "kswapd_inodesteal",
1296fa25c503SKOSAKI Motohiro "kswapd_low_wmark_hit_quickly",
1297fa25c503SKOSAKI Motohiro "kswapd_high_wmark_hit_quickly",
1298fa25c503SKOSAKI Motohiro "pageoutrun",
1299fa25c503SKOSAKI Motohiro
1300fa25c503SKOSAKI Motohiro "pgrotated",
1301fa25c503SKOSAKI Motohiro
13025509a5d2SDave Hansen "drop_pagecache",
13035509a5d2SDave Hansen "drop_slab",
13048e675f7aSKonstantin Khlebnikov "oom_kill",
13055509a5d2SDave Hansen
130603c5a6e1SMel Gorman #ifdef CONFIG_NUMA_BALANCING
130703c5a6e1SMel Gorman "numa_pte_updates",
130872403b4aSMel Gorman "numa_huge_pte_updates",
130903c5a6e1SMel Gorman "numa_hint_faults",
131003c5a6e1SMel Gorman "numa_hint_faults_local",
131103c5a6e1SMel Gorman "numa_pages_migrated",
131203c5a6e1SMel Gorman #endif
13135647bc29SMel Gorman #ifdef CONFIG_MIGRATION
13145647bc29SMel Gorman "pgmigrate_success",
13155647bc29SMel Gorman "pgmigrate_fail",
13161a5bae25SAnshuman Khandual "thp_migration_success",
13171a5bae25SAnshuman Khandual "thp_migration_fail",
13181a5bae25SAnshuman Khandual "thp_migration_split",
13195647bc29SMel Gorman #endif
1320fa25c503SKOSAKI Motohiro #ifdef CONFIG_COMPACTION
1321397487dbSMel Gorman "compact_migrate_scanned",
1322397487dbSMel Gorman "compact_free_scanned",
1323397487dbSMel Gorman "compact_isolated",
1324fa25c503SKOSAKI Motohiro "compact_stall",
1325fa25c503SKOSAKI Motohiro "compact_fail",
1326fa25c503SKOSAKI Motohiro "compact_success",
1327698b1b30SVlastimil Babka "compact_daemon_wake",
13287f354a54SDavid Rientjes "compact_daemon_migrate_scanned",
13297f354a54SDavid Rientjes "compact_daemon_free_scanned",
1330fa25c503SKOSAKI Motohiro #endif
1331fa25c503SKOSAKI Motohiro
1332fa25c503SKOSAKI Motohiro #ifdef CONFIG_HUGETLB_PAGE
1333fa25c503SKOSAKI Motohiro "htlb_buddy_alloc_success",
1334fa25c503SKOSAKI Motohiro "htlb_buddy_alloc_fail",
1335fa25c503SKOSAKI Motohiro #endif
1336bbb26920SMinchan Kim #ifdef CONFIG_CMA
1337bbb26920SMinchan Kim "cma_alloc_success",
1338bbb26920SMinchan Kim "cma_alloc_fail",
1339bbb26920SMinchan Kim #endif
1340fa25c503SKOSAKI Motohiro "unevictable_pgs_culled",
1341fa25c503SKOSAKI Motohiro "unevictable_pgs_scanned",
1342fa25c503SKOSAKI Motohiro "unevictable_pgs_rescued",
1343fa25c503SKOSAKI Motohiro "unevictable_pgs_mlocked",
1344fa25c503SKOSAKI Motohiro "unevictable_pgs_munlocked",
1345fa25c503SKOSAKI Motohiro "unevictable_pgs_cleared",
1346fa25c503SKOSAKI Motohiro "unevictable_pgs_stranded",
1347fa25c503SKOSAKI Motohiro
1348fa25c503SKOSAKI Motohiro #ifdef CONFIG_TRANSPARENT_HUGEPAGE
1349fa25c503SKOSAKI Motohiro "thp_fault_alloc",
1350fa25c503SKOSAKI Motohiro "thp_fault_fallback",
135185b9f46eSDavid Rientjes "thp_fault_fallback_charge",
1352fa25c503SKOSAKI Motohiro "thp_collapse_alloc",
1353fa25c503SKOSAKI Motohiro "thp_collapse_alloc_failed",
135495ecedcdSKirill A. Shutemov "thp_file_alloc",
1355dcdf11eeSDavid Rientjes "thp_file_fallback",
135685b9f46eSDavid Rientjes "thp_file_fallback_charge",
135795ecedcdSKirill A. Shutemov "thp_file_mapped",
1358122afea9SKirill A. Shutemov "thp_split_page",
1359122afea9SKirill A. Shutemov "thp_split_page_failed",
1360f9719a03SKirill A. Shutemov "thp_deferred_split_page",
1361122afea9SKirill A. Shutemov "thp_split_pmd",
1362e9ea874aSYang Yang "thp_scan_exceed_none_pte",
1363e9ea874aSYang Yang "thp_scan_exceed_swap_pte",
1364e9ea874aSYang Yang "thp_scan_exceed_share_pte",
1365ce9311cfSYisheng Xie #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
1366ce9311cfSYisheng Xie "thp_split_pud",
1367ce9311cfSYisheng Xie #endif
1368d8a8e1f0SKirill A. Shutemov "thp_zero_page_alloc",
1369d8a8e1f0SKirill A. Shutemov "thp_zero_page_alloc_failed",
1370225311a4SHuang Ying "thp_swpout",
1371fe490cc0SHuang Ying "thp_swpout_fallback",
1372fa25c503SKOSAKI Motohiro #endif
137309316c09SKonstantin Khlebnikov #ifdef CONFIG_MEMORY_BALLOON
137409316c09SKonstantin Khlebnikov "balloon_inflate",
137509316c09SKonstantin Khlebnikov "balloon_deflate",
137609316c09SKonstantin Khlebnikov #ifdef CONFIG_BALLOON_COMPACTION
137709316c09SKonstantin Khlebnikov "balloon_migrate",
137809316c09SKonstantin Khlebnikov #endif
137909316c09SKonstantin Khlebnikov #endif /* CONFIG_MEMORY_BALLOON */
1380ec659934SMel Gorman #ifdef CONFIG_DEBUG_TLBFLUSH
13819824cf97SDave Hansen "nr_tlb_remote_flush",
13829824cf97SDave Hansen "nr_tlb_remote_flush_received",
13839824cf97SDave Hansen "nr_tlb_local_flush_all",
13849824cf97SDave Hansen "nr_tlb_local_flush_one",
1385ec659934SMel Gorman #endif /* CONFIG_DEBUG_TLBFLUSH */
1386fa25c503SKOSAKI Motohiro
1387cbc65df2SHuang Ying #ifdef CONFIG_SWAP
1388cbc65df2SHuang Ying "swap_ra",
1389cbc65df2SHuang Ying "swap_ra_hit",
13904d45c3afSYang Yang #ifdef CONFIG_KSM
13914d45c3afSYang Yang "ksm_swpin_copy",
13924d45c3afSYang Yang #endif
1393cbc65df2SHuang Ying #endif
139494bfe85bSYang Yang #ifdef CONFIG_KSM
139594bfe85bSYang Yang "cow_ksm",
139694bfe85bSYang Yang #endif
1397f6498b77SJohannes Weiner #ifdef CONFIG_ZSWAP
1398f6498b77SJohannes Weiner "zswpin",
1399f6498b77SJohannes Weiner "zswpout",
1400f6498b77SJohannes Weiner #endif
1401575299eaSSaravanan D #ifdef CONFIG_X86
1402575299eaSSaravanan D "direct_map_level2_splits",
1403575299eaSSaravanan D "direct_map_level3_splits",
1404575299eaSSaravanan D #endif
140552f23865SSuren Baghdasaryan #ifdef CONFIG_PER_VMA_LOCK_STATS
140652f23865SSuren Baghdasaryan "vma_lock_success",
140752f23865SSuren Baghdasaryan "vma_lock_abort",
140852f23865SSuren Baghdasaryan "vma_lock_retry",
140952f23865SSuren Baghdasaryan "vma_lock_miss",
141052f23865SSuren Baghdasaryan #endif
1411ebc5d83dSKonstantin Khlebnikov #endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
1412fa25c503SKOSAKI Motohiro };
1413ebc5d83dSKonstantin Khlebnikov #endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA || CONFIG_MEMCG */
1414fa25c503SKOSAKI Motohiro
14153c486871SAndrew Morton #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
14163c486871SAndrew Morton defined(CONFIG_PROC_FS)
frag_start(struct seq_file * m,loff_t * pos)14173c486871SAndrew Morton static void *frag_start(struct seq_file *m, loff_t *pos)
14183c486871SAndrew Morton {
14193c486871SAndrew Morton pg_data_t *pgdat;
14203c486871SAndrew Morton loff_t node = *pos;
14213c486871SAndrew Morton
14223c486871SAndrew Morton for (pgdat = first_online_pgdat();
14233c486871SAndrew Morton pgdat && node;
14243c486871SAndrew Morton pgdat = next_online_pgdat(pgdat))
14253c486871SAndrew Morton --node;
14263c486871SAndrew Morton
14273c486871SAndrew Morton return pgdat;
14283c486871SAndrew Morton }
14293c486871SAndrew Morton
frag_next(struct seq_file * m,void * arg,loff_t * pos)14303c486871SAndrew Morton static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
14313c486871SAndrew Morton {
14323c486871SAndrew Morton pg_data_t *pgdat = (pg_data_t *)arg;
14333c486871SAndrew Morton
14343c486871SAndrew Morton (*pos)++;
14353c486871SAndrew Morton return next_online_pgdat(pgdat);
14363c486871SAndrew Morton }
14373c486871SAndrew Morton
frag_stop(struct seq_file * m,void * arg)14383c486871SAndrew Morton static void frag_stop(struct seq_file *m, void *arg)
14393c486871SAndrew Morton {
14403c486871SAndrew Morton }
14413c486871SAndrew Morton
1442b2bd8598SDavid Rientjes /*
1443b2bd8598SDavid Rientjes * Walk zones in a node and print using a callback.
1444b2bd8598SDavid Rientjes * If @assert_populated is true, only use callback for zones that are populated.
1445b2bd8598SDavid Rientjes */
walk_zones_in_node(struct seq_file * m,pg_data_t * pgdat,bool assert_populated,bool nolock,void (* print)(struct seq_file * m,pg_data_t *,struct zone *))14463c486871SAndrew Morton static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
1447727c080fSVinayak Menon bool assert_populated, bool nolock,
14483c486871SAndrew Morton void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
14493c486871SAndrew Morton {
14503c486871SAndrew Morton struct zone *zone;
14513c486871SAndrew Morton struct zone *node_zones = pgdat->node_zones;
14523c486871SAndrew Morton unsigned long flags;
14533c486871SAndrew Morton
14543c486871SAndrew Morton for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
1455b2bd8598SDavid Rientjes if (assert_populated && !populated_zone(zone))
14563c486871SAndrew Morton continue;
14573c486871SAndrew Morton
1458727c080fSVinayak Menon if (!nolock)
14593c486871SAndrew Morton spin_lock_irqsave(&zone->lock, flags);
14603c486871SAndrew Morton print(m, pgdat, zone);
1461727c080fSVinayak Menon if (!nolock)
14623c486871SAndrew Morton spin_unlock_irqrestore(&zone->lock, flags);
14633c486871SAndrew Morton }
14643c486871SAndrew Morton }
14653c486871SAndrew Morton #endif
14663c486871SAndrew Morton
1467d7a5752cSMel Gorman #ifdef CONFIG_PROC_FS
frag_show_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)1468467c996cSMel Gorman static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
1469467c996cSMel Gorman struct zone *zone)
1470467c996cSMel Gorman {
1471467c996cSMel Gorman int order;
1472467c996cSMel Gorman
1473f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
1474ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; ++order)
1475af1c31acSLiu Shixin /*
1476af1c31acSLiu Shixin * Access to nr_free is lockless as nr_free is used only for
1477af1c31acSLiu Shixin * printing purposes. Use data_race to avoid KCSAN warning.
1478af1c31acSLiu Shixin */
1479af1c31acSLiu Shixin seq_printf(m, "%6lu ", data_race(zone->free_area[order].nr_free));
1480f6ac2354SChristoph Lameter seq_putc(m, '\n');
1481f6ac2354SChristoph Lameter }
1482467c996cSMel Gorman
1483467c996cSMel Gorman /*
1484467c996cSMel Gorman * This walks the free areas for each zone.
1485467c996cSMel Gorman */
frag_show(struct seq_file * m,void * arg)1486467c996cSMel Gorman static int frag_show(struct seq_file *m, void *arg)
1487467c996cSMel Gorman {
1488467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
1489727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, false, frag_show_print);
1490467c996cSMel Gorman return 0;
1491467c996cSMel Gorman }
1492467c996cSMel Gorman
pagetypeinfo_showfree_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)1493467c996cSMel Gorman static void pagetypeinfo_showfree_print(struct seq_file *m,
1494467c996cSMel Gorman pg_data_t *pgdat, struct zone *zone)
1495467c996cSMel Gorman {
1496467c996cSMel Gorman int order, mtype;
1497467c996cSMel Gorman
1498467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
1499467c996cSMel Gorman seq_printf(m, "Node %4d, zone %8s, type %12s ",
1500467c996cSMel Gorman pgdat->node_id,
1501467c996cSMel Gorman zone->name,
1502467c996cSMel Gorman migratetype_names[mtype]);
1503ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; ++order) {
1504467c996cSMel Gorman unsigned long freecount = 0;
1505467c996cSMel Gorman struct free_area *area;
1506467c996cSMel Gorman struct list_head *curr;
150793b3a674SMichal Hocko bool overflow = false;
1508467c996cSMel Gorman
1509467c996cSMel Gorman area = &(zone->free_area[order]);
1510467c996cSMel Gorman
151193b3a674SMichal Hocko list_for_each(curr, &area->free_list[mtype]) {
151293b3a674SMichal Hocko /*
151393b3a674SMichal Hocko * Cap the free_list iteration because it might
151493b3a674SMichal Hocko * be really large and we are under a spinlock
151593b3a674SMichal Hocko * so a long time spent here could trigger a
151693b3a674SMichal Hocko * hard lockup detector. Anyway this is a
151793b3a674SMichal Hocko * debugging tool so knowing there is a handful
151893b3a674SMichal Hocko * of pages of this order should be more than
151993b3a674SMichal Hocko * sufficient.
152093b3a674SMichal Hocko */
152193b3a674SMichal Hocko if (++freecount >= 100000) {
152293b3a674SMichal Hocko overflow = true;
152393b3a674SMichal Hocko break;
152493b3a674SMichal Hocko }
152593b3a674SMichal Hocko }
152693b3a674SMichal Hocko seq_printf(m, "%s%6lu ", overflow ? ">" : "", freecount);
152793b3a674SMichal Hocko spin_unlock_irq(&zone->lock);
152893b3a674SMichal Hocko cond_resched();
152993b3a674SMichal Hocko spin_lock_irq(&zone->lock);
1530467c996cSMel Gorman }
1531467c996cSMel Gorman seq_putc(m, '\n');
1532467c996cSMel Gorman }
1533467c996cSMel Gorman }
1534467c996cSMel Gorman
1535467c996cSMel Gorman /* Print out the free pages at each order for each migatetype */
pagetypeinfo_showfree(struct seq_file * m,void * arg)153633090af9SMiaohe Lin static void pagetypeinfo_showfree(struct seq_file *m, void *arg)
1537467c996cSMel Gorman {
1538467c996cSMel Gorman int order;
1539467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
1540467c996cSMel Gorman
1541467c996cSMel Gorman /* Print header */
1542467c996cSMel Gorman seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
1543ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; ++order)
1544467c996cSMel Gorman seq_printf(m, "%6d ", order);
1545467c996cSMel Gorman seq_putc(m, '\n');
1546467c996cSMel Gorman
1547727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
1548467c996cSMel Gorman }
1549467c996cSMel Gorman
pagetypeinfo_showblockcount_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)1550467c996cSMel Gorman static void pagetypeinfo_showblockcount_print(struct seq_file *m,
1551467c996cSMel Gorman pg_data_t *pgdat, struct zone *zone)
1552467c996cSMel Gorman {
1553467c996cSMel Gorman int mtype;
1554467c996cSMel Gorman unsigned long pfn;
1555467c996cSMel Gorman unsigned long start_pfn = zone->zone_start_pfn;
1556108bcc96SCody P Schafer unsigned long end_pfn = zone_end_pfn(zone);
1557467c996cSMel Gorman unsigned long count[MIGRATE_TYPES] = { 0, };
1558467c996cSMel Gorman
1559467c996cSMel Gorman for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
1560467c996cSMel Gorman struct page *page;
1561467c996cSMel Gorman
1562d336e94eSMichal Hocko page = pfn_to_online_page(pfn);
1563d336e94eSMichal Hocko if (!page)
1564467c996cSMel Gorman continue;
1565467c996cSMel Gorman
1566a91c43c7SJoonsoo Kim if (page_zone(page) != zone)
1567a91c43c7SJoonsoo Kim continue;
1568a91c43c7SJoonsoo Kim
1569467c996cSMel Gorman mtype = get_pageblock_migratetype(page);
1570467c996cSMel Gorman
1571e80d6a24SMel Gorman if (mtype < MIGRATE_TYPES)
1572467c996cSMel Gorman count[mtype]++;
1573467c996cSMel Gorman }
1574467c996cSMel Gorman
1575467c996cSMel Gorman /* Print counts */
1576467c996cSMel Gorman seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
1577467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
1578467c996cSMel Gorman seq_printf(m, "%12lu ", count[mtype]);
1579467c996cSMel Gorman seq_putc(m, '\n');
1580467c996cSMel Gorman }
1581467c996cSMel Gorman
1582f113e641SSeongJae Park /* Print out the number of pageblocks for each migratetype */
pagetypeinfo_showblockcount(struct seq_file * m,void * arg)158333090af9SMiaohe Lin static void pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
1584467c996cSMel Gorman {
1585467c996cSMel Gorman int mtype;
1586467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
1587467c996cSMel Gorman
1588467c996cSMel Gorman seq_printf(m, "\n%-23s", "Number of blocks type ");
1589467c996cSMel Gorman for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
1590467c996cSMel Gorman seq_printf(m, "%12s ", migratetype_names[mtype]);
1591467c996cSMel Gorman seq_putc(m, '\n');
1592727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, false,
1593727c080fSVinayak Menon pagetypeinfo_showblockcount_print);
1594467c996cSMel Gorman }
1595467c996cSMel Gorman
159648c96a36SJoonsoo Kim /*
159748c96a36SJoonsoo Kim * Print out the number of pageblocks for each migratetype that contain pages
159848c96a36SJoonsoo Kim * of other types. This gives an indication of how well fallbacks are being
159948c96a36SJoonsoo Kim * contained by rmqueue_fallback(). It requires information from PAGE_OWNER
160048c96a36SJoonsoo Kim * to determine what is going on
160148c96a36SJoonsoo Kim */
pagetypeinfo_showmixedcount(struct seq_file * m,pg_data_t * pgdat)160248c96a36SJoonsoo Kim static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
160348c96a36SJoonsoo Kim {
160448c96a36SJoonsoo Kim #ifdef CONFIG_PAGE_OWNER
160548c96a36SJoonsoo Kim int mtype;
160648c96a36SJoonsoo Kim
16077dd80b8aSVlastimil Babka if (!static_branch_unlikely(&page_owner_inited))
160848c96a36SJoonsoo Kim return;
160948c96a36SJoonsoo Kim
161048c96a36SJoonsoo Kim drain_all_pages(NULL);
161148c96a36SJoonsoo Kim
161248c96a36SJoonsoo Kim seq_printf(m, "\n%-23s", "Number of mixed blocks ");
161348c96a36SJoonsoo Kim for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
161448c96a36SJoonsoo Kim seq_printf(m, "%12s ", migratetype_names[mtype]);
161548c96a36SJoonsoo Kim seq_putc(m, '\n');
161648c96a36SJoonsoo Kim
1617727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, true,
1618727c080fSVinayak Menon pagetypeinfo_showmixedcount_print);
161948c96a36SJoonsoo Kim #endif /* CONFIG_PAGE_OWNER */
162048c96a36SJoonsoo Kim }
162148c96a36SJoonsoo Kim
1622467c996cSMel Gorman /*
1623467c996cSMel Gorman * This prints out statistics in relation to grouping pages by mobility.
1624467c996cSMel Gorman * It is expensive to collect so do not constantly read the file.
1625467c996cSMel Gorman */
pagetypeinfo_show(struct seq_file * m,void * arg)1626467c996cSMel Gorman static int pagetypeinfo_show(struct seq_file *m, void *arg)
1627467c996cSMel Gorman {
1628467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
1629467c996cSMel Gorman
163041b25a37SKOSAKI Motohiro /* check memoryless node */
1631a47b53c5SLai Jiangshan if (!node_state(pgdat->node_id, N_MEMORY))
163241b25a37SKOSAKI Motohiro return 0;
163341b25a37SKOSAKI Motohiro
1634467c996cSMel Gorman seq_printf(m, "Page block order: %d\n", pageblock_order);
1635467c996cSMel Gorman seq_printf(m, "Pages per block: %lu\n", pageblock_nr_pages);
1636467c996cSMel Gorman seq_putc(m, '\n');
1637467c996cSMel Gorman pagetypeinfo_showfree(m, pgdat);
1638467c996cSMel Gorman pagetypeinfo_showblockcount(m, pgdat);
163948c96a36SJoonsoo Kim pagetypeinfo_showmixedcount(m, pgdat);
1640467c996cSMel Gorman
1641f6ac2354SChristoph Lameter return 0;
1642f6ac2354SChristoph Lameter }
1643f6ac2354SChristoph Lameter
16448f32f7e5SAlexey Dobriyan static const struct seq_operations fragmentation_op = {
1645f6ac2354SChristoph Lameter .start = frag_start,
1646f6ac2354SChristoph Lameter .next = frag_next,
1647f6ac2354SChristoph Lameter .stop = frag_stop,
1648f6ac2354SChristoph Lameter .show = frag_show,
1649f6ac2354SChristoph Lameter };
1650f6ac2354SChristoph Lameter
165174e2e8e8SAlexey Dobriyan static const struct seq_operations pagetypeinfo_op = {
1652467c996cSMel Gorman .start = frag_start,
1653467c996cSMel Gorman .next = frag_next,
1654467c996cSMel Gorman .stop = frag_stop,
1655467c996cSMel Gorman .show = pagetypeinfo_show,
1656467c996cSMel Gorman };
1657467c996cSMel Gorman
is_zone_first_populated(pg_data_t * pgdat,struct zone * zone)1658e2ecc8a7SMel Gorman static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
1659e2ecc8a7SMel Gorman {
1660e2ecc8a7SMel Gorman int zid;
1661e2ecc8a7SMel Gorman
1662e2ecc8a7SMel Gorman for (zid = 0; zid < MAX_NR_ZONES; zid++) {
1663e2ecc8a7SMel Gorman struct zone *compare = &pgdat->node_zones[zid];
1664e2ecc8a7SMel Gorman
1665e2ecc8a7SMel Gorman if (populated_zone(compare))
1666e2ecc8a7SMel Gorman return zone == compare;
1667e2ecc8a7SMel Gorman }
1668e2ecc8a7SMel Gorman
1669e2ecc8a7SMel Gorman return false;
1670e2ecc8a7SMel Gorman }
1671e2ecc8a7SMel Gorman
zoneinfo_show_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)1672467c996cSMel Gorman static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
1673467c996cSMel Gorman struct zone *zone)
1674f6ac2354SChristoph Lameter {
1675f6ac2354SChristoph Lameter int i;
1676f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
1677e2ecc8a7SMel Gorman if (is_zone_first_populated(pgdat, zone)) {
1678e2ecc8a7SMel Gorman seq_printf(m, "\n per-node stats");
1679e2ecc8a7SMel Gorman for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
168069473e5dSMuchun Song unsigned long pages = node_page_state_pages(pgdat, i);
168169473e5dSMuchun Song
168269473e5dSMuchun Song if (vmstat_item_print_in_thp(i))
168369473e5dSMuchun Song pages /= HPAGE_PMD_NR;
16849d7ea9a2SKonstantin Khlebnikov seq_printf(m, "\n %-12s %lu", node_stat_name(i),
168569473e5dSMuchun Song pages);
1686e2ecc8a7SMel Gorman }
1687e2ecc8a7SMel Gorman }
1688f6ac2354SChristoph Lameter seq_printf(m,
1689f6ac2354SChristoph Lameter "\n pages free %lu"
1690a6ea8b5bSLiangcai Fan "\n boost %lu"
1691f6ac2354SChristoph Lameter "\n min %lu"
1692f6ac2354SChristoph Lameter "\n low %lu"
1693f6ac2354SChristoph Lameter "\n high %lu"
1694f6ac2354SChristoph Lameter "\n spanned %lu"
16959feedc9dSJiang Liu "\n present %lu"
16963c381db1SDavid Hildenbrand "\n managed %lu"
16973c381db1SDavid Hildenbrand "\n cma %lu",
169888f5acf8SMel Gorman zone_page_state(zone, NR_FREE_PAGES),
1699a6ea8b5bSLiangcai Fan zone->watermark_boost,
170041858966SMel Gorman min_wmark_pages(zone),
170141858966SMel Gorman low_wmark_pages(zone),
170241858966SMel Gorman high_wmark_pages(zone),
1703f6ac2354SChristoph Lameter zone->spanned_pages,
17049feedc9dSJiang Liu zone->present_pages,
17053c381db1SDavid Hildenbrand zone_managed_pages(zone),
17063c381db1SDavid Hildenbrand zone_cma_pages(zone));
17072244b95aSChristoph Lameter
1708f6ac2354SChristoph Lameter seq_printf(m,
17093484b2deSMel Gorman "\n protection: (%ld",
1710f6ac2354SChristoph Lameter zone->lowmem_reserve[0]);
1711f6ac2354SChristoph Lameter for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
17123484b2deSMel Gorman seq_printf(m, ", %ld", zone->lowmem_reserve[i]);
17137dfb8bf3SDavid Rientjes seq_putc(m, ')');
17147dfb8bf3SDavid Rientjes
1715a8a4b7aeSBaoquan He /* If unpopulated, no other information is useful */
1716a8a4b7aeSBaoquan He if (!populated_zone(zone)) {
1717a8a4b7aeSBaoquan He seq_putc(m, '\n');
1718a8a4b7aeSBaoquan He return;
1719a8a4b7aeSBaoquan He }
1720a8a4b7aeSBaoquan He
17217dfb8bf3SDavid Rientjes for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
17229d7ea9a2SKonstantin Khlebnikov seq_printf(m, "\n %-12s %lu", zone_stat_name(i),
17237dfb8bf3SDavid Rientjes zone_page_state(zone, i));
17247dfb8bf3SDavid Rientjes
17253a321d2aSKemi Wang #ifdef CONFIG_NUMA
1726*f8cca70bSMengEn Sun fold_vm_zone_numa_events(zone);
1727f19298b9SMel Gorman for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++)
17289d7ea9a2SKonstantin Khlebnikov seq_printf(m, "\n %-12s %lu", numa_stat_name(i),
1729f19298b9SMel Gorman zone_numa_event_state(zone, i));
17303a321d2aSKemi Wang #endif
17313a321d2aSKemi Wang
17327dfb8bf3SDavid Rientjes seq_printf(m, "\n pagesets");
1733f6ac2354SChristoph Lameter for_each_online_cpu(i) {
173428f836b6SMel Gorman struct per_cpu_pages *pcp;
173528f836b6SMel Gorman struct per_cpu_zonestat __maybe_unused *pzstats;
1736f6ac2354SChristoph Lameter
173728f836b6SMel Gorman pcp = per_cpu_ptr(zone->per_cpu_pageset, i);
1738f6ac2354SChristoph Lameter seq_printf(m,
17393dfa5721SChristoph Lameter "\n cpu: %i"
1740f6ac2354SChristoph Lameter "\n count: %i"
1741f6ac2354SChristoph Lameter "\n high: %i"
1742f6ac2354SChristoph Lameter "\n batch: %i",
17433dfa5721SChristoph Lameter i,
174428f836b6SMel Gorman pcp->count,
174528f836b6SMel Gorman pcp->high,
174628f836b6SMel Gorman pcp->batch);
1747df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
174828f836b6SMel Gorman pzstats = per_cpu_ptr(zone->per_cpu_zonestats, i);
1749df9ecabaSChristoph Lameter seq_printf(m, "\n vm stats threshold: %d",
175028f836b6SMel Gorman pzstats->stat_threshold);
1751df9ecabaSChristoph Lameter #endif
1752f6ac2354SChristoph Lameter }
1753f6ac2354SChristoph Lameter seq_printf(m,
1754599d0c95SMel Gorman "\n node_unreclaimable: %u"
17553a50d14dSAndrey Ryabinin "\n start_pfn: %lu",
1756c73322d0SJohannes Weiner pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
17573a50d14dSAndrey Ryabinin zone->zone_start_pfn);
1758f6ac2354SChristoph Lameter seq_putc(m, '\n');
1759f6ac2354SChristoph Lameter }
1760467c996cSMel Gorman
1761467c996cSMel Gorman /*
1762b2bd8598SDavid Rientjes * Output information about zones in @pgdat. All zones are printed regardless
1763b2bd8598SDavid Rientjes * of whether they are populated or not: lowmem_reserve_ratio operates on the
1764b2bd8598SDavid Rientjes * set of all zones and userspace would not be aware of such zones if they are
1765b2bd8598SDavid Rientjes * suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio).
1766467c996cSMel Gorman */
zoneinfo_show(struct seq_file * m,void * arg)1767467c996cSMel Gorman static int zoneinfo_show(struct seq_file *m, void *arg)
1768467c996cSMel Gorman {
1769467c996cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
1770727c080fSVinayak Menon walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
1771f6ac2354SChristoph Lameter return 0;
1772f6ac2354SChristoph Lameter }
1773f6ac2354SChristoph Lameter
17745c9fe628SAlexey Dobriyan static const struct seq_operations zoneinfo_op = {
1775f6ac2354SChristoph Lameter .start = frag_start, /* iterate over all zones. The same as in
1776f6ac2354SChristoph Lameter * fragmentation. */
1777f6ac2354SChristoph Lameter .next = frag_next,
1778f6ac2354SChristoph Lameter .stop = frag_stop,
1779f6ac2354SChristoph Lameter .show = zoneinfo_show,
1780f6ac2354SChristoph Lameter };
1781f6ac2354SChristoph Lameter
17829d7ea9a2SKonstantin Khlebnikov #define NR_VMSTAT_ITEMS (NR_VM_ZONE_STAT_ITEMS + \
1783f19298b9SMel Gorman NR_VM_NUMA_EVENT_ITEMS + \
17849d7ea9a2SKonstantin Khlebnikov NR_VM_NODE_STAT_ITEMS + \
17859d7ea9a2SKonstantin Khlebnikov NR_VM_WRITEBACK_STAT_ITEMS + \
17869d7ea9a2SKonstantin Khlebnikov (IS_ENABLED(CONFIG_VM_EVENT_COUNTERS) ? \
17879d7ea9a2SKonstantin Khlebnikov NR_VM_EVENT_ITEMS : 0))
178879da826aSMichael Rubin
vmstat_start(struct seq_file * m,loff_t * pos)1789f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
1790f6ac2354SChristoph Lameter {
17912244b95aSChristoph Lameter unsigned long *v;
17929d7ea9a2SKonstantin Khlebnikov int i;
1793f6ac2354SChristoph Lameter
17949d7ea9a2SKonstantin Khlebnikov if (*pos >= NR_VMSTAT_ITEMS)
1795f6ac2354SChristoph Lameter return NULL;
1796f6ac2354SChristoph Lameter
17979d7ea9a2SKonstantin Khlebnikov BUILD_BUG_ON(ARRAY_SIZE(vmstat_text) < NR_VMSTAT_ITEMS);
1798f19298b9SMel Gorman fold_vm_numa_events();
17999d7ea9a2SKonstantin Khlebnikov v = kmalloc_array(NR_VMSTAT_ITEMS, sizeof(unsigned long), GFP_KERNEL);
18002244b95aSChristoph Lameter m->private = v;
18012244b95aSChristoph Lameter if (!v)
1802f6ac2354SChristoph Lameter return ERR_PTR(-ENOMEM);
18032244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
1804c41f012aSMichal Hocko v[i] = global_zone_page_state(i);
180579da826aSMichael Rubin v += NR_VM_ZONE_STAT_ITEMS;
180679da826aSMichael Rubin
18073a321d2aSKemi Wang #ifdef CONFIG_NUMA
1808f19298b9SMel Gorman for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++)
1809f19298b9SMel Gorman v[i] = global_numa_event_state(i);
1810f19298b9SMel Gorman v += NR_VM_NUMA_EVENT_ITEMS;
18113a321d2aSKemi Wang #endif
18123a321d2aSKemi Wang
181369473e5dSMuchun Song for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
1814ea426c2aSRoman Gushchin v[i] = global_node_page_state_pages(i);
181569473e5dSMuchun Song if (vmstat_item_print_in_thp(i))
181669473e5dSMuchun Song v[i] /= HPAGE_PMD_NR;
181769473e5dSMuchun Song }
181875ef7184SMel Gorman v += NR_VM_NODE_STAT_ITEMS;
181975ef7184SMel Gorman
182079da826aSMichael Rubin global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
182179da826aSMichael Rubin v + NR_DIRTY_THRESHOLD);
182279da826aSMichael Rubin v += NR_VM_WRITEBACK_STAT_ITEMS;
182379da826aSMichael Rubin
1824f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
182579da826aSMichael Rubin all_vm_events(v);
182679da826aSMichael Rubin v[PGPGIN] /= 2; /* sectors -> kbytes */
182779da826aSMichael Rubin v[PGPGOUT] /= 2;
1828f8891e5eSChristoph Lameter #endif
1829ff8b16d7SWu Fengguang return (unsigned long *)m->private + *pos;
1830f6ac2354SChristoph Lameter }
1831f6ac2354SChristoph Lameter
vmstat_next(struct seq_file * m,void * arg,loff_t * pos)1832f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
1833f6ac2354SChristoph Lameter {
1834f6ac2354SChristoph Lameter (*pos)++;
18359d7ea9a2SKonstantin Khlebnikov if (*pos >= NR_VMSTAT_ITEMS)
1836f6ac2354SChristoph Lameter return NULL;
1837f6ac2354SChristoph Lameter return (unsigned long *)m->private + *pos;
1838f6ac2354SChristoph Lameter }
1839f6ac2354SChristoph Lameter
vmstat_show(struct seq_file * m,void * arg)1840f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
1841f6ac2354SChristoph Lameter {
1842f6ac2354SChristoph Lameter unsigned long *l = arg;
1843f6ac2354SChristoph Lameter unsigned long off = l - (unsigned long *)m->private;
184468ba0326SAlexey Dobriyan
184568ba0326SAlexey Dobriyan seq_puts(m, vmstat_text[off]);
184675ba1d07SJoe Perches seq_put_decimal_ull(m, " ", *l);
184768ba0326SAlexey Dobriyan seq_putc(m, '\n');
18488d92890bSNeilBrown
18498d92890bSNeilBrown if (off == NR_VMSTAT_ITEMS - 1) {
18508d92890bSNeilBrown /*
18518d92890bSNeilBrown * We've come to the end - add any deprecated counters to avoid
18528d92890bSNeilBrown * breaking userspace which might depend on them being present.
18538d92890bSNeilBrown */
18548d92890bSNeilBrown seq_puts(m, "nr_unstable 0\n");
18558d92890bSNeilBrown }
1856f6ac2354SChristoph Lameter return 0;
1857f6ac2354SChristoph Lameter }
1858f6ac2354SChristoph Lameter
vmstat_stop(struct seq_file * m,void * arg)1859f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
1860f6ac2354SChristoph Lameter {
1861f6ac2354SChristoph Lameter kfree(m->private);
1862f6ac2354SChristoph Lameter m->private = NULL;
1863f6ac2354SChristoph Lameter }
1864f6ac2354SChristoph Lameter
1865b6aa44abSAlexey Dobriyan static const struct seq_operations vmstat_op = {
1866f6ac2354SChristoph Lameter .start = vmstat_start,
1867f6ac2354SChristoph Lameter .next = vmstat_next,
1868f6ac2354SChristoph Lameter .stop = vmstat_stop,
1869f6ac2354SChristoph Lameter .show = vmstat_show,
1870f6ac2354SChristoph Lameter };
1871f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
1872f6ac2354SChristoph Lameter
1873df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
1874d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
187577461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
1876d1187ed2SChristoph Lameter
187752b6f46bSHugh Dickins #ifdef CONFIG_PROC_FS
refresh_vm_stats(struct work_struct * work)187852b6f46bSHugh Dickins static void refresh_vm_stats(struct work_struct *work)
187952b6f46bSHugh Dickins {
188052b6f46bSHugh Dickins refresh_cpu_vm_stats(true);
188152b6f46bSHugh Dickins }
188252b6f46bSHugh Dickins
vmstat_refresh(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)188352b6f46bSHugh Dickins int vmstat_refresh(struct ctl_table *table, int write,
188432927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos)
188552b6f46bSHugh Dickins {
188652b6f46bSHugh Dickins long val;
188752b6f46bSHugh Dickins int err;
188852b6f46bSHugh Dickins int i;
188952b6f46bSHugh Dickins
189052b6f46bSHugh Dickins /*
189152b6f46bSHugh Dickins * The regular update, every sysctl_stat_interval, may come later
189252b6f46bSHugh Dickins * than expected: leaving a significant amount in per_cpu buckets.
189352b6f46bSHugh Dickins * This is particularly misleading when checking a quantity of HUGE
189452b6f46bSHugh Dickins * pages, immediately after running a test. /proc/sys/vm/stat_refresh,
189552b6f46bSHugh Dickins * which can equally be echo'ed to or cat'ted from (by root),
189652b6f46bSHugh Dickins * can be used to update the stats just before reading them.
189752b6f46bSHugh Dickins *
1898c41f012aSMichal Hocko * Oh, and since global_zone_page_state() etc. are so careful to hide
189952b6f46bSHugh Dickins * transiently negative values, report an error here if any of
190052b6f46bSHugh Dickins * the stats is negative, so we know to go looking for imbalance.
190152b6f46bSHugh Dickins */
190252b6f46bSHugh Dickins err = schedule_on_each_cpu(refresh_vm_stats);
190352b6f46bSHugh Dickins if (err)
190452b6f46bSHugh Dickins return err;
190552b6f46bSHugh Dickins for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
190675083aaeSHugh Dickins /*
190775083aaeSHugh Dickins * Skip checking stats known to go negative occasionally.
190875083aaeSHugh Dickins */
190975083aaeSHugh Dickins switch (i) {
191075083aaeSHugh Dickins case NR_ZONE_WRITE_PENDING:
191175083aaeSHugh Dickins case NR_FREE_CMA_PAGES:
191275083aaeSHugh Dickins continue;
191375083aaeSHugh Dickins }
191475ef7184SMel Gorman val = atomic_long_read(&vm_zone_stat[i]);
191552b6f46bSHugh Dickins if (val < 0) {
191652b6f46bSHugh Dickins pr_warn("%s: %s %ld\n",
19179d7ea9a2SKonstantin Khlebnikov __func__, zone_stat_name(i), val);
191852b6f46bSHugh Dickins }
191952b6f46bSHugh Dickins }
192076d8cc3cSHugh Dickins for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
192175083aaeSHugh Dickins /*
192275083aaeSHugh Dickins * Skip checking stats known to go negative occasionally.
192375083aaeSHugh Dickins */
192475083aaeSHugh Dickins switch (i) {
192575083aaeSHugh Dickins case NR_WRITEBACK:
192675083aaeSHugh Dickins continue;
192775083aaeSHugh Dickins }
192876d8cc3cSHugh Dickins val = atomic_long_read(&vm_node_stat[i]);
192976d8cc3cSHugh Dickins if (val < 0) {
193076d8cc3cSHugh Dickins pr_warn("%s: %s %ld\n",
193176d8cc3cSHugh Dickins __func__, node_stat_name(i), val);
193276d8cc3cSHugh Dickins }
193376d8cc3cSHugh Dickins }
193452b6f46bSHugh Dickins if (write)
193552b6f46bSHugh Dickins *ppos += *lenp;
193652b6f46bSHugh Dickins else
193752b6f46bSHugh Dickins *lenp = 0;
193852b6f46bSHugh Dickins return 0;
193952b6f46bSHugh Dickins }
194052b6f46bSHugh Dickins #endif /* CONFIG_PROC_FS */
194152b6f46bSHugh Dickins
vmstat_update(struct work_struct * w)1942d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
1943d1187ed2SChristoph Lameter {
19440eb77e98SChristoph Lameter if (refresh_cpu_vm_stats(true)) {
19457cc36bbdSChristoph Lameter /*
19467cc36bbdSChristoph Lameter * Counters were updated so we expect more updates
19477cc36bbdSChristoph Lameter * to occur in the future. Keep on running the
19487cc36bbdSChristoph Lameter * update worker thread.
19497cc36bbdSChristoph Lameter */
1950ce612879SMichal Hocko queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
1951176bed1dSLinus Torvalds this_cpu_ptr(&vmstat_work),
195298f4ebb2SAnton Blanchard round_jiffies_relative(sysctl_stat_interval));
1953f01f17d3SMichal Hocko }
1954d1187ed2SChristoph Lameter }
1955d1187ed2SChristoph Lameter
19567cc36bbdSChristoph Lameter /*
19577cc36bbdSChristoph Lameter * Check if the diffs for a certain cpu indicate that
19587cc36bbdSChristoph Lameter * an update is needed.
19597cc36bbdSChristoph Lameter */
need_update(int cpu)19607cc36bbdSChristoph Lameter static bool need_update(int cpu)
1961d1187ed2SChristoph Lameter {
19622bbd00aeSJohannes Weiner pg_data_t *last_pgdat = NULL;
19637cc36bbdSChristoph Lameter struct zone *zone;
1964d1187ed2SChristoph Lameter
19657cc36bbdSChristoph Lameter for_each_populated_zone(zone) {
196628f836b6SMel Gorman struct per_cpu_zonestat *pzstats = per_cpu_ptr(zone->per_cpu_zonestats, cpu);
19672bbd00aeSJohannes Weiner struct per_cpu_nodestat *n;
196828f836b6SMel Gorman
19697cc36bbdSChristoph Lameter /*
19707cc36bbdSChristoph Lameter * The fast way of checking if there are any vmstat diffs.
19717cc36bbdSChristoph Lameter */
197264632fd3SMiaohe Lin if (memchr_inv(pzstats->vm_stat_diff, 0, sizeof(pzstats->vm_stat_diff)))
19737cc36bbdSChristoph Lameter return true;
1974f19298b9SMel Gorman
19752bbd00aeSJohannes Weiner if (last_pgdat == zone->zone_pgdat)
19762bbd00aeSJohannes Weiner continue;
19772bbd00aeSJohannes Weiner last_pgdat = zone->zone_pgdat;
19782bbd00aeSJohannes Weiner n = per_cpu_ptr(zone->zone_pgdat->per_cpu_nodestats, cpu);
197964632fd3SMiaohe Lin if (memchr_inv(n->vm_node_stat_diff, 0, sizeof(n->vm_node_stat_diff)))
19802bbd00aeSJohannes Weiner return true;
19817cc36bbdSChristoph Lameter }
19827cc36bbdSChristoph Lameter return false;
19837cc36bbdSChristoph Lameter }
19847cc36bbdSChristoph Lameter
19857b8da4c7SChristoph Lameter /*
19867b8da4c7SChristoph Lameter * Switch off vmstat processing and then fold all the remaining differentials
19877b8da4c7SChristoph Lameter * until the diffs stay at zero. The function is used by NOHZ and can only be
19887b8da4c7SChristoph Lameter * invoked when tick processing is not active.
19897b8da4c7SChristoph Lameter */
quiet_vmstat(void)1990f01f17d3SMichal Hocko void quiet_vmstat(void)
1991f01f17d3SMichal Hocko {
1992f01f17d3SMichal Hocko if (system_state != SYSTEM_RUNNING)
1993f01f17d3SMichal Hocko return;
1994f01f17d3SMichal Hocko
19957b8da4c7SChristoph Lameter if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
1996f01f17d3SMichal Hocko return;
1997f01f17d3SMichal Hocko
1998f01f17d3SMichal Hocko if (!need_update(smp_processor_id()))
1999f01f17d3SMichal Hocko return;
2000f01f17d3SMichal Hocko
2001f01f17d3SMichal Hocko /*
2002f01f17d3SMichal Hocko * Just refresh counters and do not care about the pending delayed
2003f01f17d3SMichal Hocko * vmstat_update. It doesn't fire that often to matter and canceling
2004f01f17d3SMichal Hocko * it would be too expensive from this path.
2005f01f17d3SMichal Hocko * vmstat_shepherd will take care about that for us.
2006f01f17d3SMichal Hocko */
2007f01f17d3SMichal Hocko refresh_cpu_vm_stats(false);
2008f01f17d3SMichal Hocko }
2009f01f17d3SMichal Hocko
20107cc36bbdSChristoph Lameter /*
20117cc36bbdSChristoph Lameter * Shepherd worker thread that checks the
20127cc36bbdSChristoph Lameter * differentials of processors that have their worker
20137cc36bbdSChristoph Lameter * threads for vm statistics updates disabled because of
20147cc36bbdSChristoph Lameter * inactivity.
20157cc36bbdSChristoph Lameter */
20167cc36bbdSChristoph Lameter static void vmstat_shepherd(struct work_struct *w);
20177cc36bbdSChristoph Lameter
20180eb77e98SChristoph Lameter static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
20197cc36bbdSChristoph Lameter
vmstat_shepherd(struct work_struct * w)20207cc36bbdSChristoph Lameter static void vmstat_shepherd(struct work_struct *w)
20217cc36bbdSChristoph Lameter {
20227cc36bbdSChristoph Lameter int cpu;
20237cc36bbdSChristoph Lameter
20247625eccdSSebastian Andrzej Siewior cpus_read_lock();
20257cc36bbdSChristoph Lameter /* Check processors whose vmstat worker threads have been disabled */
20267b8da4c7SChristoph Lameter for_each_online_cpu(cpu) {
2027f01f17d3SMichal Hocko struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
20287cc36bbdSChristoph Lameter
2029be5e015dSMarcelo Tosatti /*
2030be5e015dSMarcelo Tosatti * In kernel users of vmstat counters either require the precise value and
2031be5e015dSMarcelo Tosatti * they are using zone_page_state_snapshot interface or they can live with
2032be5e015dSMarcelo Tosatti * an imprecision as the regular flushing can happen at arbitrary time and
2033be5e015dSMarcelo Tosatti * cumulative error can grow (see calculate_normal_threshold).
2034be5e015dSMarcelo Tosatti *
2035be5e015dSMarcelo Tosatti * From that POV the regular flushing can be postponed for CPUs that have
2036be5e015dSMarcelo Tosatti * been isolated from the kernel interference without critical
2037be5e015dSMarcelo Tosatti * infrastructure ever noticing. Skip regular flushing from vmstat_shepherd
2038be5e015dSMarcelo Tosatti * for all isolated CPUs to avoid interference with the isolated workload.
2039be5e015dSMarcelo Tosatti */
2040be5e015dSMarcelo Tosatti if (cpu_is_isolated(cpu))
2041be5e015dSMarcelo Tosatti continue;
2042be5e015dSMarcelo Tosatti
20437b8da4c7SChristoph Lameter if (!delayed_work_pending(dw) && need_update(cpu))
2044ce612879SMichal Hocko queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
2045fbcc8183SJiang Biao
2046fbcc8183SJiang Biao cond_resched();
2047f01f17d3SMichal Hocko }
20487625eccdSSebastian Andrzej Siewior cpus_read_unlock();
20497cc36bbdSChristoph Lameter
20507cc36bbdSChristoph Lameter schedule_delayed_work(&shepherd,
20517cc36bbdSChristoph Lameter round_jiffies_relative(sysctl_stat_interval));
20527cc36bbdSChristoph Lameter }
20537cc36bbdSChristoph Lameter
start_shepherd_timer(void)20547cc36bbdSChristoph Lameter static void __init start_shepherd_timer(void)
20557cc36bbdSChristoph Lameter {
20567cc36bbdSChristoph Lameter int cpu;
20577cc36bbdSChristoph Lameter
20587cc36bbdSChristoph Lameter for_each_possible_cpu(cpu)
2059ccde8bd4SMichal Hocko INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
20607cc36bbdSChristoph Lameter vmstat_update);
20617cc36bbdSChristoph Lameter
20627cc36bbdSChristoph Lameter schedule_delayed_work(&shepherd,
20637cc36bbdSChristoph Lameter round_jiffies_relative(sysctl_stat_interval));
2064d1187ed2SChristoph Lameter }
2065d1187ed2SChristoph Lameter
init_cpu_node_state(void)206603e86dbaSTim Chen static void __init init_cpu_node_state(void)
206703e86dbaSTim Chen {
20684c501327SSebastian Andrzej Siewior int node;
206903e86dbaSTim Chen
20704c501327SSebastian Andrzej Siewior for_each_online_node(node) {
2071b55032f1SYury Norov if (!cpumask_empty(cpumask_of_node(node)))
20724c501327SSebastian Andrzej Siewior node_set_state(node, N_CPU);
20734c501327SSebastian Andrzej Siewior }
207403e86dbaSTim Chen }
207503e86dbaSTim Chen
vmstat_cpu_online(unsigned int cpu)20765438da97SSebastian Andrzej Siewior static int vmstat_cpu_online(unsigned int cpu)
2077807a1bd2SToshi Kani {
20785ee28a44SKAMEZAWA Hiroyuki refresh_zone_stat_thresholds();
2079734c1570SOscar Salvador
2080734c1570SOscar Salvador if (!node_state(cpu_to_node(cpu), N_CPU)) {
2081ad596925SChristoph Lameter node_set_state(cpu_to_node(cpu), N_CPU);
2082734c1570SOscar Salvador }
2083734c1570SOscar Salvador
20845438da97SSebastian Andrzej Siewior return 0;
2085df9ecabaSChristoph Lameter }
2086df9ecabaSChristoph Lameter
vmstat_cpu_down_prep(unsigned int cpu)20875438da97SSebastian Andrzej Siewior static int vmstat_cpu_down_prep(unsigned int cpu)
20885438da97SSebastian Andrzej Siewior {
20895438da97SSebastian Andrzej Siewior cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
20905438da97SSebastian Andrzej Siewior return 0;
20915438da97SSebastian Andrzej Siewior }
20925438da97SSebastian Andrzej Siewior
vmstat_cpu_dead(unsigned int cpu)20935438da97SSebastian Andrzej Siewior static int vmstat_cpu_dead(unsigned int cpu)
20945438da97SSebastian Andrzej Siewior {
20955438da97SSebastian Andrzej Siewior const struct cpumask *node_cpus;
20965438da97SSebastian Andrzej Siewior int node;
20975438da97SSebastian Andrzej Siewior
20985438da97SSebastian Andrzej Siewior node = cpu_to_node(cpu);
20995438da97SSebastian Andrzej Siewior
21005438da97SSebastian Andrzej Siewior refresh_zone_stat_thresholds();
21015438da97SSebastian Andrzej Siewior node_cpus = cpumask_of_node(node);
2102b55032f1SYury Norov if (!cpumask_empty(node_cpus))
21035438da97SSebastian Andrzej Siewior return 0;
21045438da97SSebastian Andrzej Siewior
21055438da97SSebastian Andrzej Siewior node_clear_state(node, N_CPU);
2106734c1570SOscar Salvador
21075438da97SSebastian Andrzej Siewior return 0;
21085438da97SSebastian Andrzej Siewior }
21095438da97SSebastian Andrzej Siewior
21108f32f7e5SAlexey Dobriyan #endif
2111df9ecabaSChristoph Lameter
2112ce612879SMichal Hocko struct workqueue_struct *mm_percpu_wq;
2113ce612879SMichal Hocko
init_mm_internals(void)2114597b7305SMichal Hocko void __init init_mm_internals(void)
2115df9ecabaSChristoph Lameter {
2116ce612879SMichal Hocko int ret __maybe_unused;
21175438da97SSebastian Andrzej Siewior
211880d136e1SMichal Hocko mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
2119ce612879SMichal Hocko
2120ce612879SMichal Hocko #ifdef CONFIG_SMP
21215438da97SSebastian Andrzej Siewior ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead",
21225438da97SSebastian Andrzej Siewior NULL, vmstat_cpu_dead);
21235438da97SSebastian Andrzej Siewior if (ret < 0)
21245438da97SSebastian Andrzej Siewior pr_err("vmstat: failed to register 'dead' hotplug state\n");
21255438da97SSebastian Andrzej Siewior
21265438da97SSebastian Andrzej Siewior ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmstat:online",
21275438da97SSebastian Andrzej Siewior vmstat_cpu_online,
21285438da97SSebastian Andrzej Siewior vmstat_cpu_down_prep);
21295438da97SSebastian Andrzej Siewior if (ret < 0)
21305438da97SSebastian Andrzej Siewior pr_err("vmstat: failed to register 'online' hotplug state\n");
21315438da97SSebastian Andrzej Siewior
21327625eccdSSebastian Andrzej Siewior cpus_read_lock();
213303e86dbaSTim Chen init_cpu_node_state();
21347625eccdSSebastian Andrzej Siewior cpus_read_unlock();
2135d1187ed2SChristoph Lameter
21367cc36bbdSChristoph Lameter start_shepherd_timer();
21378f32f7e5SAlexey Dobriyan #endif
21388f32f7e5SAlexey Dobriyan #ifdef CONFIG_PROC_FS
2139fddda2b7SChristoph Hellwig proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
2140abaed011SMichal Hocko proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
2141fddda2b7SChristoph Hellwig proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
2142fddda2b7SChristoph Hellwig proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
21438f32f7e5SAlexey Dobriyan #endif
2144df9ecabaSChristoph Lameter }
2145d7a5752cSMel Gorman
2146d7a5752cSMel Gorman #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
2147d7a5752cSMel Gorman
2148d7a5752cSMel Gorman /*
2149d7a5752cSMel Gorman * Return an index indicating how much of the available free memory is
2150d7a5752cSMel Gorman * unusable for an allocation of the requested size.
2151d7a5752cSMel Gorman */
unusable_free_index(unsigned int order,struct contig_page_info * info)2152d7a5752cSMel Gorman static int unusable_free_index(unsigned int order,
2153d7a5752cSMel Gorman struct contig_page_info *info)
2154d7a5752cSMel Gorman {
2155d7a5752cSMel Gorman /* No free memory is interpreted as all free memory is unusable */
2156d7a5752cSMel Gorman if (info->free_pages == 0)
2157d7a5752cSMel Gorman return 1000;
2158d7a5752cSMel Gorman
2159d7a5752cSMel Gorman /*
2160d7a5752cSMel Gorman * Index should be a value between 0 and 1. Return a value to 3
2161d7a5752cSMel Gorman * decimal places.
2162d7a5752cSMel Gorman *
2163d7a5752cSMel Gorman * 0 => no fragmentation
2164d7a5752cSMel Gorman * 1 => high fragmentation
2165d7a5752cSMel Gorman */
2166d7a5752cSMel Gorman return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages);
2167d7a5752cSMel Gorman
2168d7a5752cSMel Gorman }
2169d7a5752cSMel Gorman
unusable_show_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)2170d7a5752cSMel Gorman static void unusable_show_print(struct seq_file *m,
2171d7a5752cSMel Gorman pg_data_t *pgdat, struct zone *zone)
2172d7a5752cSMel Gorman {
2173d7a5752cSMel Gorman unsigned int order;
2174d7a5752cSMel Gorman int index;
2175d7a5752cSMel Gorman struct contig_page_info info;
2176d7a5752cSMel Gorman
2177d7a5752cSMel Gorman seq_printf(m, "Node %d, zone %8s ",
2178d7a5752cSMel Gorman pgdat->node_id,
2179d7a5752cSMel Gorman zone->name);
2180ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; ++order) {
2181d7a5752cSMel Gorman fill_contig_page_info(zone, order, &info);
2182d7a5752cSMel Gorman index = unusable_free_index(order, &info);
2183d7a5752cSMel Gorman seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
2184d7a5752cSMel Gorman }
2185d7a5752cSMel Gorman
2186d7a5752cSMel Gorman seq_putc(m, '\n');
2187d7a5752cSMel Gorman }
2188d7a5752cSMel Gorman
2189d7a5752cSMel Gorman /*
2190d7a5752cSMel Gorman * Display unusable free space index
2191d7a5752cSMel Gorman *
2192d7a5752cSMel Gorman * The unusable free space index measures how much of the available free
2193d7a5752cSMel Gorman * memory cannot be used to satisfy an allocation of a given size and is a
2194d7a5752cSMel Gorman * value between 0 and 1. The higher the value, the more of free memory is
2195d7a5752cSMel Gorman * unusable and by implication, the worse the external fragmentation is. This
2196d7a5752cSMel Gorman * can be expressed as a percentage by multiplying by 100.
2197d7a5752cSMel Gorman */
unusable_show(struct seq_file * m,void * arg)2198d7a5752cSMel Gorman static int unusable_show(struct seq_file *m, void *arg)
2199d7a5752cSMel Gorman {
2200d7a5752cSMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
2201d7a5752cSMel Gorman
2202d7a5752cSMel Gorman /* check memoryless node */
2203a47b53c5SLai Jiangshan if (!node_state(pgdat->node_id, N_MEMORY))
2204d7a5752cSMel Gorman return 0;
2205d7a5752cSMel Gorman
2206727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
2207d7a5752cSMel Gorman
2208d7a5752cSMel Gorman return 0;
2209d7a5752cSMel Gorman }
2210d7a5752cSMel Gorman
221101a99560SKefeng Wang static const struct seq_operations unusable_sops = {
2212d7a5752cSMel Gorman .start = frag_start,
2213d7a5752cSMel Gorman .next = frag_next,
2214d7a5752cSMel Gorman .stop = frag_stop,
2215d7a5752cSMel Gorman .show = unusable_show,
2216d7a5752cSMel Gorman };
2217d7a5752cSMel Gorman
221801a99560SKefeng Wang DEFINE_SEQ_ATTRIBUTE(unusable);
2219d7a5752cSMel Gorman
extfrag_show_print(struct seq_file * m,pg_data_t * pgdat,struct zone * zone)2220f1a5ab12SMel Gorman static void extfrag_show_print(struct seq_file *m,
2221f1a5ab12SMel Gorman pg_data_t *pgdat, struct zone *zone)
2222f1a5ab12SMel Gorman {
2223f1a5ab12SMel Gorman unsigned int order;
2224f1a5ab12SMel Gorman int index;
2225f1a5ab12SMel Gorman
2226f1a5ab12SMel Gorman /* Alloc on stack as interrupts are disabled for zone walk */
2227f1a5ab12SMel Gorman struct contig_page_info info;
2228f1a5ab12SMel Gorman
2229f1a5ab12SMel Gorman seq_printf(m, "Node %d, zone %8s ",
2230f1a5ab12SMel Gorman pgdat->node_id,
2231f1a5ab12SMel Gorman zone->name);
2232ded1ffeaSKirill A. Shutemov for (order = 0; order < NR_PAGE_ORDERS; ++order) {
2233f1a5ab12SMel Gorman fill_contig_page_info(zone, order, &info);
223456de7263SMel Gorman index = __fragmentation_index(order, &info);
2235a9970586SLin Feng seq_printf(m, "%2d.%03d ", index / 1000, index % 1000);
2236f1a5ab12SMel Gorman }
2237f1a5ab12SMel Gorman
2238f1a5ab12SMel Gorman seq_putc(m, '\n');
2239f1a5ab12SMel Gorman }
2240f1a5ab12SMel Gorman
2241f1a5ab12SMel Gorman /*
2242f1a5ab12SMel Gorman * Display fragmentation index for orders that allocations would fail for
2243f1a5ab12SMel Gorman */
extfrag_show(struct seq_file * m,void * arg)2244f1a5ab12SMel Gorman static int extfrag_show(struct seq_file *m, void *arg)
2245f1a5ab12SMel Gorman {
2246f1a5ab12SMel Gorman pg_data_t *pgdat = (pg_data_t *)arg;
2247f1a5ab12SMel Gorman
2248727c080fSVinayak Menon walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
2249f1a5ab12SMel Gorman
2250f1a5ab12SMel Gorman return 0;
2251f1a5ab12SMel Gorman }
2252f1a5ab12SMel Gorman
225301a99560SKefeng Wang static const struct seq_operations extfrag_sops = {
2254f1a5ab12SMel Gorman .start = frag_start,
2255f1a5ab12SMel Gorman .next = frag_next,
2256f1a5ab12SMel Gorman .stop = frag_stop,
2257f1a5ab12SMel Gorman .show = extfrag_show,
2258f1a5ab12SMel Gorman };
2259f1a5ab12SMel Gorman
226001a99560SKefeng Wang DEFINE_SEQ_ATTRIBUTE(extfrag);
2261f1a5ab12SMel Gorman
extfrag_debug_init(void)2262d7a5752cSMel Gorman static int __init extfrag_debug_init(void)
2263d7a5752cSMel Gorman {
2264bde8bd8aSSasikantha babu struct dentry *extfrag_debug_root;
2265bde8bd8aSSasikantha babu
2266d7a5752cSMel Gorman extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
2267d7a5752cSMel Gorman
2268d9f7979cSGreg Kroah-Hartman debugfs_create_file("unusable_index", 0444, extfrag_debug_root, NULL,
226901a99560SKefeng Wang &unusable_fops);
2270d7a5752cSMel Gorman
2271d9f7979cSGreg Kroah-Hartman debugfs_create_file("extfrag_index", 0444, extfrag_debug_root, NULL,
227201a99560SKefeng Wang &extfrag_fops);
2273f1a5ab12SMel Gorman
2274d7a5752cSMel Gorman return 0;
2275d7a5752cSMel Gorman }
2276d7a5752cSMel Gorman
2277d7a5752cSMel Gorman module_init(extfrag_debug_init);
2278d7a5752cSMel Gorman #endif
2279