Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+39 -14
+22 -6
fs/nfs/file.c
··· 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 146 * nfs_revalidate_size - Revalidate the file size 132 147 * @inode - pointer to inode struct 133 148 * @file - pointer to struct file ··· 164 149 goto force_reval; 165 150 if (nfsi->npages != 0) 166 151 return 0; 167 - return nfs_revalidate_inode(server, inode); 152 + if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) 153 + return 0; 168 154 force_reval: 169 155 return __nfs_revalidate_inode(server, inode); 170 156 } ··· 226 210 dentry->d_parent->d_name.name, dentry->d_name.name, 227 211 (unsigned long) count, (unsigned long) pos); 228 212 229 - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); 213 + result = nfs_revalidate_file(inode, iocb->ki_filp); 230 214 if (!result) 231 215 result = generic_file_aio_read(iocb, buf, count, pos); 232 216 return result; ··· 244 228 dentry->d_parent->d_name.name, dentry->d_name.name, 245 229 (unsigned long) count, (unsigned long long) *ppos); 246 230 247 - res = nfs_revalidate_inode(NFS_SERVER(inode), inode); 231 + res = nfs_revalidate_file(inode, filp); 248 232 if (!res) 249 233 res = generic_file_sendfile(filp, ppos, count, actor, target); 250 234 return res; ··· 260 244 dfprintk(VFS, "nfs: mmap(%s/%s)\n", 261 245 dentry->d_parent->d_name.name, dentry->d_name.name); 262 246 263 - status = nfs_revalidate_inode(NFS_SERVER(inode), inode); 247 + status = nfs_revalidate_file(inode, file); 264 248 if (!status) 265 249 status = generic_file_mmap(file, vma); 266 250 return status; ··· 356 340 result = nfs_revalidate_file_size(inode, iocb->ki_filp); 357 341 if (result) 358 342 goto out; 359 - } else 360 - nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); 343 + } 344 + nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); 361 345 362 346 result = count; 363 347 if (!count)
+16 -8
fs/nfs/inode.c
··· 620 620 621 621 memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); 622 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 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 628 static void nfs_zap_acl_cache(struct inode *inode) ··· 1055 1055 goto out; 1056 1056 } 1057 1057 flags = nfsi->flags; 1058 + nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; 1058 1059 /* 1059 1060 * We may need to keep the attributes marked as invalid if 1060 1061 * we raced with nfs_end_attr_update(). ··· 1188 1187 if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 1189 1188 && nfsi->change_attr == fattr->pre_change_attr) 1190 1189 nfsi->change_attr = fattr->change_attr; 1191 - if (!data_unstable && nfsi->change_attr != fattr->change_attr) 1190 + if (nfsi->change_attr != fattr->change_attr) { 1192 1191 nfsi->flags |= NFS_INO_INVALID_ATTR; 1192 + if (!data_unstable) 1193 + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; 1194 + } 1193 1195 } 1194 1196 1195 1197 if ((fattr->valid & NFS_ATTR_FATTR) == 0) ··· 1215 1211 } 1216 1212 1217 1213 /* Verify a few of the more important attributes */ 1218 - if (!data_unstable) { 1219 - if (!timespec_equal(&inode->i_mtime, &fattr->mtime) 1220 - || cur_size != new_isize) 1221 - nfsi->flags |= NFS_INO_INVALID_ATTR; 1222 - } else if (new_isize != cur_size && nfsi->npages == 0) 1214 + if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { 1223 1215 nfsi->flags |= NFS_INO_INVALID_ATTR; 1216 + if (!data_unstable) 1217 + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; 1218 + } 1219 + if (cur_size != new_isize) { 1220 + nfsi->flags |= NFS_INO_INVALID_ATTR; 1221 + if (nfsi->npages == 0) 1222 + nfsi->flags |= NFS_INO_REVAL_PAGECACHE; 1223 + } 1224 1224 1225 1225 /* Have any file permissions changed? */ 1226 1226 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
+1
include/linux/nfs_fs.h
··· 198 198 #define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ 199 199 #define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ 200 200 #define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ 201 + #define NFS_INO_REVAL_PAGECACHE 0x1000 /* must revalidate pagecache */ 201 202 202 203 static inline struct nfs_inode *NFS_I(struct inode *inode) 203 204 {