diff -ru linux-2.4.18/fs/buffer.c linux-2.4.18-perf/fs/buffer.c
--- linux-2.4.18/fs/buffer.c	Thu Mar  7 19:59:00 2002
+++ linux-2.4.18-perf/fs/buffer.c	Wed May  1 08:33:17 2002
@@ -47,6 +47,7 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -76,6 +77,9 @@
 static spinlock_t lru_list_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 static int nr_buffers_type[NR_LIST];
 static unsigned long size_buffers_type[NR_LIST];
+static struct buffer_head **lru_hash_table; /* use with lru_list_lock */
+static struct buffer_head * __get_lru_hash_table(kdev_t dev, int block, int size);
+static kmem_cache_t *gw_array;
 
 static struct buffer_head * unused_list;
 static int nr_unused_buffer_heads;
@@ -87,6 +91,9 @@
 
 /* This is used by some architectures to estimate available memory. */
 atomic_t buffermem_pages = ATOMIC_INIT(0);
+static atomic_t nr_writing = ATOMIC_INIT(0);
+static atomic_t size_writing = ATOMIC_INIT(0);
+static atomic_t nr_waiting = ATOMIC_INIT(0);
 
 /* Here is the parameter block for the bdflush process. If you add or
  * remove any of the parameters, make sure to update kernel/sysctl.c
@@ -119,6 +126,14 @@
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
 
+struct fstune_param fstune_param = {
+	35000,
+	15000,
+	2 * HZ,
+	128,
+};
+unsigned int fstune_stat[20];
+
 void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
@@ -168,6 +183,15 @@
 	put_bh(bh);
 }
 
+static void __end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+	atomic_dec(&nr_writing);
+	atomic_sub(bh->b_size,&size_writing);
+	mark_buffer_uptodate(bh, uptodate);
+	unlock_buffer(bh);
+	put_bh(bh);
+}
+
 /*
  * The buffers have been marked clean and locked.  Just submit the dang
  * things.. 
@@ -176,7 +200,9 @@
 {
 	do {
 		struct buffer_head * bh = *array++;
-		bh->b_end_io = end_buffer_io_sync;
+		atomic_inc(&nr_writing);
+		atomic_add(bh->b_size,&size_writing);
+		bh->b_end_io = __end_buffer_io_sync;
 		submit_bh(WRITE, bh);
 	} while (--count);
 }
@@ -188,6 +214,8 @@
  * return without it!
  */
 #define NRSYNC (32)
