aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-03-19 15:35:50 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-03-19 15:35:50 -0400
commit7fe5c398fc2186ed586db11106a6692d871d0d58 (patch)
tree1133bd775a23fb07ca759e4d6c44132c14576b75 /fs/nfs
parentb1e4adf4ea41bb8b5a7bfc1a7001f137e65495df (diff)
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/file.c11
-rw-r--r--fs/nfs/inode.c41
-rw-r--r--fs/nfs/internal.h3
-rw-r--r--fs/nfs/nfs3proc.c1
-rw-r--r--fs/nfs/nfs4proc.c10
-rw-r--r--fs/nfs/proc.c1
6 files changed, 46 insertions, 21 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 1eab9c9ad242..d451073c4947 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -137,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
137 dentry->d_parent->d_name.name, 137 dentry->d_parent->d_name.name,
138 dentry->d_name.name); 138 dentry->d_name.name);
139 139
140 /* Ensure that dirty pages are flushed out with the right creds */
141 if (filp->f_mode & FMODE_WRITE)
142 nfs_wb_all(dentry->d_inode);
143 nfs_inc_stats(inode, NFSIOS_VFSRELEASE); 140 nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
144 return nfs_release(inode, filp); 141 return nfs_release(inode, filp);
145} 142}
@@ -231,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
231 struct nfs_open_context *ctx = nfs_file_open_context(file); 228 struct nfs_open_context *ctx = nfs_file_open_context(file);
232 struct dentry *dentry = file->f_path.dentry; 229 struct dentry *dentry = file->f_path.dentry;
233 struct inode *inode = dentry->d_inode; 230 struct inode *inode = dentry->d_inode;
234 int status;
235 231
236 dprintk("NFS: flush(%s/%s)\n", 232 dprintk("NFS: flush(%s/%s)\n",
237 dentry->d_parent->d_name.name, 233 dentry->d_parent->d_name.name,
@@ -241,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
241 return 0; 237 return 0;
242 nfs_inc_stats(inode, NFSIOS_VFSFLUSH); 238 nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
243 239
244 /* Ensure that data+attribute caches are up to date after close() */ 240 /* Flush writes to the server and return any errors */
245 status = nfs_do_fsync(ctx, inode); 241 return nfs_do_fsync(ctx, inode);
246 if (!status)
247 nfs_revalidate_inode(NFS_SERVER(inode), inode);
248 return status;
249} 242}
250 243
251static ssize_t 244static ssize_t
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c40adc5dd609..a834d1d850b7 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -541,6 +541,32 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
541 return err; 541 return err;
542} 542}
543 543
544/**
545 * nfs_close_context - Common close_context() routine NFSv2/v3
546 * @ctx: pointer to context
547 * @is_sync: is this a synchronous close
548 *
549 * always ensure that the attributes are up to date if we're mounted
550 * with close-to-open semantics
551 */
552void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
553{
554 struct inode *inode;
555 struct nfs_server *server;
556
557 if (!(ctx->mode & FMODE_WRITE))
558 return;
559 if (!is_sync)
560 return;
561 inode = ctx->path.dentry->d_inode;
562 if (!list_empty(&NFS_I(inode)->open_files))
563 return;
564 server = NFS_SERVER(inode);
565 if (server->flags & NFS_MOUNT_NOCTO)
566 return;
567 nfs_revalidate_inode(server, inode);
568}
569
544static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) 570static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
545{ 571{
546 struct nfs_open_context *ctx; 572 struct nfs_open_context *ctx;
@@ -567,24 +593,15 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
567 return ctx; 593 return ctx;
568} 594}
569 595
570static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) 596static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
571{ 597{
572 struct inode *inode; 598 struct inode *inode = ctx->path.dentry->d_inode;
573 599
574 if (ctx == NULL)
575 return;
576
577 inode = ctx->path.dentry->d_inode;
578 if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) 600 if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
579 return; 601 return;
580 list_del(&ctx->list); 602 list_del(&ctx->list);
581 spin_unlock(&inode->i_lock); 603 spin_unlock(&inode->i_lock);
582 if (ctx->state != NULL) { 604 NFS_PROTO(inode)->close_context(ctx, is_sync);
583 if (wait)
584 nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
585 else
586 nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
587 }
588 if (ctx->cred != NULL) 605 if (ctx->cred != NULL)
589 put_rpccred(ctx->cred); 606 put_rpccred(ctx->cred);
590 path_put(&ctx->path); 607 path_put(&ctx->path);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index a55e69aa52e5..2041f68ff1cc 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
152extern struct rpc_procinfo nfs4_procedures[]; 152extern struct rpc_procinfo nfs4_procedures[];
153#endif 153#endif
154 154
155/* proc.c */
156void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
157
155/* dir.c */ 158/* dir.c */
156extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); 159extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
157 160
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index c55be7a7679e..b82fe6847f14 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
834 .commit_done = nfs3_commit_done, 834 .commit_done = nfs3_commit_done,
835 .lock = nfs3_proc_lock, 835 .lock = nfs3_proc_lock,
836 .clear_acl_cache = nfs3_forget_cached_acls, 836 .clear_acl_cache = nfs3_forget_cached_acls,
837 .close_context = nfs_close_context,
837}; 838};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 95f171e7e05a..97bacccff579 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1572,6 +1572,15 @@ out_drop:
1572 return 0; 1572 return 0;
1573} 1573}
1574 1574
1575void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
1576{
1577 if (ctx->state == NULL)
1578 return;
1579 if (is_sync)
1580 nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
1581 else
1582 nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
1583}
1575 1584
1576static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) 1585static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
1577{ 1586{
@@ -3776,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
3776 .commit_done = nfs4_commit_done, 3785 .commit_done = nfs4_commit_done,
3777 .lock = nfs4_proc_lock, 3786 .lock = nfs4_proc_lock,
3778 .clear_acl_cache = nfs4_zap_acl_attr, 3787 .clear_acl_cache = nfs4_zap_acl_attr,
3788 .close_context = nfs4_close_context,
3779}; 3789};
3780 3790
3781/* 3791/*
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 193465210d7c..7be72d90d49d 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
663 .commit_setup = nfs_proc_commit_setup, 663 .commit_setup = nfs_proc_commit_setup,
664 .lock = nfs_proc_lock, 664 .lock = nfs_proc_lock,
665 .lock_check_bounds = nfs_lock_check_bounds, 665 .lock_check_bounds = nfs_lock_check_bounds,
666 .close_context = nfs_close_context,
666}; 667};