Blame view

mm/vmstat.c 52.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
78
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
  #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,
  		void __user *buffer, size_t *length, loff_t *ppos)
  {
  	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
326
327
328
329
330
331
332
333
334
335
336
337
  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;
  
  	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 ...
338
  /*
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
339
340
341
342
343
344
345
346
347
   * 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 ...
348
349
350
   * The increment or decrement is known and therefore one boundary check can
   * be omitted.
   *
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
351
352
353
   * NOTE: These functions are very performance sensitive. Change only
   * with care.
   *
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
354
355
356
357
358
359
360
   * 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...
361
  void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
362
  {
12938a922   Christoph Lameter   vmstat: Optimize ...
363
364
365
  	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 ...
366

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

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

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

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

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

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

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

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

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

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

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

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

0eb77e988   Christoph Lameter   vmstat: make vmst...
772
773
774
775
776
777
778
  			/*
  			 * 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 ...
779

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

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

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

e87d59f7a   Joonsoo Kim   mm/vmstat: make n...
932
933
934
935
  	for (i = 0; i < MAX_NR_ZONES; i++)
  		count += zone_page_state(zones + i, item);
  
  	return count;
c2d42c16a   Andrew Morton   mm/vmstat.c: unin...
936
  }
638032224   Kemi Wang   mm: consider the ...
937
938
939
940
  /*
   * 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...
941
942
943
944
945
946
947
948
  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 ...
949
  		count += zone_numa_state_snapshot(zones + i, item);
3a321d2a3   Kemi Wang   mm: change the ca...
950
951
952
  
  	return count;
  }
75ef71840   Mel Gorman   mm, vmstat: add i...
953
954
955
956
957
958
959
960
961
962
963
964
965
  /*
   * Determine the per node value of a stat item.
   */
  unsigned long node_page_state(struct pglist_data *pgdat,
  				enum node_stat_item item)
  {
  	long x = atomic_long_read(&pgdat->vm_stat[item]);
  #ifdef CONFIG_SMP
  	if (x < 0)
  		x = 0;
  #endif
  	return x;
  }
ca889e6c4   Christoph Lameter   [PATCH] Use Zoned...
966
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
967
  #ifdef CONFIG_COMPACTION
36deb0be3   Namhyung Kim   vmstat: include c...
968

d7a5752c0   Mel Gorman   mm: export unusab...
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
  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...
1009
1010
1011
1012
1013
1014
1015
1016
  
  /*
   * 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...
1017
  static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
f1a5ab121   Mel Gorman   mm: export fragme...
1018
1019
  {
  	unsigned long requested = 1UL << order;
88d6ac40c   Wen Yang   mm/vmstat: fix di...
1020
1021
  	if (WARN_ON_ONCE(order >= MAX_ORDER))
  		return 0;
f1a5ab121   Mel Gorman   mm: export fragme...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  	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...
1037
1038
1039
1040
1041
1042
1043
1044
1045
  
  /* 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...
1046
  #endif
0d6617c77   David Rientjes   numa: fix NUMA co...
1047
  #if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || defined(CONFIG_NUMA)
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
  #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[] = {
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1070
  	/* enum zone_stat_item countes */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1071
  	"nr_free_pages",
71c799f49   Minchan Kim   mm: add per-zone ...
1072
1073
1074
1075
1076
  	"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...
1077
  	"nr_zone_write_pending",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1078
  	"nr_mlock",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1079
1080
  	"nr_page_table_pages",
  	"nr_kernel_stack",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1081
  	"nr_bounce",
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1082
1083
1084
  #if IS_ENABLED(CONFIG_ZSMALLOC)
  	"nr_zspages",
  #endif
3a321d2a3   Kemi Wang   mm: change the ca...
1085
1086
1087
  	"nr_free_cma",
  
  	/* enum numa_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1088
1089
1090
1091
1092
1093
1094
1095
  #ifdef CONFIG_NUMA
  	"numa_hit",
  	"numa_miss",
  	"numa_foreign",
  	"numa_interleave",
  	"numa_local",
  	"numa_other",
  #endif
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1096

599d0c954   Mel Gorman   mm, vmscan: move ...
1097
1098
1099
1100
1101
1102
  	/* Node-based counters */
  	"nr_inactive_anon",
  	"nr_active_anon",
  	"nr_inactive_file",
  	"nr_active_file",
  	"nr_unevictable",
385386cff   Johannes Weiner   mm: vmstat: move ...
1103
1104
  	"nr_slab_reclaimable",
  	"nr_slab_unreclaimable",
599d0c954   Mel Gorman   mm, vmscan: move ...
1105
1106
  	"nr_isolated_anon",
  	"nr_isolated_file",
68d48e6a2   Johannes Weiner   mm: workingset: a...
1107
  	"workingset_nodes",
1e6b10857   Mel Gorman   mm, workingset: m...
1108
1109
  	"workingset_refault",
  	"workingset_activate",
1899ad18c   Johannes Weiner   mm: workingset: t...
1110
  	"workingset_restore",
1e6b10857   Mel Gorman   mm, workingset: m...
1111
  	"workingset_nodereclaim",
50658e2e0   Mel Gorman   mm: move page map...
1112
1113
  	"nr_anon_pages",
  	"nr_mapped",
11fb99898   Mel Gorman   mm: move most fil...
1114
1115
1116
1117
1118
1119
1120
  	"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...
1121
1122
  	"nr_file_hugepages",
  	"nr_file_pmdmapped",
11fb99898   Mel Gorman   mm: move most fil...
1123
1124
  	"nr_anon_transparent_hugepages",
  	"nr_unstable",
c4a25635b   Mel Gorman   mm: move vmscan w...
1125
1126
1127
1128
  	"nr_vmscan_write",
  	"nr_vmscan_immediate_reclaim",
  	"nr_dirtied",
  	"nr_written",
b29940c1a   Vlastimil Babka   mm: rename and ch...
1129
  	"nr_kernel_misc_reclaimable",
599d0c954   Mel Gorman   mm, vmscan: move ...
1130

09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1131
  	/* enum writeback_stat_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1132
1133
1134
1135
  	"nr_dirty_threshold",
  	"nr_dirty_background_threshold",
  
  #ifdef CONFIG_VM_EVENT_COUNTERS
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1136
  	/* enum vm_event_item counters */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1137
1138
1139
1140
1141
1142
  	"pgpgin",
  	"pgpgout",
  	"pswpin",
  	"pswpout",
  
  	TEXTS_FOR_ZONES("pgalloc")
7cc30fcfd   Mel Gorman   mm: vmstat: accou...
1143
1144
  	TEXTS_FOR_ZONES("allocstall")
  	TEXTS_FOR_ZONES("pgskip")
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1145
1146
1147
1148
  
  	"pgfree",
  	"pgactivate",
  	"pgdeactivate",
f7ad2a6cb   Shaohua Li   mm: move MADV_FRE...
1149
  	"pglazyfree",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1150
1151
1152
  
  	"pgfault",
  	"pgmajfault",
854e9ed09   Minchan Kim   mm: support madvi...
1153
  	"pglazyfreed",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1154

599d0c954   Mel Gorman   mm, vmscan: move ...
1155
1156
1157
1158
1159
  	"pgrefill",
  	"pgsteal_kswapd",
  	"pgsteal_direct",
  	"pgscan_kswapd",
  	"pgscan_direct",
68243e76e   Mel Gorman   mm: account for t...
1160
  	"pgscan_direct_throttle",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1161
1162
1163
1164
1165
1166
  
  #ifdef CONFIG_NUMA
  	"zone_reclaim_failed",
  #endif
  	"pginodesteal",
  	"slabs_scanned",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1167
1168
1169
  	"kswapd_inodesteal",
  	"kswapd_low_wmark_hit_quickly",
  	"kswapd_high_wmark_hit_quickly",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1170
  	"pageoutrun",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1171
1172
  
  	"pgrotated",
5509a5d27   Dave Hansen   drop_caches: add ...
1173
1174
  	"drop_pagecache",
  	"drop_slab",
8e675f7af   Konstantin Khlebnikov   mm/oom_kill: coun...
1175
  	"oom_kill",
5509a5d27   Dave Hansen   drop_caches: add ...
1176

03c5a6e16   Mel Gorman   mm: numa: Add pte...
1177
1178
  #ifdef CONFIG_NUMA_BALANCING
  	"numa_pte_updates",
72403b4a0   Mel Gorman   mm: numa: return ...
1179
  	"numa_huge_pte_updates",
03c5a6e16   Mel Gorman   mm: numa: Add pte...
1180
1181
1182
1183
  	"numa_hint_faults",
  	"numa_hint_faults_local",
  	"numa_pages_migrated",
  #endif
5647bc293   Mel Gorman   mm: compaction: M...
1184
1185
1186
1187
  #ifdef CONFIG_MIGRATION
  	"pgmigrate_success",
  	"pgmigrate_fail",
  #endif
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1188
  #ifdef CONFIG_COMPACTION
397487db6   Mel Gorman   mm: compaction: A...
1189
1190
1191
  	"compact_migrate_scanned",
  	"compact_free_scanned",
  	"compact_isolated",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1192
1193
1194
  	"compact_stall",
  	"compact_fail",
  	"compact_success",
698b1b306   Vlastimil Babka   mm, compaction: i...
1195
  	"compact_daemon_wake",
7f354a548   David Rientjes   mm, compaction: a...
1196
1197
  	"compact_daemon_migrate_scanned",
  	"compact_daemon_free_scanned",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  #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...
1211
1212
1213
1214
1215
1216
  
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  	"thp_fault_alloc",
  	"thp_fault_fallback",
  	"thp_collapse_alloc",
  	"thp_collapse_alloc_failed",
95ecedcd6   Kirill A. Shutemov   thp, vmstats: add...
1217
1218
  	"thp_file_alloc",
  	"thp_file_mapped",
122afea96   Kirill A. Shutemov   mm, vmstats: new ...
1219
1220
  	"thp_split_page",
  	"thp_split_page_failed",
f9719a03d   Kirill A. Shutemov   thp, vmstats: cou...
1221
  	"thp_deferred_split_page",
122afea96   Kirill A. Shutemov   mm, vmstats: new ...
1222
  	"thp_split_pmd",
ce9311cf9   Yisheng Xie   mm/vmstats: add t...
1223
1224
1225
  #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
  	"thp_split_pud",
  #endif
d8a8e1f0d   Kirill A. Shutemov   thp, vmstat: impl...
1226
1227
  	"thp_zero_page_alloc",
  	"thp_zero_page_alloc_failed",
225311a46   Huang Ying   mm: test code to ...
1228
  	"thp_swpout",
fe490cc0f   Huang Ying   mm, THP, swap: ad...
1229
  	"thp_swpout_fallback",
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1230
  #endif
09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
1231
1232
1233
1234
1235
1236
1237
  #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 ...
1238
  #ifdef CONFIG_DEBUG_TLBFLUSH
9824cf975   Dave Hansen   mm: vmstats: tlb ...
1239
1240
1241
1242
  	"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 ...
1243
  #endif /* CONFIG_DEBUG_TLBFLUSH */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1244

4f115147f   Davidlohr Bueso   mm,vmacache: add ...
1245
1246
1247
1248
  #ifdef CONFIG_DEBUG_VM_VMACACHE
  	"vmacache_find_calls",
  	"vmacache_find_hits",
  #endif
cbc65df24   Huang Ying   mm, swap: add swa...
1249
1250
1251
1252
  #ifdef CONFIG_SWAP
  	"swap_ra",
  	"swap_ra_hit",
  #endif
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1253
1254
  #endif /* CONFIG_VM_EVENTS_COUNTERS */
  };
