summaryrefslogtreecommitdiffstats
path: root/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thre...
diff options
context:
space:
mode:
authorKyle McMartin <kyle@redhat.com>2010-12-02 11:57:44 -0500
committerKyle McMartin <kyle@redhat.com>2010-12-02 11:57:44 -0500
commit254585788fce648441c41bf2854ac0899f3e2b1a (patch)
tree721f31cb7920dd3c1a3e116d0f4dfef24e88d7d1 /mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch
parent8077b629b4f8dedcaafadce6fc40e50de6e1f920 (diff)
downloadkernel-254585788fce648441c41bf2854ac0899f3e2b1a.tar.gz
kernel-254585788fce648441c41bf2854ac0899f3e2b1a.tar.xz
kernel-254585788fce648441c41bf2854ac0899f3e2b1a.zip
kswapd fixes from mmotm
(queuing them here since it's unclear if they'll go into .37 or wait for .38)
Diffstat (limited to 'mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch')
-rw-r--r--mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch167
1 files changed, 167 insertions, 0 deletions
diff --git a/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch b/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch
new file mode 100644
index 000000000..058b1399a
--- /dev/null
+++ b/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds.patch
@@ -0,0 +1,167 @@
+From 82e3d4969144377d13da97d511e849e8cf3e6dcc Mon Sep 17 00:00:00 2001
+From: Mel Gorman <mel@csn.ul.ie>
+Date: Wed, 24 Nov 2010 22:24:24 -0500
+Subject: [PATCH 2/2] mm: vmstat: Use a single setter function and callback for adjusting percpu thresholds
+
+reduce_pgdat_percpu_threshold() and restore_pgdat_percpu_threshold() exist
+to adjust the per-cpu vmstat thresholds while kswapd is awake to avoid
+errors due to counter drift. The functions duplicate some code so this
+patch replaces them with a single set_pgdat_percpu_threshold() that takes
+a callback function to calculate the desired threshold as a parameter.
+
+Signed-off-by: Mel Gorman <mel@csn.ul.ie>
+Reviewed-by: Christoph Lameter <cl@linux.com>
+Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+[the various mmotm patches updating this were rolled up. --kyle]
+[[http://userweb.kernel.org/~akpm/mmotm/broken-out/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds-fix-set_pgdat_percpu_threshold-dont-use-for_each_online_cpu.patch]]
+---
+ include/linux/vmstat.h | 10 ++++++----
+ mm/vmscan.c | 19 +++++++++++++++++--
+ mm/vmstat.c | 36 +++++++-----------------------------
+ 3 files changed, 30 insertions(+), 35 deletions(-)
+
+diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
+index e4cc21c..833e676 100644
+--- a/include/linux/vmstat.h
++++ b/include/linux/vmstat.h
+@@ -254,8 +254,11 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
+ extern void __dec_zone_state(struct zone *, enum zone_stat_item);
+
+ void refresh_cpu_vm_stats(int);
+-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat);
+-void restore_pgdat_percpu_threshold(pg_data_t *pgdat);
++
++int calculate_pressure_threshold(struct zone *zone);
++int calculate_normal_threshold(struct zone *zone);
++void set_pgdat_percpu_threshold(pg_data_t *pgdat,
++ int (*calculate_pressure)(struct zone *));
+ #else /* CONFIG_SMP */
+
+ /*
+@@ -300,8 +303,7 @@ static inline void __dec_zone_page_state(struct page *page,
+ #define dec_zone_page_state __dec_zone_page_state
+ #define mod_zone_page_state __mod_zone_page_state
+
+-static inline void reduce_pgdat_percpu_threshold(pg_data_t *pgdat) { }
+-static inline void restore_pgdat_percpu_threshold(pg_data_t *pgdat) { }
++#define set_pgdat_percpu_threshold(pgdat, callback) { }
+
+ static inline void refresh_cpu_vm_stats(int cpu) { }
+ #endif
+diff --git a/mm/vmscan.c b/mm/vmscan.c
+index 3e71cb1..ba39948 100644
+--- a/mm/vmscan.c
++++ b/mm/vmscan.c
+@@ -2378,9 +2378,24 @@ static int kswapd(void *p)
+ */
+ if (!sleeping_prematurely(pgdat, order, remaining)) {
+ trace_mm_vmscan_kswapd_sleep(pgdat->node_id);
+- restore_pgdat_percpu_threshold(pgdat);
++
++ /*
++ * vmstat counters are not perfectly
++ * accurate and the estimated value
++ * for counters such as NR_FREE_PAGES
++ * can deviate from the true value by
++ * nr_online_cpus * threshold. To
++ * avoid the zone watermarks being
++ * breached while under pressure, we
++ * reduce the per-cpu vmstat threshold
++ * while kswapd is awake and restore
++ * them before going back to sleep.
++ */
++ set_pgdat_percpu_threshold(pgdat,
++ calculate_normal_threshold);
+ schedule();
+- reduce_pgdat_percpu_threshold(pgdat);
++ set_pgdat_percpu_threshold(pgdat,
++ calculate_pressure_threshold);
+ } else {
+ if (remaining)
+ count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
+diff --git a/mm/vmstat.c b/mm/vmstat.c
+index 4d7faeb..511c2c0 100644
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -81,7 +81,7 @@ EXPORT_SYMBOL(vm_stat);
+
+ #ifdef CONFIG_SMP
+
+-static int calculate_pressure_threshold(struct zone *zone)
++int calculate_pressure_threshold(struct zone *zone)
+ {
+ int threshold;
+ int watermark_distance;
+@@ -105,7 +105,7 @@ static int calculate_pressure_threshold(struct zone *zone)
+ return threshold;
+ }
+
+-static int calculate_threshold(struct zone *zone)
++int calculate_normal_threshold(struct zone *zone)
+ {
+ int threshold;
+ int mem; /* memory in 128 MB units */
+@@ -164,7 +164,7 @@ static void refresh_zone_stat_thresholds(void)
+ for_each_populated_zone(zone) {
+ unsigned long max_drift, tolerate_drift;
+
+- threshold = calculate_threshold(zone);
++ threshold = calculate_normal_threshold(zone);
+
+ for_each_online_cpu(cpu)
+ per_cpu_ptr(zone->pageset, cpu)->stat_threshold
+@@ -183,46 +183,24 @@ static void refresh_zone_stat_thresholds(void)
+ }
+ }
+
+-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat)
++void set_pgdat_percpu_threshold(pg_data_t *pgdat,
++ int (*calculate_pressure)(struct zone *))
+ {
+ struct zone *zone;
+ int cpu;
+ int threshold;
+ int i;
+
+- get_online_cpus();
+- for (i = 0; i < pgdat->nr_zones; i++) {
+- zone = &pgdat->node_zones[i];
+- if (!zone->percpu_drift_mark)
+- continue;
+-
+- threshold = calculate_pressure_threshold(zone);
+- for_each_online_cpu(cpu)
+- per_cpu_ptr(zone->pageset, cpu)->stat_threshold
+- = threshold;
+- }
+- put_online_cpus();
+-}
+-
+-void restore_pgdat_percpu_threshold(pg_data_t *pgdat)
+-{
+- struct zone *zone;
+- int cpu;
+- int threshold;
+- int i;
+-
+- get_online_cpus();
+ for (i = 0; i < pgdat->nr_zones; i++) {
+ zone = &pgdat->node_zones[i];
+ if (!zone->percpu_drift_mark)
+ continue;
+
+- threshold = calculate_threshold(zone);
+- for_each_online_cpu(cpu)
++ threshold = (*calculate_pressure)(zone);
++ for_each_possible_cpu(cpu)
+ per_cpu_ptr(zone->pageset, cpu)->stat_threshold
+ = threshold;
+ }
+- put_online_cpus();
+ }
+
+ /*
+--
+1.7.3.2
+