Index: linux/mm/page_alloc.c =================================================================== --- linux.orig/mm/page_alloc.c 2004-10-04 15:11:58.000000000 -0700 +++ linux/mm/page_alloc.c 2004-10-11 16:37:37.000000000 -0700 @@ -577,6 +577,8 @@ return page; } +int vm_free_local_harder =1; + /* * This is the 'heart' of the zoned buddy allocator. * @@ -633,7 +635,17 @@ if (rt_task(p)) local_low >>= 1; min += local_low; - +#ifdef CONFIG_NUMA + /* + * If this is a local zone which does not provide enough memory + * for our needs then try to strip some caching pages before + * going off node + */ + if (vm_free_local_harder && wait && + (gfp_mask & __GFP_WAIT) && !(p->flags & (PF_MEMALLOC | PF_MEMDIE)) && + z->free_pages <= min && z->zone_pgdat->node_id == numa_node_id()) + short_zone_scan(z, gfp_mask); +#endif if (z->free_pages >= min || (!wait && z->free_pages >= z->pages_high)) { page = buffered_rmqueue(z, order, cold); Index: linux/include/linux/gfp.h =================================================================== --- linux.orig/include/linux/gfp.h 2004-10-04 15:11:39.000000000 -0700 +++ linux/include/linux/gfp.h 2004-10-11 16:18:16.000000000 -0700 @@ -86,6 +86,7 @@ } extern struct page *alloc_pages_current(unsigned gfp_mask, unsigned order); +extern int vm_free_local_harder; struct vm_area_struct; #ifdef CONFIG_NUMA Index: linux/kernel/sysctl.c =================================================================== --- linux.orig/kernel/sysctl.c 2004-10-04 15:12:01.000000000 -0700 +++ linux/kernel/sysctl.c 2004-10-11 16:26:00.000000000 -0700 @@ -816,6 +816,17 @@ .extra1 = &zero, .extra2 = &one_hundred, }, + { + .ctl_name = VM_FREE_LOCAL_HARDER, + .procname = "free_local_harder", + .data = &vm_free_local_harder, + .maxlen = sizeof(vm_free_local_harder), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero + }, + #ifdef CONFIG_HUGETLB_PAGE { .ctl_name = VM_HUGETLB_PAGES, Index: linux/include/linux/sysctl.h =================================================================== --- linux.orig/include/linux/sysctl.h 2004-10-04 15:12:01.000000000 -0700 +++ linux/include/linux/sysctl.h 2004-10-11 16:24:27.000000000 -0700 @@ -175,6 +175,7 @@ VM_BLOCK_DUMP=24, /* block dump mode */ VM_DISABLE_CAP_MLOCK=25,/* disable CAP_IPC_LOCK checking */ VM_HEAP_STACK_GAP=26, /* int: page gap between heap and stack */ + VM_FREE_LOCAL_HARDER=28, }; Index: linux/mm/vmscan.c =================================================================== --- linux.orig/mm/vmscan.c 2004-10-11 16:36:17.000000000 -0700 +++ linux/mm/vmscan.c 2004-10-11 16:35:58.000000000 -0700 @@ -831,6 +831,20 @@ return 0; } +#ifdef CONFIG_NUMA +/* + * Short scan intended mainly to throw out caching pages + * in favor of other uses for local memory + */ +int short_zone_scan(struct zone *z, int gfp_mask) { + int scanned; + struct page_state ps; + + get_page_state(&ps); + return shrink_zone(z, z->nr_inactive, gfp_mask, &scanned, &ps); +} +#endif + /* * This is the direct reclaim path, for page-allocating processes. We only * try to reclaim pages from zones which will satisfy the caller's allocation Index: linux/include/linux/swap.h =================================================================== --- linux.orig/include/linux/swap.h 2004-10-11 16:40:21.000000000 -0700 +++ linux/include/linux/swap.h 2004-10-11 16:42:32.000000000 -0700 @@ -173,6 +173,7 @@ /* linux/mm/vmscan.c */ extern int try_to_free_pages(struct zone **, unsigned int, unsigned int); +extern int short_zone_scan(struct zone *, int); extern int shrink_all_memory(int); extern int vm_swappiness;