aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-09-30 15:21:24 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-10-09 17:19:15 -0400
commit70ca88521fc7bee8ef0fc22033a439d4b9a2c70d (patch)
tree8e3943bfac55b59dc127393f8da0ecfc4aba424b
parentb64e8a5ef758888cb42b7c105dcfaaf51aab1baf (diff)
NFS: Fake up 'wcc' attributes to prevent cache invalidation after write
NFSv2 and v4 don't offer weak cache consistency attributes on WRITE calls. In NFSv3, returning wcc data is optional. In all cases, we want to prevent the client from invalidating our cached data whenever ->write_done() attempts to update the inode attributes. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/inode.c34
-rw-r--r--fs/nfs/nfs3proc.c2
-rw-r--r--fs/nfs/nfs4proc.c2
-rw-r--r--fs/nfs/proc.c2
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_xdr.h3
6 files changed, 40 insertions, 4 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 23feb9e3d8b0..c5f4e0567533 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -793,6 +793,12 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
793{ 793{
794 struct nfs_inode *nfsi = NFS_I(inode); 794 struct nfs_inode *nfsi = NFS_I(inode);
795 795
796 if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
797 nfsi->change_attr == fattr->pre_change_attr) {
798 nfsi->change_attr = fattr->change_attr;
799 if (S_ISDIR(inode->i_mode))
800 nfsi->cache_validity |= NFS_INO_INVALID_DATA;
801 }
796 /* If we have atomic WCC data, we may update some attributes */ 802 /* If we have atomic WCC data, we may update some attributes */
797 if ((fattr->valid & NFS_ATTR_WCC) != 0) { 803 if ((fattr->valid & NFS_ATTR_WCC) != 0) {
798 if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) 804 if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
@@ -923,6 +929,34 @@ out:
923 return status; 929 return status;
924} 930}
925 931
932/**
933 * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
934 * @inode - pointer to inode
935 * @fattr - updated attributes
936 *
937 * After an operation that has changed the inode metadata, mark the
938 * attribute cache as being invalid, then try to update it. Fake up
939 * weak cache consistency data, if none exist.
940 *
941 * This function is mainly designed to be used by the ->write_done() functions.
942 */
943int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
944{
945 if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
946 (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
947 fattr->pre_change_attr = NFS_I(inode)->change_attr;
948 fattr->valid |= NFS_ATTR_WCC_V4;
949 }
950 if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
951 (fattr->valid & NFS_ATTR_WCC) == 0) {
952 memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
953 memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
954 fattr->pre_size = inode->i_size;
955 fattr->valid |= NFS_ATTR_WCC;
956 }
957 return nfs_post_op_update_inode(inode, fattr);
958}
959
926/* 960/*
927 * Many nfs protocol calls return the new file attributes after 961 * Many nfs protocol calls return the new file attributes after
928 * an operation. Here we update the inode to reflect the state 962 * an operation. Here we update the inode to reflect the state
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index fc6b1193a631..ce1fb99e67e1 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -750,7 +750,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
750 if (nfs3_async_handle_jukebox(task, data->inode)) 750 if (nfs3_async_handle_jukebox(task, data->inode))
751 return -EAGAIN; 751 return -EAGAIN;
752 if (task->tk_status >= 0) 752 if (task->tk_status >= 0)
753 nfs_post_op_update_inode(data->inode, data->res.fattr); 753 nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
754 return 0; 754 return 0;
755} 755}
756 756
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d311984d2c88..796bc8ea7194 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2427,7 +2427,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
2427 } 2427 }
2428 if (task->tk_status >= 0) { 2428 if (task->tk_status >= 0) {
2429 renew_lease(NFS_SERVER(inode), data->timestamp); 2429 renew_lease(NFS_SERVER(inode), data->timestamp);
2430 nfs_post_op_update_inode(inode, data->res.fattr); 2430 nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
2431 } 2431 }
2432 return 0; 2432 return 0;
2433} 2433}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index ec3ede890bf4..97669ed05500 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -579,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
579static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) 579static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
580{ 580{
581 if (task->tk_status >= 0) 581 if (task->tk_status >= 0)
582 nfs_post_op_update_inode(data->inode, data->res.fattr); 582 nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
583 return 0; 583 return 0;
584} 584}
585 585
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 63850a884902..9449286c5867 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -293,6 +293,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
293 struct nfs_fattr *); 293 struct nfs_fattr *);
294extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); 294extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
295extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); 295extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
296extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
296extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 297extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
297extern int nfs_permission(struct inode *, int, struct nameidata *); 298extern int nfs_permission(struct inode *, int, struct nameidata *);
298extern int nfs_open(struct inode *, struct file *); 299extern int nfs_open(struct inode *, struct file *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 03032017ffaa..daab252f2e5c 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -62,7 +62,8 @@ struct nfs_fattr {
62#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */ 62#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
63#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */ 63#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
64#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */ 64#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
65#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */ 65#define NFS_ATTR_WCC_V4 0x0010 /* pre-op change attribute */
66#define NFS_ATTR_FATTR_V4_REFERRAL 0x0020 /* NFSv4 referral */
66 67
67/* 68/*
68 * Info on the file system 69 * Info on the file system