0d6617c77   David Rientjes   numa: fix NUMA co...
1255
  #endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */
fa25c503d   KOSAKI Motohiro   mm: per-node vmst...
1256

3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  #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...
1283
1284
1285
1286
  /*
   * 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/...
1287
  static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
727c080f0   Vinayak Menon   mm: avoid taking ...
1288
  		bool assert_populated, bool nolock,
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1289
1290
1291
1292
1293
1294
1295
  		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...
1296
  		if (assert_populated && !populated_zone(zone))
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1297
  			continue;
727c080f0   Vinayak Menon   mm: avoid taking ...
1298
1299
  		if (!nolock)
  			spin_lock_irqsave(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1300
  		print(m, pgdat, zone);
727c080f0   Vinayak Menon   mm: avoid taking ...
1301
1302
  		if (!nolock)
  			spin_unlock_irqrestore(&zone->lock, flags);
3c4868710   Andrew Morton   mm/vmstat.c: fix/...
1303
1304
1305
  	}
  }
  #endif
d7a5752c0   Mel Gorman   mm: export unusab...
1306
  #ifdef CONFIG_PROC_FS
467c996c1   Mel Gorman   Print out statist...
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  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 ...
1325
  	walk_zones_in_node(m, pgdat, true, false, frag_show_print);
467c996c1   Mel Gorman   Print out statist...
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
  	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...
1343
  			bool overflow = false;
467c996c1   Mel Gorman   Print out statist...
1344
1345
  
  			area = &(zone->free_area[order]);
93b3a6744   Michal Hocko   mm, vmstat: reduc...
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
  			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...
1365
  		}
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1366
1367
1368
  		seq_putc(m, '
  ');
  	}
467c996c1   Mel Gorman   Print out statist...
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
  }
  
  /* 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 ...
1383
  	walk_zones_in_node(m, pgdat, true, false, pagetypeinfo_showfree_print);
467c996c1   Mel Gorman   Print out statist...
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  
  	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...
1394
  	unsigned long end_pfn = zone_end_pfn(zone);
467c996c1   Mel Gorman   Print out statist...
1395
1396
1397
1398
  	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 ...
1399
1400
  		page = pfn_to_online_page(pfn);
  		if (!page)
467c996c1   Mel Gorman   Print out statist...
1401
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1402
1403
  		/* Watch for unexpected holes punched in the memmap */
  		if (!memmap_valid_within(pfn, page, zone))
