diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 13:16:30 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 16:07:37 -0400 |
| commit | fe51beecc55d0b0dce289e4758e7c529a642f63e (patch) | |
| tree | 9790d77fafbb52b9237ecd65c57002e87f914e12 | |
| parent | 7d52e86274e09fce8ac8f963e3605a84d0a305a7 (diff) | |
[PATCH] NFS: Ensure that fstat() always returns the correct mtime
Even if the file is open for writes.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/nfs/file.c | 28 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 24 | ||||
| -rw-r--r-- | include/linux/nfs_fs.h | 1 |
3 files changed, 39 insertions, 14 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 40436857ed42..5621ba9885f4 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -128,6 +128,21 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | /** | 130 | /** |
| 131 | * nfs_revalidate_file - Revalidate the page cache & related metadata | ||
| 132 | * @inode - pointer to inode struct | ||
| 133 | * @file - pointer to file | ||
| 134 | */ | ||
| 135 | static int nfs_revalidate_file(struct inode *inode, struct file *filp) | ||
| 136 | { | ||
| 137 | int retval = 0; | ||
| 138 | |||
| 139 | if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) | ||
| 140 | retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
| 141 | nfs_revalidate_mapping(inode, filp->f_mapping); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 131 | * nfs_revalidate_size - Revalidate the file size | 146 | * nfs_revalidate_size - Revalidate the file size |
| 132 | * @inode - pointer to inode struct | 147 | * @inode - pointer to inode struct |
| 133 | * @file - pointer to struct file | 148 | * @file - pointer to struct file |
| @@ -149,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
| 149 | goto force_reval; | 164 | goto force_reval; |
| 150 | if (nfsi->npages != 0) | 165 | if (nfsi->npages != 0) |
| 151 | return 0; | 166 | return 0; |
| 152 | return nfs_revalidate_inode(server, inode); | 167 | if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) |
| 168 | return 0; | ||
| 153 | force_reval: | 169 | force_reval: |
| 154 | return __nfs_revalidate_inode(server, inode); | 170 | return __nfs_revalidate_inode(server, inode); |
| 155 | } | 171 | } |
| @@ -210,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) | |||
| 210 | dentry->d_parent->d_name.name, dentry->d_name.name, | 226 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 211 | (unsigned long) count, (unsigned long) pos); | 227 | (unsigned long) count, (unsigned long) pos); |
| 212 | 228 | ||
| 213 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 229 | result = nfs_revalidate_file(inode, iocb->ki_filp); |
| 214 | if (!result) | 230 | if (!result) |
| 215 | result = generic_file_aio_read(iocb, buf, count, pos); | 231 | result = generic_file_aio_read(iocb, buf, count, pos); |
| 216 | return result; | 232 | return result; |
| @@ -228,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, | |||
| 228 | dentry->d_parent->d_name.name, dentry->d_name.name, | 244 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 229 | (unsigned long) count, (unsigned long long) *ppos); | 245 | (unsigned long) count, (unsigned long long) *ppos); |
| 230 | 246 | ||
| 231 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 247 | res = nfs_revalidate_file(inode, filp); |
| 232 | if (!res) | 248 | if (!res) |
| 233 | res = generic_file_sendfile(filp, ppos, count, actor, target); | 249 | res = generic_file_sendfile(filp, ppos, count, actor, target); |
| 234 | return res; | 250 | return res; |
| @@ -244,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
| 244 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", | 260 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", |
| 245 | dentry->d_parent->d_name.name, dentry->d_name.name); | 261 | dentry->d_parent->d_name.name, dentry->d_name.name); |
| 246 | 262 | ||
| 247 | status = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 263 | status = nfs_revalidate_file(inode, file); |
| 248 | if (!status) | 264 | if (!status) |
| 249 | status = generic_file_mmap(file, vma); | 265 | status = generic_file_mmap(file, vma); |
| 250 | return status; | 266 | return status; |
| @@ -340,8 +356,8 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t | |||
| 340 | result = nfs_revalidate_file_size(inode, iocb->ki_filp); | 356 | result = nfs_revalidate_file_size(inode, iocb->ki_filp); |
| 341 | if (result) | 357 | if (result) |
| 342 | goto out; | 358 | goto out; |
| 343 | } else | 359 | } |
| 344 | nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | 360 | nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); |
| 345 | 361 | ||
| 346 | result = count; | 362 | result = count; |
| 347 | if (!count) | 363 | if (!count) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a3922f4cc0a8..4f545f382ba6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -620,9 +620,9 @@ nfs_zap_caches(struct inode *inode) | |||
| 620 | 620 | ||
| 621 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | 621 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); |
| 622 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 622 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) |
| 623 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 623 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
| 624 | else | 624 | else |
| 625 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 625 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | static void nfs_zap_acl_cache(struct inode *inode) | 628 | static void nfs_zap_acl_cache(struct inode *inode) |
| @@ -1055,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 1055 | goto out; | 1055 | goto out; |
| 1056 | } | 1056 | } |
| 1057 | flags = nfsi->flags; | 1057 | flags = nfsi->flags; |
| 1058 | nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; | ||
| 1058 | /* | 1059 | /* |
| 1059 | * We may need to keep the attributes marked as invalid if | 1060 | * We may need to keep the attributes marked as invalid if |
| 1060 | * we raced with nfs_end_attr_update(). | 1061 | * we raced with nfs_end_attr_update(). |
| @@ -1187,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1187 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | 1188 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 |
| 1188 | && nfsi->change_attr == fattr->pre_change_attr) | 1189 | && nfsi->change_attr == fattr->pre_change_attr) |
| 1189 | nfsi->change_attr = fattr->change_attr; | 1190 | nfsi->change_attr = fattr->change_attr; |
| 1190 | if (!data_unstable && nfsi->change_attr != fattr->change_attr) | 1191 | if (nfsi->change_attr != fattr->change_attr) { |
| 1191 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1192 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
| 1193 | if (!data_unstable) | ||
| 1194 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
| 1195 | } | ||
| 1192 | } | 1196 | } |
| 1193 | 1197 | ||
| 1194 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1198 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
| @@ -1211,12 +1215,16 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1211 | } | 1215 | } |
| 1212 | 1216 | ||
| 1213 | /* Verify a few of the more important attributes */ | 1217 | /* Verify a few of the more important attributes */ |
| 1214 | if (!data_unstable) { | 1218 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
| 1215 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime) | ||
| 1216 | || cur_size != new_isize) | ||
| 1217 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
| 1218 | } else if (new_isize != cur_size && nfsi->npages == 0) | ||
| 1219 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1219 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
| 1220 | if (!data_unstable) | ||
| 1221 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
| 1222 | } | ||
| 1223 | if (cur_size != new_isize) { | ||
| 1224 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
| 1225 | if (nfsi->npages == 0) | ||
| 1226 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
| 1227 | } | ||
| 1220 | 1228 | ||
| 1221 | /* Have any file permissions changed? */ | 1229 | /* Have any file permissions changed? */ |
| 1222 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1230 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 443103c13e53..2954e44ed498 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -198,6 +198,7 @@ struct nfs_inode { | |||
| 198 | #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ | 198 | #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ |
| 199 | #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ | 199 | #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ |
| 200 | #define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ | 200 | #define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ |
| 201 | #define NFS_INO_REVAL_PAGECACHE 0x1000 /* must revalidate pagecache */ | ||
| 201 | 202 | ||
| 202 | static inline struct nfs_inode *NFS_I(struct inode *inode) | 203 | static inline struct nfs_inode *NFS_I(struct inode *inode) |
| 203 | { | 204 | { |
