Patch from Trond Myklebust 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 #include +#include #include #include #include @@ -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; _