--- include/linux/swap.h | 2 ++ mm/page_alloc.c | 11 +++++++++++ mm/vmscan.c | 27 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) Index: linux-2.6/include/linux/swap.h =================================================================== --- linux-2.6.orig/include/linux/swap.h 2007-08-08 04:31:06.000000000 -0700 +++ linux-2.6/include/linux/swap.h 2007-08-08 04:31:28.000000000 -0700 @@ -190,6 +190,8 @@ extern void swap_setup(void); /* linux/mm/vmscan.c */ extern unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask); +extern unsigned long emergency_free_pages(struct zone **zones, int order, + gfp_t gfp_mask); extern unsigned long shrink_all_memory(unsigned long nr_pages); extern int vm_swappiness; extern int remove_mapping(struct address_space *mapping, struct page *page); Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-08-08 04:17:33.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-08-08 04:39:26.000000000 -0700 @@ -1306,6 +1306,17 @@ nofail_alloc: zonelist, ALLOC_NO_WATERMARKS); if (page) goto got_pg; + + /* + * We cannot go into full synchrononous reclaim + * but we can still scan for easily reclaimable + * pages. + */ + if (p->flags & PF_MEMALLOC && + emergency_free_pages(zonelist->zones, order, + gfp_mask)) + goto nofail_alloc; + if (gfp_mask & __GFP_NOFAIL) { congestion_wait(WRITE, HZ/50); goto nofail_alloc; Index: linux-2.6/mm/vmscan.c =================================================================== --- linux-2.6.orig/mm/vmscan.c 2007-08-08 04:21:14.000000000 -0700 +++ linux-2.6/mm/vmscan.c 2007-08-08 04:42:24.000000000 -0700 @@ -1204,6 +1204,33 @@ out: } /* + * Emergency reclaim. We are alreedy in the vm write out path + * and we have exhausted all memory. We have to free memory without + * any additional allocations. So no writes and no swap. Get + * as bare bones as we can. + */ +unsigned long emergency_free_pages(struct zone **zones, int order, gfp_t gfp_mask) +{ + int priority; + unsigned long nr_reclaimed = 0; + struct scan_control sc = { + .gfp_mask = gfp_mask, + .swap_cluster_max = SWAP_CLUSTER_MAX, + .order = order, + }; + + for (priority = DEF_PRIORITY; priority >= 0; priority--) { + sc.nr_scanned = 0; + nr_reclaimed += shrink_zones(priority, zones, &sc); + if (nr_reclaimed >= sc.swap_cluster_max) + return 1; + } + + /* top priority shrink_caches still had more to do? don't OOM, then */ + return sc.all_unreclaimable; +} + +/* * For kswapd, balance_pgdat() will work across all this node's zones until * they are all at pages_high. *