xref: /linux/mm/vmstat.c (revision e8edc6e03a5c8562dc70a6d969f732bdb355a7e7)
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  */
11f6ac2354SChristoph Lameter 
12f6ac2354SChristoph Lameter #include <linux/mm.h>
132244b95aSChristoph Lameter #include <linux/module.h>
14df9ecabaSChristoph Lameter #include <linux/cpu.h>
15*e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
16f6ac2354SChristoph Lameter 
17f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
18f8891e5eSChristoph Lameter DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
19f8891e5eSChristoph Lameter EXPORT_PER_CPU_SYMBOL(vm_event_states);
20f8891e5eSChristoph Lameter 
21f8891e5eSChristoph Lameter static void sum_vm_events(unsigned long *ret, cpumask_t *cpumask)
22f8891e5eSChristoph Lameter {
23f8891e5eSChristoph Lameter 	int cpu = 0;
24f8891e5eSChristoph Lameter 	int i;
25f8891e5eSChristoph Lameter 
26f8891e5eSChristoph Lameter 	memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
27f8891e5eSChristoph Lameter 
28f8891e5eSChristoph Lameter 	cpu = first_cpu(*cpumask);
29f8891e5eSChristoph Lameter 	while (cpu < NR_CPUS) {
30f8891e5eSChristoph Lameter 		struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
31f8891e5eSChristoph Lameter 
32f8891e5eSChristoph Lameter 		cpu = next_cpu(cpu, *cpumask);
33f8891e5eSChristoph Lameter 
34f8891e5eSChristoph Lameter 		if (cpu < NR_CPUS)
35f8891e5eSChristoph Lameter 			prefetch(&per_cpu(vm_event_states, cpu));
36f8891e5eSChristoph Lameter 
37f8891e5eSChristoph Lameter 
38f8891e5eSChristoph Lameter 		for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
39f8891e5eSChristoph Lameter 			ret[i] += this->event[i];
40f8891e5eSChristoph Lameter 	}
41f8891e5eSChristoph Lameter }
42f8891e5eSChristoph Lameter 
43f8891e5eSChristoph Lameter /*
44f8891e5eSChristoph Lameter  * Accumulate the vm event counters across all CPUs.
45f8891e5eSChristoph Lameter  * The result is unavoidably approximate - it can change
46f8891e5eSChristoph Lameter  * during and after execution of this function.
47f8891e5eSChristoph Lameter */
48f8891e5eSChristoph Lameter void all_vm_events(unsigned long *ret)
49f8891e5eSChristoph Lameter {
50f8891e5eSChristoph Lameter 	sum_vm_events(ret, &cpu_online_map);
51f8891e5eSChristoph Lameter }
5232dd66fcSHeiko Carstens EXPORT_SYMBOL_GPL(all_vm_events);
53f8891e5eSChristoph Lameter 
54f8891e5eSChristoph Lameter #ifdef CONFIG_HOTPLUG
55f8891e5eSChristoph Lameter /*
56f8891e5eSChristoph Lameter  * Fold the foreign cpu events into our own.
57f8891e5eSChristoph Lameter  *
58f8891e5eSChristoph Lameter  * This is adding to the events on one processor
59f8891e5eSChristoph Lameter  * but keeps the global counts constant.
60f8891e5eSChristoph Lameter  */
61f8891e5eSChristoph Lameter void vm_events_fold_cpu(int cpu)
62f8891e5eSChristoph Lameter {
63f8891e5eSChristoph Lameter 	struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu);
64f8891e5eSChristoph Lameter 	int i;
65f8891e5eSChristoph Lameter 
66f8891e5eSChristoph Lameter 	for (i = 0; i < NR_VM_EVENT_ITEMS; i++) {
67f8891e5eSChristoph Lameter 		count_vm_events(i, fold_state->event[i]);
68f8891e5eSChristoph Lameter 		fold_state->event[i] = 0;
69f8891e5eSChristoph Lameter 	}
70f8891e5eSChristoph Lameter }
71f8891e5eSChristoph Lameter #endif /* CONFIG_HOTPLUG */
72f8891e5eSChristoph Lameter 
73f8891e5eSChristoph Lameter #endif /* CONFIG_VM_EVENT_COUNTERS */
74f8891e5eSChristoph Lameter 
752244b95aSChristoph Lameter /*
762244b95aSChristoph Lameter  * Manage combined zone based / global counters
772244b95aSChristoph Lameter  *
782244b95aSChristoph Lameter  * vm_stat contains the global counters
792244b95aSChristoph Lameter  */
802244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
812244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat);
822244b95aSChristoph Lameter 
832244b95aSChristoph Lameter #ifdef CONFIG_SMP
842244b95aSChristoph Lameter 
85df9ecabaSChristoph Lameter static int calculate_threshold(struct zone *zone)
86df9ecabaSChristoph Lameter {
87df9ecabaSChristoph Lameter 	int threshold;
88df9ecabaSChristoph Lameter 	int mem;	/* memory in 128 MB units */
892244b95aSChristoph Lameter 
902244b95aSChristoph Lameter 	/*
91df9ecabaSChristoph Lameter 	 * The threshold scales with the number of processors and the amount
92df9ecabaSChristoph Lameter 	 * of memory per zone. More memory means that we can defer updates for
93df9ecabaSChristoph Lameter 	 * longer, more processors could lead to more contention.
94df9ecabaSChristoph Lameter  	 * fls() is used to have a cheap way of logarithmic scaling.
952244b95aSChristoph Lameter 	 *
96df9ecabaSChristoph Lameter 	 * Some sample thresholds:
97df9ecabaSChristoph Lameter 	 *
98df9ecabaSChristoph Lameter 	 * Threshold	Processors	(fls)	Zonesize	fls(mem+1)
99df9ecabaSChristoph Lameter 	 * ------------------------------------------------------------------
100df9ecabaSChristoph Lameter 	 * 8		1		1	0.9-1 GB	4
101df9ecabaSChristoph Lameter 	 * 16		2		2	0.9-1 GB	4
102df9ecabaSChristoph Lameter 	 * 20 		2		2	1-2 GB		5
103df9ecabaSChristoph Lameter 	 * 24		2		2	2-4 GB		6
104df9ecabaSChristoph Lameter 	 * 28		2		2	4-8 GB		7
105df9ecabaSChristoph Lameter 	 * 32		2		2	8-16 GB		8
106df9ecabaSChristoph Lameter 	 * 4		2		2	<128M		1
107df9ecabaSChristoph Lameter 	 * 30		4		3	2-4 GB		5
108df9ecabaSChristoph Lameter 	 * 48		4		3	8-16 GB		8
109df9ecabaSChristoph Lameter 	 * 32		8		4	1-2 GB		4
110df9ecabaSChristoph Lameter 	 * 32		8		4	0.9-1GB		4
111df9ecabaSChristoph Lameter 	 * 10		16		5	<128M		1
112df9ecabaSChristoph Lameter 	 * 40		16		5	900M		4
113df9ecabaSChristoph Lameter 	 * 70		64		7	2-4 GB		5
114df9ecabaSChristoph Lameter 	 * 84		64		7	4-8 GB		6
115df9ecabaSChristoph Lameter 	 * 108		512		9	4-8 GB		6
116df9ecabaSChristoph Lameter 	 * 125		1024		10	8-16 GB		8
117df9ecabaSChristoph Lameter 	 * 125		1024		10	16-32 GB	9
1182244b95aSChristoph Lameter 	 */
119df9ecabaSChristoph Lameter 
120df9ecabaSChristoph Lameter 	mem = zone->present_pages >> (27 - PAGE_SHIFT);
121df9ecabaSChristoph Lameter 
122df9ecabaSChristoph Lameter 	threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem));
123df9ecabaSChristoph Lameter 
124df9ecabaSChristoph Lameter 	/*
125df9ecabaSChristoph Lameter 	 * Maximum threshold is 125
126df9ecabaSChristoph Lameter 	 */
127df9ecabaSChristoph Lameter 	threshold = min(125, threshold);
128df9ecabaSChristoph Lameter 
129df9ecabaSChristoph Lameter 	return threshold;
130df9ecabaSChristoph Lameter }
131df9ecabaSChristoph Lameter 
132df9ecabaSChristoph Lameter /*
133df9ecabaSChristoph Lameter  * Refresh the thresholds for each zone.
134df9ecabaSChristoph Lameter  */
135df9ecabaSChristoph Lameter static void refresh_zone_stat_thresholds(void)
1362244b95aSChristoph Lameter {
137df9ecabaSChristoph Lameter 	struct zone *zone;
138df9ecabaSChristoph Lameter 	int cpu;
139df9ecabaSChristoph Lameter 	int threshold;
140df9ecabaSChristoph Lameter 
141df9ecabaSChristoph Lameter 	for_each_zone(zone) {
142df9ecabaSChristoph Lameter 
143df9ecabaSChristoph Lameter 		if (!zone->present_pages)
144df9ecabaSChristoph Lameter 			continue;
145df9ecabaSChristoph Lameter 
146df9ecabaSChristoph Lameter 		threshold = calculate_threshold(zone);
147df9ecabaSChristoph Lameter 
148df9ecabaSChristoph Lameter 		for_each_online_cpu(cpu)
149df9ecabaSChristoph Lameter 			zone_pcp(zone, cpu)->stat_threshold = threshold;
150df9ecabaSChristoph Lameter 	}
1512244b95aSChristoph Lameter }
1522244b95aSChristoph Lameter 
1532244b95aSChristoph Lameter /*
1542244b95aSChristoph Lameter  * For use when we know that interrupts are disabled.
1552244b95aSChristoph Lameter  */
1562244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1572244b95aSChristoph Lameter 				int delta)
1582244b95aSChristoph Lameter {
159df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
160df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
1612244b95aSChristoph Lameter 	long x;
1622244b95aSChristoph Lameter 
1632244b95aSChristoph Lameter 	x = delta + *p;
1642244b95aSChristoph Lameter 
165df9ecabaSChristoph Lameter 	if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) {
1662244b95aSChristoph Lameter 		zone_page_state_add(x, zone, item);
1672244b95aSChristoph Lameter 		x = 0;
1682244b95aSChristoph Lameter 	}
1692244b95aSChristoph Lameter 	*p = x;
1702244b95aSChristoph Lameter }
1712244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state);
1722244b95aSChristoph Lameter 
1732244b95aSChristoph Lameter /*
1742244b95aSChristoph Lameter  * For an unknown interrupt state
1752244b95aSChristoph Lameter  */
1762244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
1772244b95aSChristoph Lameter 					int delta)
1782244b95aSChristoph Lameter {
1792244b95aSChristoph Lameter 	unsigned long flags;
1802244b95aSChristoph Lameter 
1812244b95aSChristoph Lameter 	local_irq_save(flags);
1822244b95aSChristoph Lameter 	__mod_zone_page_state(zone, item, delta);
1832244b95aSChristoph Lameter 	local_irq_restore(flags);
1842244b95aSChristoph Lameter }
1852244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state);
1862244b95aSChristoph Lameter 
1872244b95aSChristoph Lameter /*
1882244b95aSChristoph Lameter  * Optimized increment and decrement functions.
1892244b95aSChristoph Lameter  *
1902244b95aSChristoph Lameter  * These are only for a single page and therefore can take a struct page *
1912244b95aSChristoph Lameter  * argument instead of struct zone *. This allows the inclusion of the code
1922244b95aSChristoph Lameter  * generated for page_zone(page) into the optimized functions.
1932244b95aSChristoph Lameter  *
1942244b95aSChristoph Lameter  * No overflow check is necessary and therefore the differential can be
1952244b95aSChristoph Lameter  * incremented or decremented in place which may allow the compilers to
1962244b95aSChristoph Lameter  * generate better code.
1972244b95aSChristoph Lameter  * The increment or decrement is known and therefore one boundary check can
1982244b95aSChristoph Lameter  * be omitted.
1992244b95aSChristoph Lameter  *
200df9ecabaSChristoph Lameter  * NOTE: These functions are very performance sensitive. Change only
201df9ecabaSChristoph Lameter  * with care.
202df9ecabaSChristoph Lameter  *
2032244b95aSChristoph Lameter  * Some processors have inc/dec instructions that are atomic vs an interrupt.
2042244b95aSChristoph Lameter  * However, the code must first determine the differential location in a zone
2052244b95aSChristoph Lameter  * based on the processor number and then inc/dec the counter. There is no
2062244b95aSChristoph Lameter  * guarantee without disabling preemption that the processor will not change
2072244b95aSChristoph Lameter  * in between and therefore the atomicity vs. interrupt cannot be exploited
2082244b95aSChristoph Lameter  * in a useful way here.
2092244b95aSChristoph Lameter  */
210c8785385SChristoph Lameter void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
2112244b95aSChristoph Lameter {
212df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
213df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2142244b95aSChristoph Lameter 
2152244b95aSChristoph Lameter 	(*p)++;
2162244b95aSChristoph Lameter 
217df9ecabaSChristoph Lameter 	if (unlikely(*p > pcp->stat_threshold)) {
218df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
219df9ecabaSChristoph Lameter 
220df9ecabaSChristoph Lameter 		zone_page_state_add(*p + overstep, zone, item);
221df9ecabaSChristoph Lameter 		*p = -overstep;
2222244b95aSChristoph Lameter 	}
2232244b95aSChristoph Lameter }
224ca889e6cSChristoph Lameter 
225ca889e6cSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
226ca889e6cSChristoph Lameter {
227ca889e6cSChristoph Lameter 	__inc_zone_state(page_zone(page), item);
228ca889e6cSChristoph Lameter }
2292244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state);
2302244b95aSChristoph Lameter 
231c8785385SChristoph Lameter void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
2322244b95aSChristoph Lameter {
233df9ecabaSChristoph Lameter 	struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id());
234df9ecabaSChristoph Lameter 	s8 *p = pcp->vm_stat_diff + item;
2352244b95aSChristoph Lameter 
2362244b95aSChristoph Lameter 	(*p)--;
2372244b95aSChristoph Lameter 
238df9ecabaSChristoph Lameter 	if (unlikely(*p < - pcp->stat_threshold)) {
239df9ecabaSChristoph Lameter 		int overstep = pcp->stat_threshold / 2;
240df9ecabaSChristoph Lameter 
241df9ecabaSChristoph Lameter 		zone_page_state_add(*p - overstep, zone, item);
242df9ecabaSChristoph Lameter 		*p = overstep;
2432244b95aSChristoph Lameter 	}
2442244b95aSChristoph Lameter }
245c8785385SChristoph Lameter 
246c8785385SChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
247c8785385SChristoph Lameter {
248c8785385SChristoph Lameter 	__dec_zone_state(page_zone(page), item);
249c8785385SChristoph Lameter }
2502244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state);
2512244b95aSChristoph Lameter 
252ca889e6cSChristoph Lameter void inc_zone_state(struct zone *zone, enum zone_stat_item item)
253ca889e6cSChristoph Lameter {
254ca889e6cSChristoph Lameter 	unsigned long flags;
255ca889e6cSChristoph Lameter 
256ca889e6cSChristoph Lameter 	local_irq_save(flags);
257ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
258ca889e6cSChristoph Lameter 	local_irq_restore(flags);
259ca889e6cSChristoph Lameter }
260ca889e6cSChristoph Lameter 
2612244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item)
2622244b95aSChristoph Lameter {
2632244b95aSChristoph Lameter 	unsigned long flags;
2642244b95aSChristoph Lameter 	struct zone *zone;
2652244b95aSChristoph Lameter 
2662244b95aSChristoph Lameter 	zone = page_zone(page);
2672244b95aSChristoph Lameter 	local_irq_save(flags);
268ca889e6cSChristoph Lameter 	__inc_zone_state(zone, item);
2692244b95aSChristoph Lameter 	local_irq_restore(flags);
2702244b95aSChristoph Lameter }
2712244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state);
2722244b95aSChristoph Lameter 
2732244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item)
2742244b95aSChristoph Lameter {
2752244b95aSChristoph Lameter 	unsigned long flags;
2762244b95aSChristoph Lameter 
2772244b95aSChristoph Lameter 	local_irq_save(flags);
278a302eb4eSChristoph Lameter 	__dec_zone_page_state(page, item);
2792244b95aSChristoph Lameter 	local_irq_restore(flags);
2802244b95aSChristoph Lameter }
2812244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state);
2822244b95aSChristoph Lameter 
2832244b95aSChristoph Lameter /*
2842244b95aSChristoph Lameter  * Update the zone counters for one cpu.
2854037d452SChristoph Lameter  *
2864037d452SChristoph Lameter  * Note that refresh_cpu_vm_stats strives to only access
2874037d452SChristoph Lameter  * node local memory. The per cpu pagesets on remote zones are placed
2884037d452SChristoph Lameter  * in the memory local to the processor using that pageset. So the
2894037d452SChristoph Lameter  * loop over all zones will access a series of cachelines local to
2904037d452SChristoph Lameter  * the processor.
2914037d452SChristoph Lameter  *
2924037d452SChristoph Lameter  * The call to zone_page_state_add updates the cachelines with the
2934037d452SChristoph Lameter  * statistics in the remote zone struct as well as the global cachelines
2944037d452SChristoph Lameter  * with the global counters. These could cause remote node cache line
2954037d452SChristoph Lameter  * bouncing and will have to be only done when necessary.
2962244b95aSChristoph Lameter  */
2972244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu)
2982244b95aSChristoph Lameter {
2992244b95aSChristoph Lameter 	struct zone *zone;
3002244b95aSChristoph Lameter 	int i;
3012244b95aSChristoph Lameter 	unsigned long flags;
3022244b95aSChristoph Lameter 
3032244b95aSChristoph Lameter 	for_each_zone(zone) {
3044037d452SChristoph Lameter 		struct per_cpu_pageset *p;
3052244b95aSChristoph Lameter 
30639bbcb8fSChristoph Lameter 		if (!populated_zone(zone))
30739bbcb8fSChristoph Lameter 			continue;
30839bbcb8fSChristoph Lameter 
3094037d452SChristoph Lameter 		p = zone_pcp(zone, cpu);
3102244b95aSChristoph Lameter 
3112244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
3124037d452SChristoph Lameter 			if (p->vm_stat_diff[i]) {
3132244b95aSChristoph Lameter 				local_irq_save(flags);
3144037d452SChristoph Lameter 				zone_page_state_add(p->vm_stat_diff[i],
3152244b95aSChristoph Lameter 					zone, i);
3164037d452SChristoph Lameter 				p->vm_stat_diff[i] = 0;
3174037d452SChristoph Lameter #ifdef CONFIG_NUMA
3184037d452SChristoph Lameter 				/* 3 seconds idle till flush */
3194037d452SChristoph Lameter 				p->expire = 3;
3204037d452SChristoph Lameter #endif
3212244b95aSChristoph Lameter 				local_irq_restore(flags);
3222244b95aSChristoph Lameter 			}
3234037d452SChristoph Lameter #ifdef CONFIG_NUMA
3244037d452SChristoph Lameter 		/*
3254037d452SChristoph Lameter 		 * Deal with draining the remote pageset of this
3264037d452SChristoph Lameter 		 * processor
3274037d452SChristoph Lameter 		 *
3284037d452SChristoph Lameter 		 * Check if there are pages remaining in this pageset
3294037d452SChristoph Lameter 		 * if not then there is nothing to expire.
3304037d452SChristoph Lameter 		 */
3314037d452SChristoph Lameter 		if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
3324037d452SChristoph Lameter 			continue;
3334037d452SChristoph Lameter 
3344037d452SChristoph Lameter 		/*
3354037d452SChristoph Lameter 		 * We never drain zones local to this processor.
3364037d452SChristoph Lameter 		 */
3374037d452SChristoph Lameter 		if (zone_to_nid(zone) == numa_node_id()) {
3384037d452SChristoph Lameter 			p->expire = 0;
3394037d452SChristoph Lameter 			continue;
3404037d452SChristoph Lameter 		}
3414037d452SChristoph Lameter 
3424037d452SChristoph Lameter 		p->expire--;
3434037d452SChristoph Lameter 		if (p->expire)
3444037d452SChristoph Lameter 			continue;
3454037d452SChristoph Lameter 
3464037d452SChristoph Lameter 		if (p->pcp[0].count)
3474037d452SChristoph Lameter 			drain_zone_pages(zone, p->pcp + 0);
3484037d452SChristoph Lameter 
3494037d452SChristoph Lameter 		if (p->pcp[1].count)
3504037d452SChristoph Lameter 			drain_zone_pages(zone, p->pcp + 1);
3514037d452SChristoph Lameter #endif
3522244b95aSChristoph Lameter 	}
3532244b95aSChristoph Lameter }
3542244b95aSChristoph Lameter 
3552244b95aSChristoph Lameter static void __refresh_cpu_vm_stats(void *dummy)
3562244b95aSChristoph Lameter {
3572244b95aSChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
3582244b95aSChristoph Lameter }
3592244b95aSChristoph Lameter 
3602244b95aSChristoph Lameter /*
3612244b95aSChristoph Lameter  * Consolidate all counters.
3622244b95aSChristoph Lameter  *
3632244b95aSChristoph Lameter  * Note that the result is less inaccurate but still inaccurate
3642244b95aSChristoph Lameter  * if concurrent processes are allowed to run.
3652244b95aSChristoph Lameter  */
3662244b95aSChristoph Lameter void refresh_vm_stats(void)
3672244b95aSChristoph Lameter {
3682244b95aSChristoph Lameter 	on_each_cpu(__refresh_cpu_vm_stats, NULL, 0, 1);
3692244b95aSChristoph Lameter }
3702244b95aSChristoph Lameter EXPORT_SYMBOL(refresh_vm_stats);
3712244b95aSChristoph Lameter 
3722244b95aSChristoph Lameter #endif
3732244b95aSChristoph Lameter 
374ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
375ca889e6cSChristoph Lameter /*
376ca889e6cSChristoph Lameter  * zonelist = the list of zones passed to the allocator
377ca889e6cSChristoph Lameter  * z 	    = the zone from which the allocation occurred.
378ca889e6cSChristoph Lameter  *
379ca889e6cSChristoph Lameter  * Must be called with interrupts disabled.
380ca889e6cSChristoph Lameter  */
381ca889e6cSChristoph Lameter void zone_statistics(struct zonelist *zonelist, struct zone *z)
382ca889e6cSChristoph Lameter {
383ca889e6cSChristoph Lameter 	if (z->zone_pgdat == zonelist->zones[0]->zone_pgdat) {
384ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_HIT);
385ca889e6cSChristoph Lameter 	} else {
386ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_MISS);
387ca889e6cSChristoph Lameter 		__inc_zone_state(zonelist->zones[0], NUMA_FOREIGN);
388ca889e6cSChristoph Lameter 	}
3895d292343SChristoph Lameter 	if (z->node == numa_node_id())
390ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_LOCAL);
391ca889e6cSChristoph Lameter 	else
392ca889e6cSChristoph Lameter 		__inc_zone_state(z, NUMA_OTHER);
393ca889e6cSChristoph Lameter }
394ca889e6cSChristoph Lameter #endif
395ca889e6cSChristoph Lameter 
396f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS
397f6ac2354SChristoph Lameter 
398f6ac2354SChristoph Lameter #include <linux/seq_file.h>
399f6ac2354SChristoph Lameter 
400f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos)
401f6ac2354SChristoph Lameter {
402f6ac2354SChristoph Lameter 	pg_data_t *pgdat;
403f6ac2354SChristoph Lameter 	loff_t node = *pos;
404f6ac2354SChristoph Lameter 	for (pgdat = first_online_pgdat();
405f6ac2354SChristoph Lameter 	     pgdat && node;
406f6ac2354SChristoph Lameter 	     pgdat = next_online_pgdat(pgdat))
407f6ac2354SChristoph Lameter 		--node;
408f6ac2354SChristoph Lameter 
409f6ac2354SChristoph Lameter 	return pgdat;
410f6ac2354SChristoph Lameter }
411f6ac2354SChristoph Lameter 
412f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
413f6ac2354SChristoph Lameter {
414f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
415f6ac2354SChristoph Lameter 
416f6ac2354SChristoph Lameter 	(*pos)++;
417f6ac2354SChristoph Lameter 	return next_online_pgdat(pgdat);
418f6ac2354SChristoph Lameter }
419f6ac2354SChristoph Lameter 
420f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg)
421f6ac2354SChristoph Lameter {
422f6ac2354SChristoph Lameter }
423f6ac2354SChristoph Lameter 
424f6ac2354SChristoph Lameter /*
425f6ac2354SChristoph Lameter  * This walks the free areas for each zone.
426f6ac2354SChristoph Lameter  */
427f6ac2354SChristoph Lameter static int frag_show(struct seq_file *m, void *arg)
428f6ac2354SChristoph Lameter {
429f6ac2354SChristoph Lameter 	pg_data_t *pgdat = (pg_data_t *)arg;
430f6ac2354SChristoph Lameter 	struct zone *zone;
431f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
432f6ac2354SChristoph Lameter 	unsigned long flags;
433f6ac2354SChristoph Lameter 	int order;
434f6ac2354SChristoph Lameter 
435f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
436f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
437f6ac2354SChristoph Lameter 			continue;
438f6ac2354SChristoph Lameter 
439f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
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 		spin_unlock_irqrestore(&zone->lock, flags);
444f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
445f6ac2354SChristoph Lameter 	}
446f6ac2354SChristoph Lameter 	return 0;
447f6ac2354SChristoph Lameter }
448f6ac2354SChristoph Lameter 
44915ad7cdcSHelge Deller const struct seq_operations fragmentation_op = {
450f6ac2354SChristoph Lameter 	.start	= frag_start,
451f6ac2354SChristoph Lameter 	.next	= frag_next,
452f6ac2354SChristoph Lameter 	.stop	= frag_stop,
453f6ac2354SChristoph Lameter 	.show	= frag_show,
454f6ac2354SChristoph Lameter };
455f6ac2354SChristoph Lameter 
4564b51d669SChristoph Lameter #ifdef CONFIG_ZONE_DMA
4574b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx) xx "_dma",
4584b51d669SChristoph Lameter #else
4594b51d669SChristoph Lameter #define TEXT_FOR_DMA(xx)
4604b51d669SChristoph Lameter #endif
4614b51d669SChristoph Lameter 
46227bf71c2SChristoph Lameter #ifdef CONFIG_ZONE_DMA32
46327bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx) xx "_dma32",
46427bf71c2SChristoph Lameter #else
46527bf71c2SChristoph Lameter #define TEXT_FOR_DMA32(xx)
46627bf71c2SChristoph Lameter #endif
46727bf71c2SChristoph Lameter 
46827bf71c2SChristoph Lameter #ifdef CONFIG_HIGHMEM
46927bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx) xx "_high",
47027bf71c2SChristoph Lameter #else
47127bf71c2SChristoph Lameter #define TEXT_FOR_HIGHMEM(xx)
47227bf71c2SChristoph Lameter #endif
47327bf71c2SChristoph Lameter 
4744b51d669SChristoph Lameter #define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
47527bf71c2SChristoph Lameter 					TEXT_FOR_HIGHMEM(xx)
47627bf71c2SChristoph Lameter 
47715ad7cdcSHelge Deller static const char * const vmstat_text[] = {
4782244b95aSChristoph Lameter 	/* Zoned VM counters */
479d23ad423SChristoph Lameter 	"nr_free_pages",
480c8785385SChristoph Lameter 	"nr_active",
481c8785385SChristoph Lameter 	"nr_inactive",
482f3dbd344SChristoph Lameter 	"nr_anon_pages",
48365ba55f5SChristoph Lameter 	"nr_mapped",
484347ce434SChristoph Lameter 	"nr_file_pages",
48551ed4491SChristoph Lameter 	"nr_dirty",
48651ed4491SChristoph Lameter 	"nr_writeback",
487972d1a7bSChristoph Lameter 	"nr_slab_reclaimable",
488972d1a7bSChristoph Lameter 	"nr_slab_unreclaimable",
489df849a15SChristoph Lameter 	"nr_page_table_pages",
490f6ac2354SChristoph Lameter 	"nr_unstable",
491d2c5e30cSChristoph Lameter 	"nr_bounce",
492e129b5c2SAndrew Morton 	"nr_vmscan_write",
493f6ac2354SChristoph Lameter 
494ca889e6cSChristoph Lameter #ifdef CONFIG_NUMA
495ca889e6cSChristoph Lameter 	"numa_hit",
496ca889e6cSChristoph Lameter 	"numa_miss",
497ca889e6cSChristoph Lameter 	"numa_foreign",
498ca889e6cSChristoph Lameter 	"numa_interleave",
499ca889e6cSChristoph Lameter 	"numa_local",
500ca889e6cSChristoph Lameter 	"numa_other",
501ca889e6cSChristoph Lameter #endif
502ca889e6cSChristoph Lameter 
503f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
504f6ac2354SChristoph Lameter 	"pgpgin",
505f6ac2354SChristoph Lameter 	"pgpgout",
506f6ac2354SChristoph Lameter 	"pswpin",
507f6ac2354SChristoph Lameter 	"pswpout",
508f6ac2354SChristoph Lameter 
50927bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgalloc")
510f6ac2354SChristoph Lameter 
511f6ac2354SChristoph Lameter 	"pgfree",
512f6ac2354SChristoph Lameter 	"pgactivate",
513f6ac2354SChristoph Lameter 	"pgdeactivate",
514f6ac2354SChristoph Lameter 
515f6ac2354SChristoph Lameter 	"pgfault",
516f6ac2354SChristoph Lameter 	"pgmajfault",
517f6ac2354SChristoph Lameter 
51827bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgrefill")
51927bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgsteal")
52027bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_kswapd")
52127bf71c2SChristoph Lameter 	TEXTS_FOR_ZONES("pgscan_direct")
522f6ac2354SChristoph Lameter 
523f6ac2354SChristoph Lameter 	"pginodesteal",
524f6ac2354SChristoph Lameter 	"slabs_scanned",
525f6ac2354SChristoph Lameter 	"kswapd_steal",
526f6ac2354SChristoph Lameter 	"kswapd_inodesteal",
527f6ac2354SChristoph Lameter 	"pageoutrun",
528f6ac2354SChristoph Lameter 	"allocstall",
529f6ac2354SChristoph Lameter 
530f6ac2354SChristoph Lameter 	"pgrotated",
531f8891e5eSChristoph Lameter #endif
532f6ac2354SChristoph Lameter };
533f6ac2354SChristoph Lameter 
534f6ac2354SChristoph Lameter /*
535f6ac2354SChristoph Lameter  * Output information about zones in @pgdat.
536f6ac2354SChristoph Lameter  */
537f6ac2354SChristoph Lameter static int zoneinfo_show(struct seq_file *m, void *arg)
538f6ac2354SChristoph Lameter {
539f6ac2354SChristoph Lameter 	pg_data_t *pgdat = arg;
540f6ac2354SChristoph Lameter 	struct zone *zone;
541f6ac2354SChristoph Lameter 	struct zone *node_zones = pgdat->node_zones;
542f6ac2354SChristoph Lameter 	unsigned long flags;
543f6ac2354SChristoph Lameter 
544f6ac2354SChristoph Lameter 	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
545f6ac2354SChristoph Lameter 		int i;
546f6ac2354SChristoph Lameter 
547f6ac2354SChristoph Lameter 		if (!populated_zone(zone))
548f6ac2354SChristoph Lameter 			continue;
549f6ac2354SChristoph Lameter 
550f6ac2354SChristoph Lameter 		spin_lock_irqsave(&zone->lock, flags);
551f6ac2354SChristoph Lameter 		seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
552f6ac2354SChristoph Lameter 		seq_printf(m,
553f6ac2354SChristoph Lameter 			   "\n  pages free     %lu"
554f6ac2354SChristoph Lameter 			   "\n        min      %lu"
555f6ac2354SChristoph Lameter 			   "\n        low      %lu"
556f6ac2354SChristoph Lameter 			   "\n        high     %lu"
557f6ac2354SChristoph Lameter 			   "\n        scanned  %lu (a: %lu i: %lu)"
558f6ac2354SChristoph Lameter 			   "\n        spanned  %lu"
559f6ac2354SChristoph Lameter 			   "\n        present  %lu",
560d23ad423SChristoph Lameter 			   zone_page_state(zone, NR_FREE_PAGES),
561f6ac2354SChristoph Lameter 			   zone->pages_min,
562f6ac2354SChristoph Lameter 			   zone->pages_low,
563f6ac2354SChristoph Lameter 			   zone->pages_high,
564f6ac2354SChristoph Lameter 			   zone->pages_scanned,
565f6ac2354SChristoph Lameter 			   zone->nr_scan_active, zone->nr_scan_inactive,
566f6ac2354SChristoph Lameter 			   zone->spanned_pages,
567f6ac2354SChristoph Lameter 			   zone->present_pages);
5682244b95aSChristoph Lameter 
5692244b95aSChristoph Lameter 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
5702244b95aSChristoph Lameter 			seq_printf(m, "\n    %-12s %lu", vmstat_text[i],
5712244b95aSChristoph Lameter 					zone_page_state(zone, i));
5722244b95aSChristoph Lameter 
573f6ac2354SChristoph Lameter 		seq_printf(m,
574f6ac2354SChristoph Lameter 			   "\n        protection: (%lu",
575f6ac2354SChristoph Lameter 			   zone->lowmem_reserve[0]);
576f6ac2354SChristoph Lameter 		for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
577f6ac2354SChristoph Lameter 			seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
578f6ac2354SChristoph Lameter 		seq_printf(m,
579f6ac2354SChristoph Lameter 			   ")"
580f6ac2354SChristoph Lameter 			   "\n  pagesets");
581f6ac2354SChristoph Lameter 		for_each_online_cpu(i) {
582f6ac2354SChristoph Lameter 			struct per_cpu_pageset *pageset;
583f6ac2354SChristoph Lameter 			int j;
584f6ac2354SChristoph Lameter 
585f6ac2354SChristoph Lameter 			pageset = zone_pcp(zone, i);
586f6ac2354SChristoph Lameter 			for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
587f6ac2354SChristoph Lameter 				seq_printf(m,
588f6ac2354SChristoph Lameter 					   "\n    cpu: %i pcp: %i"
589f6ac2354SChristoph Lameter 					   "\n              count: %i"
590f6ac2354SChristoph Lameter 					   "\n              high:  %i"
591f6ac2354SChristoph Lameter 					   "\n              batch: %i",
592f6ac2354SChristoph Lameter 					   i, j,
593f6ac2354SChristoph Lameter 					   pageset->pcp[j].count,
594f6ac2354SChristoph Lameter 					   pageset->pcp[j].high,
595f6ac2354SChristoph Lameter 					   pageset->pcp[j].batch);
596f6ac2354SChristoph Lameter 			}
597df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
598df9ecabaSChristoph Lameter 			seq_printf(m, "\n  vm stats threshold: %d",
599df9ecabaSChristoph Lameter 					pageset->stat_threshold);
600df9ecabaSChristoph Lameter #endif
601f6ac2354SChristoph Lameter 		}
602f6ac2354SChristoph Lameter 		seq_printf(m,
603f6ac2354SChristoph Lameter 			   "\n  all_unreclaimable: %u"
604f6ac2354SChristoph Lameter 			   "\n  prev_priority:     %i"
605f6ac2354SChristoph Lameter 			   "\n  start_pfn:         %lu",
606f6ac2354SChristoph Lameter 			   zone->all_unreclaimable,
607f6ac2354SChristoph Lameter 			   zone->prev_priority,
608f6ac2354SChristoph Lameter 			   zone->zone_start_pfn);
609f6ac2354SChristoph Lameter 		spin_unlock_irqrestore(&zone->lock, flags);
610f6ac2354SChristoph Lameter 		seq_putc(m, '\n');
611f6ac2354SChristoph Lameter 	}
612f6ac2354SChristoph Lameter 	return 0;
613f6ac2354SChristoph Lameter }
614f6ac2354SChristoph Lameter 
61515ad7cdcSHelge Deller const struct seq_operations zoneinfo_op = {
616f6ac2354SChristoph Lameter 	.start	= frag_start, /* iterate over all zones. The same as in
617f6ac2354SChristoph Lameter 			       * fragmentation. */
618f6ac2354SChristoph Lameter 	.next	= frag_next,
619f6ac2354SChristoph Lameter 	.stop	= frag_stop,
620f6ac2354SChristoph Lameter 	.show	= zoneinfo_show,
621f6ac2354SChristoph Lameter };
622f6ac2354SChristoph Lameter 
623f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos)
624f6ac2354SChristoph Lameter {
6252244b95aSChristoph Lameter 	unsigned long *v;
626f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
627f8891e5eSChristoph Lameter 	unsigned long *e;
628f8891e5eSChristoph Lameter #endif
6292244b95aSChristoph Lameter 	int i;
630f6ac2354SChristoph Lameter 
631f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
632f6ac2354SChristoph Lameter 		return NULL;
633f6ac2354SChristoph Lameter 
634f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
6352244b95aSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long)
636f8891e5eSChristoph Lameter 			+ sizeof(struct vm_event_state), GFP_KERNEL);
637f8891e5eSChristoph Lameter #else
638f8891e5eSChristoph Lameter 	v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long),
639f8891e5eSChristoph Lameter 			GFP_KERNEL);
640f8891e5eSChristoph Lameter #endif
6412244b95aSChristoph Lameter 	m->private = v;
6422244b95aSChristoph Lameter 	if (!v)
643f6ac2354SChristoph Lameter 		return ERR_PTR(-ENOMEM);
6442244b95aSChristoph Lameter 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
6452244b95aSChristoph Lameter 		v[i] = global_page_state(i);
646f8891e5eSChristoph Lameter #ifdef CONFIG_VM_EVENT_COUNTERS
647f8891e5eSChristoph Lameter 	e = v + NR_VM_ZONE_STAT_ITEMS;
648f8891e5eSChristoph Lameter 	all_vm_events(e);
649f8891e5eSChristoph Lameter 	e[PGPGIN] /= 2;		/* sectors -> kbytes */
650f8891e5eSChristoph Lameter 	e[PGPGOUT] /= 2;
651f8891e5eSChristoph Lameter #endif
6522244b95aSChristoph Lameter 	return v + *pos;
653f6ac2354SChristoph Lameter }
654f6ac2354SChristoph Lameter 
655f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
656f6ac2354SChristoph Lameter {
657f6ac2354SChristoph Lameter 	(*pos)++;
658f6ac2354SChristoph Lameter 	if (*pos >= ARRAY_SIZE(vmstat_text))
659f6ac2354SChristoph Lameter 		return NULL;
660f6ac2354SChristoph Lameter 	return (unsigned long *)m->private + *pos;
661f6ac2354SChristoph Lameter }
662f6ac2354SChristoph Lameter 
663f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg)
664f6ac2354SChristoph Lameter {
665f6ac2354SChristoph Lameter 	unsigned long *l = arg;
666f6ac2354SChristoph Lameter 	unsigned long off = l - (unsigned long *)m->private;
667f6ac2354SChristoph Lameter 
668f6ac2354SChristoph Lameter 	seq_printf(m, "%s %lu\n", vmstat_text[off], *l);
669f6ac2354SChristoph Lameter 	return 0;
670f6ac2354SChristoph Lameter }
671f6ac2354SChristoph Lameter 
672f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg)
673f6ac2354SChristoph Lameter {
674f6ac2354SChristoph Lameter 	kfree(m->private);
675f6ac2354SChristoph Lameter 	m->private = NULL;
676f6ac2354SChristoph Lameter }
677f6ac2354SChristoph Lameter 
67815ad7cdcSHelge Deller const struct seq_operations vmstat_op = {
679f6ac2354SChristoph Lameter 	.start	= vmstat_start,
680f6ac2354SChristoph Lameter 	.next	= vmstat_next,
681f6ac2354SChristoph Lameter 	.stop	= vmstat_stop,
682f6ac2354SChristoph Lameter 	.show	= vmstat_show,
683f6ac2354SChristoph Lameter };
684f6ac2354SChristoph Lameter 
685f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */
686f6ac2354SChristoph Lameter 
687df9ecabaSChristoph Lameter #ifdef CONFIG_SMP
688d1187ed2SChristoph Lameter static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
68977461ab3SChristoph Lameter int sysctl_stat_interval __read_mostly = HZ;
690d1187ed2SChristoph Lameter 
691d1187ed2SChristoph Lameter static void vmstat_update(struct work_struct *w)
692d1187ed2SChristoph Lameter {
693d1187ed2SChristoph Lameter 	refresh_cpu_vm_stats(smp_processor_id());
69477461ab3SChristoph Lameter 	schedule_delayed_work(&__get_cpu_var(vmstat_work),
69577461ab3SChristoph Lameter 		sysctl_stat_interval);
696d1187ed2SChristoph Lameter }
697d1187ed2SChristoph Lameter 
698d1187ed2SChristoph Lameter static void __devinit start_cpu_timer(int cpu)
699d1187ed2SChristoph Lameter {
700d1187ed2SChristoph Lameter 	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
701d1187ed2SChristoph Lameter 
70239bf6270SChristoph Lameter 	INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
703d1187ed2SChristoph Lameter 	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
704d1187ed2SChristoph Lameter }
705d1187ed2SChristoph Lameter 
706df9ecabaSChristoph Lameter /*
707df9ecabaSChristoph Lameter  * Use the cpu notifier to insure that the thresholds are recalculated
708df9ecabaSChristoph Lameter  * when necessary.
709df9ecabaSChristoph Lameter  */
710df9ecabaSChristoph Lameter static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
711df9ecabaSChristoph Lameter 		unsigned long action,
712df9ecabaSChristoph Lameter 		void *hcpu)
713df9ecabaSChristoph Lameter {
714d1187ed2SChristoph Lameter 	long cpu = (long)hcpu;
715d1187ed2SChristoph Lameter 
716df9ecabaSChristoph Lameter 	switch (action) {
717d1187ed2SChristoph Lameter 	case CPU_ONLINE:
718d1187ed2SChristoph Lameter 	case CPU_ONLINE_FROZEN:
719d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
720d1187ed2SChristoph Lameter 		break;
721d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE:
722d1187ed2SChristoph Lameter 	case CPU_DOWN_PREPARE_FROZEN:
723d1187ed2SChristoph Lameter 		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
724d1187ed2SChristoph Lameter 		per_cpu(vmstat_work, cpu).work.func = NULL;
725d1187ed2SChristoph Lameter 		break;
726d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED:
727d1187ed2SChristoph Lameter 	case CPU_DOWN_FAILED_FROZEN:
728d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
729d1187ed2SChristoph Lameter 		break;
730df9ecabaSChristoph Lameter 	case CPU_DEAD:
7318bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
732df9ecabaSChristoph Lameter 		refresh_zone_stat_thresholds();
733df9ecabaSChristoph Lameter 		break;
734df9ecabaSChristoph Lameter 	default:
735df9ecabaSChristoph Lameter 		break;
736df9ecabaSChristoph Lameter 	}
737df9ecabaSChristoph Lameter 	return NOTIFY_OK;
738df9ecabaSChristoph Lameter }
739df9ecabaSChristoph Lameter 
740df9ecabaSChristoph Lameter static struct notifier_block __cpuinitdata vmstat_notifier =
741df9ecabaSChristoph Lameter 	{ &vmstat_cpuup_callback, NULL, 0 };
742df9ecabaSChristoph Lameter 
743df9ecabaSChristoph Lameter int __init setup_vmstat(void)
744df9ecabaSChristoph Lameter {
745d1187ed2SChristoph Lameter 	int cpu;
746d1187ed2SChristoph Lameter 
747df9ecabaSChristoph Lameter 	refresh_zone_stat_thresholds();
748df9ecabaSChristoph Lameter 	register_cpu_notifier(&vmstat_notifier);
749d1187ed2SChristoph Lameter 
750d1187ed2SChristoph Lameter 	for_each_online_cpu(cpu)
751d1187ed2SChristoph Lameter 		start_cpu_timer(cpu);
752df9ecabaSChristoph Lameter 	return 0;
753df9ecabaSChristoph Lameter }
754df9ecabaSChristoph Lameter module_init(setup_vmstat)
755df9ecabaSChristoph Lameter #endif
756