+#define NRSYNCG (512)
+
 static int write_some_buffers(kdev_t dev)
 {
 	struct buffer_head *next;
@@ -198,6 +226,7 @@
 	next = lru_list[BUF_DIRTY];
 	nr = nr_buffers_type[BUF_DIRTY];
 	count = 0;
+
 	while (next && --nr >= 0) {
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
@@ -209,6 +238,84 @@
 			continue;
 		}
 		if (atomic_set_buffer_clean(bh)) {
+		   if (!count && (bh->b_size == PAGE_SIZE)) {
+			int zone_num;
+			int zone_min;
+			int zone_max;
+			int zone_self;
+			int i;
+			unsigned long zone;
+			unsigned long blk;
+			struct buffer_head * bhf;
+			struct buffer_head **array2 = NULL;
+
+			zone_num = (2048*1024)/bh->b_size;
+			zone = bh->b_blocknr / zone_num * zone_num;
+			if (zone_num > NRSYNCG) {
+				zone_num = NRSYNCG;
+			}
+			bhf = __get_lru_hash_table(bh->b_dev,bh->b_blocknr,bh->b_size);
+			if (!bhf) {
+				goto normal;
+			}
+			if (gw_array) {
+				array2 = (struct buffer_head **)kmem_cache_alloc(
+					gw_array, SLAB_ATOMIC);
+			}
+			if (!array2) {
+				goto normal;
+			}
+			zone_self = bh->b_blocknr - zone;
+			zone_min = zone_max = zone_self;
+			__refile_buffer(bh);
+			get_bh(bh);
+			array2[zone_self] = bh;
+			for (i= zone_self - 1; i >= 0; --i) {
+				blk = zone + i;
+				bhf = __get_lru_hash_table(bh->b_dev,blk,bh->b_size);
+				if (!bhf) {
+					break;
+				}
+				if (test_and_set_bit(BH_Lock, &bhf->b_state)) {
+					break;
+				}
+				if (!atomic_set_buffer_clean(bhf)) {
+					clear_bit(BH_Lock, &bhf->b_state);
+					break;
+				}
+				__refile_buffer(bhf);
+				get_bh(bhf);
+				array2[i] = bhf;
+				zone_min = i;
+			}
+			for (i= zone_self + 1; i < zone_num; i++) {
+				blk = zone + i;
+				bhf = __get_lru_hash_table(bh->b_dev,blk,bh->b_size);
+				if (!bhf) {
+					break;
+				}
+				if (test_and_set_bit(BH_Lock, &bhf->b_state)) {
+					break;
+				}
+				if (!atomic_set_buffer_clean(bhf)) {
+					clear_bit(BH_Lock, &bhf->b_state);
+					break;
+				}
+				__refile_buffer(bhf);
+				get_bh(bhf);
+				array2[i] = bhf;
+				zone_max = i;
+			}
+			spin_unlock(&lru_list_lock);
+			count = zone_max - zone_min + 1;
+			fstune_stat[2]++;
+			fstune_stat[3] += count;
+			write_locked_buffers(array2+zone_min, count);
+			kmem_cache_free(gw_array, array2);
+			count = 0;
+			return -EAGAIN;
+		   } else {
+normal:
 			__refile_buffer(bh);
 			get_bh(bh);
 			array[count++] = bh;
@@ -216,17 +323,23 @@
 				continue;
 
 			spin_unlock(&lru_list_lock);
+			fstune_stat[0]++;
+			fstune_stat[1] += count;
 			write_locked_buffers(array, count);
 			conditional_schedule();
 			return -EAGAIN;
+		   }
 		}
 		unlock_buffer(bh);
 		__refile_buffer(bh);
 	}
 	spin_unlock(&lru_list_lock);
 
-	if (count)
+	if (count) {
+		fstune_stat[0]++;
+		fstune_stat[1] += count;
 		write_locked_buffers(array, count);
+	}
 	return 0;
 }
 
@@ -500,6 +613,7 @@
 	 (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \
 	  ((block) << (bh_hash_shift - 12))))
 #define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]
+#define lru_hash(dev,block) lru_hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]
 
 static inline void __insert_into_hash_list(struct buffer_head *bh)
 {
@@ -525,6 +639,24 @@
 	}
 }
 
+static __inline__ void __lru_hash_link(struct buffer_head *bh, struct buffer_head **head)
+{
+	if ((bh->b_next_lru = *head) != NULL)
+		bh->b_next_lru->b_pprev_lru = &bh->b_next_lru;
+	*head = bh;
+	bh->b_pprev_lru = head;
+}
+
+static __inline__ void __lru_hash_unlink(struct buffer_head *bh)
+{
+	if (bh->b_pprev_lru) {
+		if (bh->b_next_lru)
+			bh->b_next_lru->b_pprev_lru = bh->b_pprev_lru;
+		*(bh->b_pprev_lru) = bh->b_next_lru;
+		bh->b_pprev_lru = NULL;
+	}
+}
+
 static void __insert_into_lru_list(struct buffer_head * bh, int blist)
 {
 	struct buffer_head **bhp = &lru_list[blist];
@@ -541,6 +673,11 @@
 	(*bhp)->b_prev_free = bh;
 	nr_buffers_type[blist]++;
 	size_buffers_type[blist] += bh->b_size;
+
+	if (blist == BUF_DIRTY) {
+		struct buffer_head **head = &lru_hash(bh->b_dev, bh->b_blocknr);
+		__lru_hash_link(bh, head);
+	}
 }
 
 static void __remove_from_lru_list(struct buffer_head * bh)
@@ -550,6 +687,9 @@
 		struct buffer_head *prev = bh->b_prev_free;
 		int blist = bh->b_list;
 
+		if (blist == BUF_DIRTY) {
+			__lru_hash_unlink(bh);
+		}
 		prev->b_next_free = next;
 		next->b_prev_free = prev;
 		if (lru_list[blist] == bh) {
@@ -606,6 +746,19 @@
 	return bh;
 }
 
+
+static struct buffer_head * __get_lru_hash_table(kdev_t dev, int block, int size)
+{
+	struct buffer_head *bh = lru_hash(dev, block);
+
+	for (; bh; bh = bh->b_next_lru)
+		if (bh->b_blocknr == block	&&
+		    bh->b_size    == size	&&
+		    bh->b_dev     == dev)
+			break;
+	return bh;
+}
+
 void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
 {
 	spin_lock(&lru_list_lock);
@@ -1132,6 +1285,9 @@
 	soft_dirty_limit = tot * bdf_prm.b_un.nfract;
 	hard_dirty_limit = tot * bdf_prm.b_un.nfract_sync;
 
+	fstune_stat[4] = dirty / tot;
+	fstune_stat[5] = tot;
+
 	/* First, check for the "real" dirty limit. */
 	if (dirty > soft_dirty_limit) {
 		if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO))
@@ -1152,10 +1308,16 @@
 void balance_dirty(void)
 {
 	int state = balance_dirty_state();
-
 	if (state < 0)
 		return;
 
+	if (state == 0) {
+		int request_size = atomic_read(&size_writing);
+		if (request_size > 512 * 4096) {
+			return;
+		}
+	}
+
 	/* If we're getting into imbalance, start write-out */
 	spin_lock(&lru_list_lock);
 	write_some_buffers(NODEV);
@@ -1391,6 +1553,7 @@
 		bh->b_state = 0;
 		bh->b_next_free = NULL;
 		bh->b_pprev = NULL;
+		bh->b_pprev_lru = NULL;
 		atomic_set(&bh->b_count, 0);
 		bh->b_size = size;
 
@@ -1460,7 +1623,9 @@
  *
  */
 
-int try_to_release_page(struct page * page, int gfp_mask)
+static int try_to_free_buffers_sub(struct page *, unsigned int, int);
+
+int try_to_release_page(struct page * page, int gfp_mask,int clean_only)
 {
 	if (!PageLocked(page))
 		BUG();
@@ -1477,7 +1642,7 @@
 	 */
 	return 0;
 try_to_free:	
-	return try_to_free_buffers(page, gfp_mask);
+	return try_to_free_buffers_sub(page, gfp_mask, clean_only);
 }
 
 /*
@@ -1523,7 +1688,7 @@
 	 * instead.
 	 */
 	if (!offset) {
-		if (!try_to_release_page(page, 0))
+		if (!try_to_release_page(page, 0, 0))
 			return 0;
 	}
 
@@ -1646,6 +1811,7 @@
 	/* Stage 3: submit the IO */
 	do {
 		struct buffer_head *next = bh->b_this_page;
+		fstune_stat[8]++;
 		submit_bh(WRITE, bh);
 		bh = next;
 	} while (bh != head);
@@ -1677,6 +1843,7 @@
 		if (buffer_mapped(bh)) {
 			set_bit(BH_Uptodate, &bh->b_state);
 			clear_bit(BH_Dirty, &bh->b_state);
+			fstune_stat[9]++;
 			submit_bh(WRITE, bh);
 		}
 		bh = next;
@@ -2701,6 +2868,7 @@
 		get_bh(bh);
 		set_bit(BH_launder, &bh->b_state);
 		bh->b_end_io = end_buffer_io_sync;
+		fstune_stat[10]++;
 		submit_bh(WRITE, bh);
 		tryagain = 0;
 	} while ((bh = bh->b_this_page) != head);
