Add a background scanning timer to restore the watermarks to the pages_lots
level and only call on it if kswapd has not been called upon for the last 5
seconds. This allows us to balance all zones to the more generous pages_lots
watermark at a time unrelated to page allocation thus leading to lighter
levels of vm load when called upon under page allocation.

Signed-off-by: Con Kolivas <kernel@kolivas.org>

Index: linux-2.6.14-ck4/include/linux/mmzone.h
===================================================================
--- linux-2.6.14-ck4.orig/include/linux/mmzone.h	2005-11-09 20:58:26.000000000 +1100
+++ linux-2.6.14-ck4/include/linux/mmzone.h	2005-11-09 20:58:26.000000000 +1100
@@ -12,6 +12,7 @@
 #include <linux/threads.h>
 #include <linux/numa.h>
 #include <linux/init.h>
+#include <linux/timer.h>
 #include <asm/atomic.h>
 
 /* Free memory management - zoned buddy allocator.  */
@@ -282,6 +283,7 @@ typedef struct pglist_data {
 	wait_queue_head_t kswapd_wait;
 	struct task_struct *kswapd;
 	int kswapd_max_order;
+	struct timer_list watermark_timer;
 } pg_data_t;
 
 #define node_present_pages(nid)	(NODE_DATA(nid)->node_present_pages)
Index: linux-2.6.14-ck4/mm/vmscan.c
===================================================================
--- linux-2.6.14-ck4.orig/mm/vmscan.c	2005-11-09 20:58:26.000000000 +1100
+++ linux-2.6.14-ck4/mm/vmscan.c	2005-11-09 20:58:26.000000000 +1100
@@ -33,6 +33,7 @@
 #include <linux/cpuset.h>
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
+#include <linux/timer.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1196,6 +1197,8 @@ out:
 	return total_reclaimed;
 }
 
+#define WT_EXPIRY	(HZ * 5)	/* Time to wakeup watermark_timer */
+
 /*
  * The background pageout daemon, started as a kernel thread
  * from the init process. 
@@ -1246,6 +1249,8 @@ static int kswapd(void *p)
 
 		try_to_freeze();
 
+		/* kswapd has been busy so delay watermark_timer */
+		mod_timer(&pgdat->watermark_timer, jiffies + WT_EXPIRY);
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		new_order = pgdat->kswapd_max_order;
 		pgdat->kswapd_max_order = 0;
@@ -1342,13 +1347,46 @@ static int __devinit cpu_callback(struct
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
+/*
+ * We wake up kswapd every WT_EXPIRY till free ram is above pages_lots
+ */
+static void watermark_wakeup(unsigned long data)
+{
+	pg_data_t *pgdat = (pg_data_t *)data;
+	struct timer_list *wt = &pgdat->watermark_timer;
+	int i;
+
+	if (!waitqueue_active(&pgdat->kswapd_wait))
+		goto out;
+	for (i = pgdat->nr_zones - 1; i >= 0; i--) {
+		struct zone *z = pgdat->node_zones + i;
+
+		if (!z->present_pages)
+			continue;
+		if (!zone_watermark_ok(z, 0, z->pages_lots, 0, 0, 0)) {
+			wake_up_interruptible(&pgdat->kswapd_wait);
+			goto out;
+		}
+	}
+out:
+	mod_timer(wt, jiffies + WT_EXPIRY);
+	return;
+}
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
 	swap_setup();
-	for_each_pgdat(pgdat)
+	for_each_pgdat(pgdat) {
+		struct timer_list *wt = &pgdat->watermark_timer;
 		pgdat->kswapd
 		= find_task_by_pid(kernel_thread(kswapd, pgdat, CLONE_KERNEL));
+		init_timer(wt);
+		wt->data = (unsigned long)pgdat;
+		wt->function = watermark_wakeup;
+		wt->expires = jiffies + WT_EXPIRY;
+		add_timer(wt);
+	}
 	total_memory = nr_free_pagecache_pages();
 	hotcpu_notifier(cpu_callback, 0);
 	return 0;

