]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
75320d6cc99743baf6cff88dba326c6c37073721
[thirdparty/kernel/stable-queue.git] /
1 From b44129b30652c8771db2265939bb8b463724043d Mon Sep 17 00:00:00 2001
2 From: Mel Gorman <mel@csn.ul.ie>
3 Date: Thu, 13 Jan 2011 15:45:43 -0800
4 Subject: mm: vmstat: use a single setter function and callback for adjusting percpu thresholds
5
6 From: Mel Gorman <mel@csn.ul.ie>
7
8 commit b44129b30652c8771db2265939bb8b463724043d upstream.
9
10 reduce_pgdat_percpu_threshold() and restore_pgdat_percpu_threshold() exist
11 to adjust the per-cpu vmstat thresholds while kswapd is awake to avoid
12 errors due to counter drift. The functions duplicate some code so this
13 patch replaces them with a single set_pgdat_percpu_threshold() that takes
14 a callback function to calculate the desired threshold as a parameter.
15
16 [akpm@linux-foundation.org: readability tweak]
17 [kosaki.motohiro@jp.fujitsu.com: set_pgdat_percpu_threshold(): don't use for_each_online_cpu]
18 Signed-off-by: Mel Gorman <mel@csn.ul.ie>
19 Reviewed-by: Christoph Lameter <cl@linux.com>
20 Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
21 Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
22 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
23 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
24 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
25
26 ---
27 include/linux/vmstat.h | 10 ++++++----
28 mm/vmscan.c | 19 +++++++++++++++++--
29 mm/vmstat.c | 36 +++++++-----------------------------
30 3 files changed, 30 insertions(+), 35 deletions(-)
31
32 --- a/include/linux/vmstat.h
33 +++ b/include/linux/vmstat.h
34 @@ -254,8 +254,11 @@ extern void dec_zone_state(struct zone *
35 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
36
37 void refresh_cpu_vm_stats(int);
38 -void reduce_pgdat_percpu_threshold(pg_data_t *pgdat);
39 -void restore_pgdat_percpu_threshold(pg_data_t *pgdat);
40 +
41 +int calculate_pressure_threshold(struct zone *zone);
42 +int calculate_normal_threshold(struct zone *zone);
43 +void set_pgdat_percpu_threshold(pg_data_t *pgdat,
44 + int (*calculate_pressure)(struct zone *));
45 #else /* CONFIG_SMP */
46
47 /*
48 @@ -300,8 +303,7 @@ static inline void __dec_zone_page_state
49 #define dec_zone_page_state __dec_zone_page_state
50 #define mod_zone_page_state __mod_zone_page_state
51
52 -static inline void reduce_pgdat_percpu_threshold(pg_data_t *pgdat) { }
53 -static inline void restore_pgdat_percpu_threshold(pg_data_t *pgdat) { }
54 +#define set_pgdat_percpu_threshold(pgdat, callback) { }
55
56 static inline void refresh_cpu_vm_stats(int cpu) { }
57 #endif
58 --- a/mm/vmscan.c
59 +++ b/mm/vmscan.c
60 @@ -2448,9 +2448,24 @@ static int kswapd(void *p)
61 */
62 if (!sleeping_prematurely(pgdat, order, remaining)) {
63 trace_mm_vmscan_kswapd_sleep(pgdat->node_id);
64 - restore_pgdat_percpu_threshold(pgdat);
65 +
66 + /*
67 + * vmstat counters are not perfectly
68 + * accurate and the estimated value
69 + * for counters such as NR_FREE_PAGES
70 + * can deviate from the true value by
71 + * nr_online_cpus * threshold. To
72 + * avoid the zone watermarks being
73 + * breached while under pressure, we
74 + * reduce the per-cpu vmstat threshold
75 + * while kswapd is awake and restore
76 + * them before going back to sleep.
77 + */
78 + set_pgdat_percpu_threshold(pgdat,
79 + calculate_normal_threshold);
80 schedule();
81 - reduce_pgdat_percpu_threshold(pgdat);
82 + set_pgdat_percpu_threshold(pgdat,
83 + calculate_pressure_threshold);
84 } else {
85 if (remaining)
86 count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
87 --- a/mm/vmstat.c
88 +++ b/mm/vmstat.c
89 @@ -83,7 +83,7 @@ EXPORT_SYMBOL(vm_stat);
90
91 #ifdef CONFIG_SMP
92
93 -static int calculate_pressure_threshold(struct zone *zone)
94 +int calculate_pressure_threshold(struct zone *zone)
95 {
96 int threshold;
97 int watermark_distance;
98 @@ -107,7 +107,7 @@ static int calculate_pressure_threshold(
99 return threshold;
100 }
101
102 -static int calculate_threshold(struct zone *zone)
103 +int calculate_normal_threshold(struct zone *zone)
104 {
105 int threshold;
106 int mem; /* memory in 128 MB units */
107 @@ -166,7 +166,7 @@ static void refresh_zone_stat_thresholds
108 for_each_populated_zone(zone) {
109 unsigned long max_drift, tolerate_drift;
110
111 - threshold = calculate_threshold(zone);
112 + threshold = calculate_normal_threshold(zone);
113
114 for_each_online_cpu(cpu)
115 per_cpu_ptr(zone->pageset, cpu)->stat_threshold
116 @@ -185,46 +185,24 @@ static void refresh_zone_stat_thresholds
117 }
118 }
119
120 -void reduce_pgdat_percpu_threshold(pg_data_t *pgdat)
121 +void set_pgdat_percpu_threshold(pg_data_t *pgdat,
122 + int (*calculate_pressure)(struct zone *))
123 {
124 struct zone *zone;
125 int cpu;
126 int threshold;
127 int i;
128
129 - get_online_cpus();
130 for (i = 0; i < pgdat->nr_zones; i++) {
131 zone = &pgdat->node_zones[i];
132 if (!zone->percpu_drift_mark)
133 continue;
134
135 - threshold = calculate_pressure_threshold(zone);
136 - for_each_online_cpu(cpu)
137 - per_cpu_ptr(zone->pageset, cpu)->stat_threshold
138 - = threshold;
139 - }
140 - put_online_cpus();
141 -}
142 -
143 -void restore_pgdat_percpu_threshold(pg_data_t *pgdat)
144 -{
145 - struct zone *zone;
146 - int cpu;
147 - int threshold;
148 - int i;
149 -
150 - get_online_cpus();
151 - for (i = 0; i < pgdat->nr_zones; i++) {
152 - zone = &pgdat->node_zones[i];
153 - if (!zone->percpu_drift_mark)
154 - continue;
155 -
156 - threshold = calculate_threshold(zone);
157 - for_each_online_cpu(cpu)
158 + threshold = (*calculate_pressure)(zone);
159 + for_each_possible_cpu(cpu)
160 per_cpu_ptr(zone->pageset, cpu)->stat_threshold
161 = threshold;
162 }
163 - put_online_cpus();
164 }
165
166 /*