Patch from Trond Myklebust <trond.myklebust@fys.uio.no>




 nfs/pagelist.c |   31 ++++++++++++++-----------------
 nfs/write.c    |   26 +++++++++++++-------------
 2 files changed, 27 insertions(+), 30 deletions(-)

diff -puN fs/nfs/pagelist.c~nfs-oom-fix fs/nfs/pagelist.c
--- 25/fs/nfs/pagelist.c~nfs-oom-fix	2003-02-10 03:07:55.000000000 -0800
+++ 25-akpm/fs/nfs/pagelist.c	2003-02-10 03:07:55.000000000 -0800
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/mempool.h>
 #include <linux/file.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs3.h>
@@ -26,13 +27,15 @@
  */
 spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED;
 
+#define MIN_POOL_NFSPAGES	(128)
 static kmem_cache_t *nfs_page_cachep;
+static mempool_t *nfs_page_mempool;
 
 static inline struct nfs_page *
 nfs_page_alloc(void)
 {
 	struct nfs_page	*p;
-	p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
+	p = mempool_alloc(nfs_page_mempool, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->wb_list);
@@ -44,7 +47,7 @@ nfs_page_alloc(void)
 static inline void
 nfs_page_free(struct nfs_page *p)
 {
-	kmem_cache_free(nfs_page_cachep, p);
+	mempool_free(p, nfs_page_mempool);
 }
 
 /**
@@ -66,23 +69,12 @@ nfs_create_request(struct rpc_cred *cred
 		   struct page *page,
 		   unsigned int offset, unsigned int count)
 {
-	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs_page		*req;
 
-	/* Deal with hard limits.  */
-	for (;;) {
-		/* try to allocate the request struct */
-		req = nfs_page_alloc();
-		if (req != NULL)
-			break;
-
-		/* Try to free up at least one request in order to stay
-		 * below the hard limit
-		 */
-		if (signalled() && (server->flags & NFS_MOUNT_INTR))
-			return ERR_PTR(-ERESTARTSYS);
-		yield();
-	}
+	/* try to allocate the request struct */
+	req = nfs_page_alloc();
+	if (req == NULL)
+		return ERR_PTR(-ENOMEM);
 
 	/* Initialize the request struct. Initially, we assume a
 	 * long write-back delay. This will be adjusted in
@@ -352,12 +344,17 @@ int nfs_init_nfspagecache(void)
 					    NULL, NULL);
 	if (nfs_page_cachep == NULL)
 		return -ENOMEM;
+	nfs_page_mempool = mempool_create(MIN_POOL_NFSPAGES,
+			mempool_alloc_slab,
+			mempool_free_slab,
+			nfs_page_cachep);
 
 	return 0;
 }
 
 void nfs_destroy_nfspagecache(void)
 {
+	mempool_destroy(nfs_page_mempool);
 	if (kmem_cache_destroy(nfs_page_cachep))
 		printk(KERN_INFO "nfs_page: not all structures were freed\n");
 }
diff -puN fs/nfs/write.c~nfs-oom-fix fs/nfs/write.c
--- 25/fs/nfs/write.c~nfs-oom-fix	2003-02-10 03:07:55.000000000 -0800
+++ 25-akpm/fs/nfs/write.c	2003-02-10 03:07:55.000000000 -0800
@@ -227,30 +227,30 @@ nfs_writepage(struct page *page, struct 
 	struct inode *inode = page->mapping->host;
 	unsigned long end_index;
 	unsigned offset = PAGE_CACHE_SIZE;
-	int err;
+	int err = -EIO;
 
 	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 
 	/* Ensure we've flushed out any previous writes */
 	nfs_wb_page(inode,page);
 
-	/* easy case */
-	if (page->index < end_index)
-		goto do_it;
-	/* things got complicated... */
-	offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-
-	/* OK, are we completely out? */
-	err = -EIO;
-	if (page->index >= end_index+1 || !offset)
-		goto out;
-do_it:
+	/* easy case ? */
+	if (page->index >= end_index) {
+		/* things got complicated... */
+		offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+
+		/* OK, are we completely out? */
+		if (page->index >= end_index+1 || !offset)
+			goto out;
+	}
+
 	lock_kernel();
 	if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode)) {
 		err = nfs_writepage_async(NULL, inode, page, 0, offset);
 		if (err >= 0)
 			err = 0;
-	} else {
+	}
+	if (err < 0) {
 		err = nfs_writepage_sync(NULL, inode, page, 0, offset); 
 		if (err == offset)
 			err = 0;

_