NFS: Optimise NFS close()
Close-to-open cache consistency rules really only require us to flush out writes on calls to close(), and require us to revalidate attributes on the very last close of the file. Currently we appear to be doing a lot of extra attribute revalidation and cache flushes. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
b1e4adf4ea
commit
7fe5c398fc
7 changed files with 47 additions and 21 deletions
|
@ -137,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
|
|||
dentry->d_parent->d_name.name,
|
||||
dentry->d_name.name);
|
||||
|
||||
/* Ensure that dirty pages are flushed out with the right creds */
|
||||
if (filp->f_mode & FMODE_WRITE)
|
||||
nfs_wb_all(dentry->d_inode);
|
||||
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
|
||||
return nfs_release(inode, filp);
|
||||
}
|
||||
|
@ -231,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
|
|||
struct nfs_open_context *ctx = nfs_file_open_context(file);
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int status;
|
||||
|
||||
dprintk("NFS: flush(%s/%s)\n",
|
||||
dentry->d_parent->d_name.name,
|
||||
|
@ -241,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
|
|||
return 0;
|
||||
nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
|
||||
|
||||
/* Ensure that data+attribute caches are up to date after close() */
|
||||
status = nfs_do_fsync(ctx, inode);
|
||||
if (!status)
|
||||
nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
||||
return status;
|
||||
/* Flush writes to the server and return any errors */
|
||||
return nfs_do_fsync(ctx, inode);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
|
@ -541,6 +541,32 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_close_context - Common close_context() routine NFSv2/v3
|
||||
* @ctx: pointer to context
|
||||
* @is_sync: is this a synchronous close
|
||||
*
|
||||
* always ensure that the attributes are up to date if we're mounted
|
||||
* with close-to-open semantics
|
||||
*/
|
||||
void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct nfs_server *server;
|
||||
|
||||
if (!(ctx->mode & FMODE_WRITE))
|
||||
return;
|
||||
if (!is_sync)
|
||||
return;
|
||||
inode = ctx->path.dentry->d_inode;
|
||||
if (!list_empty(&NFS_I(inode)->open_files))
|
||||
return;
|
||||
server = NFS_SERVER(inode);
|
||||
if (server->flags & NFS_MOUNT_NOCTO)
|
||||
return;
|
||||
nfs_revalidate_inode(server, inode);
|
||||
}
|
||||
|
||||
static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs_open_context *ctx;
|
||||
|
@ -567,24 +593,15 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
|
|||
return ctx;
|
||||
}
|
||||
|
||||
static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
|
||||
static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = ctx->path.dentry->d_inode;
|
||||
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
inode = ctx->path.dentry->d_inode;
|
||||
if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
|
||||
return;
|
||||
list_del(&ctx->list);
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (ctx->state != NULL) {
|
||||
if (wait)
|
||||
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
|
||||
else
|
||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||
}
|
||||
NFS_PROTO(inode)->close_context(ctx, is_sync);
|
||||
if (ctx->cred != NULL)
|
||||
put_rpccred(ctx->cred);
|
||||
path_put(&ctx->path);
|
||||
|
|
|
@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
|
|||
extern struct rpc_procinfo nfs4_procedures[];
|
||||
#endif
|
||||
|
||||
/* proc.c */
|
||||
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
|
||||
|
||||
/* dir.c */
|
||||
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
|
||||
|
||||
|
|
|
@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
|
|||
.commit_done = nfs3_commit_done,
|
||||
.lock = nfs3_proc_lock,
|
||||
.clear_acl_cache = nfs3_forget_cached_acls,
|
||||
.close_context = nfs_close_context,
|
||||
};
|
||||
|
|
|
@ -1572,6 +1572,15 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
|
|||
return 0;
|
||||
}
|
||||
|
||||
void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
if (ctx->state == NULL)
|
||||
return;
|
||||
if (is_sync)
|
||||
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
|
||||
else
|
||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||
}
|
||||
|
||||
static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
||||
{
|
||||
|
@ -3776,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
|
|||
.commit_done = nfs4_commit_done,
|
||||
.lock = nfs4_proc_lock,
|
||||
.clear_acl_cache = nfs4_zap_acl_attr,
|
||||
.close_context = nfs4_close_context,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
|
|||
.commit_setup = nfs_proc_commit_setup,
|
||||
.lock = nfs_proc_lock,
|
||||
.lock_check_bounds = nfs_lock_check_bounds,
|
||||
.close_context = nfs_close_context,
|
||||
};
|
||||
|
|
|
@ -868,6 +868,7 @@ struct nfs_rpc_ops {
|
|||
int (*lock)(struct file *, int, struct file_lock *);
|
||||
int (*lock_check_bounds)(const struct file_lock *);
|
||||
void (*clear_acl_cache)(struct inode *);
|
||||
void (*close_context)(struct nfs_open_context *ctx, int);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue