diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/inode.c | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f189169348b1..8c514a1353c0 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -948,11 +948,49 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
948 | return 0; | 948 | return 0; |
949 | } | 949 | } |
950 | 950 | ||
951 | static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) | 951 | static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr) |
952 | { | 952 | { |
953 | struct nfs_inode *nfsi = NFS_I(inode); | 953 | return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0; |
954 | } | ||
955 | |||
956 | static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr) | ||
957 | { | ||
958 | return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); | ||
959 | } | ||
954 | 960 | ||
955 | if (time_after(fattr->time_start, nfsi->last_updated)) | 961 | /** |
962 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | ||
963 | * @inode - pointer to inode | ||
964 | * @fattr - attributes | ||
965 | * | ||
966 | * Attempt to divine whether or not an RPC call reply carrying stale | ||
967 | * attributes got scheduled after another call carrying updated ones. | ||
968 | * | ||
969 | * To do so, the function first assumes that a more recent ctime means | ||
970 | * that the attributes in fattr are newer, however it also attempt to | ||
971 | * catch the case where ctime either didn't change, or went backwards | ||
972 | * (if someone reset the clock on the server) by looking at whether | ||
973 | * or not this RPC call was started after the inode was last updated. | ||
974 | * Note also the check for jiffy wraparound if the last_updated timestamp | ||
975 | * is later than 'jiffies'. | ||
976 | * | ||
977 | * The function returns 'true' if it thinks the attributes in 'fattr' are | ||
978 | * more recent than the ones cached in the inode. | ||
979 | * | ||
980 | */ | ||
981 | static int nfs_inode_attrs_need_update(const struct inode *inode, const struct nfs_fattr *fattr) | ||
982 | { | ||
983 | const struct nfs_inode *nfsi = NFS_I(inode); | ||
984 | |||
985 | return nfs_ctime_need_update(inode, fattr) || | ||
986 | nfs_size_need_update(inode, fattr) || | ||
987 | time_after(fattr->time_start, nfsi->last_updated) || | ||
988 | time_after(nfsi->last_updated, jiffies); | ||
989 | } | ||
990 | |||
991 | static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) | ||
992 | { | ||
993 | if (nfs_inode_attrs_need_update(inode, fattr)) | ||
956 | return nfs_update_inode(inode, fattr); | 994 | return nfs_update_inode(inode, fattr); |
957 | return nfs_check_inode_attributes(inode, fattr); | 995 | return nfs_check_inode_attributes(inode, fattr); |
958 | } | 996 | } |