Blame view

mm/vmstat.c 53 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
2
3
4
5
6
  /*
   *  linux/mm/vmstat.c
   *
   *  Manages VM statistics
   *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
7
8
9
10
   *
   *  zoned VM statistics
   *  Copyright (C) 2006 Silicon Graphics, Inc.,
   *		Christoph Lameter <christoph@lameter.com>
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
11
   *  Copyright (C) 2008-2014 Christoph Lameter
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
12
   */
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
13
  #include <linux/fs.h>
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
14
  #include <linux/mm.h>
4e950f6f0   Alexey Dobriyan   Remove fs.h from ...
15
  #include <linux/err.h>
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
16
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
18
  #include <linux/cpu.h>
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
19
  #include <linux/cpumask.h>
c748e1340   Adrian Bunk   mm/vmstat.c: prop...
20
  #include <linux/vmstat.h>
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
21
22
23
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/debugfs.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
24
  #include <linux/sched.h>
f1a5ab121   Mel Gorman   mm: export fragme...
25
  #include <linux/math64.h>
79da826ae   Michael Rubin   writeback: report...
26
  #include <linux/writeback.h>
36deb0be3   Namhyung Kim   vmstat: include c...
27
  #include <linux/compaction.h>
6e543d578   Lisa Du   mm: vmscan: fix d...
28
  #include <linux/mm_inline.h>
48c96a368   Joonsoo Kim   mm/page_owner: ke...
29
30
  #include <linux/page_ext.h>
  #include <linux/page_owner.h>
6e543d578   Lisa Du   mm: vmscan: fix d...
31
32
  
  #include "internal.h"
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
33

1d90ca897   Kemi Wang   mm: update NUMA c...
34
  #define NUMA_STATS_THRESHOLD (U16_MAX - 2)
4518085e1   Kemi Wang   mm, sysctl: make ...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  #ifdef CONFIG_NUMA
  int sysctl_vm_numa_stat = ENABLE_NUMA_STAT;
  
  /* zero numa counters within a zone */
  static void zero_zone_numa_counters(struct zone *zone)
  {
  	int item, cpu;
  
  	for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++) {
  		atomic_long_set(&zone->vm_numa_stat[item], 0);
  		for_each_online_cpu(cpu)
  			per_cpu_ptr(zone->pageset, cpu)->vm_numa_stat_diff[item]
  						= 0;
  	}
  }
  
  /* zero numa counters of all the populated zones */
  static void zero_zones_numa_counters(void)
  {
  	struct zone *zone;
  
  	for_each_populated_zone(zone)
  		zero_zone_numa_counters(zone);
  }
  
  /* zero global numa counters */
  static void zero_global_numa_counters(void)
  {
  	int item;
  
  	for (item = 0; item < NR_VM_NUMA_STAT_ITEMS; item++)
  		atomic_long_set(&vm_numa_stat[item], 0);
  }
  
  static void invalid_numa_statistics(void)
  {
  	zero_zones_numa_counters();
  	zero_global_numa_counters();
  }
  
  static DEFINE_MUTEX(vm_numa_stat_lock);
  
  int sysctl_vm_numa_stat_handler(struct ctl_table *table, int write,
32927393d   Christoph Hellwig   sysctl: pass kern...
78
  		void *buffer, size_t *length, loff_t *ppos)
4518085e1   Kemi Wang   mm, sysctl: make ...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  {
  	int ret, oldval;
  
  	mutex_lock(&vm_numa_stat_lock);
  	if (write)
  		oldval = sysctl_vm_numa_stat;
  	ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
  	if (ret || !write)
  		goto out;
  
  	if (oldval == sysctl_vm_numa_stat)
  		goto out;
  	else if (sysctl_vm_numa_stat == ENABLE_NUMA_STAT) {
  		static_branch_enable(&vm_numa_stat_key);
  		pr_info("enable numa statistics
  ");
  	} else {
  		static_branch_disable(&vm_numa_stat_key);
  		invalid_numa_statistics();
  		pr_info("disable numa statistics, and clear numa counters
  ");
  	}
  
  out:
  	mutex_unlock(&vm_numa_stat_lock);
  	return ret;
  }
  #endif
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
107
108
109
  #ifdef CONFIG_VM_EVENT_COUNTERS
  DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
  EXPORT_PER_CPU_SYMBOL(vm_event_states);
31f961a89   Minchan Kim   mm: use for_each_...
110
  static void sum_vm_events(unsigned long *ret)
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
111
  {
9eccf2a81   Christoph Lameter   vmstat: remove pr...
112
  	int cpu;
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
113
114
115
  	int i;
  
  	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
31f961a89   Minchan Kim   mm: use for_each_...
116
  	for_each_online_cpu(cpu) {
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
117
  		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
118
119
120
121
122
123
124
125
126
127
128
129
  		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
  			ret[i] += this->event[i];
  	}
  }
  
  /*
   * Accumulate the vm event counters across all CPUs.
   * The result is unavoidably approximate - it can change
   * during and after execution of this function.
  */
  void all_vm_events(unsigned long *ret)
  {
b5be11329   KOSAKI Motohiro   make vmstat cpu-u...
130
  	get_online_cpus();
31f961a89   Minchan Kim   mm: use for_each_...
131
  	sum_vm_events(ret);
b5be11329   KOSAKI Motohiro   make vmstat cpu-u...
132
  	put_online_cpus();
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
133
  }
32dd66fce   Heiko Carstens   [PATCH] vmstat: e...
134
  EXPORT_SYMBOL_GPL(all_vm_events);
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
135

f8891e5e1   Christoph Lameter   [PATCH] Light wei...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  /*
   * Fold the foreign cpu events into our own.
   *
   * This is adding to the events on one processor
   * but keeps the global counts constant.
   */
  void vm_events_fold_cpu(int cpu)
  {
  	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
  	int i;
  
  	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
  		count_vm_events(i, fold_state->event[i]);
  		fold_state->event[i] = 0;
  	}
  }
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
152
153
  
  #endif /* CONFIG_VM_EVENT_COUNTERS */
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
154
155
156
157
158
  /*
   * Manage combined zone based / global counters
   *
   * vm_stat contains the global counters
   */
75ef71840   Mel Gorman   mm, vmstat: add i...
159
  atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;
3a321d2a3   Kemi Wang   mm: change the ca...
160
  atomic_long_t vm_numa_stat[NR_VM_NUMA_STAT_ITEMS] __cacheline_aligned_in_smp;
75ef71840   Mel Gorman   mm, vmstat: add i...
161
162
  atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;
  EXPORT_SYMBOL(vm_zone_stat);
3a321d2a3   Kemi Wang   mm: change the ca...
163
  EXPORT_SYMBOL(vm_numa_stat);
75ef71840   Mel Gorman   mm, vmstat: add i...
164
  EXPORT_SYMBOL(vm_node_stat);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
165
166
  
  #ifdef CONFIG_SMP
b44129b30   Mel Gorman   mm: vmstat: use a...
167
  int calculate_pressure_threshold(struct zone *zone)
88f5acf88   Mel Gorman   mm: page allocato...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  {
  	int threshold;
  	int watermark_distance;
  
  	/*
  	 * As vmstats are not up to date, there is drift between the estimated
  	 * and real values. For high thresholds and a high number of CPUs, it
  	 * is possible for the min watermark to be breached while the estimated
  	 * value looks fine. The pressure threshold is a reduced value such
  	 * that even the maximum amount of drift will not accidentally breach
  	 * the min watermark
  	 */
  	watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone);
  	threshold = max(1, (int)(watermark_distance / num_online_cpus()));
  
  	/*
  	 * Maximum threshold is 125
  	 */
  	threshold = min(125, threshold);
  
  	return threshold;
  }
b44129b30   Mel Gorman   mm: vmstat: use a...
190
  int calculate_normal_threshold(struct zone *zone)
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  {
  	int threshold;
  	int mem;	/* memory in 128 MB units */
  
  	/*
  	 * The threshold scales with the number of processors and the amount
  	 * of memory per zone. More memory means that we can defer updates for
  	 * longer, more processors could lead to more contention.
   	 * fls() is used to have a cheap way of logarithmic scaling.
  	 *
  	 * Some sample thresholds:
  	 *
  	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
  	 * ------------------------------------------------------------------
  	 * 8		1		1	0.9-1 GB	4
  	 * 16		2		2	0.9-1 GB	4
  	 * 20 		2		2	1-2 GB		5
  	 * 24		2		2	2-4 GB		6
  	 * 28		2		2	4-8 GB		7
  	 * 32		2		2	8-16 GB		8
  	 * 4		2		2	<128M		1
  	 * 30		4		3	2-4 GB		5
  	 * 48		4		3	8-16 GB		8
  	 * 32		8		4	1-2 GB		4
  	 * 32		8		4	0.9-1GB		4
  	 * 10		16		5	<128M		1
  	 * 40		16		5	900M		4
  	 * 70		64		7	2-4 GB		5
  	 * 84		64		7	4-8 GB		6
  	 * 108		512		9	4-8 GB		6
  	 * 125		1024		10	8-16 GB		8
  	 * 125		1024		10	16-32 GB	9
  	 */
9705bea5f   Arun KS   mm: convert zone-...
224
  	mem = zone_managed_pages(zone) >> (27 - PAGE_SHIFT);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
225
226
227
228
229
230
231
232
233
234
  
  	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
  
  	/*
  	 * Maximum threshold is 125
  	 */
  	threshold = min(125, threshold);
  
  	return threshold;
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
235
236
  
  /*
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
237
   * Refresh the thresholds for each zone.
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
238
   */
a6cccdc36   KOSAKI Motohiro   mm, mem-hotplug: ...
239
  void refresh_zone_stat_thresholds(void)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
240
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
241
  	struct pglist_data *pgdat;
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
242
243
244
  	struct zone *zone;
  	int cpu;
  	int threshold;
75ef71840   Mel Gorman   mm, vmstat: add i...
245
246
247
248
249
250
  	/* Zero current pgdat thresholds */
  	for_each_online_pgdat(pgdat) {
  		for_each_online_cpu(cpu) {
  			per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0;
  		}
  	}
ee99c71c5   KOSAKI Motohiro   mm: introduce for...
251
  	for_each_populated_zone(zone) {
75ef71840   Mel Gorman   mm, vmstat: add i...
252
  		struct pglist_data *pgdat = zone->zone_pgdat;
aa4548403   Christoph Lameter   mm: page allocato...
253
  		unsigned long max_drift, tolerate_drift;
b44129b30   Mel Gorman   mm: vmstat: use a...
254
  		threshold = calculate_normal_threshold(zone);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
255

75ef71840   Mel Gorman   mm, vmstat: add i...
256
257
  		for_each_online_cpu(cpu) {
  			int pgdat_threshold;
99dcc3e5a   Christoph Lameter   this_cpu: Page al...
258
259
  			per_cpu_ptr(zone->pageset, cpu)->stat_threshold
  							= threshold;
1d90ca897   Kemi Wang   mm: update NUMA c...
260

75ef71840   Mel Gorman   mm, vmstat: add i...
261
262
263
264
265
  			/* Base nodestat threshold on the largest populated zone. */
  			pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold;
  			per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold
  				= max(threshold, pgdat_threshold);
  		}
aa4548403   Christoph Lameter   mm: page allocato...
266
267
268
269
270
271
272
273
274
275
  		/*
  		 * Only set percpu_drift_mark if there is a danger that
  		 * NR_FREE_PAGES reports the low watermark is ok when in fact
  		 * the min watermark could be breached by an allocation
  		 */
  		tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone);
  		max_drift = num_online_cpus() * threshold;
  		if (max_drift > tolerate_drift)
  			zone->percpu_drift_mark = high_wmark_pages(zone) +
  					max_drift;
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
276
  	}
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
277
  }
b44129b30   Mel Gorman   mm: vmstat: use a...
278
279
  void set_pgdat_percpu_threshold(pg_data_t *pgdat,
  				int (*calculate_pressure)(struct zone *))
88f5acf88   Mel Gorman   mm: page allocato...
280
281
282
283
284
  {
  	struct zone *zone;
  	int cpu;
  	int threshold;
  	int i;
88f5acf88   Mel Gorman   mm: page allocato...
285
286
287
288
  	for (i = 0; i < pgdat->nr_zones; i++) {
  		zone = &pgdat->node_zones[i];
  		if (!zone->percpu_drift_mark)
  			continue;
b44129b30   Mel Gorman   mm: vmstat: use a...
289
  		threshold = (*calculate_pressure)(zone);
1d90ca897   Kemi Wang   mm: update NUMA c...
290
  		for_each_online_cpu(cpu)
88f5acf88   Mel Gorman   mm: page allocato...
291
292
293
  			per_cpu_ptr(zone->pageset, cpu)->stat_threshold
  							= threshold;
  	}
88f5acf88   Mel Gorman   mm: page allocato...
294
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
295
  /*
bea04b073   Jianyu Zhan   mm: use the light...
296
297
298
   * For use when we know that interrupts are disabled,
   * or when we know that preemption is disabled and that
   * particular counter cannot be updated from interrupt context.
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
299
300
   */
  void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
6cdb18ad9   Heiko Carstens   mm/vmstat: fix ov...
301
  			   long delta)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
302
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
303
304
  	struct per_cpu_pageset __percpu *pcp = zone->pageset;
  	s8 __percpu *p = pcp->vm_stat_diff + item;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
305
  	long x;
12938a922   Christoph Lameter   vmstat: Optimize ...
306
307
308
  	long t;
  
  	x = delta + __this_cpu_read(*p);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
309

12938a922   Christoph Lameter   vmstat: Optimize ...
310
  	t = __this_cpu_read(pcp->stat_threshold);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
311

406100762   Miaohe Lin   mm/vmstat.c: use ...
312
  	if (unlikely(abs(x) > t)) {
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
313
314
315
  		zone_page_state_add(x, zone, item);
  		x = 0;
  	}
12938a922   Christoph Lameter   vmstat: Optimize ...
316
  	__this_cpu_write(*p, x);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
