Index: linux-2.6.8.1-mm1/include/linux/sched.h
===================================================================
--- linux-2.6.8.1-mm1.orig/include/linux/sched.h	2004-08-17 20:34:39.773124288 +1000
+++ linux-2.6.8.1-mm1/include/linux/sched.h	2004-08-17 20:36:02.680520448 +1000
@@ -638,6 +638,7 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_FORKED	0x00400000	/* I have just forked */
 #define PF_YIELDED	0x00800000	/* I have just yielded */
 #define PF_UISLEEP	0x01000000	/* Uninterruptible sleep */
+#define PF_KIFLUSHD	0x02000000	/* I am kiflushd */
 
 #ifdef CONFIG_SMP
 extern int set_cpus_allowed(task_t *p, cpumask_t new_mask);
Index: linux-2.6.8.1-mm1/include/linux/swap.h
===================================================================
--- linux-2.6.8.1-mm1.orig/include/linux/swap.h	2004-08-17 20:18:54.799782072 +1000
+++ linux-2.6.8.1-mm1/include/linux/swap.h	2004-08-17 20:36:02.681520296 +1000
@@ -19,6 +19,11 @@ static inline int current_is_kswapd(void
 	return current->flags & PF_KSWAPD;
 }
 
+static inline int current_is_kiflushd(void)
+{
+	return current->flags & PF_KIFLUSHD;
+}
+
 /*
  * MAX_SWAPFILES defines the maximum number of swaptypes: things which can
  * be swapped to.  The swap type and the offset into that swap type are
@@ -175,6 +180,7 @@ extern void swap_setup(void);
 extern int try_to_free_pages(struct zone **, unsigned int, unsigned int);
 extern int shrink_all_memory(int);
 extern int vm_swappiness;
+extern int vm_flush_interval;
 
 #ifdef CONFIG_MMU
 /* linux/mm/shmem.c */
Index: linux-2.6.8.1-mm1/include/linux/sysctl.h
===================================================================
--- linux-2.6.8.1-mm1.orig/include/linux/sysctl.h	2004-08-17 20:21:21.148533680 +1000
+++ linux-2.6.8.1-mm1/include/linux/sysctl.h	2004-08-17 20:36:36.241418416 +1000
@@ -169,6 +169,7 @@ enum
 	VM_HUGETLB_GROUP=25,	/* permitted hugetlb group */
 	VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */
 	VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */
+	VM_FLUSH_INTERVAL=28,	/* Seconds between ram flushing */
 };
 
 
Index: linux-2.6.8.1-mm1/kernel/sysctl.c
===================================================================
--- linux-2.6.8.1-mm1.orig/kernel/sysctl.c	2004-08-17 20:21:21.153532920 +1000
+++ linux-2.6.8.1-mm1/kernel/sysctl.c	2004-08-17 20:36:02.682520144 +1000
@@ -748,6 +748,17 @@ static ctl_table vm_table[] = {
 		.extra1		= &zero,
 		.extra2		= &one_hundred,
 	},
+	{
+		.ctl_name	= VM_FLUSH_INTERVAL,
+		.procname	= "flush_interval",
+		.data		= &vm_flush_interval,
+		.maxlen		= sizeof(vm_flush_interval),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero,
+		.extra2		= &one_hundred,
+	},
 #ifdef CONFIG_HUGETLB_PAGE
 	 {
 		.ctl_name	= VM_HUGETLB_PAGES,
Index: linux-2.6.8.1-mm1/mm/vmscan.c
===================================================================
--- linux-2.6.8.1-mm1.orig/mm/vmscan.c	2004-08-17 20:35:53.255953200 +1000
+++ linux-2.6.8.1-mm1/mm/vmscan.c	2004-08-17 20:36:48.441563712 +1000
@@ -120,7 +120,9 @@ struct shrinker {
  * From 0 .. 100.  Higher means more swappy.
  */
 int vm_swappiness = 33;
+int vm_flush_interval = 1;
 static long total_memory;
+static int interval_shift;
 
 static LIST_HEAD(shrinker_list);
 static DECLARE_RWSEM(shrinker_rwsem);
@@ -373,6 +375,9 @@ static int shrink_list(struct list_head 
 			goto keep_locked;
 
 		sc->nr_scanned++;
+		
+		if (unlikely(current_is_kiflushd() && page_mapped(page)))
+				goto keep_locked;
 		/* Double the slab pressure for mapped and swapcache pages */
 		if (page_mapped(page) || PageSwapCache(page))
 			sc->nr_scanned++;
@@ -706,7 +711,7 @@ refill_inactive_zone(struct zone *zone, 
 	 * Now use this metric to decide whether to start moving mapped memory
 	 * onto the inactive list.
 	 */
-	if (swap_tendency >= 100)
+	if (swap_tendency >= 100 && !current_is_kiflushd())
 		reclaim_mapped = 1;
 
 	while (!list_empty(&l_hold)) {
@@ -990,6 +995,9 @@ static int balance_pgdat(pg_data_t *pgda
 		int all_zones_ok = 1;
 		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
 		unsigned long lru_pages = 0;
+		
+		if (unlikely(current_is_kiflushd() && priority < DEF_PRIORITY))
+			goto out;
 
 		if (nr_pages == 0) {
 			/*
@@ -1126,13 +1134,21 @@ static int kswapd(void *p)
 	tsk->flags |= PF_MEMALLOC|PF_KSWAPD;
 
 	for ( ; ; ) {
+		int temp_interval;
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_FREEZE);
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		schedule();
 		finish_wait(&pgdat->kswapd_wait, &wait);
-
+		/*
+		 * kswapd active implies memory pressure;
+		 * put kiflushd to sleep.
+		 */
+		temp_interval = vm_flush_interval;
+		vm_flush_interval = 0;
+		interval_shift = 6;
 		balance_pgdat(pgdat, 0);
+		vm_flush_interval = temp_interval;
 	}
 	return 0;
 }
@@ -1201,6 +1217,60 @@ static int __devinit cpu_callback(struct
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
+static void trickle_out_memory(void)
+{
+	pg_data_t *pgdat;
+	struct reclaim_state reclaim_state = {
+		.reclaimed_slab = 0,
+	};
+	
+	current->reclaim_state = &reclaim_state;
+	for_each_pgdat(pgdat)
+		balance_pgdat(pgdat, SWAP_CLUSTER_MAX);
+	current->reclaim_state = NULL;
+}
+
+static int kiflushd(void *p)
+{
+	struct task_struct *tsk = current;
+	DEFINE_WAIT(wait);
+
+	daemonize("kiflushd");
+	set_user_nice(current, 19);
+	tsk->flags |= PF_MEMALLOC | PF_KIFLUSHD;
+
+	for ( ; ; ) {
+		int mapped_ratio, used_ratio, interval = HZ * 60;
+		unsigned long total_centile, used_ram;
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!vm_flush_interval) {
+			schedule_timeout(interval);
+			continue;
+		}
+		interval = min(((HZ * vm_flush_interval) << interval_shift),
+			interval);
+		schedule_timeout(interval);
+		total_centile = totalram_pages / 100 + 1;
+		used_ram = totalram_pages - nr_free_pages();
+		used_ratio = used_ram / total_centile;
+		if (used_ratio < 67)
+			goto increase_shift;
+		mapped_ratio = read_page_state(nr_mapped) / used_ram;
+		if (mapped_ratio > 66)
+			goto increase_shift;
+		trickle_out_memory();
+		if (interval_shift)
+			interval_shift--;
+		continue;
+increase_shift:	
+		/* Doing nothing, wait longer next time */
+		if (interval_shift < 6)
+			interval_shift++;
+	}
+}
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
@@ -1213,4 +1283,11 @@ static int __init kswapd_init(void)
 	return 0;
 }
 
+static int __init kiflushd_init(void)
+{
+	kernel_thread(kiflushd, NULL, CLONE_KERNEL);
+	return 0;
+}
+
 module_init(kswapd_init)
+module_init(kiflushd_init)

