]> err.no Git - linux-2.6/commitdiff
NFS: Fake up 'wcc' attributes to prevent cache invalidation after write
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sun, 30 Sep 2007 19:21:24 +0000 (15:21 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 9 Oct 2007 21:19:15 +0000 (17:19 -0400)
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>
fs/nfs/inode.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/proc.c
include/linux/nfs_fs.h
include/linux/nfs_xdr.h

index 23feb9e3d8b00af9ff715021bf2f8ed5b0ff0c50..c5f4e0567533aa648348d73840fb094e6b4242c3 100644 (file)
@@ -793,6 +793,12 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
+       if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
+                       nfsi->change_attr == fattr->pre_change_attr) {
+               nfsi->change_attr = fattr->change_attr;
+               if (S_ISDIR(inode->i_mode))
+                       nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+       }
        /* If we have atomic WCC data, we may update some attributes */
        if ((fattr->valid & NFS_ATTR_WCC) != 0) {
                if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
@@ -923,6 +929,34 @@ out:
        return status;
 }
 
+/**
+ * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
+ * @inode - pointer to inode
+ * @fattr - updated attributes
+ *
+ * After an operation that has changed the inode metadata, mark the
+ * attribute cache as being invalid, then try to update it. Fake up
+ * weak cache consistency data, if none exist.
+ *
+ * This function is mainly designed to be used by the ->write_done() functions.
+ */
+int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
+{
+       if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+                       (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
+               fattr->pre_change_attr = NFS_I(inode)->change_attr;
+               fattr->valid |= NFS_ATTR_WCC_V4;
+       }
+       if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
+                       (fattr->valid & NFS_ATTR_WCC) == 0) {
+               memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+               memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+               fattr->pre_size = inode->i_size;
+               fattr->valid |= NFS_ATTR_WCC;
+       }
+       return nfs_post_op_update_inode(inode, fattr);
+}
+
 /*
  * Many nfs protocol calls return the new file attributes after
  * an operation.  Here we update the inode to reflect the state
index fc6b1193a6311a32a6889daa95dd11e7d618af26..ce1fb99e67e16a01f683d794d209d236c78d994a 100644 (file)
@@ -750,7 +750,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
        if (nfs3_async_handle_jukebox(task, data->inode))
                return -EAGAIN;
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode(data->inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
        return 0;
 }
 
index d311984d2c8890c46e603b1ff1c6ebe621eba6d3..796bc8ea7194c298e1b631e2ca1d47369f628bd1 100644 (file)
@@ -2427,7 +2427,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
        }
        if (task->tk_status >= 0) {
                renew_lease(NFS_SERVER(inode), data->timestamp);
-               nfs_post_op_update_inode(inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
        }
        return 0;
 }
index ec3ede890bf4af3d0473e32ce18cf43b13717831..97669ed05500c6277387f1b0323d53b6face4950 100644 (file)
@@ -579,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
 static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (task->tk_status >= 0)
-               nfs_post_op_update_inode(data->inode, data->res.fattr);
+               nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
        return 0;
 }
 
index 63850a8849022ef95b90ca28972f5b1a8ae957db..9449286c58674b7ca74f21306d7720a25a2d02af 100644 (file)
@@ -293,6 +293,7 @@ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
                                struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
+extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
 extern int nfs_open(struct inode *, struct file *);
index 03032017ffaa9979691e996b60fe21eeccbcad95..daab252f2e5cf653e41bb39721596bfc7aa89315 100644 (file)
@@ -62,7 +62,8 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR         0x0002          /* post-op attributes */
 #define NFS_ATTR_FATTR_V3      0x0004          /* NFSv3 attributes */
 #define NFS_ATTR_FATTR_V4      0x0008          /* NFSv4 change attribute */
-#define NFS_ATTR_FATTR_V4_REFERRAL     0x0010          /* NFSv4 referral */
+#define NFS_ATTR_WCC_V4                0x0010          /* pre-op change attribute */
+#define NFS_ATTR_FATTR_V4_REFERRAL     0x0020          /* NFSv4 referral */
 
 /*
  * Info on the file system