fs/nfs/pagelist.c | 6 +++++- fs/nfs/write.c | 9 +++++++++ mm/page_alloc.c | 9 +++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff -puN fs/nfs/write.c~nfs-more-oom-fix fs/nfs/write.c --- 25/fs/nfs/write.c~nfs-more-oom-fix 2003-04-20 18:03:06.000000000 -0700 +++ 25-akpm/fs/nfs/write.c 2003-04-20 18:03:06.000000000 -0700 @@ -220,6 +220,10 @@ nfs_writepage_async(struct file *file, s /* * Write an mmapped page to the server. + * + * NFS is special. It clears PF_MEMALLOC because that could cause page reclaim + * to use *all* memory writing pages to the server. But we _must_ leave memory + * available for network Rx. */ int nfs_writepage(struct page *page, struct writeback_control *wbc) @@ -228,6 +232,10 @@ nfs_writepage(struct page *page, struct unsigned long end_index; unsigned offset = PAGE_CACHE_SIZE; int err = -EIO; + int flags_save; + + flags_save = current->flags; + current->flags &= ~PF_MEMALLOC; end_index = inode->i_size >> PAGE_CACHE_SHIFT; @@ -258,6 +266,7 @@ nfs_writepage(struct page *page, struct unlock_kernel(); out: unlock_page(page); + current->flags = flags_save; return err; } diff -puN fs/nfs/pagelist.c~nfs-more-oom-fix fs/nfs/pagelist.c --- 25/fs/nfs/pagelist.c~nfs-more-oom-fix 2003-04-20 18:03:06.000000000 -0700 +++ 25-akpm/fs/nfs/pagelist.c 2003-04-20 18:03:06.000000000 -0700 @@ -31,11 +31,15 @@ spinlock_t nfs_wreq_lock = SPIN_LOCK_UNL static kmem_cache_t *nfs_page_cachep; static mempool_t *nfs_page_mempool; +/* + * Use __GFP_HIGH here so that NFS can utilise _some_ of the page reserves. + * Important, because we've turned off PF_MEMALLOC in nfs_writepage(). + */ static inline struct nfs_page * nfs_page_alloc(void) { struct nfs_page *p; - p = mempool_alloc(nfs_page_mempool, SLAB_NOFS); + p = mempool_alloc(nfs_page_mempool, SLAB_NOFS|__GFP_HIGH); if (p) { memset(p, 0, sizeof(*p)); INIT_LIST_HEAD(&p->wb_list); diff -puN mm/page_alloc.c~nfs-more-oom-fix mm/page_alloc.c --- 25/mm/page_alloc.c~nfs-more-oom-fix 2003-04-20 18:03:06.000000000 -0700 +++ 25-akpm/mm/page_alloc.c 2003-04-20 18:03:06.000000000 -0700 @@ -569,7 +569,10 @@ __alloc_pages(unsigned int gfp_mask, uns for (i = 0; zones[i] != NULL; i++) wakeup_kswapd(zones[i]); - /* Go through the zonelist again, taking __GFP_HIGH into account */ + /* + * Go through the zonelist again, taking __GFP_HIGH and in_interrupt() + * into account. + */ min = 1UL << order; for (i = 0; zones[i] != NULL; i++) { unsigned long local_min; @@ -577,7 +580,9 @@ __alloc_pages(unsigned int gfp_mask, uns local_min = z->pages_min; if (gfp_mask & __GFP_HIGH) - local_min >>= 2; + local_min >>= 1; + if (in_interrupt()) + local_min >>= 1; min += local_min; if (z->free_pages >= min || (!wait && z->free_pages >= z->pages_high)) { _