Commit d27b62f2 authored by Trond Myklebust's avatar Trond Myklebust

[PATCH] add an NFS memory pool

Ensure that we can still flush out a minimum number of read, write,
and commit requests if memory gets low.
parent ca738a2b
...@@ -811,7 +811,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) ...@@ -811,7 +811,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags); rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
task->tk_calldata = data; task->tk_calldata = data;
/* Release requests */ /* Release requests */
task->tk_release = nfs_writedata_release; task->tk_release = nfs_commit_release;
msg.rpc_proc = NFS3PROC_COMMIT; msg.rpc_proc = NFS3PROC_COMMIT;
msg.rpc_argp = &data->u.v3.args; msg.rpc_argp = &data->u.v3.args;
......
...@@ -1481,7 +1481,7 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) ...@@ -1481,7 +1481,7 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
task->tk_calldata = data; task->tk_calldata = data;
/* Release requests */ /* Release requests */
task->tk_release = nfs_writedata_release; task->tk_release = nfs_commit_release;
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mempool.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
...@@ -37,11 +38,14 @@ ...@@ -37,11 +38,14 @@
static int nfs_pagein_one(struct list_head *, struct inode *); static int nfs_pagein_one(struct list_head *, struct inode *);
static kmem_cache_t *nfs_rdata_cachep; static kmem_cache_t *nfs_rdata_cachep;
static mempool_t *nfs_rdata_mempool;
#define MIN_POOL_READ (32)
static __inline__ struct nfs_read_data *nfs_readdata_alloc(void) static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
{ {
struct nfs_read_data *p; struct nfs_read_data *p;
p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NOFS); p = (struct nfs_read_data *)mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
...@@ -51,7 +55,7 @@ static __inline__ struct nfs_read_data *nfs_readdata_alloc(void) ...@@ -51,7 +55,7 @@ static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
static __inline__ void nfs_readdata_free(struct nfs_read_data *p) static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
{ {
kmem_cache_free(nfs_rdata_cachep, p); mempool_free(p, nfs_rdata_mempool);
} }
void nfs_readdata_release(struct rpc_task *task) void nfs_readdata_release(struct rpc_task *task)
...@@ -417,11 +421,19 @@ int nfs_init_readpagecache(void) ...@@ -417,11 +421,19 @@ int nfs_init_readpagecache(void)
if (nfs_rdata_cachep == NULL) if (nfs_rdata_cachep == NULL)
return -ENOMEM; return -ENOMEM;
nfs_rdata_mempool = mempool_create(MIN_POOL_READ,
mempool_alloc_slab,
mempool_free_slab,
nfs_rdata_cachep);
if (nfs_rdata_mempool == NULL)
return -ENOMEM;
return 0; return 0;
} }
void nfs_destroy_readpagecache(void) void nfs_destroy_readpagecache(void)
{ {
mempool_destroy(nfs_rdata_mempool);
if (kmem_cache_destroy(nfs_rdata_cachep)) if (kmem_cache_destroy(nfs_rdata_cachep))
printk(KERN_INFO "nfs_read_data: not all structures were freed\n"); printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
} }
...@@ -62,9 +62,13 @@ ...@@ -62,9 +62,13 @@
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/mempool.h>
#define NFSDBG_FACILITY NFSDBG_PAGECACHE #define NFSDBG_FACILITY NFSDBG_PAGECACHE
#define MIN_POOL_WRITE (32)
#define MIN_POOL_COMMIT (4)
/* /*
* Local function declarations * Local function declarations
*/ */
...@@ -74,11 +78,13 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *, ...@@ -74,11 +78,13 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *,
static void nfs_strategy(struct inode *inode); static void nfs_strategy(struct inode *inode);
static kmem_cache_t *nfs_wdata_cachep; static kmem_cache_t *nfs_wdata_cachep;
static mempool_t *nfs_wdata_mempool;
static mempool_t *nfs_commit_mempool;
static __inline__ struct nfs_write_data *nfs_writedata_alloc(void) static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
{ {
struct nfs_write_data *p; struct nfs_write_data *p;
p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NOFS); p = (struct nfs_write_data *)mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
...@@ -88,7 +94,7 @@ static __inline__ struct nfs_write_data *nfs_writedata_alloc(void) ...@@ -88,7 +94,7 @@ static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
static __inline__ void nfs_writedata_free(struct nfs_write_data *p) static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
{ {
kmem_cache_free(nfs_wdata_cachep, p); mempool_free(p, nfs_wdata_mempool);
} }
void nfs_writedata_release(struct rpc_task *task) void nfs_writedata_release(struct rpc_task *task)
...@@ -97,6 +103,28 @@ void nfs_writedata_release(struct rpc_task *task) ...@@ -97,6 +103,28 @@ void nfs_writedata_release(struct rpc_task *task)
nfs_writedata_free(wdata); nfs_writedata_free(wdata);
} }
static __inline__ struct nfs_write_data *nfs_commit_alloc(void)
{
struct nfs_write_data *p;
p = (struct nfs_write_data *)mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
if (p) {
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
}
return p;
}
static __inline__ void nfs_commit_free(struct nfs_write_data *p)
{
mempool_free(p, nfs_commit_mempool);
}
void nfs_commit_release(struct rpc_task *task)
{
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
nfs_commit_free(wdata);
}
/* /*
* This function will be used to simulate weak cache consistency * This function will be used to simulate weak cache consistency
* under NFSv2 when the NFSv3 attribute patch is included. * under NFSv2 when the NFSv3 attribute patch is included.
...@@ -1093,7 +1121,7 @@ nfs_commit_list(struct list_head *head, int how) ...@@ -1093,7 +1121,7 @@ nfs_commit_list(struct list_head *head, int how)
struct nfs_page *req; struct nfs_page *req;
sigset_t oldset; sigset_t oldset;
data = nfs_writedata_alloc(); data = nfs_commit_alloc();
if (!data) if (!data)
goto out_bad; goto out_bad;
...@@ -1237,11 +1265,27 @@ int nfs_init_writepagecache(void) ...@@ -1237,11 +1265,27 @@ int nfs_init_writepagecache(void)
if (nfs_wdata_cachep == NULL) if (nfs_wdata_cachep == NULL)
return -ENOMEM; return -ENOMEM;
nfs_wdata_mempool = mempool_create(MIN_POOL_WRITE,
mempool_alloc_slab,
mempool_free_slab,
nfs_wdata_cachep);
if (nfs_wdata_mempool == NULL)
return -ENOMEM;
nfs_commit_mempool = mempool_create(MIN_POOL_COMMIT,
mempool_alloc_slab,
mempool_free_slab,
nfs_wdata_cachep);
if (nfs_commit_mempool == NULL)
return -ENOMEM;
return 0; return 0;
} }
void nfs_destroy_writepagecache(void) void nfs_destroy_writepagecache(void)
{ {
mempool_destroy(nfs_commit_mempool);
mempool_destroy(nfs_wdata_mempool);
if (kmem_cache_destroy(nfs_wdata_cachep)) if (kmem_cache_destroy(nfs_wdata_cachep))
printk(KERN_INFO "nfs_write_data: not all structures were freed\n"); printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
} }
......
...@@ -327,6 +327,7 @@ extern void nfs_writeback_done(struct rpc_task *task, int stable, ...@@ -327,6 +327,7 @@ extern void nfs_writeback_done(struct rpc_task *task, int stable,
extern void nfs_writedata_release(struct rpc_task *task); extern void nfs_writedata_release(struct rpc_task *task);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
extern void nfs_commit_release(struct rpc_task *task);
extern void nfs_commit_done(struct rpc_task *); extern void nfs_commit_done(struct rpc_task *);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment