Blame view

mm/vmstat.c 53.1 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

12938a922   Christoph Lameter   vmstat: Optimize ...
312
  	if (unlikely(x > t || 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
333
334
335
336
337
338
339
340
  	x = delta + __this_cpu_read(*p);
  
  	t = __this_cpu_read(pcp->stat_threshold);
  
  	if (unlikely(x > t || x < -t)) {
  		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 ...
341
  /*
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
342
343
344
345
346
347
348
349
350
   * 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 ...
351
352
353
   * The increment or decrement is known and therefore one boundary check can
   * be omitted.
   *
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
354
355
356
   * NOTE: These functions are very performance sensitive. Change only
   * with care.
   *
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
357
358
359
360
361
362
363
   * 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...
364
  void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
365
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
366
367
368
  	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 ...
369

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

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

75ef71840   Mel Gorman   mm, vmstat: add i...
380
381
382
383
384
  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...
385
  	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
75ef71840   Mel Gorman   mm, vmstat: add i...
386
387
388
389
390
391
392
393
394
  	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...
395
396
397
398
  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 ...
399
  EXPORT_SYMBOL(__inc_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
400
401
402
403
404
  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...
405
  void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
406
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
407
408
409
  	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 ...
410

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

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

75ef71840   Mel Gorman   mm, vmstat: add i...
421
422
423
424
425
  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...
426
  	VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
75ef71840   Mel Gorman   mm, vmstat: add i...
427
428
429
430
431
432
433
434
435
  	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...
436
437
438
439
  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 ...
440
  EXPORT_SYMBOL(__dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
441
442
443
444
445
  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...
446
  #ifdef CONFIG_HAVE_CMPXCHG_LOCAL
7c8391206   Christoph Lameter   vmstat: User per ...
447
448
449
450
451
452
453
454
455
456
457
458
  /*
   * 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...
459
460
  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 ...
461
462
463
464
465
466
467
468
469
470
471
  {
  	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...
472
473
474
475
476
477
  		 * 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 ...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  		 */
  		t = this_cpu_read(pcp->stat_threshold);
  
  		o = this_cpu_read(*p);
  		n = delta + o;
  
  		if (n > t || n < -t) {
  			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...
498
  			 long delta)
7c8391206   Christoph Lameter   vmstat: User per ...
499
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
500
  	mod_zone_state(zone, item, delta, 0);
7c8391206   Christoph Lameter   vmstat: User per ...
501
502
  }
  EXPORT_SYMBOL(mod_zone_page_state);
7c8391206   Christoph Lameter   vmstat: User per ...
503
504
  void inc_zone_page_state(struct page *page, enum zone_stat_item item)
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
505
  	mod_zone_state(page_zone(page), item, 1, 1);
7c8391206   Christoph Lameter   vmstat: User per ...
506
507
508
509
510
  }
  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...
511
  	mod_zone_state(page_zone(page), item, -1, -1);
7c8391206   Christoph Lameter   vmstat: User per ...
512
513
  }
  EXPORT_SYMBOL(dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
514
515
516
517
518
519
520
  
  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...
521
522
523
524
  	if (vmstat_item_in_bytes(item)) {
  		VM_WARN_ON_ONCE(delta & (PAGE_SIZE - 1));
  		delta >>= PAGE_SHIFT;
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
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
576
577
578
  	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;
  
  		if (n > t || n < -t) {
  			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 ...
579
580
581
582
583
  #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...
584
  			 long delta)
7c8391206   Christoph Lameter   vmstat: User per ...
585
586
587
588
589
590
591
592
  {
  	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 ...
593
594
595
596
  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 ...
597
598
599
  
  	zone = page_zone(page);
  	local_irq_save(flags);
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
600
  	__inc_zone_state(zone, item);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
601
602
603
604
605
606
607
  	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 ...
608

2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
609
  	local_irq_save(flags);
a302eb4e4   Christoph Lameter   [PATCH] ZVC: Over...
610
  	__dec_zone_page_state(page, item);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
611
612
613
  	local_irq_restore(flags);
  }
  EXPORT_SYMBOL(dec_zone_page_state);
75ef71840   Mel Gorman   mm, vmstat: add i...
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
654
655
656
  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...
657
658
659
660
661
  
  /*
   * Fold a differential into the global counters.
   * Returns the number of counters updated.
   */
3a321d2a3   Kemi Wang   mm: change the ca...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  #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...
688
  static int fold_diff(int *zone_diff, int *node_diff)
4edb0748b   Christoph Lameter   vmstat: create fo...
689
690
  {
  	int i;
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
691
  	int changes = 0;
4edb0748b   Christoph Lameter   vmstat: create fo...
692
693
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
75ef71840   Mel Gorman   mm, vmstat: add i...
694
695
696
697
698
699
700
701
  		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...
702
703
704
  			changes++;
  	}
  	return changes;
4edb0748b   Christoph Lameter   vmstat: create fo...
705
  }
3a321d2a3   Kemi Wang   mm: change the ca...
706
  #endif /* CONFIG_NUMA */
4edb0748b   Christoph Lameter   vmstat: create fo...
707

2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
708
  /*
2bb921e52   Christoph Lameter   vmstat: create se...
709
   * Update the zone counters for the current cpu.
a7f75e258   Christoph Lameter   vmstat: small rev...
710
   *
4037d4522   Christoph Lameter   Move remote node ...
711
712
713
714
715
716
717
718
719
720
   * 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...
721
722
   *
   * The function returns the number of global counters updated.
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
723
   */
0eb77e988   Christoph Lameter   vmstat: make vmst...
724
  static int refresh_cpu_vm_stats(bool do_pagesets)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
725
  {
75ef71840   Mel Gorman   mm, vmstat: add i...
726
  	struct pglist_data *pgdat;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
727
728
  	struct zone *zone;
  	int i;
75ef71840   Mel Gorman   mm, vmstat: add i...
729
  	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3a321d2a3   Kemi Wang   mm: change the ca...
730
731
732
  #ifdef CONFIG_NUMA
  	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
  #endif
75ef71840   Mel Gorman   mm, vmstat: add i...
733
  	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
734
  	int changes = 0;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
735

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

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

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

a7f75e258   Christoph Lameter   vmstat: small rev...
745
  				atomic_long_add(v, &zone->vm_stat[i]);
75ef71840   Mel Gorman   mm, vmstat: add i...
746
  				global_zone_diff[i] += v;
4037d4522   Christoph Lameter   Move remote node ...
747
748
  #ifdef CONFIG_NUMA
  				/* 3 seconds idle till flush */
fbc2edb05   Christoph Lameter   vmstat: use this_...
749
  				__this_cpu_write(p->expire, 3);
4037d4522   Christoph Lameter   Move remote node ...
750
  #endif
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
751
  			}
fbc2edb05   Christoph Lameter   vmstat: use this_...
752
  		}
4037d4522   Christoph Lameter   Move remote node ...
753
  #ifdef CONFIG_NUMA
3a321d2a3   Kemi Wang   mm: change the ca...
754
755
756
757
758
759
760
761
762
763
764
  		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...
765
766
767
768
769
770
771
772
773
774
  		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_...
775
  			       !__this_cpu_read(p->pcp.count))
0eb77e988   Christoph Lameter   vmstat: make vmst...
776
  				continue;
4037d4522   Christoph Lameter   Move remote node ...
777

0eb77e988   Christoph Lameter   vmstat: make vmst...
778
779
780
781
782
783
784
  			/*
  			 * 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 ...
785

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

0eb77e988   Christoph Lameter   vmstat: make vmst...
789
790
791
792
  			if (__this_cpu_read(p->pcp.count)) {
  				drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
  				changes++;
  			}
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
793
  		}
4037d4522   Christoph Lameter   Move remote node ...
794
  #endif
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
795
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  
  	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...
810
811
812
813
  #ifdef CONFIG_NUMA
  	changes += fold_diff(global_zone_diff, global_numa_diff,
  			     global_node_diff);
  #else
75ef71840   Mel Gorman   mm, vmstat: add i...
814
  	changes += fold_diff(global_zone_diff, global_node_diff);
3a321d2a3   Kemi Wang   mm: change the ca...
815
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
816
  	return changes;
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
817
  }
40f4b1ead   Cody P Schafer   mm/vmstat: add no...
818
  /*
2bb921e52   Christoph Lameter   vmstat: create se...
819
820
821
822
823
824
   * 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...
825
  	struct pglist_data *pgdat;
2bb921e52   Christoph Lameter   vmstat: create se...
826
827
  	struct zone *zone;
  	int i;
75ef71840   Mel Gorman   mm, vmstat: add i...
828
  	int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3a321d2a3   Kemi Wang   mm: change the ca...
829
830
831
  #ifdef CONFIG_NUMA
  	int global_numa_diff[NR_VM_NUMA_STAT_ITEMS] = { 0, };
  #endif
75ef71840   Mel Gorman   mm, vmstat: add i...
832
  	int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, };
2bb921e52   Christoph Lameter   vmstat: create se...
833
834
835
836
837
838
839
840
841
842
843
844
845
  
  	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...
846
  				global_zone_diff[i] += v;
2bb921e52   Christoph Lameter   vmstat: create se...
847
  			}
3a321d2a3   Kemi Wang   mm: change the ca...
848
849
850
851
852
853
854
855
856
857
858
859
  
  #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...
860
  	}
75ef71840   Mel Gorman   mm, vmstat: add i...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
  	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...
876
877
878
  #ifdef CONFIG_NUMA
  	fold_diff(global_zone_diff, global_numa_diff, global_node_diff);
  #else
75ef71840   Mel Gorman   mm, vmstat: add i...
879
  	fold_diff(global_zone_diff, global_node_diff);
3a321d2a3   Kemi Wang   mm: change the ca...
880
  #endif
2bb921e52   Christoph Lameter   vmstat: create se...
881
882
883
  }
  
  /*
40f4b1ead   Cody P Schafer   mm/vmstat: add no...
884
885
886
   * 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...
887
888
889
890
891
892
893
894
895
  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...
896
  			atomic_long_add(v, &vm_zone_stat[i]);
5a8838138   Minchan Kim   memory-hotplug: f...
897
  		}
3a321d2a3   Kemi Wang   mm: change the ca...
898
899
900
901
902
903
904
905
906
907
908
  
  #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...
909
  }
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
910
  #endif
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
911
  #ifdef CONFIG_NUMA
3a321d2a3   Kemi Wang   mm: change the ca...
912
913
914
915
  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...
916
917
  	u16 __percpu *p = pcp->vm_numa_stat_diff + item;
  	u16 v;
3a321d2a3   Kemi Wang   mm: change the ca...
918
919
  
  	v = __this_cpu_inc_return(*p);
3a321d2a3   Kemi Wang   mm: change the ca...
920

1d90ca897   Kemi Wang   mm: update NUMA c...
921
922
923
  	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...
924
925
  	}
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
926
  /*
75ef71840   Mel Gorman   mm, vmstat: add i...
927
928
929
   * 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...
930
   */
75ef71840   Mel Gorman   mm, vmstat: add i...
931
932
  unsigned long sum_zone_node_page_state(int node,
  				 enum zone_stat_item item)
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
933
934
  {
  	struct zone *zones = NODE_DATA(node)->node_zones;
e87d59f7a   Joonsoo Kim   mm/vmstat: make n...
935
936
  	int i;
  	unsigned long count = 0;
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
937

e87d59f7a   Joonsoo Kim   mm/vmstat: make n...
938
939
940
941
  	for (i = 0; i < MAX_NR_ZONES; i++)
  		count += zone_page_state(zones + i, item);
  
  	return count;
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
942
  }
638032224   Kemi Wang   mm: consider the ...
943
944
945
946
  /*
   * 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...
947
948
949
950
951
952
953
954
  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 ...
955
  		count += zone_numa_state_snapshot(zones + i, item);
3a321d2a3   Kemi Wang   mm: change the ca...
956
957
958
  
  	return count;
  }
75ef71840   Mel Gorman   mm, vmstat: add i...
959
960
961
  /*
   * Determine the per node value of a stat item.
   */
ea426c2a7   Roman Gushchin   mm: memcg: prepar...
962
963
  unsigned long node_page_state_pages(struct pglist_data *pgdat,
  				    enum node_stat_item item)
75ef71840   Mel Gorman   mm, vmstat: add i...
964
965
966
967
968
969
970
971
  {
  	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...
972
973
974
975
976
977
978
979
  
  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...
980
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
981
  #ifdef CONFIG_COMPACTION
36deb0be3   Namhyung Kim   vmstat: include c...
982

d7a5752c0   Mel Gorman   mm: export unusab...
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
1020
1021
1022
  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...
1023
1024
1025
1026
1027
1028
1029
1030
  
  /*
   * 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...
1031
  static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
f1a5ab121   Mel Gorman   mm: export fragme...
1032
1033
  {
  	unsigned long requested = 1UL << order;
88d6ac40c   Wen Yang   mm/vmstat: fix di...
1034
1035
  	if (WARN_ON_ONCE(order >= MAX_ORDER))
  		return 0;
f1a5ab121   Mel Gorman   mm: export fragme...
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  	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...
1051

facdaa917   Nitin Gupta   mm: proactive com...
1052
1053
1054
1055
1056
  /*
   * 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 ...
1057
  unsigned int extfrag_for_order(struct zone *zone, unsigned int order)
facdaa917   Nitin Gupta   mm: proactive com...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
  {
  	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...
1069
1070
1071
1072
1073
1074
1075
1076
  /* 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...
1077
  #endif
ebc5d83d0   Konstantin Khlebnikov   mm/memcontrol: us...
1078
1079
  #if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || \
      defined(CONFIG_NUMA) || defined(CONFIG_MEMCG)
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  #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...
1102
  	/* enum zone_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1103
  	"nr_free_pages",
71c799f49   Minchan Kim   mm: add per-zone ...
1104
1105
1106
1107
1108
  	"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...
1109
  	"nr_zone_write_pending",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1110
  	"nr_mlock",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1111
  	"nr_page_table_pages",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1112
  	"nr_bounce",
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1113
1114
1115
  #if IS_ENABLED(CONFIG_ZSMALLOC)
  	"nr_zspages",
  #endif
3a321d2a3   Kemi Wang   mm: change the ca...
1116
1117
1118
  	"nr_free_cma",
  
  	/* enum numa_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1119
1120
1121
1122
1123
1124
1125
1126
  #ifdef CONFIG_NUMA
  	"numa_hit",
  	"numa_miss",
  	"numa_foreign",
  	"numa_interleave",
  	"numa_local",
  	"numa_other",
  #endif
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1127

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

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

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

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

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

3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  #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...
1331
1332
1333
1334
  /*
   * 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/...
1335
  static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
727c080f0   Vinayak Menon   mm: avoid taking ...
1336
  		bool assert_populated, bool nolock,
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1337
1338
1339
1340
1341
1342
1343
  		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...
1344
  		if (assert_populated && !populated_zone(zone))
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1345
  			continue;
727c080f0   Vinayak Menon   mm: avoid taking ...
1346
1347
  		if (!nolock)
  			spin_lock_irqsave(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1348
  		print(m, pgdat, zone);
727c080f0   Vinayak Menon   mm: avoid taking ...
1349
1350
  		if (!nolock)
  			spin_unlock_irqrestore(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1351
1352
1353
  	}
  }
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
1354
  #ifdef CONFIG_PROC_FS
467c996c1   Mel Gorman   Print out statist...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
  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 ...
1373
  	walk_zones_in_node(m, pgdat, true, false, frag_show_print);
467c996c1   Mel Gorman   Print out statist...
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
  	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...
1391
  			bool overflow = false;
467c996c1   Mel Gorman   Print out statist...
1392
1393
  
  			area = &(zone->free_area[order]);
93b3a6744   Michal Hocko   mm, vmstat: reduc...
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  			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...
1413
  		}
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1414
1415
1416
  		seq_putc(m, '
  ');
  	}
467c996c1   Mel Gorman   Print out statist...
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
  }
  
  /* 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 ...
1431
  	walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
467c996c1   Mel Gorman   Print out statist...
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
  
  	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...
1442
  	unsigned long end_pfn = zone_end_pfn(zone);
467c996c1   Mel Gorman   Print out statist...
1443
1444
1445
1446
  	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 ...
1447
1448
  		page = pfn_to_online_page(pfn);
  		if (!page)
467c996c1   Mel Gorman   Print out statist...
1449
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1450
1451
  		/* Watch for unexpected holes punched in the memmap */
  		if (!memmap_valid_within(pfn, page, zone))
e80d6a248   Mel Gorman   [ARM] Skip memory...
1452
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1453

a91c43c73   Joonsoo Kim   mm/vmstat: add zo...
1454
1455
  		if (page_zone(page) != zone)
  			continue;
467c996c1   Mel Gorman   Print out statist...
1456
  		mtype = get_pageblock_migratetype(page);
e80d6a248   Mel Gorman   [ARM] Skip memory...
1457
1458
  		if (mtype < MIGRATE_TYPES)
  			count[mtype]++;
467c996c1   Mel Gorman   Print out statist...
1459
1460
1461
1462
1463
1464
1465
1466
1467
  	}
  
  	/* 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 ...
1468
  /* Print out the number of pageblocks for each migratetype */
467c996c1   Mel Gorman   Print out statist...
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  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 ...
1480
1481
  	walk_zones_in_node(m, pgdat, true, false,
  		pagetypeinfo_showblockcount_print);
467c996c1   Mel Gorman   Print out statist...
1482
1483
1484
  
  	return 0;
  }
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
  /*
   * 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...
1495
  	if (!static_branch_unlikely(&page_owner_inited))
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  		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 ...
1506
1507
  	walk_zones_in_node(m, pgdat, true, true,
  		pagetypeinfo_showmixedcount_print);
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1508
1509
  #endif /* CONFIG_PAGE_OWNER */
  }
467c996c1   Mel Gorman   Print out statist...
1510
1511
1512
1513
1514
1515
1516
  /*
   * 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...
1517
  	/* check memoryless node */
a47b53c5f   Lai Jiangshan   vmstat: use N_MEM...
1518
  	if (!node_state(pgdat->node_id, N_MEMORY))
41b25a378   KOSAKI Motohiro   /proc/pagetypeinf...
1519
  		return 0;
467c996c1   Mel Gorman   Print out statist...
1520
1521
1522
1523
1524
1525
1526
1527
  	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...
1528
  	pagetypeinfo_showmixedcount(m, pgdat);
467c996c1   Mel Gorman   Print out statist...
1529

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

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

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

99dcc3e5a   Christoph Lameter   this_cpu: Page al...
1622
  		pageset = per_cpu_ptr(zone->pageset, i);
3dfa5721f   Christoph Lameter   Page allocator: g...
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
  		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...
1636
  #ifdef CONFIG_SMP
467c996c1   Mel Gorman   Print out statist...
1637
1638
1639
  		seq_printf(m, "
    vm stats threshold: %d",
  				pageset->stat_threshold);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1640
  #endif
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1641
  	}
