Skip to content

Commit

Permalink
NFS: Optimise NFS close()
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Mar 19, 2009
1 parent b1e4adf commit 7fe5c39
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 21 deletions.
11 changes: 2 additions & 9 deletions fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
41 changes: 29 additions & 12 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions fs/nfs/nfs3proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
10 changes: 10 additions & 0 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
};

/*
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
1 change: 1 addition & 0 deletions include/linux/nfs_xdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

/*
Expand Down

0 comments on commit 7fe5c39

Please sign in to comment.