xref: /linux/mm/vmstat.c (revision ad596925eaf9a48ed61bc9210088828f1f8e0552)
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
62244b95aSChristoph Lameter  *
72244b95aSChristoph Lameter  *  zoned VM statistics
82244b95aSChristoph Lameter  *  Copyright (C) 2006 Silicon Graphics, Inc.,
92244b95aSChristoph Lameter  *		Christoph Lameter <christoph@lameter.com>
10f6ac2354SChristoph Lameter  */
118f32f7e5SAlexey Dobriyan #include <linux/fs.h>
12f6ac2354SChristoph Lameter #include <linux/mm.h>
134e950f6fSAlexey Dobriyan #include <linux/err.h>
142244b95aSChristoph Lameter #include <linux/module.h>
15df9ecabaSChristoph Lameter #include <linux/cpu.h>
16c748e134SAdrian Bunk #include <linux/vmstat.h>
17e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
18f6ac2354SChristoph Lameter 
19f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
20f8891e5eSChristoph Lameter DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
21f8891e5eSChristoph Lameter EXPORT_PER_CPU_SYMBOL(vm_event_states);
22f8891e5eSChristoph Lameter 
23174596a0SRusty Russell static void sum_vm_events(unsigned long *ret, const struct cpumask *cpumask)
24f8891e5eSChristoph Lameter {
259eccf2a8SChristoph Lameter 	int cpu;
26f8891e5eSChristoph Lameter 	int i;
27f8891e5eSChristoph Lameter 
28f8891e5eSChristoph Lameter 	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
29f8891e5eSChristoph Lameter 
30aa85ea5bSRusty Russell 	for_each_cpu(cpu, cpumask) {
31f8891e5eSChristoph Lameter 		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
32f8891e5eSChristoph Lameter 
33f8891e5eSChristoph Lameter 		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
34f8891e5eSChristoph Lameter 			ret[i] += this->event[i];
35f8891e5eSChristoph Lameter 	}
36f8891e5eSChristoph Lameter }
37f8891e5eSChristoph Lameter 
38f8891e5eSChristoph Lameter /*
39f8891e5eSChristoph Lameter  * Accumulate the vm event counters across all CPUs.
40f8891e5eSChristoph Lameter  * The result is unavoidably approximate - it can change
41f8891e5eSChristoph Lameter  * during and after execution of this function.
42f8891e5eSChristoph Lameter */
43f8891e5eSChristoph Lameter void all_vm_events(unsigned long *ret)
44f8891e5eSChristoph Lameter {
45b5be1132SKOSAKI Motohiro 	get_online_cpus();
46174596a0SRusty Russell 	sum_vm_events(ret, cpu_online_mask);
47b5be1132SKOSAKI Motohiro 	put_online_cpus();
48f8891e5eSChristoph Lameter }
4932dd66fcSHeiko Carstens EXPORT_SYMBOL_GPL(all_vm_events);
50f8891e5eSChristoph Lameter 
51f8891e5eSChristoph Lameter #ifdef CONFIG_HOTPLUG
52f8891e5eSChristoph Lameter /*
53f8891e5eSChristoph Lameter  * Fold the foreign cpu events into our own.
54f8891e5eSChristoph Lameter  *
55f8891e5eSChristoph Lameter  * This is adding to the events on one processor
56f8891e5eSChristoph Lameter  * but keeps the global counts constant.
57f8891e5eSChristoph Lameter  */
58f8891e5eSChristoph Lameter void vm_events_fold_cpu(int cpu)
59f8891e5eSChristoph Lameter {
60f8891e5eSChristoph Lameter 	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
61f8891e5eSChristoph Lameter 	int i;
62f8891e5eSChristoph Lameter 
63f8891e5eSChristoph Lameter 	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
64f8891e5eSChristoph Lameter 		count_vm_events(i, fold_state->event[i]);
65f8891e5eSChristoph Lameter 		fold_state->event[i] = 0;
66f8891e5eSChristoph Lameter 	}
67f8891e5eSChristoph Lameter }
68f8891e5eSChristoph Lameter #endif /* CONFIG_HOTPLUG */
69f8891e5eSChristoph Lameter 
70f8891e5eSChristoph Lameter #endif /* CONFIG_VM_EVENT_COUNTERS */
71f8891e5eSChristoph Lameter 
722244b95aSChristoph Lameter /*
732244b95aSChristoph Lameter  * Manage combined zone based / global counters
742244b95aSChristoph Lameter  *
752244b95aSChristoph Lameter  * vm_stat contains the global counters
762244b95aSChristoph Lameter  */
772244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
782244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat);
792244b95aSChristoph Lameter 
802244b95aSChristoph Lameter #ifdef CONFIG_SMP
812244b95aSChristoph Lameter 
82df9ecabaSChristoph Lameter static int calculate_threshold(struct zone *zone)
83df9ecabaSChristoph Lameter {
84df9ecabaSChristoph Lameter 	int threshold;
85df9ecabaSChristoph Lameter 	int mem;	/* memory in 128 MB units */
862244b95aSChristoph Lameter 
872244b95aSChristoph Lameter 	/*
88df9ecabaSChristoph Lameter 	 * The threshold scales with the number of processors and the amount
89df9ecabaSChristoph Lameter 	 * of memory per zone. More memory means that we can defer updates for
90df9ecabaSChristoph Lameter 	 * longer, more processors could lead to more contention.
91df9ecabaSChristoph Lameter  	 * fls() is used to have a cheap way of logarithmic scaling.
922244b95aSChristoph Lameter 	 *
93df9ecabaSChristoph Lameter 	 * Some sample thresholds:
94df9ecabaSChristoph Lameter 	 *
95df9ecabaSChristoph Lameter 	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
96df9ecabaSChristoph Lameter 	 * ------------------------------------------------------------------
97df9ecabaSChristoph Lameter 	 * 8		1		1	0.9-1 GB	4
98df9ecabaSChristoph Lameter 	 * 16		2		2	0.9-1 GB	4
99df9ecabaSChristoph Lameter 	 * 20 		2		2	1-2 GB		5
100df9ecabaSChristoph Lameter 	 * 24		2		2	2-4 GB		6
101df9ecabaSChristoph Lameter 	 * 28		2		2	4-8 GB		7
102df9ecabaSChristoph Lameter 	 * 32		2		2	8-16 GB		8
103df9ecabaSChristoph Lameter 	 * 4		2		2	<128M		1
104df9ecabaSChristoph Lameter 	 * 30		4		3	2-4 GB		5
105df9ecabaSChristoph Lameter 	 * 48		4		3	8-16 GB		8
106df9ecabaSChristoph Lameter 	 * 32		8		4	1-2 GB		4
107df9ecabaSChristoph Lameter 	 * 32		8		4	0.9-1GB		4
108df9ecabaSChristoph Lameter 	 * 10		16		5	<128M		1
109df9ecabaSChristoph Lameter 	 * 40		16		5	900M		4
110df9ecabaSChristoph Lameter 	 * 70		64		7	2-4 GB		5
111df9ecabaSChristoph Lameter 	 * 84		64		7	4-8 GB		6
112df9ecabaSChristoph Lameter 	 * 108		512		9	4-8 GB		6
113df9ecabaSChristoph Lameter 	 * 125		1024		10	8-16 GB		8
114df9ecabaSChristoph Lameter 	 * 125		1024		10	16-32 GB	9
1152244b95aSChristoph Lameter 	 */
116df9ecabaSChristoph Lameter 
117df9ecabaSChristoph Lameter 	mem = zone->present_pages >> (27 - PAGE_SHIFT);
118df9ecabaSChristoph Lameter 
119df9ecabaSChristoph Lameter 	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
120df9ecabaSChristoph Lameter 
121df9ecabaSChristoph Lameter 	/*
122df9ecabaSChristoph Lameter 	 * Maximum threshold is 125
123df9ecabaSChristoph Lameter 	 */
124df9ecabaSChristoph Lameter 	threshold = min(125, threshold);
125df9ecabaSChristoph Lameter 
126df9ecabaSChristoph Lameter 	return threshold;
127df9ecabaSChristoph Lameter }
128df9ecabaSChristoph Lameter 
129df9ecabaSChristoph Lameter /*
130df9ecabaSChristoph Lameter  * Refresh the thresholds for each zone.
131df9ecabaSChristoph Lameter  */
132df9ecabaSChristoph Lameter static void refresh_zone_stat_thresholds(void)
1332244b95aSChristoph Lameter {
134df9ecabaSChristoph Lameter 	struct zone *zone;
135df9ecabaSChristoph Lameter 	int cpu;
136df9ecabaSChristoph Lameter 	int threshold;
137df9ecabaSChristoph Lameter 
138ee99c71cSKOSAKI Motohiro 	for_each_populated_zone(zone) {
139df9ecabaSChristoph Lameter 		threshold = calculate_threshold(zone);
140df9ecabaSChristoph Lameter 
141df9ecabaSChristoph Lameter 		for_each_online_cpu(cpu)
14299dcc3e5SChristoph Lameter 			per_cpu_ptr(zone->pageset, cpu)->stat_threshold
14399dcc3e5SChristoph Lameter 							= threshold;
144df9ecabaSChristoph Lameter 	}
1452244b95aSChristoph Lameter }
1462244b95aSChristoph Lameter 
1472244b95aSChristoph Lameter /*
1482244b95aSChristoph Lameter  * For use when we know that interrupts are disabled.
1492244b95aSChristoph Lameter  */
1502244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1512244b95aSChristoph Lameter 				int delta)
1522244b95aSChristoph Lameter {
15399dcc3e5SChristoph Lameter 	struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
15499dcc3e5SChristoph Lameter 
155df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
1562244b95aSChristoph Lameter 	long x;
1572244b95aSChristoph Lameter 
1582244b95aSChristoph Lameter 	x = delta + *p;
1592244b95aSChristoph Lameter 
160df9ecabaSChristoph Lameter 	if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) {
1612244b95aSChristoph Lameter 		zone_page_state_add(x, zone, item);
1622244b95aSChristoph Lameter 		x = 0;
1632244b95aSChristoph Lameter 	}
1642244b95aSChristoph Lameter 	*p = x;
1652244b95aSChristoph Lameter }
1662244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
1672244b95aSChristoph Lameter 
1682244b95aSChristoph Lameter /*
1692244b95aSChristoph Lameter  * For an unknown interrupt state
1702244b95aSChristoph Lameter  */
1712244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1722244b95aSChristoph Lameter 					int delta)
1732244b95aSChristoph Lameter {
1742244b95aSChristoph Lameter 	unsigned long flags;
1752244b95aSChristoph Lameter 
1762244b95aSChristoph Lameter 	local_irq_save(flags);
1772244b95aSChristoph Lameter 	__mod_zone_page_state(zone, item, delta);
1782244b95aSChristoph Lameter 	local_irq_restore(flags);
1792244b95aSChristoph Lameter }
1802244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
1812244b95aSChristoph Lameter 
1822244b95aSChristoph Lameter /*
1832244b95aSChristoph Lameter  * Optimized increment and decrement functions.
1842244b95aSChristoph Lameter  *
1852244b95aSChristoph Lameter  * These are only for a single page and therefore can take a struct page *
1862244b95aSChristoph Lameter  * argument instead of struct zone *. This allows the inclusion of the code
1872244b95aSChristoph Lameter  * generated for page_zone(page) into the optimized functions.
1882244b95aSChristoph Lameter  *
1892244b95aSChristoph Lameter  * No overflow check is necessary and therefore the differential can be
1902244b95aSChristoph Lameter  * incremented or decremented in place which may allow the compilers to
1912244b95aSChristoph Lameter  * generate better code.
1922244b95aSChristoph Lameter  * The increment or decrement is known and therefore one boundary check can
1932244b95aSChristoph Lameter  * be omitted.
1942244b95aSChristoph Lameter  *
195df9ecabaSChristoph Lameter  * NOTE: These functions are very performance sensitive. Change only
196df9ecabaSChristoph Lameter  * with care.
197df9ecabaSChristoph Lameter  *
1982244b95aSChristoph Lameter  * Some processors have inc/dec instructions that are atomic vs an interrupt.
1992244b95aSChristoph Lameter  * However, the code must first determine the differential location in a zone
2002244b95aSChristoph Lameter  * based on the processor number and then inc/dec the counter. There is no
2012244b95aSChristoph Lameter  * guarantee without disabling preemption that the processor will not change
2022244b95aSChristoph Lameter  * in between and therefore the atomicity vs. interrupt cannot be exploited
2032244b95aSChristoph Lameter  * in a useful way here.
2042244b95aSChristoph Lameter  */
205c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2062244b95aSChristoph Lameter {
20799dcc3e5SChristoph Lameter 	struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
208df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2092244b95aSChristoph Lameter 
2102244b95aSChristoph Lameter 	(*p)++;
2112244b95aSChristoph Lameter 
212df9ecabaSChristoph Lameter 	if (unlikely(*p > pcp->stat_threshold)) {
213df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
214df9ecabaSChristoph Lameter 
215df9ecabaSChristoph Lameter 		zone_page_state_add(*p + overstep, zone, item);
216df9ecabaSChristoph Lameter 		*p = -overstep;
2172244b95aSChristoph Lameter 	}
2182244b95aSChristoph Lameter }
219ca889e6cSChristoph Lameter 
220ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
221ca889e6cSChristoph Lameter {
222ca889e6cSChristoph Lameter 	__inc_zone_state(page_zone(page), item);
223ca889e6cSChristoph Lameter }
2242244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
2252244b95aSChristoph Lameter 
226c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2272244b95aSChristoph Lameter {
22899dcc3e5SChristoph Lameter 	struct per_cpu_pageset *pcp = this_cpu_ptr(zone->pageset);
229df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2302244b95aSChristoph Lameter 
2312244b95aSChristoph Lameter 	(*p)--;
2322244b95aSChristoph Lameter 
233df9ecabaSChristoph Lameter 	if (unlikely(*p < - pcp->stat_threshold)) {
234df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
235df9ecabaSChristoph Lameter 
236df9ecabaSChristoph Lameter 		zone_page_state_add(*p - overstep, zone, item);
237df9ecabaSChristoph Lameter 		*p = overstep;
2382244b95aSChristoph Lameter 	}
2392244b95aSChristoph Lameter }
240c8785385SChristoph Lameter 
241c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
242c8785385SChristoph Lameter {
243c8785385SChristoph Lameter 	__dec_zone_state(page_zone(page), item);
244c8785385SChristoph Lameter }
2452244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
2462244b95aSChristoph Lameter 
247ca889e6cSChristoph Lameter void inc_zone_state(struct zone *zone, enum zone_stat_item item)
248ca889e6cSChristoph Lameter {
249ca889e6cSChristoph Lameter 	unsigned long flags;
250ca889e6cSChristoph Lameter 
251ca889e6cSChristoph Lameter 	local_irq_save(flags);
252ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
253ca889e6cSChristoph Lameter 	local_irq_restore(flags);
254ca889e6cSChristoph Lameter }
255ca889e6cSChristoph Lameter 
2562244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
2572244b95aSChristoph Lameter {
2582244b95aSChristoph Lameter 	unsigned long flags;
2592244b95aSChristoph Lameter 	struct zone *zone;
2602244b95aSChristoph Lameter 
2612244b95aSChristoph Lameter 	zone = page_zone(page);
2622244b95aSChristoph Lameter 	local_irq_save(flags);
263ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
2642244b95aSChristoph Lameter 	local_irq_restore(flags);
2652244b95aSChristoph Lameter }
2662244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
2672244b95aSChristoph Lameter 
2682244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
2692244b95aSChristoph Lameter {
2702244b95aSChristoph Lameter 	unsigned long flags;
2712244b95aSChristoph Lameter 
2722244b95aSChristoph Lameter 	local_irq_save(flags);
273a302eb4eSChristoph Lameter 	__dec_zone_page_state(page, item);
2742244b95aSChristoph Lameter 	local_irq_restore(flags);
2752244b95aSChristoph Lameter }
2762244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
2772244b95aSChristoph Lameter 
2782244b95aSChristoph Lameter /*
2792244b95aSChristoph Lameter  * Update the zone counters for one cpu.
2804037d452SChristoph Lameter  *
281a7f75e25SChristoph Lameter  * The cpu specified must be either the current cpu or a processor that
282a7f75e25SChristoph Lameter  * is not online. If it is the current cpu then the execution thread must
283a7f75e25SChristoph Lameter  * be pinned to the current cpu.
284a7f75e25SChristoph Lameter  *
2854037d452SChristoph Lameter  * Note that refresh_cpu_vm_stats strives to only access
2864037d452SChristoph Lameter  * node local memory. The per cpu pagesets on remote zones are placed
2874037d452SChristoph Lameter  * in the memory local to the processor using that pageset. So the
2884037d452SChristoph Lameter  * loop over all zones will access a series of cachelines local to
2894037d452SChristoph Lameter  * the processor.
2904037d452SChristoph Lameter  *
2914037d452SChristoph Lameter  * The call to zone_page_state_add updates the cachelines with the
2924037d452SChristoph Lameter  * statistics in the remote zone struct as well as the global cachelines
2934037d452SChristoph Lameter  * with the global counters. These could cause remote node cache line
2944037d452SChristoph Lameter  * bouncing and will have to be only done when necessary.
2952244b95aSChristoph Lameter  */
2962244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu)
2972244b95aSChristoph Lameter {
2982244b95aSChristoph Lameter 	struct zone *zone;
2992244b95aSChristoph Lameter 	int i;
300a7f75e25SChristoph Lameter 	int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
3012244b95aSChristoph Lameter 
302ee99c71cSKOSAKI Motohiro 	for_each_populated_zone(zone) {
3034037d452SChristoph Lameter 		struct per_cpu_pageset *p;
3042244b95aSChristoph Lameter 
30599dcc3e5SChristoph Lameter 		p = per_cpu_ptr(zone->pageset, cpu);
3062244b95aSChristoph Lameter 
3072244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
3084037d452SChristoph Lameter 			if (p->vm_stat_diff[i]) {
309a7f75e25SChristoph Lameter 				unsigned long flags;
310a7f75e25SChristoph Lameter 				int v;
311a7f75e25SChristoph Lameter 
3122244b95aSChristoph Lameter 				local_irq_save(flags);
313a7f75e25SChristoph Lameter 				v = p->vm_stat_diff[i];
3144037d452SChristoph Lameter 				p->vm_stat_diff[i] = 0;
315a7f75e25SChristoph Lameter 				local_irq_restore(flags);
316a7f75e25SChristoph Lameter 				atomic_long_add(v, &zone->vm_stat[i]);
317a7f75e25SChristoph Lameter 				global_diff[i] += v;
3184037d452SChristoph Lameter #ifdef CONFIG_NUMA
3194037d452SChristoph Lameter 				/* 3 seconds idle till flush */
3204037d452SChristoph Lameter 				p->expire = 3;
3214037d452SChristoph Lameter #endif
3222244b95aSChristoph Lameter 			}
323468fd62eSDimitri Sivanich 		cond_resched();
3244037d452SChristoph Lameter #ifdef CONFIG_NUMA
3254037d452SChristoph Lameter 		/*
3264037d452SChristoph Lameter 		 * Deal with draining the remote pageset of this
3274037d452SChristoph Lameter 		 * processor
3284037d452SChristoph Lameter 		 *
3294037d452SChristoph Lameter 		 * Check if there are pages remaining in this pageset
3304037d452SChristoph Lameter 		 * if not then there is nothing to expire.
3314037d452SChristoph Lameter 		 */
3323dfa5721SChristoph Lameter 		if (!p->expire || !p->pcp.count)
3334037d452SChristoph Lameter 			continue;
3344037d452SChristoph Lameter 
3354037d452SChristoph Lameter 		/*
3364037d452SChristoph Lameter 		 * We never drain zones local to this processor.
3374037d452SChristoph Lameter 		 */
3384037d452SChristoph Lameter 		if (zone_to_nid(zone) == numa_node_id()) {
3394037d452SChristoph Lameter 			p->expire = 0;
3404037d452SChristoph Lameter 			continue;
3414037d452SChristoph Lameter 		}
3424037d452SChristoph Lameter 
3434037d452SChristoph Lameter 		p->expire--;
3444037d452SChristoph Lameter 		if (p->expire)
3454037d452SChristoph Lameter 			continue;
3464037d452SChristoph Lameter 
3473dfa5721SChristoph Lameter 		if (p->pcp.count)
3483dfa5721SChristoph Lameter 			drain_zone_pages(zone, &p->pcp);
3494037d452SChristoph Lameter #endif
3502244b95aSChristoph Lameter 	}
351a7f75e25SChristoph Lameter 
352a7f75e25SChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
353a7f75e25SChristoph Lameter 		if (global_diff[i])
354a7f75e25SChristoph Lameter 			atomic_long_add(global_diff[i], &vm_stat[i]);
3552244b95aSChristoph Lameter }
3562244b95aSChristoph Lameter 
3572244b95aSChristoph Lameter #endif
3582244b95aSChristoph Lameter 
359ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
360ca889e6cSChristoph Lameter /*
361ca889e6cSChristoph Lameter  * zonelist = the list of zones passed to the allocator
362ca889e6cSChristoph Lameter  * z 	    = the zone from which the allocation occurred.
363ca889e6cSChristoph Lameter  *
364ca889e6cSChristoph Lameter  * Must be called with interrupts disabled.
365ca889e6cSChristoph Lameter  */
36618ea7e71SMel Gorman void zone_statistics(struct zone *preferred_zone, struct zone *z)
367ca889e6cSChristoph Lameter {
36818ea7e71SMel Gorman 	if (z->zone_pgdat == preferred_zone->zone_pgdat) {
369ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_HIT);
370ca889e6cSChristoph Lameter 	} else {
371ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_MISS);
37218ea7e71SMel Gorman 		__inc_zone_state(preferred_zone, NUMA_FOREIGN);
373ca889e6cSChristoph Lameter 	}
3745d292343SChristoph Lameter 	if (z->node == numa_node_id())
375ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_LOCAL);
376ca889e6cSChristoph Lameter 	else
377ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_OTHER);
378ca889e6cSChristoph Lameter }
379ca889e6cSChristoph Lameter #endif
380ca889e6cSChristoph Lameter 
381f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS
3828f32f7e5SAlexey Dobriyan #include <linux/proc_fs.h>
383f6ac2354SChristoph Lameter #include <linux/seq_file.h>
384f6ac2354SChristoph Lameter 
385467c996cSMel Gorman static char * const migratetype_names[MIGRATE_TYPES] = {
386467c996cSMel Gorman 	"Unmovable",
387467c996cSMel Gorman 	"Reclaimable",
388467c996cSMel Gorman 	"Movable",
389467c996cSMel Gorman 	"Reserve",
39091446b06SKOSAKI Motohiro 	"Isolate",
391467c996cSMel Gorman };
392467c996cSMel Gorman 
393f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos)
394f6ac2354SChristoph Lameter {
395f6ac2354SChristoph Lameter 	pg_data_t *pgdat;
396f6ac2354SChristoph Lameter 	loff_t node = *pos;
397f6ac2354SChristoph Lameter 	for (pgdat = first_online_pgdat();
398f6ac2354SChristoph Lameter 	     pgdat && node;
399f6ac2354SChristoph Lameter 	     pgdat = next_online_pgdat(pgdat))
400f6ac2354SChristoph Lameter 		--node;
401f6ac2354SChristoph Lameter 
402f6ac2354SChristoph Lameter 	return pgdat;
403f6ac2354SChristoph Lameter }
404f6ac2354SChristoph Lameter 
405f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
406f6ac2354SChristoph Lameter {
407f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
408f6ac2354SChristoph Lameter 
409f6ac2354SChristoph Lameter 	(*pos)++;
410f6ac2354SChristoph Lameter 	return next_online_pgdat(pgdat);
411f6ac2354SChristoph Lameter }
412f6ac2354SChristoph Lameter 
413f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg)
414f6ac2354SChristoph Lameter {
415f6ac2354SChristoph Lameter }
416f6ac2354SChristoph Lameter 
417467c996cSMel Gorman /* Walk all the zones in a node and print using a callback */
418467c996cSMel Gorman static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
419467c996cSMel Gorman 		void (*print)(struct seq_file *m, pg_data_t *, struct zone *))
420f6ac2354SChristoph Lameter {
421f6ac2354SChristoph Lameter 	struct zone *zone;
422f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
423f6ac2354SChristoph Lameter 	unsigned long flags;
424f6ac2354SChristoph Lameter 
425f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
426f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
427f6ac2354SChristoph Lameter 			continue;
428f6ac2354SChristoph Lameter 
429f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
430467c996cSMel Gorman 		print(m, pgdat, zone);
431467c996cSMel Gorman 		spin_unlock_irqrestore(&zone->lock, flags);
432467c996cSMel Gorman 	}
433467c996cSMel Gorman }
434467c996cSMel Gorman 
435467c996cSMel Gorman static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
436467c996cSMel Gorman 						struct zone *zone)
437467c996cSMel Gorman {
438467c996cSMel Gorman 	int order;
439467c996cSMel Gorman 
440f6ac2354SChristoph Lameter 	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
441f6ac2354SChristoph Lameter 	for (order = 0; order < MAX_ORDER; ++order)
442f6ac2354SChristoph Lameter 		seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
443f6ac2354SChristoph Lameter 	seq_putc(m, '\n');
444f6ac2354SChristoph Lameter }
445467c996cSMel Gorman 
446467c996cSMel Gorman /*
447467c996cSMel Gorman  * This walks the free areas for each zone.
448467c996cSMel Gorman  */
449467c996cSMel Gorman static int frag_show(struct seq_file *m, void *arg)
450467c996cSMel Gorman {
451467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
452467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, frag_show_print);
453467c996cSMel Gorman 	return 0;
454467c996cSMel Gorman }
455467c996cSMel Gorman 
456467c996cSMel Gorman static void pagetypeinfo_showfree_print(struct seq_file *m,
457467c996cSMel Gorman 					pg_data_t *pgdat, struct zone *zone)
458467c996cSMel Gorman {
459467c996cSMel Gorman 	int order, mtype;
460467c996cSMel Gorman 
461467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) {
462467c996cSMel Gorman 		seq_printf(m, "Node %4d, zone %8s, type %12s ",
463467c996cSMel Gorman 					pgdat->node_id,
464467c996cSMel Gorman 					zone->name,
465467c996cSMel Gorman 					migratetype_names[mtype]);
466467c996cSMel Gorman 		for (order = 0; order < MAX_ORDER; ++order) {
467467c996cSMel Gorman 			unsigned long freecount = 0;
468467c996cSMel Gorman 			struct free_area *area;
469467c996cSMel Gorman 			struct list_head *curr;
470467c996cSMel Gorman 
471467c996cSMel Gorman 			area = &(zone->free_area[order]);
472467c996cSMel Gorman 
473467c996cSMel Gorman 			list_for_each(curr, &area->free_list[mtype])
474467c996cSMel Gorman 				freecount++;
475467c996cSMel Gorman 			seq_printf(m, "%6lu ", freecount);
476467c996cSMel Gorman 		}
477467c996cSMel Gorman 		seq_putc(m, '\n');
478467c996cSMel Gorman 	}
479467c996cSMel Gorman }
480467c996cSMel Gorman 
481467c996cSMel Gorman /* Print out the free pages at each order for each migatetype */
482467c996cSMel Gorman static int pagetypeinfo_showfree(struct seq_file *m, void *arg)
483467c996cSMel Gorman {
484467c996cSMel Gorman 	int order;
485467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
486467c996cSMel Gorman 
487467c996cSMel Gorman 	/* Print header */
488467c996cSMel Gorman 	seq_printf(m, "%-43s ", "Free pages count per migrate type at order");
489467c996cSMel Gorman 	for (order = 0; order < MAX_ORDER; ++order)
490467c996cSMel Gorman 		seq_printf(m, "%6d ", order);
491467c996cSMel Gorman 	seq_putc(m, '\n');
492467c996cSMel Gorman 
493467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print);
494467c996cSMel Gorman 
495467c996cSMel Gorman 	return 0;
496467c996cSMel Gorman }
497467c996cSMel Gorman 
498467c996cSMel Gorman static void pagetypeinfo_showblockcount_print(struct seq_file *m,
499467c996cSMel Gorman 					pg_data_t *pgdat, struct zone *zone)
500467c996cSMel Gorman {
501467c996cSMel Gorman 	int mtype;
502467c996cSMel Gorman 	unsigned long pfn;
503467c996cSMel Gorman 	unsigned long start_pfn = zone->zone_start_pfn;
504467c996cSMel Gorman 	unsigned long end_pfn = start_pfn + zone->spanned_pages;
505467c996cSMel Gorman 	unsigned long count[MIGRATE_TYPES] = { 0, };
506467c996cSMel Gorman 
507467c996cSMel Gorman 	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
508467c996cSMel Gorman 		struct page *page;
509467c996cSMel Gorman 
510467c996cSMel Gorman 		if (!pfn_valid(pfn))
511467c996cSMel Gorman 			continue;
512467c996cSMel Gorman 
513467c996cSMel Gorman 		page = pfn_to_page(pfn);
514eb33575cSMel Gorman 
515eb33575cSMel Gorman 		/* Watch for unexpected holes punched in the memmap */
516eb33575cSMel Gorman 		if (!memmap_valid_within(pfn, page, zone))
517e80d6a24SMel Gorman 			continue;
518eb33575cSMel Gorman 
519467c996cSMel Gorman 		mtype = get_pageblock_migratetype(page);
520467c996cSMel Gorman 
521e80d6a24SMel Gorman 		if (mtype < MIGRATE_TYPES)
522467c996cSMel Gorman 			count[mtype]++;
523467c996cSMel Gorman 	}
524467c996cSMel Gorman 
525467c996cSMel Gorman 	/* Print counts */
526467c996cSMel Gorman 	seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
527467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
528467c996cSMel Gorman 		seq_printf(m, "%12lu ", count[mtype]);
529467c996cSMel Gorman 	seq_putc(m, '\n');
530467c996cSMel Gorman }
531467c996cSMel Gorman 
532467c996cSMel Gorman /* Print out the free pages at each order for each migratetype */
533467c996cSMel Gorman static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
534467c996cSMel Gorman {
535467c996cSMel Gorman 	int mtype;
536467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
537467c996cSMel Gorman 
538467c996cSMel Gorman 	seq_printf(m, "\n%-23s", "Number of blocks type ");
539467c996cSMel Gorman 	for (mtype = 0; mtype < MIGRATE_TYPES; mtype++)
540467c996cSMel Gorman 		seq_printf(m, "%12s ", migratetype_names[mtype]);
541467c996cSMel Gorman 	seq_putc(m, '\n');
542467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print);
543467c996cSMel Gorman 
544467c996cSMel Gorman 	return 0;
545467c996cSMel Gorman }
546467c996cSMel Gorman 
547467c996cSMel Gorman /*
548467c996cSMel Gorman  * This prints out statistics in relation to grouping pages by mobility.
549467c996cSMel Gorman  * It is expensive to collect so do not constantly read the file.
550467c996cSMel Gorman  */
551467c996cSMel Gorman static int pagetypeinfo_show(struct seq_file *m, void *arg)
552467c996cSMel Gorman {
553467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
554467c996cSMel Gorman 
55541b25a37SKOSAKI Motohiro 	/* check memoryless node */
55641b25a37SKOSAKI Motohiro 	if (!node_state(pgdat->node_id, N_HIGH_MEMORY))
55741b25a37SKOSAKI Motohiro 		return 0;
55841b25a37SKOSAKI Motohiro 
559467c996cSMel Gorman 	seq_printf(m, "Page block order: %d\n", pageblock_order);
560467c996cSMel Gorman 	seq_printf(m, "Pages per block:  %lu\n", pageblock_nr_pages);
561467c996cSMel Gorman 	seq_putc(m, '\n');
562467c996cSMel Gorman 	pagetypeinfo_showfree(m, pgdat);
563467c996cSMel Gorman 	pagetypeinfo_showblockcount(m, pgdat);
564467c996cSMel Gorman 
565f6ac2354SChristoph Lameter 	return 0;
566f6ac2354SChristoph Lameter }
567f6ac2354SChristoph Lameter 
5688f32f7e5SAlexey Dobriyan static const struct seq_operations fragmentation_op = {
569f6ac2354SChristoph Lameter 	.start	= frag_start,
570f6ac2354SChristoph Lameter 	.next	= frag_next,
571f6ac2354SChristoph Lameter 	.stop	= frag_stop,
572f6ac2354SChristoph Lameter 	.show	= frag_show,
573f6ac2354SChristoph Lameter };
574f6ac2354SChristoph Lameter 
5758f32f7e5SAlexey Dobriyan static int fragmentation_open(struct inode *inode, struct file *file)
5768f32f7e5SAlexey Dobriyan {
5778f32f7e5SAlexey Dobriyan 	return seq_open(file, &fragmentation_op);
5788f32f7e5SAlexey Dobriyan }
5798f32f7e5SAlexey Dobriyan 
5808f32f7e5SAlexey Dobriyan static const struct file_operations fragmentation_file_operations = {
5818f32f7e5SAlexey Dobriyan 	.open		= fragmentation_open,
5828f32f7e5SAlexey Dobriyan 	.read		= seq_read,
5838f32f7e5SAlexey Dobriyan 	.llseek		= seq_lseek,
5848f32f7e5SAlexey Dobriyan 	.release	= seq_release,
5858f32f7e5SAlexey Dobriyan };
5868f32f7e5SAlexey Dobriyan 
58774e2e8e8SAlexey Dobriyan static const struct seq_operations pagetypeinfo_op = {
588467c996cSMel Gorman 	.start	= frag_start,
589467c996cSMel Gorman 	.next	= frag_next,
590467c996cSMel Gorman 	.stop	= frag_stop,
591467c996cSMel Gorman 	.show	= pagetypeinfo_show,
592467c996cSMel Gorman };
593467c996cSMel Gorman 
59474e2e8e8SAlexey Dobriyan static int pagetypeinfo_open(struct inode *inode, struct file *file)
59574e2e8e8SAlexey Dobriyan {
59674e2e8e8SAlexey Dobriyan 	return seq_open(file, &pagetypeinfo_op);
59774e2e8e8SAlexey Dobriyan }
59874e2e8e8SAlexey Dobriyan 
59974e2e8e8SAlexey Dobriyan static const struct file_operations pagetypeinfo_file_ops = {
60074e2e8e8SAlexey Dobriyan 	.open		= pagetypeinfo_open,
60174e2e8e8SAlexey Dobriyan 	.read		= seq_read,
60274e2e8e8SAlexey Dobriyan 	.llseek		= seq_lseek,
60374e2e8e8SAlexey Dobriyan 	.release	= seq_release,
60474e2e8e8SAlexey Dobriyan };
60574e2e8e8SAlexey Dobriyan 
6064b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA
6074b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma",
6084b51d669SChristoph Lameter #else
6094b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx)
6104b51d669SChristoph Lameter #endif
6114b51d669SChristoph Lameter 
61227bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32
61327bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32",
61427bf71c2SChristoph Lameter #else
61527bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx)
61627bf71c2SChristoph Lameter #endif
61727bf71c2SChristoph Lameter 
61827bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM
61927bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high",
62027bf71c2SChristoph Lameter #else
62127bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx)
62227bf71c2SChristoph Lameter #endif
62327bf71c2SChristoph Lameter 
6244b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
6252a1e274aSMel Gorman 					TEXT_FOR_HIGHMEM(xx) xx "_movable",
62627bf71c2SChristoph Lameter 
62715ad7cdcSHelge Deller static const char * const vmstat_text[] = {
6282244b95aSChristoph Lameter 	/* Zoned VM counters */
629d23ad423SChristoph Lameter 	"nr_free_pages",
6304f98a2feSRik van Riel 	"nr_inactive_anon",
6314f98a2feSRik van Riel 	"nr_active_anon",
6324f98a2feSRik van Riel 	"nr_inactive_file",
6334f98a2feSRik van Riel 	"nr_active_file",
6347b854121SLee Schermerhorn 	"nr_unevictable",
6355344b7e6SNick Piggin 	"nr_mlock",
636f3dbd344SChristoph Lameter 	"nr_anon_pages",
63765ba55f5SChristoph Lameter 	"nr_mapped",
638347ce434SChristoph Lameter 	"nr_file_pages",
63951ed4491SChristoph Lameter 	"nr_dirty",
64051ed4491SChristoph Lameter 	"nr_writeback",
641972d1a7bSChristoph Lameter 	"nr_slab_reclaimable",
642972d1a7bSChristoph Lameter 	"nr_slab_unreclaimable",
643df849a15SChristoph Lameter 	"nr_page_table_pages",
644c6a7f572SKOSAKI Motohiro 	"nr_kernel_stack",
645f6ac2354SChristoph Lameter 	"nr_unstable",
646d2c5e30cSChristoph Lameter 	"nr_bounce",
647e129b5c2SAndrew Morton 	"nr_vmscan_write",
648fc3ba692SMiklos Szeredi 	"nr_writeback_temp",
649a731286dSKOSAKI Motohiro 	"nr_isolated_anon",
650a731286dSKOSAKI Motohiro 	"nr_isolated_file",
6514b02108aSKOSAKI Motohiro 	"nr_shmem",
652ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
653ca889e6cSChristoph Lameter 	"numa_hit",
654ca889e6cSChristoph Lameter 	"numa_miss",
655ca889e6cSChristoph Lameter 	"numa_foreign",
656ca889e6cSChristoph Lameter 	"numa_interleave",
657ca889e6cSChristoph Lameter 	"numa_local",
658ca889e6cSChristoph Lameter 	"numa_other",
659ca889e6cSChristoph Lameter #endif
660ca889e6cSChristoph Lameter 
661f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
662f6ac2354SChristoph Lameter 	"pgpgin",
663f6ac2354SChristoph Lameter 	"pgpgout",
664f6ac2354SChristoph Lameter 	"pswpin",
665f6ac2354SChristoph Lameter 	"pswpout",
666f6ac2354SChristoph Lameter 
66727bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgalloc")
668f6ac2354SChristoph Lameter 
669f6ac2354SChristoph Lameter 	"pgfree",
670f6ac2354SChristoph Lameter 	"pgactivate",
671f6ac2354SChristoph Lameter 	"pgdeactivate",
672f6ac2354SChristoph Lameter 
673f6ac2354SChristoph Lameter 	"pgfault",
674f6ac2354SChristoph Lameter 	"pgmajfault",
675f6ac2354SChristoph Lameter 
67627bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgrefill")
67727bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgsteal")
67827bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_kswapd")
67927bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_direct")
680f6ac2354SChristoph Lameter 
68124cf7251SMel Gorman #ifdef CONFIG_NUMA
68224cf7251SMel Gorman 	"zone_reclaim_failed",
68324cf7251SMel Gorman #endif
684f6ac2354SChristoph Lameter 	"pginodesteal",
685f6ac2354SChristoph Lameter 	"slabs_scanned",
686f6ac2354SChristoph Lameter 	"kswapd_steal",
687f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
688bb3ab596SKOSAKI Motohiro 	"kswapd_low_wmark_hit_quickly",
689bb3ab596SKOSAKI Motohiro 	"kswapd_high_wmark_hit_quickly",
690bb3ab596SKOSAKI Motohiro 	"kswapd_skip_congestion_wait",
691f6ac2354SChristoph Lameter 	"pageoutrun",
692f6ac2354SChristoph Lameter 	"allocstall",
693f6ac2354SChristoph Lameter 
694f6ac2354SChristoph Lameter 	"pgrotated",
6953b116300SAdam Litke #ifdef CONFIG_HUGETLB_PAGE
6963b116300SAdam Litke 	"htlb_buddy_alloc_success",
6973b116300SAdam Litke 	"htlb_buddy_alloc_fail",
6983b116300SAdam Litke #endif
699bbfd28eeSLee Schermerhorn 	"unevictable_pgs_culled",
700bbfd28eeSLee Schermerhorn 	"unevictable_pgs_scanned",
701bbfd28eeSLee Schermerhorn 	"unevictable_pgs_rescued",
7025344b7e6SNick Piggin 	"unevictable_pgs_mlocked",
7035344b7e6SNick Piggin 	"unevictable_pgs_munlocked",
7045344b7e6SNick Piggin 	"unevictable_pgs_cleared",
7055344b7e6SNick Piggin 	"unevictable_pgs_stranded",
706985737cfSLee Schermerhorn 	"unevictable_pgs_mlockfreed",
707bbfd28eeSLee Schermerhorn #endif
708f6ac2354SChristoph Lameter };
709f6ac2354SChristoph Lameter 
710467c996cSMel Gorman static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
711467c996cSMel Gorman 							struct zone *zone)
712f6ac2354SChristoph Lameter {
713f6ac2354SChristoph Lameter 	int i;
714f6ac2354SChristoph Lameter 	seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
715f6ac2354SChristoph Lameter 	seq_printf(m,
716f6ac2354SChristoph Lameter 		   "\n  pages free     %lu"
717f6ac2354SChristoph Lameter 		   "\n        min      %lu"
718f6ac2354SChristoph Lameter 		   "\n        low      %lu"
719f6ac2354SChristoph Lameter 		   "\n        high     %lu"
72008d9ae7cSWu Fengguang 		   "\n        scanned  %lu"
721f6ac2354SChristoph Lameter 		   "\n        spanned  %lu"
722f6ac2354SChristoph Lameter 		   "\n        present  %lu",
723d23ad423SChristoph Lameter 		   zone_page_state(zone, NR_FREE_PAGES),
72441858966SMel Gorman 		   min_wmark_pages(zone),
72541858966SMel Gorman 		   low_wmark_pages(zone),
72641858966SMel Gorman 		   high_wmark_pages(zone),
727f6ac2354SChristoph Lameter 		   zone->pages_scanned,
728f6ac2354SChristoph Lameter 		   zone->spanned_pages,
729f6ac2354SChristoph Lameter 		   zone->present_pages);
7302244b95aSChristoph Lameter 
7312244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
7322244b95aSChristoph Lameter 		seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
7332244b95aSChristoph Lameter 				zone_page_state(zone, i));
7342244b95aSChristoph Lameter 
735f6ac2354SChristoph Lameter 	seq_printf(m,
736f6ac2354SChristoph Lameter 		   "\n        protection: (%lu",
737f6ac2354SChristoph Lameter 		   zone->lowmem_reserve[0]);
738f6ac2354SChristoph Lameter 	for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
739f6ac2354SChristoph Lameter 		seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
740f6ac2354SChristoph Lameter 	seq_printf(m,
741f6ac2354SChristoph Lameter 		   ")"
742f6ac2354SChristoph Lameter 		   "\n  pagesets");
743f6ac2354SChristoph Lameter 	for_each_online_cpu(i) {
744f6ac2354SChristoph Lameter 		struct per_cpu_pageset *pageset;
745f6ac2354SChristoph Lameter 
74699dcc3e5SChristoph Lameter 		pageset = per_cpu_ptr(zone->pageset, i);
747f6ac2354SChristoph Lameter 		seq_printf(m,
7483dfa5721SChristoph Lameter 			   "\n    cpu: %i"
749f6ac2354SChristoph Lameter 			   "\n              count: %i"
750f6ac2354SChristoph Lameter 			   "\n              high:  %i"
751f6ac2354SChristoph Lameter 			   "\n              batch: %i",
7523dfa5721SChristoph Lameter 			   i,
7533dfa5721SChristoph Lameter 			   pageset->pcp.count,
7543dfa5721SChristoph Lameter 			   pageset->pcp.high,
7553dfa5721SChristoph Lameter 			   pageset->pcp.batch);
756df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
757df9ecabaSChristoph Lameter 		seq_printf(m, "\n  vm stats threshold: %d",
758df9ecabaSChristoph Lameter 				pageset->stat_threshold);
759df9ecabaSChristoph Lameter #endif
760f6ac2354SChristoph Lameter 	}
761f6ac2354SChristoph Lameter 	seq_printf(m,
762f6ac2354SChristoph Lameter 		   "\n  all_unreclaimable: %u"
763f6ac2354SChristoph Lameter 		   "\n  prev_priority:     %i"
764556adecbSRik van Riel 		   "\n  start_pfn:         %lu"
765556adecbSRik van Riel 		   "\n  inactive_ratio:    %u",
766e815af95SDavid Rientjes 			   zone_is_all_unreclaimable(zone),
767f6ac2354SChristoph Lameter 		   zone->prev_priority,
768556adecbSRik van Riel 		   zone->zone_start_pfn,
769556adecbSRik van Riel 		   zone->inactive_ratio);
770f6ac2354SChristoph Lameter 	seq_putc(m, '\n');
771f6ac2354SChristoph Lameter }
772467c996cSMel Gorman 
773467c996cSMel Gorman /*
774467c996cSMel Gorman  * Output information about zones in @pgdat.
775467c996cSMel Gorman  */
776467c996cSMel Gorman static int zoneinfo_show(struct seq_file *m, void *arg)
777467c996cSMel Gorman {
778467c996cSMel Gorman 	pg_data_t *pgdat = (pg_data_t *)arg;
779467c996cSMel Gorman 	walk_zones_in_node(m, pgdat, zoneinfo_show_print);
780f6ac2354SChristoph Lameter 	return 0;
781f6ac2354SChristoph Lameter }
782f6ac2354SChristoph Lameter 
7835c9fe628SAlexey Dobriyan static const struct seq_operations zoneinfo_op = {
784f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
785f6ac2354SChristoph Lameter 			       * fragmentation. */
786f6ac2354SChristoph Lameter 	.next	= frag_next,
787f6ac2354SChristoph Lameter 	.stop	= frag_stop,
788f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
789f6ac2354SChristoph Lameter };
790f6ac2354SChristoph Lameter 
7915c9fe628SAlexey Dobriyan static int zoneinfo_open(struct inode *inode, struct file *file)
7925c9fe628SAlexey Dobriyan {
7935c9fe628SAlexey Dobriyan 	return seq_open(file, &zoneinfo_op);
7945c9fe628SAlexey Dobriyan }
7955c9fe628SAlexey Dobriyan 
7965c9fe628SAlexey Dobriyan static const struct file_operations proc_zoneinfo_file_operations = {
7975c9fe628SAlexey Dobriyan 	.open		= zoneinfo_open,
7985c9fe628SAlexey Dobriyan 	.read		= seq_read,
7995c9fe628SAlexey Dobriyan 	.llseek		= seq_lseek,
8005c9fe628SAlexey Dobriyan 	.release	= seq_release,
8015c9fe628SAlexey Dobriyan };
8025c9fe628SAlexey Dobriyan 
803f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
804f6ac2354SChristoph Lameter {
8052244b95aSChristoph Lameter 	unsigned long *v;
806f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
807f8891e5eSChristoph Lameter 	unsigned long *e;
808f8891e5eSChristoph Lameter #endif
8092244b95aSChristoph Lameter 	int i;
810f6ac2354SChristoph Lameter 
811f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
812f6ac2354SChristoph Lameter 		return NULL;
813f6ac2354SChristoph Lameter 
814f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
8152244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
816f8891e5eSChristoph Lameter 			+ sizeof(struct vm_event_state), GFP_KERNEL);
817f8891e5eSChristoph Lameter #else
818f8891e5eSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
819f8891e5eSChristoph Lameter 			GFP_KERNEL);
820f8891e5eSChristoph Lameter #endif
8212244b95aSChristoph Lameter 	m->private = v;
8222244b95aSChristoph Lameter 	if (!v)
823f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
8242244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
8252244b95aSChristoph Lameter 		v[i] = global_page_state(i);
826f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
827f8891e5eSChristoph Lameter 	e = v + NR_VM_ZONE_STAT_ITEMS;
828f8891e5eSChristoph Lameter 	all_vm_events(e);
829f8891e5eSChristoph Lameter 	e[PGPGIN] /= 2;		/* sectors -> kbytes */
830f8891e5eSChristoph Lameter 	e[PGPGOUT] /= 2;
831f8891e5eSChristoph Lameter #endif
8322244b95aSChristoph Lameter 	return v + *pos;
833f6ac2354SChristoph Lameter }
834f6ac2354SChristoph Lameter 
835f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
836f6ac2354SChristoph Lameter {
837f6ac2354SChristoph Lameter 	(*pos)++;
838f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
839f6ac2354SChristoph Lameter 		return NULL;
840f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
841f6ac2354SChristoph Lameter }
842f6ac2354SChristoph Lameter 
843f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
844f6ac2354SChristoph Lameter {
845f6ac2354SChristoph Lameter 	unsigned long *l = arg;
846f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
847f6ac2354SChristoph Lameter 
848f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
849f6ac2354SChristoph Lameter 	return 0;
850f6ac2354SChristoph Lameter }
851f6ac2354SChristoph Lameter 
852f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
853f6ac2354SChristoph Lameter {
854f6ac2354SChristoph Lameter 	kfree(m->private);
855f6ac2354SChristoph Lameter 	m->private = NULL;
856f6ac2354SChristoph Lameter }
857f6ac2354SChristoph Lameter 
858b6aa44abSAlexey Dobriyan static const struct seq_operations vmstat_op = {
859f6ac2354SChristoph Lameter 	.start	= vmstat_start,
860f6ac2354SChristoph Lameter 	.next	= vmstat_next,
861f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
862f6ac2354SChristoph Lameter 	.show	= vmstat_show,
863f6ac2354SChristoph Lameter };
864f6ac2354SChristoph Lameter 
865b6aa44abSAlexey Dobriyan static int vmstat_open(struct inode *inode, struct file *file)
866b6aa44abSAlexey Dobriyan {
867b6aa44abSAlexey Dobriyan 	return seq_open(file, &vmstat_op);
868b6aa44abSAlexey Dobriyan }
869b6aa44abSAlexey Dobriyan 
870b6aa44abSAlexey Dobriyan static const struct file_operations proc_vmstat_file_operations = {
871b6aa44abSAlexey Dobriyan 	.open		= vmstat_open,
872b6aa44abSAlexey Dobriyan 	.read		= seq_read,
873b6aa44abSAlexey Dobriyan 	.llseek		= seq_lseek,
874b6aa44abSAlexey Dobriyan 	.release	= seq_release,
875b6aa44abSAlexey Dobriyan };
876f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
877f6ac2354SChristoph Lameter 
878df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
879d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
88077461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
881d1187ed2SChristoph Lameter 
882d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
883d1187ed2SChristoph Lameter {
884d1187ed2SChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
88577461ab3SChristoph Lameter 	schedule_delayed_work(&__get_cpu_var(vmstat_work),
88698f4ebb2SAnton Blanchard 		round_jiffies_relative(sysctl_stat_interval));
887d1187ed2SChristoph Lameter }
888d1187ed2SChristoph Lameter 
88942614fcdSRandy Dunlap static void __cpuinit start_cpu_timer(int cpu)
890d1187ed2SChristoph Lameter {
8911871e52cSTejun Heo 	struct delayed_work *work = &per_cpu(vmstat_work, cpu);
892d1187ed2SChristoph Lameter 
8931871e52cSTejun Heo 	INIT_DELAYED_WORK_DEFERRABLE(work, vmstat_update);
8941871e52cSTejun Heo 	schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
895d1187ed2SChristoph Lameter }
896d1187ed2SChristoph Lameter 
897df9ecabaSChristoph Lameter /*
898df9ecabaSChristoph Lameter  * Use the cpu notifier to insure that the thresholds are recalculated
899df9ecabaSChristoph Lameter  * when necessary.
900df9ecabaSChristoph Lameter  */
901df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
902df9ecabaSChristoph Lameter 		unsigned long action,
903df9ecabaSChristoph Lameter 		void *hcpu)
904df9ecabaSChristoph Lameter {
905d1187ed2SChristoph Lameter 	long cpu = (long)hcpu;
906d1187ed2SChristoph Lameter 
907df9ecabaSChristoph Lameter 	switch (action) {
908d1187ed2SChristoph Lameter 	case CPU_ONLINE:
909d1187ed2SChristoph Lameter 	case CPU_ONLINE_FROZEN:
910d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
911*ad596925SChristoph Lameter 		node_set_state(cpu_to_node(cpu), N_CPU);
912d1187ed2SChristoph Lameter 		break;
913d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE:
914d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE_FROZEN:
915d1187ed2SChristoph Lameter 		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
916d1187ed2SChristoph Lameter 		per_cpu(vmstat_work, cpu).work.func = NULL;
917d1187ed2SChristoph Lameter 		break;
918d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED:
919d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED_FROZEN:
920d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
921d1187ed2SChristoph Lameter 		break;
922df9ecabaSChristoph Lameter 	case CPU_DEAD:
9238bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
924df9ecabaSChristoph Lameter 		refresh_zone_stat_thresholds();
925df9ecabaSChristoph Lameter 		break;
926df9ecabaSChristoph Lameter 	default:
927df9ecabaSChristoph Lameter 		break;
928df9ecabaSChristoph Lameter 	}
929df9ecabaSChristoph Lameter 	return NOTIFY_OK;
930df9ecabaSChristoph Lameter }
931df9ecabaSChristoph Lameter 
932df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier =
933df9ecabaSChristoph Lameter 	{ &vmstat_cpuup_callback, NULL, 0 };
9348f32f7e5SAlexey Dobriyan #endif
935df9ecabaSChristoph Lameter 
936e2fc88d0SAdrian Bunk static int __init setup_vmstat(void)
937df9ecabaSChristoph Lameter {
9388f32f7e5SAlexey Dobriyan #ifdef CONFIG_SMP
939d1187ed2SChristoph Lameter 	int cpu;
940d1187ed2SChristoph Lameter 
941df9ecabaSChristoph Lameter 	refresh_zone_stat_thresholds();
942df9ecabaSChristoph Lameter 	register_cpu_notifier(&vmstat_notifier);
943d1187ed2SChristoph Lameter 
944d1187ed2SChristoph Lameter 	for_each_online_cpu(cpu)
945d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
9468f32f7e5SAlexey Dobriyan #endif
9478f32f7e5SAlexey Dobriyan #ifdef CONFIG_PROC_FS
9488f32f7e5SAlexey Dobriyan 	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
94974e2e8e8SAlexey Dobriyan 	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
950b6aa44abSAlexey Dobriyan 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
9515c9fe628SAlexey Dobriyan 	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
9528f32f7e5SAlexey Dobriyan #endif
953df9ecabaSChristoph Lameter 	return 0;
954df9ecabaSChristoph Lameter }
955df9ecabaSChristoph Lameter module_init(setup_vmstat)
956