[PATCH] NFS: Ensure that fstat() always returns the correct mtime
Trond Myklebust [Wed, 22 Jun 2005 17:16:30 +0000 (17:16 +0000)]
 Even if the file is open for writes.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

fs/nfs/file.c
fs/nfs/inode.c
include/linux/nfs_fs.h

index 4043685..5621ba9 100644 (file)
@@ -128,6 +128,21 @@ nfs_file_release(struct inode *inode, struct file *filp)
 }
 
 /**
+ * nfs_revalidate_file - Revalidate the page cache & related metadata
+ * @inode - pointer to inode struct
+ * @file - pointer to file
+ */
+static int nfs_revalidate_file(struct inode *inode, struct file *filp)
+{
+       int retval = 0;
+
+       if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode))
+               retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       nfs_revalidate_mapping(inode, filp->f_mapping);
+       return 0;
+}
+
+/**
  * nfs_revalidate_size - Revalidate the file size
  * @inode - pointer to inode struct
  * @file - pointer to struct file
@@ -149,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
                goto force_reval;
        if (nfsi->npages != 0)
                return 0;
-       return nfs_revalidate_inode(server, inode);
+       if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode))
+               return 0;
 force_reval:
        return __nfs_revalidate_inode(server, inode);
 }
@@ -210,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
                dentry->d_parent->d_name.name, dentry->d_name.name,
                (unsigned long) count, (unsigned long) pos);
 
-       result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       result = nfs_revalidate_file(inode, iocb->ki_filp);
        if (!result)
                result = generic_file_aio_read(iocb, buf, count, pos);
        return result;
@@ -228,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
                dentry->d_parent->d_name.name, dentry->d_name.name,
                (unsigned long) count, (unsigned long long) *ppos);
 
-       res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       res = nfs_revalidate_file(inode, filp);
        if (!res)
                res = generic_file_sendfile(filp, ppos, count, actor, target);
        return res;
@@ -244,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
        dfprintk(VFS, "nfs: mmap(%s/%s)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       status = nfs_revalidate_file(inode, file);
        if (!status)
                status = generic_file_mmap(file, vma);
        return status;
@@ -340,8 +356,8 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
                result = nfs_revalidate_file_size(inode, iocb->ki_filp);
                if (result)
                        goto out;
-       } else
-               nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
+       }
+       nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
 
        result = count;
        if (!count)
index a3922f4..4f545f3 100644 (file)
@@ -620,9 +620,9 @@ nfs_zap_caches(struct inode *inode)
 
        memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
        if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
-               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
        else
-               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
 }
 
 static void nfs_zap_acl_cache(struct inode *inode)
@@ -1055,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                goto out;
        }
        flags = nfsi->flags;
+       nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE;
        /*
         * We may need to keep the attributes marked as invalid if
         * we raced with nfs_end_attr_update().
@@ -1187,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
                                && nfsi->change_attr == fattr->pre_change_attr)
                        nfsi->change_attr = fattr->change_attr;
-               if (!data_unstable && nfsi->change_attr != fattr->change_attr)
+               if (nfsi->change_attr != fattr->change_attr) {
                        nfsi->flags |= NFS_INO_INVALID_ATTR;
+                       if (!data_unstable)
+                               nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+               }
        }
 
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
@@ -1211,12 +1215,16 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        }
 
        /* Verify a few of the more important attributes */
-       if (!data_unstable) {
-               if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
-                               || cur_size != new_isize)
-                       nfsi->flags |= NFS_INO_INVALID_ATTR;
-       } else if (new_isize != cur_size && nfsi->npages == 0)
+       if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
                nfsi->flags |= NFS_INO_INVALID_ATTR;
+               if (!data_unstable)
+                       nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+       }
+       if (cur_size != new_isize) {
+               nfsi->flags |= NFS_INO_INVALID_ATTR;
+               if (nfsi->npages == 0)
+                       nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+       }
 
        /* Have any file permissions changed? */
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
index 443103c..2954e44 100644 (file)
@@ -198,6 +198,7 @@ struct nfs_inode {
 #define NFS_INO_INVALID_ATIME  0x0020          /* cached atime is invalid */
 #define NFS_INO_INVALID_ACCESS 0x0040          /* cached access cred invalid */
 #define NFS_INO_INVALID_ACL    0x0080          /* cached acls are invalid */
+#define NFS_INO_REVAL_PAGECACHE        0x1000          /* must revalidate pagecache */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {