nfsd: rip out the raparms cache
The raparms cache was set up in order to ensure that we carry readahead information forward from one RPC call to the next. In other words, it was set up because each RPC call was forced to open a struct file, then close it, causing the loss of readahead information that is normally cached in that struct file, and used to keep the page cache filled when a user calls read() multiple times on the same file descriptor. Now that we cache the struct file, and reuse it for all the I/O calls to a given file by a given user, we no longer have to keep a separate readahead cache. Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
6b556ca287
commit
501cb1849f
|
@ -317,22 +317,12 @@ static int nfsd_startup_generic(int nrservs)
|
||||||
ret = nfsd_file_cache_init();
|
ret = nfsd_file_cache_init();
|
||||||
if (ret)
|
if (ret)
|
||||||
goto dec_users;
|
goto dec_users;
|
||||||
/*
|
|
||||||
* Readahead param cache - will no-op if it already exists.
|
|
||||||
* (Note therefore results will be suboptimal if number of
|
|
||||||
* threads is modified after nfsd start.)
|
|
||||||
*/
|
|
||||||
ret = nfsd_racache_init(2*nrservs);
|
|
||||||
if (ret)
|
|
||||||
goto out_file_cache;
|
|
||||||
|
|
||||||
ret = nfs4_state_start();
|
ret = nfs4_state_start();
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_racache;
|
goto out_file_cache;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_racache:
|
|
||||||
nfsd_racache_shutdown();
|
|
||||||
out_file_cache:
|
out_file_cache:
|
||||||
nfsd_file_cache_shutdown();
|
nfsd_file_cache_shutdown();
|
||||||
dec_users:
|
dec_users:
|
||||||
|
@ -347,7 +337,6 @@ static void nfsd_shutdown_generic(void)
|
||||||
|
|
||||||
nfs4_state_shutdown();
|
nfs4_state_shutdown();
|
||||||
nfsd_file_cache_shutdown();
|
nfsd_file_cache_shutdown();
|
||||||
nfsd_racache_shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nfsd_needs_lockd(struct nfsd_net *nn)
|
static bool nfsd_needs_lockd(struct nfsd_net *nn)
|
||||||
|
|
149
fs/nfsd/vfs.c
149
fs/nfsd/vfs.c
|
@ -49,34 +49,6 @@
|
||||||
|
|
||||||
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
|
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a cache of readahead params that help us choose the proper
|
|
||||||
* readahead strategy. Initially, we set all readahead parameters to 0
|
|
||||||
* and let the VFS handle things.
|
|
||||||
* If you increase the number of cached files very much, you'll need to
|
|
||||||
* add a hash table here.
|
|
||||||
*/
|
|
||||||
struct raparms {
|
|
||||||
struct raparms *p_next;
|
|
||||||
unsigned int p_count;
|
|
||||||
ino_t p_ino;
|
|
||||||
dev_t p_dev;
|
|
||||||
int p_set;
|
|
||||||
struct file_ra_state p_ra;
|
|
||||||
unsigned int p_hindex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct raparm_hbucket {
|
|
||||||
struct raparms *pb_head;
|
|
||||||
spinlock_t pb_lock;
|
|
||||||
} ____cacheline_aligned_in_smp;
|
|
||||||
|
|
||||||
#define RAPARM_HASH_BITS 4
|
|
||||||
#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
|
|
||||||
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
|
|
||||||
static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
|
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
|
||||||
* a mount point.
|
* a mount point.
|
||||||
|
@ -822,67 +794,6 @@ nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct raparms *
|
|
||||||
nfsd_init_raparms(struct file *file)
|
|
||||||
{
|
|
||||||
struct inode *inode = file_inode(file);
|
|
||||||
dev_t dev = inode->i_sb->s_dev;
|
|
||||||
ino_t ino = inode->i_ino;
|
|
||||||
struct raparms *ra, **rap, **frap = NULL;
|
|
||||||
int depth = 0;
|
|
||||||
unsigned int hash;
|
|
||||||
struct raparm_hbucket *rab;
|
|
||||||
|
|
||||||
hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
|
|
||||||
rab = &raparm_hash[hash];
|
|
||||||
|
|
||||||
spin_lock(&rab->pb_lock);
|
|
||||||
for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
|
|
||||||
if (ra->p_ino == ino && ra->p_dev == dev)
|
|
||||||
goto found;
|
|
||||||
depth++;
|
|
||||||
if (ra->p_count == 0)
|
|
||||||
frap = rap;
|
|
||||||
}
|
|
||||||
depth = nfsdstats.ra_size;
|
|
||||||
if (!frap) {
|
|
||||||
spin_unlock(&rab->pb_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
rap = frap;
|
|
||||||
ra = *frap;
|
|
||||||
ra->p_dev = dev;
|
|
||||||
ra->p_ino = ino;
|
|
||||||
ra->p_set = 0;
|
|
||||||
ra->p_hindex = hash;
|
|
||||||
found:
|
|
||||||
if (rap != &rab->pb_head) {
|
|
||||||
*rap = ra->p_next;
|
|
||||||
ra->p_next = rab->pb_head;
|
|
||||||
rab->pb_head = ra;
|
|
||||||
}
|
|
||||||
ra->p_count++;
|
|
||||||
nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
|
|
||||||
spin_unlock(&rab->pb_lock);
|
|
||||||
|
|
||||||
if (ra->p_set)
|
|
||||||
file->f_ra = ra->p_ra;
|
|
||||||
return ra;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfsd_put_raparams(struct file *file, struct raparms *ra)
|
|
||||||
{
|
|
||||||
struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
|
|
||||||
|
|
||||||
spin_lock(&rab->pb_lock);
|
|
||||||
ra->p_ra = file->f_ra;
|
|
||||||
ra->p_set = 1;
|
|
||||||
ra->p_count--;
|
|
||||||
spin_unlock(&rab->pb_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grab and keep cached pages associated with a file in the svc_rqst
|
* Grab and keep cached pages associated with a file in the svc_rqst
|
||||||
* so that they can be passed to the network sendmsg/sendpage routines
|
* so that they can be passed to the network sendmsg/sendpage routines
|
||||||
|
@ -2094,63 +2005,3 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
|
||||||
|
|
||||||
return err? nfserrno(err) : 0;
|
return err? nfserrno(err) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nfsd_racache_shutdown(void)
|
|
||||||
{
|
|
||||||
struct raparms *raparm, *last_raparm;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
dprintk("nfsd: freeing readahead buffers.\n");
|
|
||||||
|
|
||||||
for (i = 0; i < RAPARM_HASH_SIZE; i++) {
|
|
||||||
raparm = raparm_hash[i].pb_head;
|
|
||||||
while(raparm) {
|
|
||||||
last_raparm = raparm;
|
|
||||||
raparm = raparm->p_next;
|
|
||||||
kfree(last_raparm);
|
|
||||||
}
|
|
||||||
raparm_hash[i].pb_head = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Initialize readahead param cache
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
nfsd_racache_init(int cache_size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int j = 0;
|
|
||||||
int nperbucket;
|
|
||||||
struct raparms **raparm = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
if (raparm_hash[0].pb_head)
|
|
||||||
return 0;
|
|
||||||
nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
|
|
||||||
nperbucket = max(2, nperbucket);
|
|
||||||
cache_size = nperbucket * RAPARM_HASH_SIZE;
|
|
||||||
|
|
||||||
dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
|
|
||||||
|
|
||||||
for (i = 0; i < RAPARM_HASH_SIZE; i++) {
|
|
||||||
spin_lock_init(&raparm_hash[i].pb_lock);
|
|
||||||
|
|
||||||
raparm = &raparm_hash[i].pb_head;
|
|
||||||
for (j = 0; j < nperbucket; j++) {
|
|
||||||
*raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
|
|
||||||
if (!*raparm)
|
|
||||||
goto out_nomem;
|
|
||||||
raparm = &(*raparm)->p_next;
|
|
||||||
}
|
|
||||||
*raparm = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nfsdstats.ra_size = cache_size;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_nomem:
|
|
||||||
dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
|
|
||||||
nfsd_racache_shutdown();
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
|
@ -40,8 +40,6 @@
|
||||||
typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
|
typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
|
||||||
|
|
||||||
/* nfsd/vfs.c */
|
/* nfsd/vfs.c */
|
||||||
int nfsd_racache_init(int);
|
|
||||||
void nfsd_racache_shutdown(void);
|
|
||||||
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
||||||
struct svc_export **expp);
|
struct svc_export **expp);
|
||||||
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
|
||||||
|
@ -80,7 +78,6 @@ __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
|
||||||
int, struct file **);
|
int, struct file **);
|
||||||
__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, umode_t,
|
__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, umode_t,
|
||||||
int, struct file **);
|
int, struct file **);
|
||||||
struct raparms;
|
|
||||||
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
struct file *file, loff_t offset,
|
struct file *file, loff_t offset,
|
||||||
unsigned long *count);
|
unsigned long *count);
|
||||||
|
@ -118,9 +115,6 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
|
||||||
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
|
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
|
||||||
struct dentry *, int);
|
struct dentry *, int);
|
||||||
|
|
||||||
struct raparms *nfsd_init_raparms(struct file *file);
|
|
||||||
void nfsd_put_raparams(struct file *file, struct raparms *ra);
|
|
||||||
|
|
||||||
static inline int fh_want_write(struct svc_fh *fh)
|
static inline int fh_want_write(struct svc_fh *fh)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
Loading…
Reference in New Issue