467c996c1   Mel Gorman   Print out statist...
1642
  	seq_printf(m,
599d0c954   Mel Gorman   mm, vmscan: move ...
1643
1644
  		   "
    node_unreclaimable:  %u"
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1645
1646
  		   "
    start_pfn:           %lu",
c73322d09   Johannes Weiner   mm: fix 100% CPU ...
1647
  		   pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1648
  		   zone->zone_start_pfn);
467c996c1   Mel Gorman   Print out statist...
1649
1650
1651
1652
1653
  	seq_putc(m, '
  ');
  }
  
  /*
b2bd85981   David Rientjes   mm, vmstat: print...
1654
1655
1656
1657
   * 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...
1658
1659
1660
1661
   */
  static int zoneinfo_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
727c080f0   Vinayak Menon   mm: avoid taking ...
1662
  	walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1663
1664
  	return 0;
  }
5c9fe6281   Alexey Dobriyan   proc: move /proc/...
1665
  static const struct seq_operations zoneinfo_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1666
1667
1668
1669
1670
1671
  	.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...
1672
1673
1674
1675
1676
1677
  #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...
1678

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

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

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

52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1759
1760
1761
1762
1763
1764
1765
  #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...
1766
  		   void *buffer, size_t *lenp, loff_t *ppos)
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
  {
  	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...
1780
  	 * Oh, and since global_zone_page_state() etc. are so careful to hide
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1781
1782
1783
1784
1785
1786
1787
  	 * 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...
1788
  		val = atomic_long_read(&vm_zone_stat[i]);
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1789
  		if (val < 0) {
c822f6223   Johannes Weiner   mm: delete NR_PAG...
1790
1791
  			pr_warn("%s: %s %ld
  ",
9d7ea9a29   Konstantin Khlebnikov   mm/vmstat: add he...
1792
  				__func__, zone_stat_name(i), val);
c822f6223   Johannes Weiner   mm: delete NR_PAG...
1793
  			err = -EINVAL;
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1794
1795
  		}
  	}
3a321d2a3   Kemi Wang   mm: change the ca...
1796
1797
1798
1799
1800
1801
  #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...
1802
  				__func__, numa_stat_name(i), val);
3a321d2a3   Kemi Wang   mm: change the ca...
1803
1804
1805
1806
  			err = -EINVAL;
  		}
  	}
  #endif
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1807
1808
1809
1810
1811
1812
1813
1814
1815
  	if (err)
  		return err;
  	if (write)
  		*ppos += *lenp;
  	else
  		*lenp = 0;
  	return 0;
  }
  #endif /* CONFIG_PROC_FS */
d1187ed21   Christoph Lameter   vmstat: use our o...
1816
1817
  static void vmstat_update(struct work_struct *w)
  {
0eb77e988   Christoph Lameter   vmstat: make vmst...
1818
  	if (refresh_cpu_vm_stats(true)) {
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1819
1820
1821
1822
1823
  		/*
  		 * 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 ...
1824
  		queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
f01f17d37   Michal Hocko   mm, vmstat: make ...
1825
1826
  				this_cpu_ptr(&vmstat_work),
  				round_jiffies_relative(sysctl_stat_interval));
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1827
1828
1829
1830
  	}
  }
  
  /*
0eb77e988   Christoph Lameter   vmstat: make vmst...
1831
1832
1833
1834
   * 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...
1835
  /*
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
   * 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...
1847
  #ifdef CONFIG_NUMA
1d90ca897   Kemi Wang   mm: update NUMA c...
1848
  		BUILD_BUG_ON(sizeof(p->vm_numa_stat_diff[0]) != 2);
3a321d2a3   Kemi Wang   mm: change the ca...
1849
  #endif
638032224   Kemi Wang   mm: consider the ...
1850

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1851
1852
  		/*
  		 * The fast way of checking if there are any vmstat diffs.
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1853
  		 */
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1854
1855
  		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...
1856
  			return true;
3a321d2a3   Kemi Wang   mm: change the ca...
1857
  #ifdef CONFIG_NUMA
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1858
1859
  		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...
1860
1861
  			return true;
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1862
1863
1864
  	}
  	return false;
  }
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1865
1866
1867
1868
1869
  /*
   * 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 ...
1870
1871
1872
1873
  void quiet_vmstat(void)
  {
  	if (system_state != SYSTEM_RUNNING)
  		return;
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1874
  	if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
f01f17d37   Michal Hocko   mm, vmstat: make ...
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
  		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...
1888
1889
1890
1891
1892
1893
1894
  /*
   * 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...
1895
  static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1896
1897
1898
1899
1900
1901
1902
  
  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...
1903
  	for_each_online_cpu(cpu) {
f01f17d37   Michal Hocko   mm, vmstat: make ...
1904
  		struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1905

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

4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1928
1929
1930
1931
  	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...
1932
  }
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
  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...
1947
  {
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1948
  	const struct cpumask *node_cpus;
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1949
  	int node;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1950

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

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

80d136e13   Michal Hocko   mm: make mm_percp...
1968
  	mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
ce612879d   Michal Hocko   mm: move pcp and ...
1969
1970
  
  #ifdef CONFIG_SMP
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
  	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...
1985
  	init_cpu_node_state();
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1986
  	put_online_cpus();
d1187ed21   Christoph Lameter   vmstat: use our o...
1987

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1988
  	start_shepherd_timer();
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1989
1990
  #endif
  #ifdef CONFIG_PROC_FS
fddda2b7b   Christoph Hellwig   proc: introduce p...
1991
  	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
abaed0112   Michal Hocko   mm, vmstat: hide ...
1992
  	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
fddda2b7b   Christoph Hellwig   proc: introduce p...
1993
1994
  	proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
  	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1995
  #endif
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1996
  }
d7a5752c0   Mel Gorman   mm: export unusab...
1997
1998
  
  #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
d7a5752c0   Mel Gorman   mm: export unusab...
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
2052
2053
2054
2055
  
  /*
   * 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...
2056
  	if (!node_state(pgdat->node_id, N_MEMORY))
d7a5752c0   Mel Gorman   mm: export unusab...
2057
  		return 0;
727c080f0   Vinayak Menon   mm: avoid taking ...
2058
  	walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
d7a5752c0   Mel Gorman   mm: export unusab...
2059
2060
2061
  
  	return 0;
  }
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2062
  static const struct seq_operations unusable_sops = {
d7a5752c0   Mel Gorman   mm: export unusab...
2063
2064
2065
2066
2067
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= unusable_show,
  };
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2068
  DEFINE_SEQ_ATTRIBUTE(unusable);
d7a5752c0   Mel Gorman   mm: export unusab...
2069

f1a5ab121   Mel Gorman   mm: export fragme...
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
  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...
2084
  		index = __fragmentation_index(order, &info);
f1a5ab121   Mel Gorman   mm: export fragme...
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
  		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 ...
2098
  	walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
f1a5ab121   Mel Gorman   mm: export fragme...
2099
2100
2101
  
  	return 0;
  }
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2102
  static const struct seq_operations extfrag_sops = {
f1a5ab121   Mel Gorman   mm: export fragme...
2103
2104
2105
2106
2107
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= extfrag_show,
  };
01a995600   Kefeng Wang   mm/vmstat.c: conv...
2108
  DEFINE_SEQ_ATTRIBUTE(extfrag);
f1a5ab121   Mel Gorman   mm: export fragme...
2109

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

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

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

d7a5752c0   Mel Gorman   mm: export unusab...
2121
2122
2123
2124
2125
  	return 0;
  }
  
  module_init(extfrag_debug_init);
  #endif