xref: /linux/mm/vmstat.c (revision 2244b95a7bcf8d24196f8a3a44187ba5dfff754c)
1f6ac2354SChristoph Lameter /*
2f6ac2354SChristoph Lameter  *  linux/mm/vmstat.c
3f6ac2354SChristoph Lameter  *
4f6ac2354SChristoph Lameter  *  Manages VM statistics
5f6ac2354SChristoph Lameter  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
6*2244b95aSChristoph Lameter  *
7*2244b95aSChristoph Lameter  *  zoned VM statistics
8*2244b95aSChristoph Lameter  *  Copyright (C) 2006 Silicon Graphics, Inc.,
9*2244b95aSChristoph Lameter  *		Christoph Lameter <christoph@lameter.com>
10f6ac2354SChristoph Lameter  */
11f6ac2354SChristoph Lameter 
12f6ac2354SChristoph Lameter #include <linux/config.h>
13f6ac2354SChristoph Lameter #include <linux/mm.h>
14*2244b95aSChristoph Lameter #include <linux/module.h>
15f6ac2354SChristoph Lameter 
16f6ac2354SChristoph Lameter /*
17f6ac2354SChristoph Lameter  * Accumulate the page_state information across all CPUs.
18f6ac2354SChristoph Lameter  * The result is unavoidably approximate - it can change
19f6ac2354SChristoph Lameter  * during and after execution of this function.
20f6ac2354SChristoph Lameter  */
21f6ac2354SChristoph Lameter DEFINE_PER_CPU(struct page_state, page_states) = {0};
22f6ac2354SChristoph Lameter 
23f6ac2354SChristoph Lameter atomic_t nr_pagecache = ATOMIC_INIT(0);
24f6ac2354SChristoph Lameter EXPORT_SYMBOL(nr_pagecache);
25f6ac2354SChristoph Lameter #ifdef CONFIG_SMP
26f6ac2354SChristoph Lameter DEFINE_PER_CPU(long, nr_pagecache_local) = 0;
27f6ac2354SChristoph Lameter #endif
28f6ac2354SChristoph Lameter 
29f6ac2354SChristoph Lameter static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
30f6ac2354SChristoph Lameter {
31f6ac2354SChristoph Lameter 	unsigned cpu;
32f6ac2354SChristoph Lameter 
33f6ac2354SChristoph Lameter 	memset(ret, 0, nr * sizeof(unsigned long));
34f6ac2354SChristoph Lameter 	cpus_and(*cpumask, *cpumask, cpu_online_map);
35f6ac2354SChristoph Lameter 
36f6ac2354SChristoph Lameter 	for_each_cpu_mask(cpu, *cpumask) {
37f6ac2354SChristoph Lameter 		unsigned long *in;
38f6ac2354SChristoph Lameter 		unsigned long *out;
39f6ac2354SChristoph Lameter 		unsigned off;
40f6ac2354SChristoph Lameter 		unsigned next_cpu;
41f6ac2354SChristoph Lameter 
42f6ac2354SChristoph Lameter 		in = (unsigned long *)&per_cpu(page_states, cpu);
43f6ac2354SChristoph Lameter 
44f6ac2354SChristoph Lameter 		next_cpu = next_cpu(cpu, *cpumask);
45f6ac2354SChristoph Lameter 		if (likely(next_cpu < NR_CPUS))
46f6ac2354SChristoph Lameter 			prefetch(&per_cpu(page_states, next_cpu));
47f6ac2354SChristoph Lameter 
48f6ac2354SChristoph Lameter 		out = (unsigned long *)ret;
49f6ac2354SChristoph Lameter 		for (off = 0; off < nr; off++)
50f6ac2354SChristoph Lameter 			*out++ += *in++;
51f6ac2354SChristoph Lameter 	}
52f6ac2354SChristoph Lameter }
53f6ac2354SChristoph Lameter 
54f6ac2354SChristoph Lameter void get_page_state_node(struct page_state *ret, int node)
55f6ac2354SChristoph Lameter {
56f6ac2354SChristoph Lameter 	int nr;
57f6ac2354SChristoph Lameter 	cpumask_t mask = node_to_cpumask(node);
58f6ac2354SChristoph Lameter 
59f6ac2354SChristoph Lameter 	nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
60f6ac2354SChristoph Lameter 	nr /= sizeof(unsigned long);
61f6ac2354SChristoph Lameter 
62f6ac2354SChristoph Lameter 	__get_page_state(ret, nr+1, &mask);
63f6ac2354SChristoph Lameter }
64f6ac2354SChristoph Lameter 
65f6ac2354SChristoph Lameter void get_page_state(struct page_state *ret)
66f6ac2354SChristoph Lameter {
67f6ac2354SChristoph Lameter 	int nr;
68f6ac2354SChristoph Lameter 	cpumask_t mask = CPU_MASK_ALL;
69f6ac2354SChristoph Lameter 
70f6ac2354SChristoph Lameter 	nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
71f6ac2354SChristoph Lameter 	nr /= sizeof(unsigned long);
72f6ac2354SChristoph Lameter 
73f6ac2354SChristoph Lameter 	__get_page_state(ret, nr + 1, &mask);
74f6ac2354SChristoph Lameter }
75f6ac2354SChristoph Lameter 
76f6ac2354SChristoph Lameter void get_full_page_state(struct page_state *ret)
77f6ac2354SChristoph Lameter {
78f6ac2354SChristoph Lameter 	cpumask_t mask = CPU_MASK_ALL;
79f6ac2354SChristoph Lameter 
80f6ac2354SChristoph Lameter 	__get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask);
81f6ac2354SChristoph Lameter }
82f6ac2354SChristoph Lameter 
83f6ac2354SChristoph Lameter unsigned long read_page_state_offset(unsigned long offset)
84f6ac2354SChristoph Lameter {
85f6ac2354SChristoph Lameter 	unsigned long ret = 0;
86f6ac2354SChristoph Lameter 	int cpu;
87f6ac2354SChristoph Lameter 
88f6ac2354SChristoph Lameter 	for_each_online_cpu(cpu) {
89f6ac2354SChristoph Lameter 		unsigned long in;
90f6ac2354SChristoph Lameter 
91f6ac2354SChristoph Lameter 		in = (unsigned long)&per_cpu(page_states, cpu) + offset;
92f6ac2354SChristoph Lameter 		ret += *((unsigned long *)in);
93f6ac2354SChristoph Lameter 	}
94f6ac2354SChristoph Lameter 	return ret;
95f6ac2354SChristoph Lameter }
96f6ac2354SChristoph Lameter 
97f6ac2354SChristoph Lameter void __mod_page_state_offset(unsigned long offset, unsigned long delta)
98f6ac2354SChristoph Lameter {
99f6ac2354SChristoph Lameter 	void *ptr;
100f6ac2354SChristoph Lameter 
101f6ac2354SChristoph Lameter 	ptr = &__get_cpu_var(page_states);
102f6ac2354SChristoph Lameter 	*(unsigned long *)(ptr + offset) += delta;
103f6ac2354SChristoph Lameter }
104f6ac2354SChristoph Lameter EXPORT_SYMBOL(__mod_page_state_offset);
105f6ac2354SChristoph Lameter 
106f6ac2354SChristoph Lameter void mod_page_state_offset(unsigned long offset, unsigned long delta)
107f6ac2354SChristoph Lameter {
108f6ac2354SChristoph Lameter 	unsigned long flags;
109f6ac2354SChristoph Lameter 	void *ptr;
110f6ac2354SChristoph Lameter 
111f6ac2354SChristoph Lameter 	local_irq_save(flags);
112f6ac2354SChristoph Lameter 	ptr = &__get_cpu_var(page_states);
113f6ac2354SChristoph Lameter 	*(unsigned long *)(ptr + offset) += delta;
114f6ac2354SChristoph Lameter 	local_irq_restore(flags);
115f6ac2354SChristoph Lameter }
116f6ac2354SChristoph Lameter EXPORT_SYMBOL(mod_page_state_offset);
117f6ac2354SChristoph Lameter 
118f6ac2354SChristoph Lameter void __get_zone_counts(unsigned long *active, unsigned long *inactive,
119f6ac2354SChristoph Lameter 			unsigned long *free, struct pglist_data *pgdat)
120f6ac2354SChristoph Lameter {
121f6ac2354SChristoph Lameter 	struct zone *zones = pgdat->node_zones;
122f6ac2354SChristoph Lameter 	int i;
123f6ac2354SChristoph Lameter 
124f6ac2354SChristoph Lameter 	*active = 0;
125f6ac2354SChristoph Lameter 	*inactive = 0;
126f6ac2354SChristoph Lameter 	*free = 0;
127f6ac2354SChristoph Lameter 	for (i = 0; i < MAX_NR_ZONES; i++) {
128f6ac2354SChristoph Lameter 		*active += zones[i].nr_active;
129f6ac2354SChristoph Lameter 		*inactive += zones[i].nr_inactive;
130f6ac2354SChristoph Lameter 		*free += zones[i].free_pages;
131f6ac2354SChristoph Lameter 	}
132f6ac2354SChristoph Lameter }
133f6ac2354SChristoph Lameter 
134f6ac2354SChristoph Lameter void get_zone_counts(unsigned long *active,
135f6ac2354SChristoph Lameter 		unsigned long *inactive, unsigned long *free)
136f6ac2354SChristoph Lameter {
137f6ac2354SChristoph Lameter 	struct pglist_data *pgdat;
138f6ac2354SChristoph Lameter 
139f6ac2354SChristoph Lameter 	*active = 0;
140f6ac2354SChristoph Lameter 	*inactive = 0;
141f6ac2354SChristoph Lameter 	*free = 0;
142f6ac2354SChristoph Lameter 	for_each_online_pgdat(pgdat) {
143f6ac2354SChristoph Lameter 		unsigned long l, m, n;
144f6ac2354SChristoph Lameter 		__get_zone_counts(&l, &m, &n, pgdat);
145f6ac2354SChristoph Lameter 		*active += l;
146f6ac2354SChristoph Lameter 		*inactive += m;
147f6ac2354SChristoph Lameter 		*free += n;
148f6ac2354SChristoph Lameter 	}
149f6ac2354SChristoph Lameter }
150f6ac2354SChristoph Lameter 
151*2244b95aSChristoph Lameter /*
152*2244b95aSChristoph Lameter  * Manage combined zone based / global counters
153*2244b95aSChristoph Lameter  *
154*2244b95aSChristoph Lameter  * vm_stat contains the global counters
155*2244b95aSChristoph Lameter  */
156*2244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
157*2244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat);
158*2244b95aSChristoph Lameter 
159*2244b95aSChristoph Lameter #ifdef CONFIG_SMP
160*2244b95aSChristoph Lameter 
161*2244b95aSChristoph Lameter #define STAT_THRESHOLD 32
162*2244b95aSChristoph Lameter 
163*2244b95aSChristoph Lameter /*
164*2244b95aSChristoph Lameter  * Determine pointer to currently valid differential byte given a zone and
165*2244b95aSChristoph Lameter  * the item number.
166*2244b95aSChristoph Lameter  *
167*2244b95aSChristoph Lameter  * Preemption must be off
168*2244b95aSChristoph Lameter  */
169*2244b95aSChristoph Lameter static inline s8 *diff_pointer(struct zone *zone, enum zone_stat_item item)
170*2244b95aSChristoph Lameter {
171*2244b95aSChristoph Lameter 	return &zone_pcp(zone, smp_processor_id())->vm_stat_diff[item];
172*2244b95aSChristoph Lameter }
173*2244b95aSChristoph Lameter 
174*2244b95aSChristoph Lameter /*
175*2244b95aSChristoph Lameter  * For use when we know that interrupts are disabled.
176*2244b95aSChristoph Lameter  */
177*2244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
178*2244b95aSChristoph Lameter 				int delta)
179*2244b95aSChristoph Lameter {
180*2244b95aSChristoph Lameter 	s8 *p;
181*2244b95aSChristoph Lameter 	long x;
182*2244b95aSChristoph Lameter 
183*2244b95aSChristoph Lameter 	p = diff_pointer(zone, item);
184*2244b95aSChristoph Lameter 	x = delta + *p;
185*2244b95aSChristoph Lameter 
186*2244b95aSChristoph Lameter 	if (unlikely(x > STAT_THRESHOLD || x < -STAT_THRESHOLD)) {
187*2244b95aSChristoph Lameter 		zone_page_state_add(x, zone, item);
188*2244b95aSChristoph Lameter 		x = 0;
189*2244b95aSChristoph Lameter 	}
190*2244b95aSChristoph Lameter 
191*2244b95aSChristoph Lameter 	*p = x;
192*2244b95aSChristoph Lameter }
193*2244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
194*2244b95aSChristoph Lameter 
195*2244b95aSChristoph Lameter /*
196*2244b95aSChristoph Lameter  * For an unknown interrupt state
197*2244b95aSChristoph Lameter  */
198*2244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
199*2244b95aSChristoph Lameter 					int delta)
200*2244b95aSChristoph Lameter {
201*2244b95aSChristoph Lameter 	unsigned long flags;
202*2244b95aSChristoph Lameter 
203*2244b95aSChristoph Lameter 	local_irq_save(flags);
204*2244b95aSChristoph Lameter 	__mod_zone_page_state(zone, item, delta);
205*2244b95aSChristoph Lameter 	local_irq_restore(flags);
206*2244b95aSChristoph Lameter }
207*2244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
208*2244b95aSChristoph Lameter 
209*2244b95aSChristoph Lameter /*
210*2244b95aSChristoph Lameter  * Optimized increment and decrement functions.
211*2244b95aSChristoph Lameter  *
212*2244b95aSChristoph Lameter  * These are only for a single page and therefore can take a struct page *
213*2244b95aSChristoph Lameter  * argument instead of struct zone *. This allows the inclusion of the code
214*2244b95aSChristoph Lameter  * generated for page_zone(page) into the optimized functions.
215*2244b95aSChristoph Lameter  *
216*2244b95aSChristoph Lameter  * No overflow check is necessary and therefore the differential can be
217*2244b95aSChristoph Lameter  * incremented or decremented in place which may allow the compilers to
218*2244b95aSChristoph Lameter  * generate better code.
219*2244b95aSChristoph Lameter  *
220*2244b95aSChristoph Lameter  * The increment or decrement is known and therefore one boundary check can
221*2244b95aSChristoph Lameter  * be omitted.
222*2244b95aSChristoph Lameter  *
223*2244b95aSChristoph Lameter  * Some processors have inc/dec instructions that are atomic vs an interrupt.
224*2244b95aSChristoph Lameter  * However, the code must first determine the differential location in a zone
225*2244b95aSChristoph Lameter  * based on the processor number and then inc/dec the counter. There is no
226*2244b95aSChristoph Lameter  * guarantee without disabling preemption that the processor will not change
227*2244b95aSChristoph Lameter  * in between and therefore the atomicity vs. interrupt cannot be exploited
228*2244b95aSChristoph Lameter  * in a useful way here.
229*2244b95aSChristoph Lameter  */
230*2244b95aSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
231*2244b95aSChristoph Lameter {
232*2244b95aSChristoph Lameter 	struct zone *zone = page_zone(page);
233*2244b95aSChristoph Lameter 	s8 *p = diff_pointer(zone, item);
234*2244b95aSChristoph Lameter 
235*2244b95aSChristoph Lameter 	(*p)++;
236*2244b95aSChristoph Lameter 
237*2244b95aSChristoph Lameter 	if (unlikely(*p > STAT_THRESHOLD)) {
238*2244b95aSChristoph Lameter 		zone_page_state_add(*p, zone, item);
239*2244b95aSChristoph Lameter 		*p = 0;
240*2244b95aSChristoph Lameter 	}
241*2244b95aSChristoph Lameter }
242*2244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
243*2244b95aSChristoph Lameter 
244*2244b95aSChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
245*2244b95aSChristoph Lameter {
246*2244b95aSChristoph Lameter 	struct zone *zone = page_zone(page);
247*2244b95aSChristoph Lameter 	s8 *p = diff_pointer(zone, item);
248*2244b95aSChristoph Lameter 
249*2244b95aSChristoph Lameter 	(*p)--;
250*2244b95aSChristoph Lameter 
251*2244b95aSChristoph Lameter 	if (unlikely(*p < -STAT_THRESHOLD)) {
252*2244b95aSChristoph Lameter 		zone_page_state_add(*p, zone, item);
253*2244b95aSChristoph Lameter 		*p = 0;
254*2244b95aSChristoph Lameter 	}
255*2244b95aSChristoph Lameter }
256*2244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
257*2244b95aSChristoph Lameter 
258*2244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
259*2244b95aSChristoph Lameter {
260*2244b95aSChristoph Lameter 	unsigned long flags;
261*2244b95aSChristoph Lameter 	struct zone *zone;
262*2244b95aSChristoph Lameter 	s8 *p;
263*2244b95aSChristoph Lameter 
264*2244b95aSChristoph Lameter 	zone = page_zone(page);
265*2244b95aSChristoph Lameter 	local_irq_save(flags);
266*2244b95aSChristoph Lameter 	p = diff_pointer(zone, item);
267*2244b95aSChristoph Lameter 
268*2244b95aSChristoph Lameter 	(*p)++;
269*2244b95aSChristoph Lameter 
270*2244b95aSChristoph Lameter 	if (unlikely(*p > STAT_THRESHOLD)) {
271*2244b95aSChristoph Lameter 		zone_page_state_add(*p, zone, item);
272*2244b95aSChristoph Lameter 		*p = 0;
273*2244b95aSChristoph Lameter 	}
274*2244b95aSChristoph Lameter 	local_irq_restore(flags);
275*2244b95aSChristoph Lameter }
276*2244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
277*2244b95aSChristoph Lameter 
278*2244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
279*2244b95aSChristoph Lameter {
280*2244b95aSChristoph Lameter 	unsigned long flags;
281*2244b95aSChristoph Lameter 	struct zone *zone;
282*2244b95aSChristoph Lameter 	s8 *p;
283*2244b95aSChristoph Lameter 
284*2244b95aSChristoph Lameter 	zone = page_zone(page);
285*2244b95aSChristoph Lameter 	local_irq_save(flags);
286*2244b95aSChristoph Lameter 	p = diff_pointer(zone, item);
287*2244b95aSChristoph Lameter 
288*2244b95aSChristoph Lameter 	(*p)--;
289*2244b95aSChristoph Lameter 
290*2244b95aSChristoph Lameter 	if (unlikely(*p < -STAT_THRESHOLD)) {
291*2244b95aSChristoph Lameter 		zone_page_state_add(*p, zone, item);
292*2244b95aSChristoph Lameter 		*p = 0;
293*2244b95aSChristoph Lameter 	}
294*2244b95aSChristoph Lameter 	local_irq_restore(flags);
295*2244b95aSChristoph Lameter }
296*2244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
297*2244b95aSChristoph Lameter 
298*2244b95aSChristoph Lameter /*
299*2244b95aSChristoph Lameter  * Update the zone counters for one cpu.
300*2244b95aSChristoph Lameter  */
301*2244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu)
302*2244b95aSChristoph Lameter {
303*2244b95aSChristoph Lameter 	struct zone *zone;
304*2244b95aSChristoph Lameter 	int i;
305*2244b95aSChristoph Lameter 	unsigned long flags;
306*2244b95aSChristoph Lameter 
307*2244b95aSChristoph Lameter 	for_each_zone(zone) {
308*2244b95aSChristoph Lameter 		struct per_cpu_pageset *pcp;
309*2244b95aSChristoph Lameter 
310*2244b95aSChristoph Lameter 		pcp = zone_pcp(zone, cpu);
311*2244b95aSChristoph Lameter 
312*2244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
313*2244b95aSChristoph Lameter 			if (pcp->vm_stat_diff[i]) {
314*2244b95aSChristoph Lameter 				local_irq_save(flags);
315*2244b95aSChristoph Lameter 				zone_page_state_add(pcp->vm_stat_diff[i],
316*2244b95aSChristoph Lameter 					zone, i);
317*2244b95aSChristoph Lameter 				pcp->vm_stat_diff[i] = 0;
318*2244b95aSChristoph Lameter 				local_irq_restore(flags);
319*2244b95aSChristoph Lameter 			}
320*2244b95aSChristoph Lameter 	}
321*2244b95aSChristoph Lameter }
322*2244b95aSChristoph Lameter 
323*2244b95aSChristoph Lameter static void __refresh_cpu_vm_stats(void *dummy)
324*2244b95aSChristoph Lameter {
325*2244b95aSChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
326*2244b95aSChristoph Lameter }
327*2244b95aSChristoph Lameter 
328*2244b95aSChristoph Lameter /*
329*2244b95aSChristoph Lameter  * Consolidate all counters.
330*2244b95aSChristoph Lameter  *
331*2244b95aSChristoph Lameter  * Note that the result is less inaccurate but still inaccurate
332*2244b95aSChristoph Lameter  * if concurrent processes are allowed to run.
333*2244b95aSChristoph Lameter  */
334*2244b95aSChristoph Lameter void refresh_vm_stats(void)
335*2244b95aSChristoph Lameter {
336*2244b95aSChristoph Lameter 	on_each_cpu(__refresh_cpu_vm_stats, NULL, 0, 1);
337*2244b95aSChristoph Lameter }
338*2244b95aSChristoph Lameter EXPORT_SYMBOL(refresh_vm_stats);
339*2244b95aSChristoph Lameter 
340*2244b95aSChristoph Lameter #endif
341*2244b95aSChristoph Lameter 
342f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS
343f6ac2354SChristoph Lameter 
344f6ac2354SChristoph Lameter #include <linux/seq_file.h>
345f6ac2354SChristoph Lameter 
346f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos)
347f6ac2354SChristoph Lameter {
348f6ac2354SChristoph Lameter 	pg_data_t *pgdat;
349f6ac2354SChristoph Lameter 	loff_t node = *pos;
350f6ac2354SChristoph Lameter 	for (pgdat = first_online_pgdat();
351f6ac2354SChristoph Lameter 	     pgdat && node;
352f6ac2354SChristoph Lameter 	     pgdat = next_online_pgdat(pgdat))
353f6ac2354SChristoph Lameter 		--node;
354f6ac2354SChristoph Lameter 
355f6ac2354SChristoph Lameter 	return pgdat;
356f6ac2354SChristoph Lameter }
357f6ac2354SChristoph Lameter 
358f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
359f6ac2354SChristoph Lameter {
360f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
361f6ac2354SChristoph Lameter 
362f6ac2354SChristoph Lameter 	(*pos)++;
363f6ac2354SChristoph Lameter 	return next_online_pgdat(pgdat);
364f6ac2354SChristoph Lameter }
365f6ac2354SChristoph Lameter 
366f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg)
367f6ac2354SChristoph Lameter {
368f6ac2354SChristoph Lameter }
369f6ac2354SChristoph Lameter 
370f6ac2354SChristoph Lameter /*
371f6ac2354SChristoph Lameter  * This walks the free areas for each zone.
372f6ac2354SChristoph Lameter  */
373f6ac2354SChristoph Lameter static int frag_show(struct seq_file *m, void *arg)
374f6ac2354SChristoph Lameter {
375f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
376f6ac2354SChristoph Lameter 	struct zone *zone;
377f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
378f6ac2354SChristoph Lameter 	unsigned long flags;
379f6ac2354SChristoph Lameter 	int order;
380f6ac2354SChristoph Lameter 
381f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
382f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
383f6ac2354SChristoph Lameter 			continue;
384f6ac2354SChristoph Lameter 
385f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
386f6ac2354SChristoph Lameter 		seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
387f6ac2354SChristoph Lameter 		for (order = 0; order < MAX_ORDER; ++order)
388f6ac2354SChristoph Lameter 			seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
389f6ac2354SChristoph Lameter 		spin_unlock_irqrestore(&zone->lock, flags);
390f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
391f6ac2354SChristoph Lameter 	}
392f6ac2354SChristoph Lameter 	return 0;
393f6ac2354SChristoph Lameter }
394f6ac2354SChristoph Lameter 
395f6ac2354SChristoph Lameter struct seq_operations fragmentation_op = {
396f6ac2354SChristoph Lameter 	.start	= frag_start,
397f6ac2354SChristoph Lameter 	.next	= frag_next,
398f6ac2354SChristoph Lameter 	.stop	= frag_stop,
399f6ac2354SChristoph Lameter 	.show	= frag_show,
400f6ac2354SChristoph Lameter };
401f6ac2354SChristoph Lameter 
402f6ac2354SChristoph Lameter static char *vmstat_text[] = {
403*2244b95aSChristoph Lameter 	/* Zoned VM counters */
404*2244b95aSChristoph Lameter 
405*2244b95aSChristoph Lameter 	/* Page state */
406f6ac2354SChristoph Lameter 	"nr_dirty",
407f6ac2354SChristoph Lameter 	"nr_writeback",
408f6ac2354SChristoph Lameter 	"nr_unstable",
409f6ac2354SChristoph Lameter 	"nr_page_table_pages",
410f6ac2354SChristoph Lameter 	"nr_mapped",
411f6ac2354SChristoph Lameter 	"nr_slab",
412f6ac2354SChristoph Lameter 
413f6ac2354SChristoph Lameter 	"pgpgin",
414f6ac2354SChristoph Lameter 	"pgpgout",
415f6ac2354SChristoph Lameter 	"pswpin",
416f6ac2354SChristoph Lameter 	"pswpout",
417f6ac2354SChristoph Lameter 
418f6ac2354SChristoph Lameter 	"pgalloc_high",
419f6ac2354SChristoph Lameter 	"pgalloc_normal",
420f6ac2354SChristoph Lameter 	"pgalloc_dma32",
421f6ac2354SChristoph Lameter 	"pgalloc_dma",
422f6ac2354SChristoph Lameter 
423f6ac2354SChristoph Lameter 	"pgfree",
424f6ac2354SChristoph Lameter 	"pgactivate",
425f6ac2354SChristoph Lameter 	"pgdeactivate",
426f6ac2354SChristoph Lameter 
427f6ac2354SChristoph Lameter 	"pgfault",
428f6ac2354SChristoph Lameter 	"pgmajfault",
429f6ac2354SChristoph Lameter 
430f6ac2354SChristoph Lameter 	"pgrefill_high",
431f6ac2354SChristoph Lameter 	"pgrefill_normal",
432f6ac2354SChristoph Lameter 	"pgrefill_dma32",
433f6ac2354SChristoph Lameter 	"pgrefill_dma",
434f6ac2354SChristoph Lameter 
435f6ac2354SChristoph Lameter 	"pgsteal_high",
436f6ac2354SChristoph Lameter 	"pgsteal_normal",
437f6ac2354SChristoph Lameter 	"pgsteal_dma32",
438f6ac2354SChristoph Lameter 	"pgsteal_dma",
439f6ac2354SChristoph Lameter 
440f6ac2354SChristoph Lameter 	"pgscan_kswapd_high",
441f6ac2354SChristoph Lameter 	"pgscan_kswapd_normal",
442f6ac2354SChristoph Lameter 	"pgscan_kswapd_dma32",
443f6ac2354SChristoph Lameter 	"pgscan_kswapd_dma",
444f6ac2354SChristoph Lameter 
445f6ac2354SChristoph Lameter 	"pgscan_direct_high",
446f6ac2354SChristoph Lameter 	"pgscan_direct_normal",
447f6ac2354SChristoph Lameter 	"pgscan_direct_dma32",
448f6ac2354SChristoph Lameter 	"pgscan_direct_dma",
449f6ac2354SChristoph Lameter 
450f6ac2354SChristoph Lameter 	"pginodesteal",
451f6ac2354SChristoph Lameter 	"slabs_scanned",
452f6ac2354SChristoph Lameter 	"kswapd_steal",
453f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
454f6ac2354SChristoph Lameter 	"pageoutrun",
455f6ac2354SChristoph Lameter 	"allocstall",
456f6ac2354SChristoph Lameter 
457f6ac2354SChristoph Lameter 	"pgrotated",
458f6ac2354SChristoph Lameter 	"nr_bounce",
459f6ac2354SChristoph Lameter };
460f6ac2354SChristoph Lameter 
461f6ac2354SChristoph Lameter /*
462f6ac2354SChristoph Lameter  * Output information about zones in @pgdat.
463f6ac2354SChristoph Lameter  */
464f6ac2354SChristoph Lameter static int zoneinfo_show(struct seq_file *m, void *arg)
465f6ac2354SChristoph Lameter {
466f6ac2354SChristoph Lameter 	pg_data_t *pgdat = arg;
467f6ac2354SChristoph Lameter 	struct zone *zone;
468f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
469f6ac2354SChristoph Lameter 	unsigned long flags;
470f6ac2354SChristoph Lameter 
471f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
472f6ac2354SChristoph Lameter 		int i;
473f6ac2354SChristoph Lameter 
474f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
475f6ac2354SChristoph Lameter 			continue;
476f6ac2354SChristoph Lameter 
477f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
478f6ac2354SChristoph Lameter 		seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
479f6ac2354SChristoph Lameter 		seq_printf(m,
480f6ac2354SChristoph Lameter 			   "\n  pages free     %lu"
481f6ac2354SChristoph Lameter 			   "\n        min      %lu"
482f6ac2354SChristoph Lameter 			   "\n        low      %lu"
483f6ac2354SChristoph Lameter 			   "\n        high     %lu"
484f6ac2354SChristoph Lameter 			   "\n        active   %lu"
485f6ac2354SChristoph Lameter 			   "\n        inactive %lu"
486f6ac2354SChristoph Lameter 			   "\n        scanned  %lu (a: %lu i: %lu)"
487f6ac2354SChristoph Lameter 			   "\n        spanned  %lu"
488f6ac2354SChristoph Lameter 			   "\n        present  %lu",
489f6ac2354SChristoph Lameter 			   zone->free_pages,
490f6ac2354SChristoph Lameter 			   zone->pages_min,
491f6ac2354SChristoph Lameter 			   zone->pages_low,
492f6ac2354SChristoph Lameter 			   zone->pages_high,
493f6ac2354SChristoph Lameter 			   zone->nr_active,
494f6ac2354SChristoph Lameter 			   zone->nr_inactive,
495f6ac2354SChristoph Lameter 			   zone->pages_scanned,
496f6ac2354SChristoph Lameter 			   zone->nr_scan_active, zone->nr_scan_inactive,
497f6ac2354SChristoph Lameter 			   zone->spanned_pages,
498f6ac2354SChristoph Lameter 			   zone->present_pages);
499*2244b95aSChristoph Lameter 
500*2244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
501*2244b95aSChristoph Lameter 			seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
502*2244b95aSChristoph Lameter 					zone_page_state(zone, i));
503*2244b95aSChristoph Lameter 
504f6ac2354SChristoph Lameter 		seq_printf(m,
505f6ac2354SChristoph Lameter 			   "\n        protection: (%lu",
506f6ac2354SChristoph Lameter 			   zone->lowmem_reserve[0]);
507f6ac2354SChristoph Lameter 		for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
508f6ac2354SChristoph Lameter 			seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
509f6ac2354SChristoph Lameter 		seq_printf(m,
510f6ac2354SChristoph Lameter 			   ")"
511f6ac2354SChristoph Lameter 			   "\n  pagesets");
512f6ac2354SChristoph Lameter 		for_each_online_cpu(i) {
513f6ac2354SChristoph Lameter 			struct per_cpu_pageset *pageset;
514f6ac2354SChristoph Lameter 			int j;
515f6ac2354SChristoph Lameter 
516f6ac2354SChristoph Lameter 			pageset = zone_pcp(zone, i);
517f6ac2354SChristoph Lameter 			for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
518f6ac2354SChristoph Lameter 				if (pageset->pcp[j].count)
519f6ac2354SChristoph Lameter 					break;
520f6ac2354SChristoph Lameter 			}
521f6ac2354SChristoph Lameter 			if (j == ARRAY_SIZE(pageset->pcp))
522f6ac2354SChristoph Lameter 				continue;
523f6ac2354SChristoph Lameter 			for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
524f6ac2354SChristoph Lameter 				seq_printf(m,
525f6ac2354SChristoph Lameter 					   "\n    cpu: %i pcp: %i"
526f6ac2354SChristoph Lameter 					   "\n              count: %i"
527f6ac2354SChristoph Lameter 					   "\n              high:  %i"
528f6ac2354SChristoph Lameter 					   "\n              batch: %i",
529f6ac2354SChristoph Lameter 					   i, j,
530f6ac2354SChristoph Lameter 					   pageset->pcp[j].count,
531f6ac2354SChristoph Lameter 					   pageset->pcp[j].high,
532f6ac2354SChristoph Lameter 					   pageset->pcp[j].batch);
533f6ac2354SChristoph Lameter 			}
534f6ac2354SChristoph Lameter #ifdef CONFIG_NUMA
535f6ac2354SChristoph Lameter 			seq_printf(m,
536f6ac2354SChristoph Lameter 				   "\n            numa_hit:       %lu"
537f6ac2354SChristoph Lameter 				   "\n            numa_miss:      %lu"
538f6ac2354SChristoph Lameter 				   "\n            numa_foreign:   %lu"
539f6ac2354SChristoph Lameter 				   "\n            interleave_hit: %lu"
540f6ac2354SChristoph Lameter 				   "\n            local_node:     %lu"
541f6ac2354SChristoph Lameter 				   "\n            other_node:     %lu",
542f6ac2354SChristoph Lameter 				   pageset->numa_hit,
543f6ac2354SChristoph Lameter 				   pageset->numa_miss,
544f6ac2354SChristoph Lameter 				   pageset->numa_foreign,
545f6ac2354SChristoph Lameter 				   pageset->interleave_hit,
546f6ac2354SChristoph Lameter 				   pageset->local_node,
547f6ac2354SChristoph Lameter 				   pageset->other_node);
548f6ac2354SChristoph Lameter #endif
549f6ac2354SChristoph Lameter 		}
550f6ac2354SChristoph Lameter 		seq_printf(m,
551f6ac2354SChristoph Lameter 			   "\n  all_unreclaimable: %u"
552f6ac2354SChristoph Lameter 			   "\n  prev_priority:     %i"
553f6ac2354SChristoph Lameter 			   "\n  temp_priority:     %i"
554f6ac2354SChristoph Lameter 			   "\n  start_pfn:         %lu",
555f6ac2354SChristoph Lameter 			   zone->all_unreclaimable,
556f6ac2354SChristoph Lameter 			   zone->prev_priority,
557f6ac2354SChristoph Lameter 			   zone->temp_priority,
558f6ac2354SChristoph Lameter 			   zone->zone_start_pfn);
559f6ac2354SChristoph Lameter 		spin_unlock_irqrestore(&zone->lock, flags);
560f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
561f6ac2354SChristoph Lameter 	}
562f6ac2354SChristoph Lameter 	return 0;
563f6ac2354SChristoph Lameter }
564f6ac2354SChristoph Lameter 
565f6ac2354SChristoph Lameter struct seq_operations zoneinfo_op = {
566f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
567f6ac2354SChristoph Lameter 			       * fragmentation. */
568f6ac2354SChristoph Lameter 	.next	= frag_next,
569f6ac2354SChristoph Lameter 	.stop	= frag_stop,
570f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
571f6ac2354SChristoph Lameter };
572f6ac2354SChristoph Lameter 
573f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
574f6ac2354SChristoph Lameter {
575*2244b95aSChristoph Lameter 	unsigned long *v;
576f6ac2354SChristoph Lameter 	struct page_state *ps;
577*2244b95aSChristoph Lameter 	int i;
578f6ac2354SChristoph Lameter 
579f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
580f6ac2354SChristoph Lameter 		return NULL;
581f6ac2354SChristoph Lameter 
582*2244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
583*2244b95aSChristoph Lameter 			+ sizeof(*ps), GFP_KERNEL);
584*2244b95aSChristoph Lameter 	m->private = v;
585*2244b95aSChristoph Lameter 	if (!v)
586f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
587*2244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
588*2244b95aSChristoph Lameter 		v[i] = global_page_state(i);
589*2244b95aSChristoph Lameter 	ps = (struct page_state *)(v + NR_VM_ZONE_STAT_ITEMS);
590f6ac2354SChristoph Lameter 	get_full_page_state(ps);
591f6ac2354SChristoph Lameter 	ps->pgpgin /= 2;		/* sectors -> kbytes */
592f6ac2354SChristoph Lameter 	ps->pgpgout /= 2;
593*2244b95aSChristoph Lameter 	return v + *pos;
594f6ac2354SChristoph Lameter }
595f6ac2354SChristoph Lameter 
596f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
597f6ac2354SChristoph Lameter {
598f6ac2354SChristoph Lameter 	(*pos)++;
599f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
600f6ac2354SChristoph Lameter 		return NULL;
601f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
602f6ac2354SChristoph Lameter }
603f6ac2354SChristoph Lameter 
604f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
605f6ac2354SChristoph Lameter {
606f6ac2354SChristoph Lameter 	unsigned long *l = arg;
607f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
608f6ac2354SChristoph Lameter 
609f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
610f6ac2354SChristoph Lameter 	return 0;
611f6ac2354SChristoph Lameter }
612f6ac2354SChristoph Lameter 
613f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
614f6ac2354SChristoph Lameter {
615f6ac2354SChristoph Lameter 	kfree(m->private);
616f6ac2354SChristoph Lameter 	m->private = NULL;
617f6ac2354SChristoph Lameter }
618f6ac2354SChristoph Lameter 
619f6ac2354SChristoph Lameter struct seq_operations vmstat_op = {
620f6ac2354SChristoph Lameter 	.start	= vmstat_start,
621f6ac2354SChristoph Lameter 	.next	= vmstat_next,
622f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
623f6ac2354SChristoph Lameter 	.show	= vmstat_show,
624f6ac2354SChristoph Lameter };
625f6ac2354SChristoph Lameter 
626f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
627f6ac2354SChristoph Lameter 
628