e80d6a248   Mel Gorman   [ARM] Skip memory...
1404
  			continue;
eb33575cf   Mel Gorman   [ARM] Double chec...
1405

a91c43c73   Joonsoo Kim   mm/vmstat: add zo...
1406
1407
  		if (page_zone(page) != zone)
  			continue;
467c996c1   Mel Gorman   Print out statist...
1408
  		mtype = get_pageblock_migratetype(page);
e80d6a248   Mel Gorman   [ARM] Skip memory...
1409
1410
  		if (mtype < MIGRATE_TYPES)
  			count[mtype]++;
467c996c1   Mel Gorman   Print out statist...
1411
1412
1413
1414
1415
1416
1417
1418
1419
  	}
  
  	/* 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 ...
1420
  /* Print out the number of pageblocks for each migratetype */
467c996c1   Mel Gorman   Print out statist...
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
  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 ...
1432
1433
  	walk_zones_in_node(m, pgdat, true, false,
  		pagetypeinfo_showblockcount_print);
467c996c1   Mel Gorman   Print out statist...
1434
1435
1436
  
  	return 0;
  }
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
  /*
   * 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...
1447
  	if (!static_branch_unlikely(&page_owner_inited))
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
  		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 ...
1458
1459
  	walk_zones_in_node(m, pgdat, true, true,
  		pagetypeinfo_showmixedcount_print);
48c96a368   Joonsoo Kim   mm/page_owner: ke...
1460
1461
  #endif /* CONFIG_PAGE_OWNER */
  }
467c996c1   Mel Gorman   Print out statist...
1462
1463
1464
1465
1466
1467
1468
  /*
   * 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...
1469
  	/* check memoryless node */
a47b53c5f   Lai Jiangshan   vmstat: use N_MEM...
1470
  	if (!node_state(pgdat->node_id, N_MEMORY))
41b25a378   KOSAKI Motohiro   /proc/pagetypeinf...
1471
  		return 0;
467c996c1   Mel Gorman   Print out statist...
1472
1473
1474
1475
1476
1477
1478
1479
  	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...
1480
  	pagetypeinfo_showmixedcount(m, pgdat);
467c996c1   Mel Gorman   Print out statist...
1481

f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1482
1483
  	return 0;
  }
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1484
  static const struct seq_operations fragmentation_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1485
1486
1487
1488
1489
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= frag_show,
  };
74e2e8e8c   Alexey Dobriyan   proc: move /proc/...
1490
  static const struct seq_operations pagetypeinfo_op = {
467c996c1   Mel Gorman   Print out statist...
1491
1492
1493
1494
1495
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= pagetypeinfo_show,
  };
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  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...
1506
1507
  	return false;
  }
467c996c1   Mel Gorman   Print out statist...
1508
1509
  static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
  							struct zone *zone)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1510
  {
467c996c1   Mel Gorman   Print out statist...
1511
1512
  	int i;
  	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1513
1514
1515
1516
1517
1518
  	if (is_zone_first_populated(pgdat, zone)) {
  		seq_printf(m, "
    per-node stats");
  		for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
  			seq_printf(m, "
        %-12s %lu",
3a321d2a3   Kemi Wang   mm: change the ca...
1519
1520
  				vmstat_text[i + NR_VM_ZONE_STAT_ITEMS +
  				NR_VM_NUMA_STAT_ITEMS],
e2ecc8a79   Mel Gorman   mm, vmstat: print...
1521
1522
1523
  				node_page_state(pgdat, i));
  		}
  	}
467c996c1   Mel Gorman   Print out statist...
1524
1525
1526
1527
1528
1529
1530
1531
1532
  	seq_printf(m,
  		   "
    pages free     %lu"
  		   "
          min      %lu"
  		   "
          low      %lu"
  		   "
          high     %lu"
467c996c1   Mel Gorman   Print out statist...
1533
1534
  		   "
          spanned  %lu"
9feedc9d8   Jiang Liu   mm: introduce new...
1535
1536
1537
1538
  		   "
          present  %lu"
  		   "
          managed  %lu",
88f5acf88   Mel Gorman   mm: page allocato...
1539
  		   zone_page_state(zone, NR_FREE_PAGES),
418589663   Mel Gorman   page allocator: u...
1540
1541
1542
  		   min_wmark_pages(zone),
  		   low_wmark_pages(zone),
  		   high_wmark_pages(zone),
467c996c1   Mel Gorman   Print out statist...
1543
  		   zone->spanned_pages,
9feedc9d8   Jiang Liu   mm: introduce new...
1544
  		   zone->present_pages,
9705bea5f   Arun KS   mm: convert zone-...
1545
  		   zone_managed_pages(zone));
467c996c1   Mel Gorman   Print out statist...
1546

467c996c1   Mel Gorman   Print out statist...
1547
  	seq_printf(m,
3484b2de9   Mel Gorman   mm: rearrange zon...
1548
1549
  		   "
          protection: (%ld",
467c996c1   Mel Gorman   Print out statist...
1550
1551
  		   zone->lowmem_reserve[0]);
  	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
3484b2de9   Mel Gorman   mm: rearrange zon...
1552
  		seq_printf(m, ", %ld", zone->lowmem_reserve[i]);
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
  	seq_putc(m, ')');
  
  	/* If unpopulated, no other information is useful */
  	if (!populated_zone(zone)) {
  		seq_putc(m, '
  ');
  		return;
  	}
  
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
  		seq_printf(m, "
        %-12s %lu", vmstat_text[i],
  				zone_page_state(zone, i));
3a321d2a3   Kemi Wang   mm: change the ca...
1566
1567
1568
1569
1570
  #ifdef CONFIG_NUMA
  	for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
  		seq_printf(m, "
        %-12s %lu",
  				vmstat_text[i + NR_VM_ZONE_STAT_ITEMS],
638032224   Kemi Wang   mm: consider the ...
1571
  				zone_numa_state_snapshot(zone, i));
3a321d2a3   Kemi Wang   mm: change the ca...
1572
  #endif
7dfb8bf3b   David Rientjes   mm, vmstat: suppr...
1573
1574
  	seq_printf(m, "
    pagesets");
467c996c1   Mel Gorman   Print out statist...
1575
1576
  	for_each_online_cpu(i) {
  		struct per_cpu_pageset *pageset;
467c996c1   Mel Gorman   Print out statist...
1577

99dcc3e5a   Christoph Lameter   this_cpu: Page al...
1578
  		pageset = per_cpu_ptr(zone->pageset, i);
3dfa5721f   Christoph Lameter   Page allocator: g...
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
  		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...
1592
  #ifdef CONFIG_SMP
467c996c1   Mel Gorman   Print out statist...
1593
1594
1595
  		seq_printf(m, "
    vm stats threshold: %d",
  				pageset->stat_threshold);
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1596
  #endif
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1597
  	}
467c996c1   Mel Gorman   Print out statist...
1598
  	seq_printf(m,
599d0c954   Mel Gorman   mm, vmscan: move ...
1599
1600
  		   "
    node_unreclaimable:  %u"
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1601
1602
  		   "
    start_pfn:           %lu",
c73322d09   Johannes Weiner   mm: fix 100% CPU ...
1603
  		   pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
3a50d14d0   Andrey Ryabinin   mm: remove unused...
1604
  		   zone->zone_start_pfn);
467c996c1   Mel Gorman   Print out statist...
1605
1606
1607
1608
1609
  	seq_putc(m, '
  ');
  }
  
  /*
b2bd85981   David Rientjes   mm, vmstat: print...
1610
1611
1612
1613
   * 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...
1614
1615
1616
1617
   */
  static int zoneinfo_show(struct seq_file *m, void *arg)
  {
  	pg_data_t *pgdat = (pg_data_t *)arg;
727c080f0   Vinayak Menon   mm: avoid taking ...
1618
  	walk_zones_in_node(m, pgdat, false, false, zoneinfo_show_print);
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1619
1620
  	return 0;
  }
5c9fe6281   Alexey Dobriyan   proc: move /proc/...
1621
  static const struct seq_operations zoneinfo_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1622
1623
1624
1625
1626
1627
  	.start	= frag_start, /* iterate over all zones. The same as in
  			       * fragmentation. */
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= zoneinfo_show,
  };
79da826ae   Michael Rubin   writeback: report...
1628
1629
1630
1631
1632
  enum writeback_stat_item {
  	NR_DIRTY_THRESHOLD,
  	NR_DIRTY_BG_THRESHOLD,
  	NR_VM_WRITEBACK_STAT_ITEMS,
  };
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1633
1634
  static void *vmstat_start(struct seq_file *m, loff_t *pos)
  {
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1635
  	unsigned long *v;
79da826ae   Michael Rubin   writeback: report...
1636
  	int i, stat_items_size;
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1637
1638
1639
  
  	if (*pos >= ARRAY_SIZE(vmstat_text))
  		return NULL;
79da826ae   Michael Rubin   writeback: report...
1640
  	stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) +
3a321d2a3   Kemi Wang   mm: change the ca...
1641
  			  NR_VM_NUMA_STAT_ITEMS * sizeof(unsigned long) +
75ef71840   Mel Gorman   mm, vmstat: add i...
1642
  			  NR_VM_NODE_STAT_ITEMS * sizeof(unsigned long) +
79da826ae   Michael Rubin   writeback: report...
1643
  			  NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long);
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1644

f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1645
  #ifdef CONFIG_VM_EVENT_COUNTERS
79da826ae   Michael Rubin   writeback: report...
1646
  	stat_items_size += sizeof(struct vm_event_state);
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1647
  #endif
79da826ae   Michael Rubin   writeback: report...
1648

f0ecf25a0   Jann Horn   mm/vmstat.c: asse...
1649
1650
  	BUILD_BUG_ON(stat_items_size !=
  		     ARRAY_SIZE(vmstat_text) * sizeof(unsigned long));
79da826ae   Michael Rubin   writeback: report...
1651
  	v = kmalloc(stat_items_size, GFP_KERNEL);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1652
1653
  	m->private = v;
  	if (!v)
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1654
  		return ERR_PTR(-ENOMEM);
2244b95a7   Christoph Lameter   [PATCH] zoned vm ...
1655
  	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
c41f012ad   Michal Hocko   mm: rename global...
1656
  		v[i] = global_zone_page_state(i);
79da826ae   Michael Rubin   writeback: report...
1657
  	v += NR_VM_ZONE_STAT_ITEMS;
3a321d2a3   Kemi Wang   mm: change the ca...
1658
1659
1660
1661
1662
  #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...
1663
1664
1665
  	for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
  		v[i] = global_node_page_state(i);
  	v += NR_VM_NODE_STAT_ITEMS;
79da826ae   Michael Rubin   writeback: report...
1666
1667
1668
  	global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD,
  			    v + NR_DIRTY_THRESHOLD);
  	v += NR_VM_WRITEBACK_STAT_ITEMS;
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1669
  #ifdef CONFIG_VM_EVENT_COUNTERS
79da826ae   Michael Rubin   writeback: report...
1670
1671
1672
  	all_vm_events(v);
  	v[PGPGIN] /= 2;		/* sectors -> kbytes */
  	v[PGPGOUT] /= 2;
f8891e5e1   Christoph Lameter   [PATCH] Light wei...
1673
  #endif
ff8b16d7e   Wu Fengguang   vmstat: fix offse...
1674
  	return (unsigned long *)m->private + *pos;
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
  }
  
  static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
  {
  	(*pos)++;
  	if (*pos >= ARRAY_SIZE(vmstat_text))
  		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...
1689
1690
  
  	seq_puts(m, vmstat_text[off]);
75ba1d07f   Joe Perches   seq/proc: modify ...
1691
  	seq_put_decimal_ull(m, " ", *l);
68ba0326b   Alexey Dobriyan   proc: much faster...
1692
1693
  	seq_putc(m, '
  ');
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1694
1695
1696
1697
1698
1699
1700
1701
  	return 0;
  }
  
  static void vmstat_stop(struct seq_file *m, void *arg)
  {
  	kfree(m->private);
  	m->private = NULL;
  }
b6aa44ab6   Alexey Dobriyan   proc: move /proc/...
1702
  static const struct seq_operations vmstat_op = {
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1703
1704
1705
1706
1707
  	.start	= vmstat_start,
  	.next	= vmstat_next,
  	.stop	= vmstat_stop,
  	.show	= vmstat_show,
  };
f6ac2354d   Christoph Lameter   [PATCH] zoned vm ...
1708
  #endif /* CONFIG_PROC_FS */
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1709
  #ifdef CONFIG_SMP
d1187ed21   Christoph Lameter   vmstat: use our o...
1710
  static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
77461ab33   Christoph Lameter   Make vm statistic...
1711
  int sysctl_stat_interval __read_mostly = HZ;
d1187ed21   Christoph Lameter   vmstat: use our o...
1712

52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
  #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,
  		   void __user *buffer, size_t *lenp, loff_t *ppos)
  {
  	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...
1734
  	 * Oh, and since global_zone_page_state() etc. are so careful to hide
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1735
1736
1737
1738
1739
1740
1741
  	 * 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...
1742
  		val = atomic_long_read(&vm_zone_stat[i]);
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1743
  		if (val < 0) {
c822f6223   Johannes Weiner   mm: delete NR_PAG...
1744
1745
1746
1747
  			pr_warn("%s: %s %ld
  ",
  				__func__, vmstat_text[i], val);
  			err = -EINVAL;
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1748
1749
  		}
  	}