@@ -2725,7 +2893,7 @@
  *       obtain a reference to a buffer head within a page.  So we must
  *	 lock out all of these paths to cleanly toss the page.
  */
-int try_to_free_buffers(struct page * page, unsigned int gfp_mask)
+static int try_to_free_buffers_sub(struct page * page, unsigned int gfp_mask, int clean_only)
 {
 	struct buffer_head * tmp, * bh = page->buffers;
 
@@ -2772,6 +2940,9 @@
 	write_unlock(&hash_table_lock);
 	spin_unlock(&lru_list_lock);
 	gfp_mask = pf_gfp_mask(gfp_mask);
+	if (clean_only) {
+		return 0;
+	}
 	if (gfp_mask & __GFP_IO) {
 		if ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)) {
 			if (sync_page_buffers(bh)) {
@@ -2785,6 +2956,10 @@
 		wakeup_bdflush();
 	return 0;
 }
+
+int try_to_free_buffers(struct page * page, unsigned int gfp_mask) {
+	return try_to_free_buffers_sub(page,gfp_mask, 0);
+}
 EXPORT_SYMBOL(try_to_free_buffers);
 
 /* ================== Debugging =================== */
@@ -2875,7 +3050,23 @@
 
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
+		lru_hash_table = (struct buffer_head **)
+		    __get_free_pages(GFP_ATOMIC, order);
 	} while (hash_table == NULL && --order > 0);
+	if (hash_table && !lru_hash_table) {
+		unsigned long tmp;
+
+		--order;
+		nr_hash = (PAGE_SIZE << order) / sizeof(struct buffer_head *);
+		bh_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		bh_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			bh_hash_shift++;
+		lru_hash_table = hash_table + nr_hash;
+	}
+
 	printk(KERN_INFO "Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
 	       nr_hash, order, (PAGE_SIZE << order));
 
@@ -2885,11 +3076,20 @@
 	/* Setup hash chains. */
 	for(i = 0; i < nr_hash; i++)
 		hash_table[i] = NULL;
+	for(i = 0; i < nr_hash; i++)
+		lru_hash_table[i] = NULL;
 
 	/* Setup lru lists. */
 	for(i = 0; i < NR_LIST; i++)
 		lru_list[i] = NULL;
 
+	gw_array = kmem_cache_create(
+			"gw_array",
+			sizeof(void *) * NRSYNCG,
+			0,
+			SLAB_HWCACHE_ALIGN,
+			NULL, NULL);
+
 }
 
 
diff -ru linux-2.4.18/fs/dcache.c linux-2.4.18-perf/fs/dcache.c
--- linux-2.4.18/fs/dcache.c	Thu Mar  7 19:59:00 2002
+++ linux-2.4.18-perf/fs/dcache.c	Tue Apr 30 22:01:48 2002
@@ -593,7 +593,15 @@
 	if (!(gfp_mask & __GFP_FS))
 		return 0;
 
-	count = dentry_stat.nr_unused / priority;
+	if (priority == 0) {	/* special case */
+		if (dentry_stat.nr_dentry > fstune_param.dcache_limit) { /* XXX suz */
+			count = dentry_stat.nr_unused / 6;
+		} else {
+			return 0;
+		}
+	} else {
+		count = dentry_stat.nr_unused / priority;
+	}
 
 	prune_dcache(count);
 	kmem_cache_shrink(dentry_cache);
@@ -616,7 +624,18 @@
 {
 	char * str;
 	struct dentry *dentry;
+	int nr_dentry = dentry_stat.nr_dentry;
+	int nr_unused = dentry_stat.nr_unused;
 
+	if (nr_dentry > fstune_param.dcache_limit) { /* XXX suz */
+#if 1
+		shrink_dcache_memory(6,GFP_KERNEL);
+		shrink_icache_memory(3,GFP_KERNEL);
+#else
+		prune_dcache(2000);
+		prune_icache(2000);
+#endif
+	}
 	dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); 
 	if (!dentry)
 		return NULL;
diff -ru linux-2.4.18/fs/inode.c linux-2.4.18-perf/fs/inode.c
--- linux-2.4.18/fs/inode.c	Thu Mar  7 19:59:00 2002
+++ linux-2.4.18-perf/fs/inode.c	Tue Apr 30 23:01:36 2002
@@ -60,6 +60,8 @@
 static struct list_head *inode_hashtable;
 static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */
 
+static void check_unused_inode(void);
+
 /*
  * A simple spinlock to protect the list manipulations.
  *
@@ -740,7 +742,6 @@
 int shrink_icache_memory(int priority, int gfp_mask)
 {
 	int count = 0;
-
 	/*
 	 * Nasty deadlock avoidance..
 	 *
@@ -751,13 +752,35 @@
 	if (!(gfp_mask & __GFP_FS))
 		return 0;
 
-	count = inodes_stat.nr_unused / priority;
+	if (priority == 0) {
+		if (inodes_stat.nr_unused > fstune_param.unused_icache_limit) { /* XXX suz */
+			count = inodes_stat.nr_unused / 6;
+		} else {
+			return 0;
+		}
+	} else {
+		count = inodes_stat.nr_unused / priority;
+	}
 
 	prune_icache(count);
 	kmem_cache_shrink(inode_cachep);
 	return 0;
 }
 
+static unsigned long last_check_time;
+
+static void check_unused_inode() {
+	extern unsigned fstune_stat[];
+	fstune_stat[6] = inodes_stat.nr_inodes;
+	fstune_stat[7] = inodes_stat.nr_unused;
+	if (jiffies - last_check_time  > fstune_param.icache_check_interval) {
+		if (inodes_stat.nr_unused > fstune_param.unused_icache_limit) { /* XXX suz */
+			shrink_icache_memory(6, SLAB_KERNEL);
+		}
+		last_check_time = jiffies;
+	}
+}
+
 /*
  * Called with the inode lock held.
  * NOTE: we are not increasing the inode-refcount, you must call __iget()
@@ -837,7 +860,10 @@
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
-	
+
+#if 1
+	check_unused_inode();
+#endif	
 	inode = alloc_inode();
 	if (inode)
 	{
@@ -867,6 +893,9 @@
 {
 	struct inode * inode;
 
+#if 1
+	check_unused_inode();
+#endif
 	inode = alloc_inode();
 	if (inode) {
 		struct inode * old;
diff -ru linux-2.4.18/fs/proc/proc_misc.c linux-2.4.18-perf/fs/proc/proc_misc.c
--- linux-2.4.18/fs/proc/proc_misc.c	Wed Nov 21 14:29:09 2001
+++ linux-2.4.18-perf/fs/proc/proc_misc.c	Tue Apr 30 22:41:20 2002
@@ -65,6 +65,8 @@
 extern int get_ds1286_status(char *);
 #endif
 
+extern unsigned int fstune_stat[];
+
 static int proc_calc_metrics(char *page, char **start, off_t off,
 				 int count, int *eof, int len)
 {
@@ -310,6 +312,13 @@
 		xtime.tv_sec - jif / HZ,
 		total_forks);
 
+	len += sprintf(page + len,
+		"fstune %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
+		fstune_stat[0],fstune_stat[1],fstune_stat[2],fstune_stat[3],
+		fstune_stat[4], fstune_stat[5],fstune_stat[6],fstune_stat[7],
+		fstune_stat[8], fstune_stat[9],fstune_stat[10],fstune_stat[11],
+		fstune_stat[12], fstune_stat[13],fstune_stat[14],fstune_stat[15]);
+
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
diff -ru linux-2.4.18/include/linux/fs.h linux-2.4.18-perf/include/linux/fs.h
--- linux-2.4.18/include/linux/fs.h	Thu Mar  7 20:33:08 2002
+++ linux-2.4.18-perf/include/linux/fs.h	Tue Apr 30 21:59:42 2002
@@ -255,6 +255,8 @@
 	struct buffer_head *b_reqnext;	/* request queue */
 
 	struct buffer_head **b_pprev;	/* doubly linked list of hash-queue */
+	struct buffer_head *b_next_lru;	/* LRU Hash queue list */
+	struct buffer_head **b_pprev_lru; /* doubly linked list of LRU hash-queue */
 	char * b_data;			/* pointer to data block */
 	struct page *b_page;		/* the page this bh is mapped to */
 	void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
@@ -1398,7 +1400,7 @@
 typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int);
 
 /* Generic buffer handling for block filesystems.. */
-extern int try_to_release_page(struct page * page, int gfp_mask);
+extern int try_to_release_page(struct page * page, int gfp_mask,int clean_only);
 extern int discard_bh_page(struct page *, unsigned long, int);
 #define block_flushpage(page, offset) discard_bh_page(page, offset, 1)
 #define block_invalidate_page(page) discard_bh_page(page, 0, 0)
@@ -1609,6 +1611,15 @@
 	dput(d2);
 }
 
+
+struct fstune_param {
+	int	dcache_limit;
+	int	unused_icache_limit;
+	int	icache_check_interval;
+	int	shrink_clean_pages;
+};
+extern struct fstune_param fstune_param;
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_FS_H */
diff -ru linux-2.4.18/mm/vmscan.c linux-2.4.18-perf/mm/vmscan.c
--- linux-2.4.18/mm/vmscan.c	Tue Feb 26 04:38:14 2002
+++ linux-2.4.18-perf/mm/vmscan.c	Tue Apr 30 22:02:26 2002
@@ -333,8 +333,8 @@
 	return 0;
 }
 
-static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority));
-static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority)
+static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority,int clean_only));
+static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority, int clean_only)
 {
 	struct list_head * entry;
 	int max_scan = nr_inactive_pages / priority;
@@ -369,7 +369,7 @@
 		if (unlikely(!page_count(page)))
 			continue;
 
-		if (!memclass(page->zone, classzone))
+		if (!clean_only && !memclass(page->zone, classzone))
 			continue;
 
 		/* Racy check to avoid trylocking when not worthwhile */
@@ -381,6 +381,9 @@
 		 * Move it to the back of the list.
 		 */
 		if (unlikely(TryLockPage(page))) {
+			if (clean_only) {
+				continue;
+			}
 			if (PageLaunder(page) && (gfp_mask & __GFP_FS)) {
 				page_cache_get(page);
 				spin_unlock(&pagemap_lru_lock);
@@ -402,6 +405,10 @@
 			 */
 			int (*writepage)(struct page *);
 
+			if (clean_only) {
+				UnlockPage(page);
+				continue;
+			}
 			writepage = page->mapping->a_ops->writepage;
 			if ((gfp_mask & __GFP_FS) && writepage) {
 				ClearPageDirty(page);
@@ -428,7 +435,7 @@
 			/* avoid to free a locked page */
 			page_cache_get(page);
 
-			if (try_to_release_page(page, gfp_mask)) {
+			if (try_to_release_page(page, gfp_mask,clean_only)) {
 				if (!page->mapping) {
 					/*
 					 * We must not allow an anon page
@@ -524,6 +531,7 @@
 	return nr_pages;
 }
 
+
 /*
  * This moves pages from the active list to
  * the inactive list.
@@ -572,7 +580,20 @@
 	ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2);
 	refill_inactive(ratio);
 
-	nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority);
+	if (classzone->free_pages < classzone->pages_high * 3) {
+		int tmp;
+		shrink_icache_memory(0, gfp_mask);
+		tmp = shrink_cache(fstune_param.shrink_clean_pages, classzone, gfp_mask, priority, 1); /* XXX suz */
+		nr_pages -= (128 - tmp);
+		if (nr_pages <= 0)
+			return 0;
+	}
+	if (classzone->free_pages > classzone->pages_high) {
+		return 0;
+	}
+	
+
+	nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority, 0);
 	if (nr_pages <= 0)
 		return 0;
 