317
318
  }
  EXPORT_SYMBOL(__mod_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
319
320
321
322
323
324
325
  void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
  				long delta)
  {
  	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
  	s8 __percpu *p = pcp->vm_node_stat_diff + item;
  	long x;
  	long t;
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
326
327
328
329
  	if (vmstat_item_in_bytes(item)) {
  		VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
  		delta >>= PAGE_SHIFT;
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
330
331
332
  	x = delta + __this_cpu_read(*p);
  
  	t = __this_cpu_read(pcp->stat_threshold);
406100762   Miaohe Lin   mm/vmstat.c: use ...
333
  	if (unlikely(abs(x) > t)) {
75ef71840   Mel Gorman   mm, vmstat: add i...
334
335
336
337
338
339
  		node_page_state_add(x, pgdat, item);
  		x = 0;
  	}
  	__this_cpu_write(*p, x);
  }
  EXPORT_SYMBOL(__mod_node_page_state);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
340
  /*
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
341
342
343
344
345
346
347
348
349
   * Optimized increment and decrement functions.
   *
   * These are only for a single page and therefore can take a struct page *
   * argument instead of struct zone *. This allows the inclusion of the code
   * generated for page_zone(page) into the optimized functions.
   *
   * No overflow check is necessary and therefore the differential can be
   * incremented or decremented in place which may allow the compilers to
   * generate better code.
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
350
351
352
   * The increment or decrement is known and therefore one boundary check can
   * be omitted.
   *
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
353
354
355
   * NOTE: These functions are very performance sensitive. Change only
   * with care.
   *
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
356
357
358
359
360
361
362
   * Some processors have inc/dec instructions that are atomic vs an interrupt.
   * However, the code must first determine the differential location in a zone
   * based on the processor number and then inc/dec the counter. There is no
   * guarantee without disabling preemption that the processor will not change
   * in between and therefore the atomicity vs. interrupt cannot be exploited
   * in a useful way here.
   */
c87853859   Christoph Lameter   [PATCH] Use ZVC f...
363
  void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
364
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
365
366
367
  	struct per_cpu_pageset __percpu *pcp = zone->pageset;
  	s8 __percpu *p = pcp->vm_stat_diff + item;
  	s8 v, t;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
368

908ee0f12   Christoph Lameter   vmstat: Use this_...
369
  	v = __this_cpu_inc_return(*p);
12938a922   Christoph Lameter   vmstat: Optimize ...
370
371
372
  	t = __this_cpu_read(pcp->stat_threshold);
  	if (unlikely(v > t)) {
  		s8 overstep = t >> 1;
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
373

12938a922   Christoph Lameter   vmstat: Optimize ...
374
375
  		zone_page_state_add(v + overstep, zone, item);
  		__this_cpu_write(*p, -overstep);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
376
377
  	}
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
378

75ef71840   Mel Gorman   mm, vmstat: add i...
379
380
381
382
383
  void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
  {
  	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
  	s8 __percpu *p = pcp->vm_node_stat_diff + item;
  	s8 v, t;
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
384
  	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
75ef71840   Mel Gorman   mm, vmstat: add i...
385
386
387
388
389
390
391
392
393
  	v = __this_cpu_inc_return(*p);
  	t = __this_cpu_read(pcp->stat_threshold);
  	if (unlikely(v > t)) {
  		s8 overstep = t >> 1;
  
  		node_page_state_add(v + overstep, pgdat, item);
  		__this_cpu_write(*p, -overstep);
  	}
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
394
395
396
397
  void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
  {
  	__inc_zone_state(page_zone(page), item);
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
398
  EXPORT_SYMBOL(__inc_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
399
400
401
402
403
  void __inc_node_page_state(struct page *page, enum node_stat_item item)
  {
  	__inc_node_state(page_pgdat(page), item);
  }
  EXPORT_SYMBOL(__inc_node_page_state);
c87853859   Christoph Lameter   [PATCH] Use ZVC f...
404
  void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
405
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
406
407
408
  	struct per_cpu_pageset __percpu *pcp = zone->pageset;
  	s8 __percpu *p = pcp->vm_stat_diff + item;
  	s8 v, t;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
409

908ee0f12   Christoph Lameter   vmstat: Use this_...
410
  	v = __this_cpu_dec_return(*p);
12938a922   Christoph Lameter   vmstat: Optimize ...
411
412
413
  	t = __this_cpu_read(pcp->stat_threshold);
  	if (unlikely(v < - t)) {
  		s8 overstep = t >> 1;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
414

12938a922   Christoph Lameter   vmstat: Optimize ...
415
416
  		zone_page_state_add(v - overstep, zone, item);
  		__this_cpu_write(*p, overstep);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
417
418
  	}
  }
c87853859   Christoph Lameter   [PATCH] Use ZVC f...
419

75ef71840   Mel Gorman   mm, vmstat: add i...
420
421
422
423
424
  void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
  {
  	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
  	s8 __percpu *p = pcp->vm_node_stat_diff + item;
  	s8 v, t;
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
425
  	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
75ef71840   Mel Gorman   mm, vmstat: add i...
426
427
428
429
430
431
432
433
434
  	v = __this_cpu_dec_return(*p);
  	t = __this_cpu_read(pcp->stat_threshold);
  	if (unlikely(v < - t)) {
  		s8 overstep = t >> 1;
  
  		node_page_state_add(v - overstep, pgdat, item);
  		__this_cpu_write(*p, overstep);
  	}
  }
c87853859   Christoph Lameter   [PATCH] Use ZVC f...
435
436
437
438
  void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
  {
  	__dec_zone_state(page_zone(page), item);
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
439
  EXPORT_SYMBOL(__dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
440
441
442
443
444
  void __dec_node_page_state(struct page *page, enum node_stat_item item)
  {
  	__dec_node_state(page_pgdat(page), item);
  }
  EXPORT_SYMBOL(__dec_node_page_state);
4156153c4   Heiko Carstens   mm,x86,um: move C...
445
  #ifdef CONFIG_HAVE_CMPXCHG_LOCAL
7c8391206   Christoph Lameter   vmstat: User per ...
446
447
448
449
450
451
452
453
454
455
456
457
  /*
   * If we have cmpxchg_local support then we do not need to incur the overhead
   * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
   *
   * mod_state() modifies the zone counter state through atomic per cpu
   * operations.
   *
   * Overstep mode specifies how overstep should handled:
   *     0       No overstepping
   *     1       Overstepping half of threshold
   *     -1      Overstepping minus half of threshold
  */
75ef71840   Mel Gorman   mm, vmstat: add i...
458
459
  static inline void mod_zone_state(struct zone *zone,
         enum zone_stat_item item, long delta, int overstep_mode)
7c8391206   Christoph Lameter   vmstat: User per ...
460
461
462
463
464
465
466
467
468
469
470
  {
  	struct per_cpu_pageset __percpu *pcp = zone->pageset;
  	s8 __percpu *p = pcp->vm_stat_diff + item;
  	long o, n, t, z;
  
  	do {
  		z = 0;  /* overflow to zone counters */
  
  		/*
  		 * The fetching of the stat_threshold is racy. We may apply
  		 * a counter threshold to the wrong the cpu if we get
d3bc23671   Christoph Lameter   vmstat: update co...
471
472
473
474
475
476
  		 * rescheduled while executing here. However, the next
  		 * counter update will apply the threshold again and
  		 * therefore bring the counter under the threshold again.
  		 *
  		 * Most of the time the thresholds are the same anyways
  		 * for all cpus in a zone.
7c8391206   Christoph Lameter   vmstat: User per ...
477
478
479
480
481
  		 */
  		t = this_cpu_read(pcp->stat_threshold);
  
  		o = this_cpu_read(*p);
  		n = delta + o;
406100762   Miaohe Lin   mm/vmstat.c: use ...
482
  		if (abs(n) > t) {
7c8391206   Christoph Lameter   vmstat: User per ...
483
484
485
486
487
488
489
490
491
492
493
494
495
  			int os = overstep_mode * (t >> 1) ;
  
  			/* Overflow must be added to zone counters */
  			z = n + os;
  			n = -os;
  		}
  	} while (this_cpu_cmpxchg(*p, o, n) != o);
  
  	if (z)
  		zone_page_state_add(z, zone, item);
  }
  
  void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
6cdb18ad9   Heiko Carstens   mm/vmstat: fix ov...
496
  			 long delta)
7c8391206   Christoph Lameter   vmstat: User per ...
497
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
498
  	mod_zone_state(zone, item, delta, 0);
7c8391206   Christoph Lameter   vmstat: User per ...
499
500
  }
  EXPORT_SYMBOL(mod_zone_page_state);
7c8391206   Christoph Lameter   vmstat: User per ...
501
502
  void inc_zone_page_state(struct page *page, enum zone_stat_item item)
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
503
  	mod_zone_state(page_zone(page), item, 1, 1);
7c8391206   Christoph Lameter   vmstat: User per ...
504
505
506
507
508
  }
  EXPORT_SYMBOL(inc_zone_page_state);
  
  void dec_zone_page_state(struct page *page, enum zone_stat_item item)
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
509
  	mod_zone_state(page_zone(page), item, -1, -1);
7c8391206   Christoph Lameter   vmstat: User per ...
510
511
  }
  EXPORT_SYMBOL(dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
512
513
514
515
516
517
518
  
  static inline void mod_node_state(struct pglist_data *pgdat,
         enum node_stat_item item, int delta, int overstep_mode)
  {
  	struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats;
  	s8 __percpu *p = pcp->vm_node_stat_diff + item;
  	long o, n, t, z;
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
519
520
521
522
  	if (vmstat_item_in_bytes(item)) {
  		VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
  		delta >>= PAGE_SHIFT;
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  	do {
  		z = 0;  /* overflow to node counters */
  
  		/*
  		 * The fetching of the stat_threshold is racy. We may apply
  		 * a counter threshold to the wrong the cpu if we get
  		 * rescheduled while executing here. However, the next
  		 * counter update will apply the threshold again and
  		 * therefore bring the counter under the threshold again.
  		 *
  		 * Most of the time the thresholds are the same anyways
  		 * for all cpus in a node.
  		 */
  		t = this_cpu_read(pcp->stat_threshold);
  
  		o = this_cpu_read(*p);
  		n = delta + o;
406100762   Miaohe Lin   mm/vmstat.c: use ...
540
  		if (abs(n) > t) {
75ef71840   Mel Gorman   mm, vmstat: add i...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  			int os = overstep_mode * (t >> 1) ;
  
  			/* Overflow must be added to node counters */
  			z = n + os;
  			n = -os;
  		}
  	} while (this_cpu_cmpxchg(*p, o, n) != o);
  
  	if (z)
  		node_page_state_add(z, pgdat, item);
  }
  
  void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
  					long delta)
  {
  	mod_node_state(pgdat, item, delta, 0);
  }
  EXPORT_SYMBOL(mod_node_page_state);
  
  void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
  {
  	mod_node_state(pgdat, item, 1, 1);
  }
  
  void inc_node_page_state(struct page *page, enum node_stat_item item)
  {
  	mod_node_state(page_pgdat(page), item, 1, 1);
  }
  EXPORT_SYMBOL(inc_node_page_state);
  
  void dec_node_page_state(struct page *page, enum node_stat_item item)
  {
  	mod_node_state(page_pgdat(page), item, -1, -1);
  }
  EXPORT_SYMBOL(dec_node_page_state);
7c8391206   Christoph Lameter   vmstat: User per ...
576
577
578
579
580
  #else
  /*
   * Use interrupt disable to serialize counter updates
   */
  void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
6cdb18ad9   Heiko Carstens   mm/vmstat: fix ov...
581
  			 long delta)
7c8391206   Christoph Lameter   vmstat: User per ...
582
583
584
585
586
587
588
589
  {
  	unsigned long flags;
  
  	local_irq_save(flags);
  	__mod_zone_page_state(zone, item, delta);
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(mod_zone_page_state);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
590
591
592
593
  void inc_zone_page_state(struct page *page, enum zone_stat_item item)
  {
  	unsigned long flags;
  	struct zone *zone;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
594
595
596
  
  	zone = page_zone(page);
  	local_irq_save(flags);
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
597
  	__inc_zone_state(zone, item);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
598
599
600
601
602
603
604
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(inc_zone_page_state);
  
  void dec_zone_page_state(struct page *page, enum zone_stat_item item)
  {
  	unsigned long flags;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
605

2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
606
  	local_irq_save(flags);
a302eb4e4   Christoph Lameter   [PATCH] ZVC: Over...
607
  	__dec_zone_page_state(page, item);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
608
609
610
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
  void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
  {
  	unsigned long flags;
  
  	local_irq_save(flags);
  	__inc_node_state(pgdat, item);
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(inc_node_state);
  
  void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
  					long delta)
  {
  	unsigned long flags;
  
  	local_irq_save(flags);
  	__mod_node_page_state(pgdat, item, delta);
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(mod_node_page_state);
  
  void inc_node_page_state(struct page *page, enum node_stat_item item)
  {
  	unsigned long flags;
  	struct pglist_data *pgdat;
  
  	pgdat = page_pgdat(page);
  	local_irq_save(flags);
  	__inc_node_state(pgdat, item);
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(inc_node_page_state);
  
  void dec_node_page_state(struct page *page, enum node_stat_item item)
  {
  	unsigned long flags;
  
  	local_irq_save(flags);
  	__dec_node_page_state(page, item);
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(dec_node_page_state);
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
654
655
656
657
658
  
  /*
   * Fold a differential into the global counters.
   * Returns the number of counters updated.
   */
3a321d2a3   Kemi Wang   mm: change the ca...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  #ifdef CONFIG_NUMA
  static int fold_diff(int *zone_diff, int *numa_diff, int *node_diff)
  {
  	int i;
  	int changes = 0;
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
  		if (zone_diff[i]) {
  			atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
  			changes++;
  	}
  
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
  		if (numa_diff[i]) {
  			atomic_long_add(numa_diff[i], &vm_numa_stat[i]);
  			changes++;
  	}
  
  	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
  		if (node_diff[i]) {
  			atomic_long_add(node_diff[i], &vm_node_stat[i]);
  			changes++;
  	}
  	return changes;
  }
  #else
75ef71840   Mel Gorman   mm, vmstat: add i...
685
  static int fold_diff(int *zone_diff, int *node_diff)
4edb0748b   Christoph Lameter   vmstat: create fo...
686
687
  {
  	int i;
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
688
  	int changes = 0;
4edb0748b   Christoph Lameter   vmstat: create fo...
689
690
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
75ef71840   Mel Gorman   mm, vmstat: add i...
691
692
693
694
695
696
697
698
  		if (zone_diff[i]) {
  			atomic_long_add(zone_diff[i], &vm_zone_stat[i]);
  			changes++;
  	}
  
  	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
  		if (node_diff[i]) {
  			atomic_long_add(node_diff[i], &vm_node_stat[i]);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
699
700
701
  			changes++;
  	}
  	return changes;
4edb0748b   Christoph Lameter   vmstat: create fo...
702
  }
3a321d2a3   Kemi Wang   mm: change the ca...
703
  #endif /* CONFIG_NUMA */
4edb0748b   Christoph Lameter   vmstat: create fo...
704

2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
705
  /*
2bb921e52   Christoph Lameter   vmstat: create se...
706
   * Update the zone counters for the current cpu.
a7f75e258   Christoph Lameter   vmstat: small rev...
707
   *
4037d4522   Christoph Lameter   Move remote node ...
708
709
710
711
712
713
714
715
716
717
   * Note that refresh_cpu_vm_stats strives to only access
   * node local memory. The per cpu pagesets on remote zones are placed
   * in the memory local to the processor using that pageset. So the
   * loop over all zones will access a series of cachelines local to
   * the processor.
   *
   * The call to zone_page_state_add updates the cachelines with the
   * statistics in the remote zone struct as well as the global cachelines
   * with the global counters. These could cause remote node cache line
   * bouncing and will have to be only done when necessary.
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
718
719
   *
   * The function returns the number of global counters updated.
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
720
   */
0eb77e988   Christoph Lameter   vmstat: make vmst...
721
  static int refresh_cpu_vm_stats(bool do_pagesets)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
722
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
723
  	struct pglist_data *pgdat;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
724
725
  	struct zone *zone;
  	int i;
75ef71840   Mel Gorman   mm, vmstat: add i...
726
  	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3a321d2a3   Kemi Wang   mm: change the ca...
727
728
729
  #ifdef CONFIG_NUMA
  	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
  #endif
75ef71840   Mel Gorman   mm, vmstat: add i...
730
  	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
731
  	int changes = 0;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
732

ee99c71c5   KOSAKI Motohiro   mm: introduce for...
733
  	for_each_populated_zone(zone) {
fbc2edb05   Christoph Lameter   vmstat: use this_...
734
  		struct per_cpu_pageset __percpu *p = zone->pageset;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
735

fbc2edb05   Christoph Lameter   vmstat: use this_...
736
737
  		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
  			int v;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
738

fbc2edb05   Christoph Lameter   vmstat: use this_...
739
740
  			v = this_cpu_xchg(p->vm_stat_diff[i], 0);
  			if (v) {
a7f75e258   Christoph Lameter   vmstat: small rev...
741

a7f75e258   Christoph Lameter   vmstat: small rev...
742
  				atomic_long_add(v, &zone->vm_stat[i]);
75ef71840   Mel Gorman   mm, vmstat: add i...
743
  				global_zone_diff[i] += v;
4037d4522   Christoph Lameter   Move remote node ...
744
745
  #ifdef CONFIG_NUMA
  				/* 3 seconds idle till flush */
fbc2edb05   Christoph Lameter   vmstat: use this_...
746
  				__this_cpu_write(p->expire, 3);
4037d4522   Christoph Lameter   Move remote node ...
747
  #endif
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
748
  			}
fbc2edb05   Christoph Lameter   vmstat: use this_...
749
  		}
4037d4522   Christoph Lameter   Move remote node ...
750
  #ifdef CONFIG_NUMA
3a321d2a3   Kemi Wang   mm: change the ca...
751
752
753
754
755
756
757
758
759
760
761
  		for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
  			int v;
  
  			v = this_cpu_xchg(p->vm_numa_stat_diff[i], 0);
  			if (v) {
  
  				atomic_long_add(v, &zone->vm_numa_stat[i]);
  				global_numa_diff[i] += v;
  				__this_cpu_write(p->expire, 3);
  			}
  		}
0eb77e988   Christoph Lameter   vmstat: make vmst...
762
763
764
765
766
767
768
769
770
771
  		if (do_pagesets) {
  			cond_resched();
  			/*
  			 * Deal with draining the remote pageset of this
  			 * processor
  			 *
  			 * Check if there are pages remaining in this pageset
  			 * if not then there is nothing to expire.
  			 */
  			if (!__this_cpu_read(p->expire) ||
fbc2edb05   Christoph Lameter   vmstat: use this_...
772
  			       !__this_cpu_read(p->pcp.count))
0eb77e988   Christoph Lameter   vmstat: make vmst...
773
  				continue;
4037d4522   Christoph Lameter   Move remote node ...
774

0eb77e988   Christoph Lameter   vmstat: make vmst...
775
776
777
778
779
780
781
  			/*
  			 * We never drain zones local to this processor.
  			 */
  			if (zone_to_nid(zone) == numa_node_id()) {
  				__this_cpu_write(p->expire, 0);
  				continue;
  			}
4037d4522   Christoph Lameter   Move remote node ...
782

0eb77e988   Christoph Lameter   vmstat: make vmst...
783
784
  			if (__this_cpu_dec_return(p->expire))
  				continue;
4037d4522   Christoph Lameter   Move remote node ...
785

0eb77e988   Christoph Lameter   vmstat: make vmst...
786
787
788
789
  			if (__this_cpu_read(p->pcp.count)) {
  				drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
  				changes++;
  			}
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
790
  		}
4037d4522   Christoph Lameter   Move remote node ...
791
  #endif
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
792
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  
  	for_each_online_pgdat(pgdat) {
  		struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats;
  
  		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
  			int v;
  
  			v = this_cpu_xchg(p->vm_node_stat_diff[i], 0);
  			if (v) {
  				atomic_long_add(v, &pgdat->vm_stat[i]);
  				global_node_diff[i] += v;
  			}
  		}
  	}
3a321d2a3   Kemi Wang   mm: change the ca...
807
808
809
810
  #ifdef CONFIG_NUMA
  	changes += fold_diff(global_zone_diff, global_numa_diff,
  			     global_node_diff);
  #else
75ef71840   Mel Gorman   mm, vmstat: add i...
811
  	changes += fold_diff(global_zone_diff, global_node_diff);
3a321d2a3   Kemi Wang   mm: change the ca...
812
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
813
  	return changes;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
814
  }
40f4b1ead   Cody P Schafer   mm/vmstat: add no...
815
  /*
2bb921e52   Christoph Lameter   vmstat: create se...
816
817
818
819
820
821
   * Fold the data for an offline cpu into the global array.
   * There cannot be any access by the offline cpu and therefore
   * synchronization is simplified.
   */
  void cpu_vm_stats_fold(int cpu)
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
822
  	struct pglist_data *pgdat;
2bb921e52   Christoph Lameter   vmstat: create se...
823
824
  	struct zone *zone;
  	int i;
75ef71840   Mel Gorman   mm, vmstat: add i...
825
  	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3a321d2a3   Kemi Wang   mm: change the ca...
826
827
828
  #ifdef CONFIG_NUMA
  	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
  #endif
75ef71840   Mel Gorman   mm, vmstat: add i...
829
  	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
2bb921e52   Christoph Lameter   vmstat: create se...
830
831
832
833
834
835
836
837
838
839
840
841
842
  
  	for_each_populated_zone(zone) {
  		struct per_cpu_pageset *p;
  
  		p = per_cpu_ptr(zone->pageset, cpu);
  
  		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
  			if (p->vm_stat_diff[i]) {
  				int v;
  
  				v = p->vm_stat_diff[i];
  				p->vm_stat_diff[i] = 0;
  				atomic_long_add(v, &zone->vm_stat[i]);
75ef71840   Mel Gorman   mm, vmstat: add i...
843
  				global_zone_diff[i] += v;
2bb921e52   Christoph Lameter   vmstat: create se...
844
  			}
3a321d2a3   Kemi Wang   mm: change the ca...
845
846
847
848
849
850
851
852
853
854
855
856
  
  #ifdef CONFIG_NUMA
  		for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
  			if (p->vm_numa_stat_diff[i]) {
  				int v;
  
  				v = p->vm_numa_stat_diff[i];
  				p->vm_numa_stat_diff[i] = 0;
  				atomic_long_add(v, &zone->vm_numa_stat[i]);
  				global_numa_diff[i] += v;
  			}
  #endif
2bb921e52   Christoph Lameter   vmstat: create se...
857
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  	for_each_online_pgdat(pgdat) {
  		struct per_cpu_nodestat *p;
  
  		p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
  
  		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
  			if (p->vm_node_stat_diff[i]) {
  				int v;
  
  				v = p->vm_node_stat_diff[i];
  				p->vm_node_stat_diff[i] = 0;
  				atomic_long_add(v, &pgdat->vm_stat[i]);
  				global_node_diff[i] += v;
  			}
  	}
3a321d2a3   Kemi Wang   mm: change the ca...
873
874
875
  #ifdef CONFIG_NUMA
  	fold_diff(global_zone_diff, global_numa_diff, global_node_diff);
  #else
75ef71840   Mel Gorman   mm, vmstat: add i...
876
  	fold_diff(global_zone_diff, global_node_diff);
3a321d2a3   Kemi Wang   mm: change the ca...
877
  #endif
2bb921e52   Christoph Lameter   vmstat: create se...
878
879
880
  }
  
  /*
40f4b1ead   Cody P Schafer   mm/vmstat: add no...
881
882
883
   * this is only called if !populated_zone(zone), which implies no other users of
   * pset->vm_stat_diff[] exsist.
   */
5a8838138   Minchan Kim   memory-hotplug: f...
884
885
886
887
888
889
890
891
892
  void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
  {
  	int i;
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
  		if (pset->vm_stat_diff[i]) {
  			int v = pset->vm_stat_diff[i];
  			pset->vm_stat_diff[i] = 0;
  			atomic_long_add(v, &zone->vm_stat[i]);
75ef71840   Mel Gorman   mm, vmstat: add i...
893
  			atomic_long_add(v, &vm_zone_stat[i]);
5a8838138   Minchan Kim   memory-hotplug: f...
894
  		}
3a321d2a3   Kemi Wang   mm: change the ca...
895
896
897
898
899
900
901
902
903
904
905
  
  #ifdef CONFIG_NUMA
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
  		if (pset->vm_numa_stat_diff[i]) {
  			int v = pset->vm_numa_stat_diff[i];
  
  			pset->vm_numa_stat_diff[i] = 0;
  			atomic_long_add(v, &zone->vm_numa_stat[i]);
  			atomic_long_add(v, &vm_numa_stat[i]);
  		}
  #endif
5a8838138   Minchan Kim   memory-hotplug: f...
906
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
907
  #endif
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
908
  #ifdef CONFIG_NUMA
3a321d2a3   Kemi Wang   mm: change the ca...
909
910
911
912
  void __inc_numa_state(struct zone *zone,
  				 enum numa_stat_item item)
  {
  	struct per_cpu_pageset __percpu *pcp = zone->pageset;
1d90ca897   Kemi Wang   mm: update NUMA c...
913
914
  	u16 __percpu *p = pcp->vm_numa_stat_diff + item;
  	u16 v;
3a321d2a3   Kemi Wang   mm: change the ca...
915
916
  
  	v = __this_cpu_inc_return(*p);
3a321d2a3   Kemi Wang   mm: change the ca...
917

1d90ca897   Kemi Wang   mm: update NUMA c...
918
919
920
  	if (unlikely(v > NUMA_STATS_THRESHOLD)) {
  		zone_numa_state_add(v, zone, item);
  		__this_cpu_write(*p, 0);
3a321d2a3   Kemi Wang   mm: change the ca...
921
922
  	}
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
923
  /*
75ef71840   Mel Gorman   mm, vmstat: add i...
924
925
926
   * Determine the per node value of a stat item. This function
   * is called frequently in a NUMA machine, so try to be as
   * frugal as possible.
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
927
   */
75ef71840   Mel Gorman   mm, vmstat: add i...
928
929
  unsigned long sum_zone_node_page_state(int node,
  				 enum zone_stat_item item)
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
930
931
  {
  	struct zone *zones = NODE_DATA(node)->node_zones;
e87d59f7a   Joonsoo Kim   mm/vmstat: make n...
932
933
  	int i;
  	unsigned long count = 0;
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
934

e87d59f7a   Joonsoo Kim   mm/vmstat: make n...
935
936
937
938
  	for (i = 0; i < MAX_NR_ZONES; i++)
  		count += zone_page_state(zones + i, item);
  
  	return count;
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
939
  }
638032224   Kemi Wang   mm: consider the ...
940
941
942
943
  /*
   * Determine the per node value of a numa stat item. To avoid deviation,
   * the per cpu stat number in vm_numa_stat_diff[] is also included.
   */
3a321d2a3   Kemi Wang   mm: change the ca...
944
945
946
947
948
949
950
951
  unsigned long sum_zone_numa_state(int node,
  				 enum numa_stat_item item)
  {
  	struct zone *zones = NODE_DATA(node)->node_zones;
  	int i;
  	unsigned long count = 0;
  
  	for (i = 0; i < MAX_NR_ZONES; i++)
638032224   Kemi Wang   mm: consider the ...
952
  		count += zone_numa_state_snapshot(zones + i, item);
3a321d2a3   Kemi Wang   mm: change the ca...
953
954
955
  
  	return count;
  }
75ef71840   Mel Gorman   mm, vmstat: add i...
956
957
958
  /*
   * Determine the per node value of a stat item.
   */
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
959
960
  unsigned long node_page_state_pages(struct pglist_data *pgdat,
  				    enum node_stat_item item)
75ef71840   Mel Gorman   mm, vmstat: add i...
961
962
963
964
965
966
967
968
  {
  	long x = atomic_long_read(&pgdat->vm_stat[item]);
  #ifdef CONFIG_SMP
  	if (x < 0)
  		x = 0;
  #endif
  	return x;
  }
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
969
970
971
972
973
974
975
976
  
  unsigned long node_page_state(struct pglist_data *pgdat,
  			      enum node_stat_item item)
  {
  	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
  
  	return node_page_state_pages(pgdat, item);
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
977
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
978
  #ifdef CONFIG_COMPACTION
36deb0be3   Namhyung Kim   vmstat: include c...
979

d7a5752c0   Mel Gorman   mm: export unusab...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
  struct contig_page_info {
  	unsigned long free_pages;
  	unsigned long free_blocks_total;
  	unsigned long free_blocks_suitable;
  };
  
  /*
   * Calculate the number of free pages in a zone, how many contiguous
   * pages are free and how many are large enough to satisfy an allocation of
   * the target size. Note that this function makes no attempt to estimate
   * how many suitable free blocks there *might* be if MOVABLE pages were
   * migrated. Calculating that is possible, but expensive and can be
   * figured out from userspace
   */
  static void fill_contig_page_info(struct zone *zone,
  				unsigned int suitable_order,
  				struct contig_page_info *info)
  {
  	unsigned int order;
  
  	info->free_pages = 0;
  	info->free_blocks_total = 0;
  	info->free_blocks_suitable = 0;
  
  	for (order = 0; order < MAX_ORDER; order++) {
  		unsigned long blocks;
  
  		/* Count number of free blocks */
  		blocks = zone->free_area[order].nr_free;
  		info->free_blocks_total += blocks;
  
  		/* Count free base pages */
  		info->free_pages += blocks << order;
  
  		/* Count the suitable free blocks */
  		if (order >= suitable_order)
  			info->free_blocks_suitable += blocks <<
  						(order - suitable_order);
  	}
  }
f1a5ab121   Mel Gorman   mm: export fragme...
1020
1021
1022
1023
1024
1025
1026
1027
  
  /*
   * A fragmentation index only makes sense if an allocation of a requested
   * size would fail. If that is true, the fragmentation index indicates
   * whether external fragmentation or a lack of memory was the problem.
   * The value can be used to determine if page reclaim or compaction
   * should be used
   */
56de7263f   Mel Gorman   mm: compaction: d...
1028
  static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
f1a5ab121   Mel Gorman   mm: export fragme...
1029
1030
  {
  	unsigned long requested = 1UL << order;
88d6ac40c   Wen Yang   mm/vmstat: fix di...
1031
1032
  	if (WARN_ON_ONCE(order >= MAX_ORDER))
  		return 0;
f1a5ab121   Mel Gorman   mm: export fragme...
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  	if (!info->free_blocks_total)
  		return 0;
  
  	/* Fragmentation index only makes sense when a request would fail */
  	if (info->free_blocks_suitable)
  		return -1000;
  
  	/*
  	 * Index is between 0 and 1 so return within 3 decimal places
  	 *
  	 * 0 => allocation would fail due to lack of memory
  	 * 1 => allocation would fail due to fragmentation
  	 */
  	return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
  }
56de7263f   Mel Gorman   mm: compaction: d...
1048

facdaa917   Nitin Gupta   mm: proactive com...
1049
1050
1051
1052
1053
  /*
   * Calculates external fragmentation within a zone wrt the given order.
   * It is defined as the percentage of pages found in blocks of size
   * less than 1 << order. It returns values in range [0, 100].
   */
d34c0a759   Nitin Gupta   mm: use unsigned ...
1054
  unsigned int extfrag_for_order(struct zone *zone, unsigned int order)
facdaa917   Nitin Gupta   mm: proactive com...
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  {
  	struct contig_page_info info;
  
  	fill_contig_page_info(zone, order, &info);
  	if (info.free_pages == 0)
  		return 0;
  
  	return div_u64((info.free_pages -
  			(info.free_blocks_suitable << order)) * 100,
  			info.free_pages);
  }
56de7263f   Mel Gorman   mm: compaction: d...
1066
1067
1068
1069
1070
1071
1072
1073
  /* Same as __fragmentation index but allocs contig_page_info on stack */
  int fragmentation_index(struct zone *zone, unsigned int order)
  {
  	struct contig_page_info info;
  
  	fill_contig_page_info(zone, order, &info);
  	return __fragmentation_index(order, &info);
  }
d7a5752c0   Mel Gorman   mm: export unusab...
1074
  #endif
ebc5d83d0   Konstantin Khlebnikov   mm/memcontrol: us...
1075
1076
  #if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
      defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  #ifdef CONFIG_ZONE_DMA
  #define TEXT_FOR_DMA(xx) xx "_dma",
  #else
  #define TEXT_FOR_DMA(xx)
  #endif
  
  #ifdef CONFIG_ZONE_DMA32
  #define TEXT_FOR_DMA32(xx) xx "_dma32",
  #else
  #define TEXT_FOR_DMA32(xx)
  #endif
  
  #ifdef CONFIG_HIGHMEM
  #define TEXT_FOR_HIGHMEM(xx) xx "_high",
  #else
  #define TEXT_FOR_HIGHMEM(xx)
  #endif
  
  #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
  					TEXT_FOR_HIGHMEM(xx) xx "_movable",
  
  const char * const vmstat_text[] = {
8d92890bd   NeilBrown   mm/writeback: dis...
1099
  	/* enum zone_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1100
  	"nr_free_pages",
71c799f49   Minchan Kim   mm: add per-zone ...
1101
1102
1103
1104
1105
  	"nr_zone_inactive_anon",
  	"nr_zone_active_anon",
  	"nr_zone_inactive_file",
  	"nr_zone_active_file",
  	"nr_zone_unevictable",
5a1c84b40   Mel Gorman   mm: remove reclai...
1106
  	"nr_zone_write_pending",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1107
  	"nr_mlock",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1108
  	"nr_page_table_pages",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1109
  	"nr_bounce",
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1110
  	"nr_zspages",
3a321d2a3   Kemi Wang   mm: change the ca...
1111
1112
1113
  	"nr_free_cma",
  
  	/* enum numa_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1114
1115
1116
1117
1118
1119
1120
1121
  #ifdef CONFIG_NUMA
  	"numa_hit",
  	"numa_miss",
  	"numa_foreign",
  	"numa_interleave",
  	"numa_local",
  	"numa_other",
  #endif
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1122

9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1123
  	/* enum node_stat_item counters */
599d0c954   Mel Gorman   mm, vmscan: move ...
1124
1125
1126
1127
1128
  	"nr_inactive_anon",
  	"nr_active_anon",
  	"nr_inactive_file",
  	"nr_active_file",
  	"nr_unevictable",
385386cff   Johannes Weiner   mm: vmstat: move ...
1129
1130
  	"nr_slab_reclaimable",
  	"nr_slab_unreclaimable",
599d0c954   Mel Gorman   mm, vmscan: move ...
1131
1132
  	"nr_isolated_anon",
  	"nr_isolated_file",
68d48e6a2   Johannes Weiner   mm: workingset: a...
1133
  	"workingset_nodes",
170b04b7a   Joonsoo Kim   mm/workingset: pr...
1134
1135
1136
1137
1138
1139
  	"workingset_refault_anon",
  	"workingset_refault_file",
  	"workingset_activate_anon",
  	"workingset_activate_file",
  	"workingset_restore_anon",
  	"workingset_restore_file",
1e6b10857   Mel Gorman   mm, workingset: m...
1140
  	"workingset_nodereclaim",
50658e2e0   Mel Gorman   mm: move page map...
1141
1142
  	"nr_anon_pages",
  	"nr_mapped",
11fb99898   Mel Gorman   mm: move most fil...
1143
1144
1145
1146
1147
1148
1149
  	"nr_file_pages",
  	"nr_dirty",
  	"nr_writeback",
  	"nr_writeback_temp",
  	"nr_shmem",
  	"nr_shmem_hugepages",
  	"nr_shmem_pmdmapped",
60fbf0ab5   Song Liu   mm,thp: stats for...
1150
1151
  	"nr_file_hugepages",
  	"nr_file_pmdmapped",
11fb99898   Mel Gorman   mm: move most fil...
1152
  	"nr_anon_transparent_hugepages",
c4a25635b   Mel Gorman   mm: move vmscan w...
1153
1154
1155
1156
  	"nr_vmscan_write",
  	"nr_vmscan_immediate_reclaim",
  	"nr_dirtied",
  	"nr_written",
b29940c1a   Vlastimil Babka   mm: rename and ch...
1157
  	"nr_kernel_misc_reclaimable",
1970dc6f5   John Hubbard   mm/gup: /proc/vms...
1158
1159
  	"nr_foll_pin_acquired",
  	"nr_foll_pin_released",
991e76738   Shakeel Butt   mm: memcontrol: a...
1160
1161
1162
1163
  	"nr_kernel_stack",
  #if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
  	"nr_shadow_call_stack",
  #endif
599d0c954   Mel Gorman   mm, vmscan: move ...
1164

09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1165
  	/* enum writeback_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1166
1167
  	"nr_dirty_threshold",
  	"nr_dirty_background_threshold",
ebc5d83d0   Konstantin Khlebnikov   mm/memcontrol: us...
1168
  #if defined(CONFIG_VM_EVENT_COUNTERS) || defined(CONFIG_MEMCG)
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1169
  	/* enum vm_event_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1170
1171
1172
1173
1174
1175
  	"pgpgin",
  	"pgpgout",
  	"pswpin",
  	"pswpout",
  
  	TEXTS_FOR_ZONES("pgalloc")
7cc30fcfd   Mel Gorman   mm: vmstat: accou...
1176
1177
  	TEXTS_FOR_ZONES("allocstall")
  	TEXTS_FOR_ZONES("pgskip")
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1178
1179
1180
1181
  
  	"pgfree",
  	"pgactivate",
  	"pgdeactivate",
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
1182
  	"pglazyfree",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1183
1184
1185
  
  	"pgfault",
  	"pgmajfault",
854e9ed09   Minchan Kim   mm: support madvi...
1186
  	"pglazyfreed",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1187

599d0c954   Mel Gorman   mm, vmscan: move ...
1188
  	"pgrefill",
798a6b87e   Peter Xu   mm: Add PGREUSE c...
1189
  	"pgreuse",
599d0c954   Mel Gorman   mm, vmscan: move ...
1190
1191
1192
1193
  	"pgsteal_kswapd",
  	"pgsteal_direct",
  	"pgscan_kswapd",
  	"pgscan_direct",
68243e76e   Mel Gorman   mm: account for t...
1194
  	"pgscan_direct_throttle",
497a6c1b0   Johannes Weiner   mm: keep separate...
1195
1196
1197
1198
  	"pgscan_anon",
  	"pgscan_file",
  	"pgsteal_anon",
  	"pgsteal_file",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1199
1200
1201
1202
1203
1204
  
  #ifdef CONFIG_NUMA
  	"zone_reclaim_failed",
  #endif
  	"pginodesteal",
  	"slabs_scanned",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1205
1206
1207
  	"kswapd_inodesteal",
  	"kswapd_low_wmark_hit_quickly",
  	"kswapd_high_wmark_hit_quickly",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1208
  	"pageoutrun",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1209
1210
  
  	"pgrotated",
5509a5d27   Dave Hansen   drop_caches: add ...
1211
1212
  	"drop_pagecache",
  	"drop_slab",
8e675f7af   Konstantin Khlebnikov   mm/oom_kill: coun...
1213
  	"oom_kill",
5509a5d27   Dave Hansen   drop_caches: add ...
1214

03c5a6e16   Mel Gorman   mm: numa: Add pte...
1215
1216
  #ifdef CONFIG_NUMA_BALANCING
  	"numa_pte_updates",
72403b4a0   Mel Gorman   mm: numa: return ...
1217
  	"numa_huge_pte_updates",
03c5a6e16   Mel Gorman   mm: numa: Add pte...
1218
1219
1220
1221
  	"numa_hint_faults",
  	"numa_hint_faults_local",
  	"numa_pages_migrated",
  #endif
5647bc293   Mel Gorman   mm: compaction: M...
1222
1223
1224
  #ifdef CONFIG_MIGRATION
  	"pgmigrate_success",
  	"pgmigrate_fail",
1a5bae25e   Anshuman Khandual   mm/vmstat: add ev...
1225
1226
1227
  	"thp_migration_success",
  	"thp_migration_fail",
  	"thp_migration_split",
5647bc293   Mel Gorman   mm: compaction: M...
1228
  #endif
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1229
  #ifdef CONFIG_COMPACTION
397487db6   Mel Gorman   mm: compaction: A...
1230
1231
1232
  	"compact_migrate_scanned",
  	"compact_free_scanned",
  	"compact_isolated",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1233
1234
1235
  	"compact_stall",
  	"compact_fail",
  	"compact_success",
698b1b306   Vlastimil Babka   mm, compaction: i...
1236
  	"compact_daemon_wake",
7f354a548   David Rientjes   mm, compaction: a...
1237
1238
  	"compact_daemon_migrate_scanned",
  	"compact_daemon_free_scanned",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
  #endif
  
  #ifdef CONFIG_HUGETLB_PAGE
  	"htlb_buddy_alloc_success",
  	"htlb_buddy_alloc_fail",
  #endif
  	"unevictable_pgs_culled",
  	"unevictable_pgs_scanned",
  	"unevictable_pgs_rescued",
  	"unevictable_pgs_mlocked",
  	"unevictable_pgs_munlocked",
  	"unevictable_pgs_cleared",
  	"unevictable_pgs_stranded",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1252
1253
1254
1255
  
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  	"thp_fault_alloc",
  	"thp_fault_fallback",
85b9f46e8   David Rientjes   mm, thp: track fa...
1256
  	"thp_fault_fallback_charge",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1257
1258
  	"thp_collapse_alloc",
  	"thp_collapse_alloc_failed",
95ecedcd6   Kirill A. Shutemov   thp, vmstats: add...
1259
  	"thp_file_alloc",
dcdf11ee1   David Rientjes   mm, shmem: add vm...
1260
  	"thp_file_fallback",
85b9f46e8   David Rientjes   mm, thp: track fa...
1261
  	"thp_file_fallback_charge",
95ecedcd6   Kirill A. Shutemov   thp, vmstats: add...
1262
  	"thp_file_mapped",
122afea96   Kirill A. Shutemov   mm, vmstats: new ...
1263
1264
  	"thp_split_page",
  	"thp_split_page_failed",
f9719a03d   Kirill A. Shutemov   thp, vmstats: cou...
1265
  	"thp_deferred_split_page",
122afea96   Kirill A. Shutemov   mm, vmstats: new ...
1266
  	"thp_split_pmd",
ce9311cf9   Yisheng Xie   mm/vmstats: add t...
1267
1268
1269
  #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
  	"thp_split_pud",
  #endif
d8a8e1f0d   Kirill A. Shutemov   thp, vmstat: impl...
1270
1271
  	"thp_zero_page_alloc",
  	"thp_zero_page_alloc_failed",
225311a46   Huang Ying   mm: test code to ...
1272
  	"thp_swpout",
fe490cc0f   Huang Ying   mm, THP, swap: ad...
1273
  	"thp_swpout_fallback",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1274
  #endif
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1275
1276
1277
1278
1279
1280
1281
  #ifdef CONFIG_MEMORY_BALLOON
  	"balloon_inflate",
  	"balloon_deflate",
  #ifdef CONFIG_BALLOON_COMPACTION
  	"balloon_migrate",
  #endif
  #endif /* CONFIG_MEMORY_BALLOON */
ec6599344   Mel Gorman   mm, x86: Account ...
1282
  #ifdef CONFIG_DEBUG_TLBFLUSH
9824cf975   Dave Hansen   mm: vmstats: tlb ...
1283
1284
1285
1286
  	"nr_tlb_remote_flush",
  	"nr_tlb_remote_flush_received",
  	"nr_tlb_local_flush_all",
  	"nr_tlb_local_flush_one",
ec6599344   Mel Gorman   mm, x86: Account ...
1287
  #endif /* CONFIG_DEBUG_TLBFLUSH */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1288

4f115147f   Davidlohr Bueso   mm,vmacache: add ...
1289
1290
1291
1292
  #ifdef CONFIG_DEBUG_VM_VMACACHE
  	"vmacache_find_calls",
  	"vmacache_find_hits",
  #endif
cbc65df24   Huang Ying   mm, swap: add swa...
1293
1294
1295
1296
  #ifdef CONFIG_SWAP
  	"swap_ra",
  	"swap_ra_hit",
  #endif
ebc5d83d0   Konstantin Khlebnikov   mm/memcontrol: us...
1297
  #endif /* CONFIG_VM_EVENT_COUNTERS || CONFIG_MEMCG */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1298
  };
ebc5d83d0   Konstantin Khlebnikov   mm/memcontrol: us...
1299
  #endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA || CONFIG_MEMCG */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1300

3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
  #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \
       defined(CONFIG_PROC_FS)
  static void *frag_start(struct seq_file *m, loff_t *pos)
  {
  	pg_data_t *pgdat;
  	loff_t node = *pos;
  
  	for (pgdat = first_online_pgdat();
  	     pgdat && node;
  	     pgdat = next_online_pgdat(pgdat))
  		--node;
  
  	return pgdat;
  }
  
  static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
  
  	(*pos)++;
  	return next_online_pgdat(pgdat);
  }
  
  static void frag_stop(struct seq_file *m, void *arg)
  {
  }
b2bd85981   David Rientjes   mm, vmstat: print...
1327
1328
1329
1330
  /*
   * Walk zones in a node and print using a callback.
   * If @assert_populated is true, only use callback for zones that are populated.
   */
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1331
  static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
727c080f0   Vinayak Menon   mm: avoid taking ...
1332
  		bool assert_populated, bool nolock,
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1333
1334
1335
1336
1337
1338
1339
  		void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
  {
  	struct zone *zone;
  	struct zone *node_zones = pgdat->node_zones;
  	unsigned long flags;
  
  	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
b2bd85981   David Rientjes   mm, vmstat: print...
1340
  		if (assert_populated && !populated_zone(zone))
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1341
  			continue;
727c080f0   Vinayak Menon   mm: avoid taking ...
1342
1343
  		if (!nolock)
  			spin_lock_irqsave(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1344
  		print(m, pgdat, zone);
727c080f0   Vinayak Menon   mm: avoid taking ...
1345
1346
  		if (!nolock)
  			spin_unlock_irqrestore(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1347
1348
1349
  	}
  }
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
1350
  #ifdef CONFIG_PROC_FS
467c996c1   Mel Gorman   Print out statist...
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
  						struct zone *zone)
  {
  	int order;
  
  	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
  	for (order = 0; order < MAX_ORDER; ++order)
  		seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
  	seq_putc(m, '
  ');
  }
  
  /*
   * This walks the free areas for each zone.
   */
  static int frag_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
727c080f0   Vinayak Menon   mm: avoid taking ...
1369
  	walk_zones_in_node(m, pgdat, true, false, frag_show_print);
467c996c1   Mel Gorman   Print out statist...
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  	return 0;
  }
  
  static void pagetypeinfo_showfree_print(struct seq_file *m,
  					pg_data_t *pgdat, struct zone *zone)
  {
  	int order, mtype;
  
  	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
  		seq_printf(m, "Node %4d, zone %8s, type %12s ",
  					pgdat->node_id,
  					zone->name,
  					migratetype_names[mtype]);
  		for (order = 0; order < MAX_ORDER; ++order) {
  			unsigned long freecount = 0;
  			struct free_area *area;
  			struct list_head *curr;
93b3a6744   Michal Hocko   mm, vmstat: reduc...
1387
  			bool overflow = false;
467c996c1   Mel Gorman   Print out statist...
1388
1389
  
  			area = &(zone->free_area[order]);
93b3a6744   Michal Hocko   mm, vmstat: reduc...
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
  			list_for_each(curr, &area->free_list[mtype]) {
  				/*
  				 * Cap the free_list iteration because it might
  				 * be really large and we are under a spinlock
  				 * so a long time spent here could trigger a
  				 * hard lockup detector. Anyway this is a
  				 * debugging tool so knowing there is a handful
  				 * of pages of this order should be more than
  				 * sufficient.
  				 */
  				if (++freecount >= 100000) {
  					overflow = true;
  					break;
  				}
  			}
  			seq_printf(m, "%s%6lu ", overflow ? ">" : "", freecount);
  			spin_unlock_irq(&zone->lock);
  			cond_resched();
  			spin_lock_irq(&zone->lock);
467c996c1   Mel Gorman   Print out statist...
1409
  		}
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1410
1411
1412
  		seq_putc(m, '
  ');
  	}
467c996c1   Mel Gorman   Print out statist...
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  }
  
  /* Print out the free pages at each order for each migatetype */
  static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
  {
  	int order;
  	pg_data_t *pgdat = (pg_data_t *)arg;
  
  	/* Print header */
  	seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
  	for (order = 0; order < MAX_ORDER; ++order)
  		seq_printf(m, "%6d ", order);
  	seq_putc(m, '
  ');
727c080f0   Vinayak Menon   mm: avoid taking ...
1427
  	walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
467c996c1   Mel Gorman   Print out statist...
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
  
  	return 0;
  }
  
  static void pagetypeinfo_showblockcount_print(struct seq_file *m,
  					pg_data_t *pgdat, struct zone *zone)
  {
  	int mtype;
  	unsigned long pfn;
  	unsigned long start_pfn = zone->zone_start_pfn;
108bcc96e   Cody P Schafer   mm: add & use zon...
1438
  	unsigned long end_pfn = zone_end_pfn(zone);
467c996c1   Mel Gorman   Print out statist...
1439
1440
1441
1442
  	unsigned long count[MIGRATE_TYPES] = { 0, };
  
  	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
  		struct page *page;
d336e94e4   Michal Hocko   mm, vmstat: skip ...
1443
1444
  		page = pfn_to_online_page(pfn);
  		if (!page)
467c996c1   Mel Gorman   Print out statist...
1445
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1446
1447
  		/* Watch for unexpected holes punched in the memmap */
  		if (!memmap_valid_within(pfn, page, zone))
e80d6a248   Mel Gorman   [ARM] Skip memory...
1448
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1449

a91c43c73   Joonsoo Kim   mm/vmstat: add zo...
1450
1451
  		if (page_zone(page) != zone)
  			continue;
467c996c1   Mel Gorman   Print out statist...
1452
  		mtype = get_pageblock_migratetype(page);
e80d6a248   Mel Gorman   [ARM] Skip memory...
1453
1454
  		if (mtype < MIGRATE_TYPES)
  			count[mtype]++;
467c996c1   Mel Gorman   Print out statist...
1455
1456
1457
1458
1459
1460
1461
1462
1463
  	}
  
  	/* Print counts */
  	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
  	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
  		seq_printf(m, "%12lu ", count[mtype]);
  	seq_putc(m, '
  ');
  }
f113e6412   SeongJae Park   mm/vmstat.c: fix ...
1464
  /* Print out the number of pageblocks for each migratetype */
467c996c1   Mel Gorman   Print out statist...
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
  {
  	int mtype;
  	pg_data_t *pgdat = (pg_data_t *)arg;
  
  	seq_printf(m, "
  %-23s", "Number of blocks type ");
  	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
  		seq_printf(m, "%12s ", migratetype_names[mtype]);
  	seq_putc(m, '
  ');
727c080f0   Vinayak Menon   mm: avoid taking ...
1476
1477
  	walk_zones_in_node(m, pgdat, true, false,
  		pagetypeinfo_showblockcount_print);
467c996c1   Mel Gorman   Print out statist...
1478
1479
1480
  
  	return 0;
  }
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
  /*
   * Print out the number of pageblocks for each migratetype that contain pages
   * of other types. This gives an indication of how well fallbacks are being
   * contained by rmqueue_fallback(). It requires information from PAGE_OWNER
   * to determine what is going on
   */
  static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
  {
  #ifdef CONFIG_PAGE_OWNER
  	int mtype;
7dd80b8af   Vlastimil Babka   mm, page_owner: c...
1491
  	if (!static_branch_unlikely(&page_owner_inited))
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
  		return;
  
  	drain_all_pages(NULL);
  
  	seq_printf(m, "
  %-23s", "Number of mixed blocks ");
  	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
  		seq_printf(m, "%12s ", migratetype_names[mtype]);
  	seq_putc(m, '
  ');
727c080f0   Vinayak Menon   mm: avoid taking ...
1502
1503
  	walk_zones_in_node(m, pgdat, true, true,
  		pagetypeinfo_showmixedcount_print);
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1504
1505
  #endif /* CONFIG_PAGE_OWNER */
  }
467c996c1   Mel Gorman   Print out statist...
1506
1507
1508
1509
1510
1511
1512
  /*
   * This prints out statistics in relation to grouping pages by mobility.
   * It is expensive to collect so do not constantly read the file.
   */
  static int pagetypeinfo_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
41b25a378   KOSAKI Motohiro   /proc/pagetypeinf...
1513
  	/* check memoryless node */
a47b53c5f   Lai Jiangshan   vmstat: use N_MEM...
1514
  	if (!node_state(pgdat->node_id, N_MEMORY))
41b25a378   KOSAKI Motohiro   /proc/pagetypeinf...
1515
  		return 0;
467c996c1   Mel Gorman   Print out statist...
1516
1517
1518
1519
1520
1521
1522
1523
  	seq_printf(m, "Page block order: %d
  ", pageblock_order);
  	seq_printf(m, "Pages per block:  %lu
  ", pageblock_nr_pages);
  	seq_putc(m, '
  ');
  	pagetypeinfo_showfree(m, pgdat);
  	pagetypeinfo_showblockcount(m, pgdat);
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1524
  	pagetypeinfo_showmixedcount(m, pgdat);
467c996c1   Mel Gorman   Print out statist...
1525

f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1526
1527
  	return 0;
  }
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1528
  static const struct seq_operations fragmentation_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1529
1530
1531
1532
1533
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= frag_show,
  };
74e2e8e8c   Alexey Dobriyan   proc: move /proc/...
1534
  static const struct seq_operations pagetypeinfo_op = {
467c996c1   Mel Gorman   Print out statist...
1535
1536
1537
1538
1539
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= pagetypeinfo_show,
  };
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
  static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone)
  {
  	int zid;
  
  	for (zid = 0; zid < MAX_NR_ZONES; zid++) {
  		struct zone *compare = &pgdat->node_zones[zid];
  
  		if (populated_zone(compare))
  			return zone == compare;
  	}
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1550
1551
  	return false;
  }
467c996c1   Mel Gorman   Print out statist...
1552
1553
  static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
  							struct zone *zone)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1554
  {
467c996c1   Mel Gorman   Print out statist...
1555
1556
  	int i;
  	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1557
1558
1559
1560
  	if (is_zone_first_populated(pgdat, zone)) {
  		seq_printf(m, "
    per-node stats");
  		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1561
1562
  			seq_printf(m, "
        %-12s %lu", node_stat_name(i),
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
1563
  				   node_page_state_pages(pgdat, i));
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1564
1565
  		}
  	}
467c996c1   Mel Gorman   Print out statist...
1566
1567
1568
1569
1570
1571
1572
1573
1574
  	seq_printf(m,
  		   "
    pages free     %lu"
  		   "
          min      %lu"
  		   "
          low      %lu"
  		   "
          high     %lu"
467c996c1   Mel Gorman   Print out statist...
1575
1576
  		   "
          spanned  %lu"
9feedc9d8   Jiang Liu   mm: introduce new...
1577
1578
1579
1580
  		   "
          present  %lu"
  		   "
          managed  %lu",
88f5acf88   Mel Gorman   mm: page allocato...
1581
  		   zone_page_state(zone, NR_FREE_PAGES),
418589663   Mel Gorman   page allocator: u...
1582
1583
1584
  		   min_wmark_pages(zone),
  		   low_wmark_pages(zone),
  		   high_wmark_pages(zone),
467c996c1   Mel Gorman   Print out statist...
1585
  		   zone->spanned_pages,
9feedc9d8   Jiang Liu   mm: introduce new...
1586
  		   zone->present_pages,
9705bea5f   Arun KS   mm: convert zone-...
1587
  		   zone_managed_pages(zone));
467c996c1   Mel Gorman   Print out statist...
1588

467c996c1   Mel Gorman   Print out statist...
1589
  	seq_printf(m,
3484b2de9   Mel Gorman   mm: rearrange zon...
1590
1591
  		   "
          protection: (%ld",
467c996c1   Mel Gorman   Print out statist...
1592
1593
  		   zone->lowmem_reserve[0]);
  	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
3484b2de9   Mel Gorman   mm: rearrange zon...
1594
  		seq_printf(m, ", %ld", zone->lowmem_reserve[i]);
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1595
  	seq_putc(m, ')');
a8a4b7aea   Baoquan He   Revert "mm/vmstat...
1596
1597
1598
1599
1600
1601
  	/* If unpopulated, no other information is useful */
  	if (!populated_zone(zone)) {
  		seq_putc(m, '
  ');
  		return;
  	}
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1602
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1603
1604
1605
  		seq_printf(m, "
        %-12s %lu", zone_stat_name(i),
  			   zone_page_state(zone, i));
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1606

3a321d2a3   Kemi Wang   mm: change the ca...
1607
1608
  #ifdef CONFIG_NUMA
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1609
1610
1611
  		seq_printf(m, "
        %-12s %lu", numa_stat_name(i),
  			   zone_numa_state_snapshot(zone, i));
3a321d2a3   Kemi Wang   mm: change the ca...
1612
  #endif
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1613
1614
  	seq_printf(m, "
    pagesets");
467c996c1   Mel Gorman   Print out statist...
1615
1616
  	for_each_online_cpu(i) {
  		struct per_cpu_pageset *pageset;
467c996c1   Mel Gorman   Print out statist...
1617

99dcc3e5a   Christoph Lameter   this_cpu: Page al...
1618
  		pageset = per_cpu_ptr(zone->pageset, i);
3dfa5721f   Christoph Lameter   Page allocator: g...
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
  		seq_printf(m,
  			   "
      cpu: %i"
  			   "
                count: %i"
  			   "
                high:  %i"
  			   "
                batch: %i",
  			   i,
  			   pageset->pcp.count,
  			   pageset->pcp.high,
  			   pageset->pcp.batch);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1632
  #ifdef CONFIG_SMP
467c996c1   Mel Gorman   Print out statist...
1633
1634
1635
  		seq_printf(m, "
    vm stats threshold: %d",
  				pageset->stat_threshold);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1636
  #endif
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1637
  	}
467c996c1   Mel Gorman   Print out statist...
1638
  	seq_printf(m,
599d0c954   Mel Gorman   mm, vmscan: move ...
1639
1640
  		   "
    node_unreclaimable:  %u"
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1641
1642
  		   "
    start_pfn:           %lu",
c73322d09   Johannes Weiner   mm: fix 100% CPU ...
1643
  		   pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1644
  		   zone->zone_start_pfn);
467c996c1   Mel Gorman   Print out statist...
1645
1646
1647
1648
1649
  	seq_putc(m, '
  ');
  }
  
  /*
b2bd85981   David Rientjes   mm, vmstat: print...
1650
1651
1652
1653
   * Output information about zones in @pgdat.  All zones are printed regardless
   * of whether they are populated or not: lowmem_reserve_ratio operates on the
   * set of all zones and userspace would not be aware of such zones if they are
   * suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio).
467c996c1   Mel Gorman   Print out statist...
1654
1655
1656
1657
   */
  static int zoneinfo_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
727c080f0   Vinayak Menon   mm: avoid taking ...
1658
  	walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1659
1660
  	return 0;
  }
5c9fe6281   Alexey Dobriyan   proc: move /proc/...
1661
  static const struct seq_operations zoneinfo_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1662
1663
1664
1665
1666
1667
  	.start	= frag_start, /* iterate over all zones. The same as in
  			       * fragmentation. */
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= zoneinfo_show,
  };
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1668
1669
1670
1671
1672
1673
  #define NR_VMSTAT_ITEMS (NR_VM_ZONE_STAT_ITEMS + \
  			 NR_VM_NUMA_STAT_ITEMS + \
  			 NR_VM_NODE_STAT_ITEMS + \
  			 NR_VM_WRITEBACK_STAT_ITEMS + \
  			 (IS_ENABLED(CONFIG_VM_EVENT_COUNTERS) ? \
  			  NR_VM_EVENT_ITEMS : 0))
79da826ae   Michael Rubin   writeback: report...
1674

f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1675
1676
  static void *vmstat_start(struct seq_file *m, loff_t *pos)
  {
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1677
  	unsigned long *v;
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1678
  	int i;
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1679

9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1680
  	if (*pos >= NR_VMSTAT_ITEMS)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1681
  		return NULL;
79da826ae   Michael Rubin   writeback: report...
1682

9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1683
1684
  	BUILD_BUG_ON(ARRAY_SIZE(vmstat_text) < NR_VMSTAT_ITEMS);
  	v = kmalloc_array(NR_VMSTAT_ITEMS, sizeof(unsigned long), GFP_KERNEL);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1685
1686
  	m->private = v;
  	if (!v)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1687
  		return ERR_PTR(-ENOMEM);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1688
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
c41f012ad   Michal Hocko   mm: rename global...
1689
  		v[i] = global_zone_page_state(i);
79da826ae   Michael Rubin   writeback: report...
1690
  	v += NR_VM_ZONE_STAT_ITEMS;
3a321d2a3   Kemi Wang   mm: change the ca...
1691
1692
1693
1694
1695
  #ifdef CONFIG_NUMA
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
  		v[i] = global_numa_state(i);
  	v += NR_VM_NUMA_STAT_ITEMS;
  #endif
75ef71840   Mel Gorman   mm, vmstat: add i...
1696
  	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
1697
  		v[i] = global_node_page_state_pages(i);
75ef71840   Mel Gorman   mm, vmstat: add i...
1698
  	v += NR_VM_NODE_STAT_ITEMS;
79da826ae   Michael Rubin   writeback: report...
1699
1700
1701
  	global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
  			    v + NR_DIRTY_THRESHOLD);
  	v += NR_VM_WRITEBACK_STAT_ITEMS;
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1702
  #ifdef CONFIG_VM_EVENT_COUNTERS
79da826ae   Michael Rubin   writeback: report...
1703
1704
1705
  	all_vm_events(v);
  	v[PGPGIN] /= 2;		/* sectors -> kbytes */
  	v[PGPGOUT] /= 2;
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1706
  #endif
ff8b16d7e   Wu Fengguang   vmstat: fix offse...
1707
  	return (unsigned long *)m->private + *pos;
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1708
1709
1710
1711
1712
  }
  
  static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
  {
  	(*pos)++;
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1713
  	if (*pos >= NR_VMSTAT_ITEMS)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1714
1715
1716
1717
1718
1719
1720
1721
  		return NULL;
  	return (unsigned long *)m->private + *pos;
  }
  
  static int vmstat_show(struct seq_file *m, void *arg)
  {
  	unsigned long *l = arg;
  	unsigned long off = l - (unsigned long *)m->private;
68ba0326b   Alexey Dobriyan   proc: much faster...
1722
1723
  
  	seq_puts(m, vmstat_text[off]);
75ba1d07f   Joe Perches   seq/proc: modify ...
1724
  	seq_put_decimal_ull(m, " ", *l);
68ba0326b   Alexey Dobriyan   proc: much faster...
1725
1726
  	seq_putc(m, '
  ');
8d92890bd   NeilBrown   mm/writeback: dis...
1727
1728
1729
1730
1731
1732
1733
1734
1735
  
  	if (off == NR_VMSTAT_ITEMS - 1) {
  		/*
  		 * We've come to the end - add any deprecated counters to avoid
  		 * breaking userspace which might depend on them being present.
  		 */
  		seq_puts(m, "nr_unstable 0
  ");
  	}
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1736
1737
1738
1739
1740
1741
1742
1743
  	return 0;
  }
  
  static void vmstat_stop(struct seq_file *m, void *arg)
  {
  	kfree(m->private);
  	m->private = NULL;
  }
b6aa44ab6   Alexey Dobriyan   proc: move /proc/...
1744
  static const struct seq_operations vmstat_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1745
1746
1747
1748
1749
  	.start	= vmstat_start,
  	.next	= vmstat_next,
  	.stop	= vmstat_stop,
  	.show	= vmstat_show,
  };
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1750
  #endif /* CONFIG_PROC_FS */
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1751
  #ifdef CONFIG_SMP
d1187ed21   Christoph Lameter   vmstat: use our o...
1752
  static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
77461ab33   Christoph Lameter   Make vm statistic...
1753
  int sysctl_stat_interval __read_mostly = HZ;
d1187ed21   Christoph Lameter   vmstat: use our o...
1754

52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1755
1756
1757
1758
1759
1760
1761
  #ifdef CONFIG_PROC_FS
  static void refresh_vm_stats(struct work_struct *work)
  {
  	refresh_cpu_vm_stats(true);
  }
  
  int vmstat_refresh(struct ctl_table *table, int write,
32927393d   Christoph Hellwig   sysctl: pass kern...
1762
  		   void *buffer, size_t *lenp, loff_t *ppos)
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  {
  	long val;
  	int err;
  	int i;
  
  	/*
  	 * The regular update, every sysctl_stat_interval, may come later
  	 * than expected: leaving a significant amount in per_cpu buckets.
  	 * This is particularly misleading when checking a quantity of HUGE
  	 * pages, immediately after running a test.  /proc/sys/vm/stat_refresh,
  	 * which can equally be echo'ed to or cat'ted from (by root),
  	 * can be used to update the stats just before reading them.
  	 *
c41f012ad   Michal Hocko   mm: rename global...
1776
  	 * Oh, and since global_zone_page_state() etc. are so careful to hide
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1777
1778
1779
1780
1781
1782
1783
  	 * transiently negative values, report an error here if any of
  	 * the stats is negative, so we know to go looking for imbalance.
  	 */
  	err = schedule_on_each_cpu(refresh_vm_stats);
  	if (err)
  		return err;
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
75ef71840   Mel Gorman   mm, vmstat: add i...
1784
  		val = atomic_long_read(&vm_zone_stat[i]);
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1785
  		if (val < 0) {
c822f6223   Johannes Weiner   mm: delete NR_PAG...
1786
1787
  			pr_warn("%s: %s %ld
  ",
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1788
  				__func__, zone_stat_name(i), val);
c822f6223   Johannes Weiner   mm: delete NR_PAG...
1789
  			err = -EINVAL;
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1790
1791
  		}
  	}
3a321d2a3   Kemi Wang   mm: change the ca...
1792
1793
1794
1795
1796
1797
  #ifdef CONFIG_NUMA
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
  		val = atomic_long_read(&vm_numa_stat[i]);
  		if (val < 0) {
  			pr_warn("%s: %s %ld
  ",
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1798
  				__func__, numa_stat_name(i), val);
3a321d2a3   Kemi Wang   mm: change the ca...
1799
1800
1801
1802
  			err = -EINVAL;
  		}
  	}
  #endif
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1803
1804
1805
1806
1807
1808
1809
1810
1811
  	if (err)
  		return err;
  	if (write)
  		*ppos += *lenp;
  	else
  		*lenp = 0;
  	return 0;
  }
  #endif /* CONFIG_PROC_FS */
d1187ed21   Christoph Lameter   vmstat: use our o...
1812
1813
  static void vmstat_update(struct work_struct *w)
  {
0eb77e988   Christoph Lameter   vmstat: make vmst...
1814
  	if (refresh_cpu_vm_stats(true)) {
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1815
1816
1817
1818
1819
  		/*
  		 * Counters were updated so we expect more updates
  		 * to occur in the future. Keep on running the
  		 * update worker thread.
  		 */
ce612879d   Michal Hocko   mm: move pcp and ...
1820
  		queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
f01f17d37   Michal Hocko   mm, vmstat: make ...
1821
1822
  				this_cpu_ptr(&vmstat_work),
  				round_jiffies_relative(sysctl_stat_interval));
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1823
1824
1825
1826
  	}
  }
  
  /*
0eb77e988   Christoph Lameter   vmstat: make vmst...
1827
1828
1829
1830
   * Switch off vmstat processing and then fold all the remaining differentials
   * until the diffs stay at zero. The function is used by NOHZ and can only be
   * invoked when tick processing is not active.
   */
0eb77e988   Christoph Lameter   vmstat: make vmst...
1831
  /*
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
   * Check if the diffs for a certain cpu indicate that
   * an update is needed.
   */
  static bool need_update(int cpu)
  {
  	struct zone *zone;
  
  	for_each_populated_zone(zone) {
  		struct per_cpu_pageset *p = per_cpu_ptr(zone->pageset, cpu);
  
  		BUILD_BUG_ON(sizeof(p->vm_stat_diff[0]) != 1);
3a321d2a3   Kemi Wang   mm: change the ca...
1843
  #ifdef CONFIG_NUMA
1d90ca897   Kemi Wang   mm: update NUMA c...
1844
  		BUILD_BUG_ON(sizeof(p->vm_numa_stat_diff[0]) != 2);
3a321d2a3   Kemi Wang   mm: change the ca...
1845
  #endif
638032224   Kemi Wang   mm: consider the ...
1846

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1847
1848
  		/*
  		 * The fast way of checking if there are any vmstat diffs.
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1849
  		 */
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1850
1851
  		if (memchr_inv(p->vm_stat_diff, 0, NR_VM_ZONE_STAT_ITEMS *
  			       sizeof(p->vm_stat_diff[0])))
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1852
  			return true;
3a321d2a3   Kemi Wang   mm: change the ca...
1853
  #ifdef CONFIG_NUMA
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1854
1855
  		if (memchr_inv(p->vm_numa_stat_diff, 0, NR_VM_NUMA_STAT_ITEMS *
  			       sizeof(p->vm_numa_stat_diff[0])))
3a321d2a3   Kemi Wang   mm: change the ca...
1856
1857
  			return true;
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1858
1859
1860
  	}
  	return false;
  }
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1861
1862
1863
1864
1865
  /*
   * Switch off vmstat processing and then fold all the remaining differentials
   * until the diffs stay at zero. The function is used by NOHZ and can only be
   * invoked when tick processing is not active.
   */
f01f17d37   Michal Hocko   mm, vmstat: make ...
1866
1867
1868
1869
  void quiet_vmstat(void)
  {
  	if (system_state != SYSTEM_RUNNING)
  		return;
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1870
  	if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
f01f17d37   Michal Hocko   mm, vmstat: make ...
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
  		return;
  
  	if (!need_update(smp_processor_id()))
  		return;
  
  	/*
  	 * Just refresh counters and do not care about the pending delayed
  	 * vmstat_update. It doesn't fire that often to matter and canceling
  	 * it would be too expensive from this path.
  	 * vmstat_shepherd will take care about that for us.
  	 */
  	refresh_cpu_vm_stats(false);
  }
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1884
1885
1886
1887
1888
1889
1890
  /*
   * Shepherd worker thread that checks the
   * differentials of processors that have their worker
   * threads for vm statistics updates disabled because of
   * inactivity.
   */
  static void vmstat_shepherd(struct work_struct *w);
0eb77e988   Christoph Lameter   vmstat: make vmst...
1891
  static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1892
1893
1894
1895
1896
1897
1898
  
  static void vmstat_shepherd(struct work_struct *w)
  {
  	int cpu;
  
  	get_online_cpus();
  	/* Check processors whose vmstat worker threads have been disabled */
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1899
  	for_each_online_cpu(cpu) {
f01f17d37   Michal Hocko   mm, vmstat: make ...
1900
  		struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1901

7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1902
  		if (!delayed_work_pending(dw) && need_update(cpu))
ce612879d   Michal Hocko   mm: move pcp and ...
1903
  			queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
f01f17d37   Michal Hocko   mm, vmstat: make ...
1904
  	}
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1905
1906
1907
  	put_online_cpus();
  
  	schedule_delayed_work(&shepherd,
98f4ebb29   Anton Blanchard   mm: align vmstat_...
1908
  		round_jiffies_relative(sysctl_stat_interval));
d1187ed21   Christoph Lameter   vmstat: use our o...
1909
  }
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1910
  static void __init start_shepherd_timer(void)
d1187ed21   Christoph Lameter   vmstat: use our o...
1911
  {
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1912
1913
1914
  	int cpu;
  
  	for_each_possible_cpu(cpu)
ccde8bd40   Michal Hocko   vmstat: make vmst...
1915
  		INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1916
  			vmstat_update);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1917
1918
  	schedule_delayed_work(&shepherd,
  		round_jiffies_relative(sysctl_stat_interval));
d1187ed21   Christoph Lameter   vmstat: use our o...
1919
  }
03e86dba5   Tim Chen   cpu: fix node sta...
1920
1921
  static void __init init_cpu_node_state(void)
  {
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1922
  	int node;
03e86dba5   Tim Chen   cpu: fix node sta...
1923

4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1924
1925
1926
1927
  	for_each_online_node(node) {
  		if (cpumask_weight(cpumask_of_node(node)) > 0)
  			node_set_state(node, N_CPU);
  	}
03e86dba5   Tim Chen   cpu: fix node sta...
1928
  }
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
  static int vmstat_cpu_online(unsigned int cpu)
  {
  	refresh_zone_stat_thresholds();
  	node_set_state(cpu_to_node(cpu), N_CPU);
  	return 0;
  }
  
  static int vmstat_cpu_down_prep(unsigned int cpu)
  {
  	cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
  	return 0;
  }
  
  static int vmstat_cpu_dead(unsigned int cpu)
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1943
  {
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1944
  	const struct cpumask *node_cpus;
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1945
  	int node;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1946

5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1947
1948
1949
  	node = cpu_to_node(cpu);
  
  	refresh_zone_stat_thresholds();
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1950
1951
  	node_cpus = cpumask_of_node(node);
  	if (cpumask_weight(node_cpus) > 0)
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1952
  		return 0;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1953
1954
  
  	node_clear_state(node, N_CPU);
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1955
  	return 0;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1956
  }
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1957
  #endif
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1958

ce612879d   Michal Hocko   mm: move pcp and ...
1959
  struct workqueue_struct *mm_percpu_wq;
597b7305d   Michal Hocko   mm: move mm_percp...
1960
  void __init init_mm_internals(void)
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1961
  {
ce612879d   Michal Hocko   mm: move pcp and ...
1962
  	int ret __maybe_unused;
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1963

80d136e13   Michal Hocko   mm: make mm_percp...
1964
  	mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
ce612879d   Michal Hocko   mm: move pcp and ...
1965
1966
  
  #ifdef CONFIG_SMP
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
  	ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead",
  					NULL, vmstat_cpu_dead);
  	if (ret < 0)
  		pr_err("vmstat: failed to register 'dead' hotplug state
  ");
  
  	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmstat:online",
  					vmstat_cpu_online,
  					vmstat_cpu_down_prep);
  	if (ret < 0)
  		pr_err("vmstat: failed to register 'online' hotplug state
  ");
  
  	get_online_cpus();
03e86dba5   Tim Chen   cpu: fix node sta...
1981
  	init_cpu_node_state();
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1982
  	put_online_cpus();
d1187ed21   Christoph Lameter   vmstat: use our o...
1983

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1984
  	start_shepherd_timer();
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1985
1986
  #endif
  #ifdef CONFIG_PROC_FS
fddda2b7b   Christoph Hellwig   proc: introduce p...
1987
  	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
abaed0112   Michal Hocko   mm, vmstat: hide ...
1988
  	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
fddda2b7b   Christoph Hellwig   proc: introduce p...
1989
1990
  	proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
  	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1991
  #endif
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1992
  }
d7a5752c0   Mel Gorman   mm: export unusab...
1993
1994
  
  #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
d7a5752c0   Mel Gorman   mm: export unusab...
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
  
  /*
   * Return an index indicating how much of the available free memory is
   * unusable for an allocation of the requested size.
   */
  static int unusable_free_index(unsigned int order,
  				struct contig_page_info *info)
  {
  	/* No free memory is interpreted as all free memory is unusable */
  	if (info->free_pages == 0)
  		return 1000;
  
  	/*
  	 * Index should be a value between 0 and 1. Return a value to 3
  	 * decimal places.
  	 *
  	 * 0 => no fragmentation
  	 * 1 => high fragmentation
  	 */
  	return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages);
  
  }
  
  static void unusable_show_print(struct seq_file *m,
  					pg_data_t *pgdat, struct zone *zone)
  {
  	unsigned int order;
  	int index;
  	struct contig_page_info info;
  
  	seq_printf(m, "Node %d, zone %8s ",
  				pgdat->node_id,
  				zone->name);
  	for (order = 0; order < MAX_ORDER; ++order) {
  		fill_contig_page_info(zone, order, &info);
  		index = unusable_free_index(order, &info);
  		seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
  	}
  
  	seq_putc(m, '
  ');
  }
  
  /*
   * Display unusable free space index
   *
   * The unusable free space index measures how much of the available free
   * memory cannot be used to satisfy an allocation of a given size and is a
   * value between 0 and 1. The higher the value, the more of free memory is
   * unusable and by implication, the worse the external fragmentation is. This
   * can be expressed as a percentage by multiplying by 100.
   */
  static int unusable_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
  
  	/* check memoryless node */
a47b53c5f   Lai Jiangshan   vmstat: use N_MEM...
2052
  	if (!node_state(pgdat->node_id, N_MEMORY))
d7a5752c0   Mel Gorman   mm: export unusab...
2053
  		return 0;
727c080f0   Vinayak Menon   mm: avoid taking ...
2054
  	walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
d7a5752c0   Mel Gorman   mm: export unusab...
2055
2056
2057
  
  	return 0;
  }
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2058
  static const struct seq_operations unusable_sops = {
d7a5752c0   Mel Gorman   mm: export unusab...
2059
2060
2061
2062
2063
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= unusable_show,
  };
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2064
  DEFINE_SEQ_ATTRIBUTE(unusable);
d7a5752c0   Mel Gorman   mm: export unusab...
2065

f1a5ab121   Mel Gorman   mm: export fragme...
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
  static void extfrag_show_print(struct seq_file *m,
  					pg_data_t *pgdat, struct zone *zone)
  {
  	unsigned int order;
  	int index;
  
  	/* Alloc on stack as interrupts are disabled for zone walk */
  	struct contig_page_info info;
  
  	seq_printf(m, "Node %d, zone %8s ",
  				pgdat->node_id,
  				zone->name);
  	for (order = 0; order < MAX_ORDER; ++order) {
  		fill_contig_page_info(zone, order, &info);
56de7263f   Mel Gorman   mm: compaction: d...
2080
  		index = __fragmentation_index(order, &info);
f1a5ab121   Mel Gorman   mm: export fragme...
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
  		seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
  	}
  
  	seq_putc(m, '
  ');
  }
  
  /*
   * Display fragmentation index for orders that allocations would fail for
   */
  static int extfrag_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
727c080f0   Vinayak Menon   mm: avoid taking ...
2094
  	walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
f1a5ab121   Mel Gorman   mm: export fragme...
2095
2096
2097
  
  	return 0;
  }
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2098
  static const struct seq_operations extfrag_sops = {
f1a5ab121   Mel Gorman   mm: export fragme...
2099
2100
2101
2102
2103
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= extfrag_show,
  };
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2104
  DEFINE_SEQ_ATTRIBUTE(extfrag);
f1a5ab121   Mel Gorman   mm: export fragme...
2105

d7a5752c0   Mel Gorman   mm: export unusab...
2106
2107
  static int __init extfrag_debug_init(void)
  {
bde8bd8a1   Sasikantha babu   mm/vmstat.c: remo...
2108
  	struct dentry *extfrag_debug_root;
d7a5752c0   Mel Gorman   mm: export unusab...
2109
  	extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
d7a5752c0   Mel Gorman   mm: export unusab...
2110

d9f7979c9   Greg Kroah-Hartman   mm: no need to ch...
2111
  	debugfs_create_file("unusable_index", 0444, extfrag_debug_root, NULL,
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2112
  			    &unusable_fops);
d7a5752c0   Mel Gorman   mm: export unusab...
2113

d9f7979c9   Greg Kroah-Hartman   mm: no need to ch...
2114
  	debugfs_create_file("extfrag_index", 0444, extfrag_debug_root, NULL,
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2115
  			    &extfrag_fops);
f1a5ab121   Mel Gorman   mm: export fragme...
2116

d7a5752c0   Mel Gorman   mm: export unusab...
2117
2118
2119
2120
2121
  	return 0;
  }
  
  module_init(extfrag_debug_init);
  #endif