3a321d2a3   Kemi Wang   mm: change the ca...
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
  #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
  ",
  				__func__, vmstat_text[i + NR_VM_ZONE_STAT_ITEMS], val);
  			err = -EINVAL;
  		}
  	}
  #endif
52b6f46bc   Hugh Dickins   mm: /proc/sys/vm/...
1761
1762
1763
1764
1765
1766
1767
1768
1769
  	if (err)
  		return err;
  	if (write)
  		*ppos += *lenp;
  	else
  		*lenp = 0;
  	return 0;
  }
  #endif /* CONFIG_PROC_FS */
d1187ed21   Christoph Lameter   vmstat: use our o...
1770
1771
  static void vmstat_update(struct work_struct *w)
  {
0eb77e988   Christoph Lameter   vmstat: make vmst...
1772
  	if (refresh_cpu_vm_stats(true)) {
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1773
1774
1775
1776
1777
  		/*
  		 * 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 ...
1778
  		queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
f01f17d37   Michal Hocko   mm, vmstat: make ...
1779
1780
  				this_cpu_ptr(&vmstat_work),
  				round_jiffies_relative(sysctl_stat_interval));
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1781
1782
1783
1784
  	}
  }
  
  /*
0eb77e988   Christoph Lameter   vmstat: make vmst...
1785
1786
1787
1788
   * 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...
1789
  /*
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
   * 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...
1801
  #ifdef CONFIG_NUMA
1d90ca897   Kemi Wang   mm: update NUMA c...
1802
  		BUILD_BUG_ON(sizeof(p->vm_numa_stat_diff[0]) != 2);
3a321d2a3   Kemi Wang   mm: change the ca...
1803
  #endif
638032224   Kemi Wang   mm: consider the ...
1804

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1805
1806
  		/*
  		 * The fast way of checking if there are any vmstat diffs.
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1807
  		 */
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1808
1809
  		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...
1810
  			return true;
3a321d2a3   Kemi Wang   mm: change the ca...
1811
  #ifdef CONFIG_NUMA
13c9aaf7f   Janne Huttunen   mm/vmstat.c: fix ...
1812
1813
  		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...
1814
1815
  			return true;
  #endif
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1816
1817
1818
  	}
  	return false;
  }
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1819
1820
1821
1822
1823
  /*
   * 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 ...
1824
1825
1826
1827
  void quiet_vmstat(void)
  {
  	if (system_state != SYSTEM_RUNNING)
  		return;
7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1828
  	if (!delayed_work_pending(this_cpu_ptr(&vmstat_work)))
f01f17d37   Michal Hocko   mm, vmstat: make ...
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
  		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...
1842
1843
1844
1845
1846
1847
1848
  /*
   * 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...
1849
  static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1850
1851
1852
1853
1854
1855
1856
  
  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...
1857
  	for_each_online_cpu(cpu) {
f01f17d37   Michal Hocko   mm, vmstat: make ...
1858
  		struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1859

7b8da4c7f   Christoph Lameter   vmstat: get rid o...
1860
  		if (!delayed_work_pending(dw) && need_update(cpu))
ce612879d   Michal Hocko   mm: move pcp and ...
1861
  			queue_delayed_work_on(cpu, mm_percpu_wq, dw, 0);
f01f17d37   Michal Hocko   mm, vmstat: make ...
1862
  	}
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1863
1864
1865
  	put_online_cpus();
  
  	schedule_delayed_work(&shepherd,
98f4ebb29   Anton Blanchard   mm: align vmstat_...
1866
  		round_jiffies_relative(sysctl_stat_interval));
d1187ed21   Christoph Lameter   vmstat: use our o...
1867
  }
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1868
  static void __init start_shepherd_timer(void)
d1187ed21   Christoph Lameter   vmstat: use our o...
1869
  {
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1870
1871
1872
  	int cpu;
  
  	for_each_possible_cpu(cpu)
ccde8bd40   Michal Hocko   vmstat: make vmst...
1873
  		INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1874
  			vmstat_update);
7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1875
1876
  	schedule_delayed_work(&shepherd,
  		round_jiffies_relative(sysctl_stat_interval));
d1187ed21   Christoph Lameter   vmstat: use our o...
1877
  }
03e86dba5   Tim Chen   cpu: fix node sta...
1878
1879
  static void __init init_cpu_node_state(void)
  {
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1880
  	int node;
03e86dba5   Tim Chen   cpu: fix node sta...
1881

4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1882
1883
1884
1885
  	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...
1886
  }
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
  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...
1901
  {
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1902
  	const struct cpumask *node_cpus;
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1903
  	int node;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1904

5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1905
1906
1907
  	node = cpu_to_node(cpu);
  
  	refresh_zone_stat_thresholds();
4c501327b   Sebastian Andrzej Siewior   mm/vmstat: Avoid ...
1908
1909
  	node_cpus = cpumask_of_node(node);
  	if (cpumask_weight(node_cpus) > 0)
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1910
  		return 0;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1911
1912
  
  	node_clear_state(node, N_CPU);
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1913
  	return 0;
807a1bd2b   Toshi Kani   mm: clear N_CPU f...
1914
  }
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1915
  #endif
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1916

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

80d136e13   Michal Hocko   mm: make mm_percp...
1922
  	mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0);
ce612879d   Michal Hocko   mm: move pcp and ...
1923
1924
  
  #ifdef CONFIG_SMP
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
  	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...
1939
  	init_cpu_node_state();
5438da977   Sebastian Andrzej Siewior   mm/vmstat: Conver...
1940
  	put_online_cpus();
d1187ed21   Christoph Lameter   vmstat: use our o...
1941

7cc36bbdd   Christoph Lameter   vmstat: on-demand...
1942
  	start_shepherd_timer();
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1943
1944
  #endif
  #ifdef CONFIG_PROC_FS
fddda2b7b   Christoph Hellwig   proc: introduce p...
1945
  	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
abaed0112   Michal Hocko   mm, vmstat: hide ...
1946
  	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
fddda2b7b   Christoph Hellwig   proc: introduce p...
1947
1948
  	proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
  	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
8f32f7e5a   Alexey Dobriyan   proc: move /proc/...
1949
  #endif
df9ecaba3   Christoph Lameter   [PATCH] ZVC: Scal...
1950
  }
d7a5752c0   Mel Gorman   mm: export unusab...
1951
1952
  
  #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
d7a5752c0   Mel Gorman   mm: export unusab...
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
  
  /*
   * 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...
2010
  	if (!node_state(pgdat->node_id, N_MEMORY))
d7a5752c0   Mel Gorman   mm: export unusab...
2011
  		return 0;
727c080f0   Vinayak Menon   mm: avoid taking ...
2012
  	walk_zones_in_node(m, pgdat, true, false, unusable_show_print);
d7a5752c0   Mel Gorman   mm: export unusab...
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
  
  	return 0;
  }
  
  static const struct seq_operations unusable_op = {
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= unusable_show,
  };
  
  static int unusable_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &unusable_op);
  }
  
  static const struct file_operations unusable_file_ops = {
  	.open		= unusable_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
f1a5ab121   Mel Gorman   mm: export fragme...
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
  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...
2049
  		index = __fragmentation_index(order, &info);
f1a5ab121   Mel Gorman   mm: export fragme...
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
  		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 ...
2063
  	walk_zones_in_node(m, pgdat, true, false, extfrag_show_print);
f1a5ab121   Mel Gorman   mm: export fragme...
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
  
  	return 0;
  }
  
  static const struct seq_operations extfrag_op = {
  	.start	= frag_start,
  	.next	= frag_next,
  	.stop	= frag_stop,
  	.show	= extfrag_show,
  };
  
  static int extfrag_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &extfrag_op);
  }
  
  static const struct file_operations extfrag_file_ops = {
  	.open		= extfrag_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
d7a5752c0   Mel Gorman   mm: export unusab...
2086
2087
  static int __init extfrag_debug_init(void)
  {
bde8bd8a1   Sasikantha babu   mm/vmstat.c: remo...
2088
  	struct dentry *extfrag_debug_root;
d7a5752c0   Mel Gorman   mm: export unusab...
2089
  	extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
d7a5752c0   Mel Gorman   mm: export unusab...
2090

d9f7979c9   Greg Kroah-Hartman   mm: no need to ch...
2091
2092
  	debugfs_create_file("unusable_index", 0444, extfrag_debug_root, NULL,
  			    &unusable_file_ops);
d7a5752c0   Mel Gorman   mm: export unusab...
2093

d9f7979c9   Greg Kroah-Hartman   mm: no need to ch...
2094
2095
  	debugfs_create_file("extfrag_index", 0444, extfrag_debug_root, NULL,
  			    &extfrag_file_ops);
f1a5ab121   Mel Gorman   mm: export fragme...
2096

d7a5752c0   Mel Gorman   mm: export unusab...
2097
2098
2099
2100
2101
  	return 0;
  }
  
  module_init(extfrag_debug_init);
  #endif