]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/inode.c
NFS: Convert __nfs_revalidate_inode() to use nfs_refresh_inode()
[mv-sheeva.git] / fs / nfs / inode.c
index df23f987da6beeb006496ece538f20765599acb7..697157c1fdd1d04077555ff506c9176f98f41828 100644 (file)
@@ -724,16 +724,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                goto out;
        }
 
-       spin_lock(&inode->i_lock);
-       status = nfs_update_inode(inode, &fattr);
+       status = nfs_refresh_inode(inode, &fattr);
        if (status) {
-               spin_unlock(&inode->i_lock);
                dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
                         inode->i_sb->s_id,
                         (long long)NFS_FILEID(inode), status);
                goto out;
        }
-       spin_unlock(&inode->i_lock);
 
        if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
                nfs_zap_acl_cache(inode);
@@ -948,6 +945,53 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        return 0;
 }
 
+static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
+{
+       return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
+}
+
+static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
+{
+       return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
+}
+
+/**
+ * nfs_inode_attrs_need_update - check if the inode attributes need updating
+ * @inode - pointer to inode
+ * @fattr - attributes
+ *
+ * Attempt to divine whether or not an RPC call reply carrying stale
+ * attributes got scheduled after another call carrying updated ones.
+ *
+ * To do so, the function first assumes that a more recent ctime means
+ * that the attributes in fattr are newer, however it also attempt to
+ * catch the case where ctime either didn't change, or went backwards
+ * (if someone reset the clock on the server) by looking at whether
+ * or not this RPC call was started after the inode was last updated.
+ * Note also the check for jiffy wraparound if the last_updated timestamp
+ * is later than 'jiffies'.
+ *
+ * The function returns 'true' if it thinks the attributes in 'fattr' are
+ * more recent than the ones cached in the inode.
+ *
+ */
+static int nfs_inode_attrs_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
+{
+       const struct nfs_inode *nfsi = NFS_I(inode);
+
+       return nfs_ctime_need_update(inode, fattr) ||
+                       nfs_size_need_update(inode, fattr) ||
+                       time_after(fattr->time_start, nfsi->last_updated) ||
+                       time_after(nfsi->last_updated, jiffies);
+}
+
+static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+{
+       if (nfs_inode_attrs_need_update(inode, fattr))
+               return nfs_update_inode(inode, fattr);
+       return nfs_check_inode_attributes(inode, fattr);
+}
+
 /**
  * nfs_refresh_inode - try to update the inode attribute cache
  * @inode - pointer to inode
@@ -960,21 +1004,28 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
  */
 int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
-       struct nfs_inode *nfsi = NFS_I(inode);
        int status;
 
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
                return 0;
        spin_lock(&inode->i_lock);
-       if (time_after(fattr->time_start, nfsi->last_updated))
-               status = nfs_update_inode(inode, fattr);
-       else
-               status = nfs_check_inode_attributes(inode, fattr);
-
+       status = nfs_refresh_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
        return status;
 }
 
+static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
+       if (S_ISDIR(inode->i_mode))
+               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+               return 0;
+       return nfs_refresh_inode_locked(inode, fattr);
+}
+
 /**
  * nfs_post_op_update_inode - try to update the inode attribute cache
  * @inode - pointer to inode
@@ -991,14 +1042,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
  */
 int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
-       struct nfs_inode *nfsi = NFS_I(inode);
+       int status;
 
        spin_lock(&inode->i_lock);
-       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
-       if (S_ISDIR(inode->i_mode))
-               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+       status = nfs_post_op_update_inode_locked(inode, fattr);
        spin_unlock(&inode->i_lock);
-       return nfs_refresh_inode(inode, fattr);
+       return status;
 }
 
 /**
@@ -1014,6 +1063,15 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  */
 int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
 {
+       int status;
+
+       spin_lock(&inode->i_lock);
+       /* Don't do a WCC update if these attributes are already stale */
+       if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
+                       !nfs_inode_attrs_need_update(inode, fattr)) {
+               fattr->valid &= ~(NFS_ATTR_WCC_V4|NFS_ATTR_WCC);
+               goto out_noforce;
+       }
        if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
                        (fattr->valid & NFS_ATTR_WCC_V4) == 0) {
                fattr->pre_change_attr = NFS_I(inode)->change_attr;
@@ -1026,7 +1084,10 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
                fattr->pre_size = i_size_read(inode);
                fattr->valid |= NFS_ATTR_WCC;
        }
-       return nfs_post_op_update_inode(inode, fattr);
+out_noforce:
+       status = nfs_post_op_update_inode_locked(inode, fattr);
+       spin_unlock(&inode->i_lock);
+       return status;
 }
 
 /*
@@ -1242,7 +1303,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
 #endif
 }
 
-static void init_once(struct kmem_cache * cachep, void *foo)
+static void init_once(void *foo)
 {
        struct nfs_inode *nfsi = (struct nfs_inode *) foo;