diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-10-14 19:16:07 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-10-14 19:23:17 -0400 |
commit | 4704f0e274829e3af00737d2d9adace2d71a9605 (patch) | |
tree | 048404f927dc210f1d7c695cb39e28e4e7d49030 /fs/nfs/inode.c | |
parent | 921615f111108258820226a3258a047d9bf1d96a (diff) |
NFS: Fix the resolution problem with nfs_inode_attrs_need_update()
It appears that 'jiffies' timestamps do not have high enough resolution for
nfs_inode_attrs_need_update(). One problem is that a GETATTR can be
launched within < 1 jiffy of the last operation that updated the attribute.
Another problem is that RPC calls can take < 1 jiffy to execute.
We can fix this by switching the variables to use a simple global counter
that gets incremented every time we start another GETATTR call.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index de3f11e6234e..116a3bd2bc9b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -305,7 +305,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
305 | init_special_inode(inode, inode->i_mode, fattr->rdev); | 305 | init_special_inode(inode, inode->i_mode, fattr->rdev); |
306 | 306 | ||
307 | nfsi->read_cache_jiffies = fattr->time_start; | 307 | nfsi->read_cache_jiffies = fattr->time_start; |
308 | nfsi->last_updated = now; | 308 | nfsi->attr_gencount = fattr->gencount; |
309 | nfsi->cache_change_attribute = now; | 309 | nfsi->cache_change_attribute = now; |
310 | inode->i_atime = fattr->atime; | 310 | inode->i_atime = fattr->atime; |
311 | inode->i_mtime = fattr->mtime; | 311 | inode->i_mtime = fattr->mtime; |
@@ -909,6 +909,30 @@ static int nfs_size_need_update(const struct inode *inode, const struct nfs_fatt | |||
909 | return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); | 909 | return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); |
910 | } | 910 | } |
911 | 911 | ||
912 | static unsigned long nfs_attr_generation_counter; | ||
913 | |||
914 | static unsigned long nfs_read_attr_generation_counter(void) | ||
915 | { | ||
916 | smp_rmb(); | ||
917 | return nfs_attr_generation_counter; | ||
918 | } | ||
919 | |||
920 | unsigned long nfs_inc_attr_generation_counter(void) | ||
921 | { | ||
922 | unsigned long ret; | ||
923 | smp_rmb(); | ||
924 | ret = ++nfs_attr_generation_counter; | ||
925 | smp_wmb(); | ||
926 | return ret; | ||
927 | } | ||
928 | |||
929 | void nfs_fattr_init(struct nfs_fattr *fattr) | ||
930 | { | ||
931 | fattr->valid = 0; | ||
932 | fattr->time_start = jiffies; | ||
933 | fattr->gencount = nfs_inc_attr_generation_counter(); | ||
934 | } | ||
935 | |||
912 | /** | 936 | /** |
913 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | 937 | * nfs_inode_attrs_need_update - check if the inode attributes need updating |
914 | * @inode - pointer to inode | 938 | * @inode - pointer to inode |
@@ -922,8 +946,7 @@ static int nfs_size_need_update(const struct inode *inode, const struct nfs_fatt | |||
922 | * catch the case where ctime either didn't change, or went backwards | 946 | * catch the case where ctime either didn't change, or went backwards |
923 | * (if someone reset the clock on the server) by looking at whether | 947 | * (if someone reset the clock on the server) by looking at whether |
924 | * or not this RPC call was started after the inode was last updated. | 948 | * or not this RPC call was started after the inode was last updated. |
925 | * Note also the check for jiffy wraparound if the last_updated timestamp | 949 | * Note also the check for wraparound of 'attr_gencount' |
926 | * is later than 'jiffies'. | ||
927 | * | 950 | * |
928 | * The function returns 'true' if it thinks the attributes in 'fattr' are | 951 | * The function returns 'true' if it thinks the attributes in 'fattr' are |
929 | * more recent than the ones cached in the inode. | 952 | * more recent than the ones cached in the inode. |
@@ -933,10 +956,10 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n | |||
933 | { | 956 | { |
934 | const struct nfs_inode *nfsi = NFS_I(inode); | 957 | const struct nfs_inode *nfsi = NFS_I(inode); |
935 | 958 | ||
936 | return time_after(fattr->time_start, nfsi->last_updated) || | 959 | return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 || |
937 | nfs_ctime_need_update(inode, fattr) || | 960 | nfs_ctime_need_update(inode, fattr) || |
938 | nfs_size_need_update(inode, fattr) || | 961 | nfs_size_need_update(inode, fattr) || |
939 | time_after(nfsi->last_updated, jiffies); | 962 | ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); |
940 | } | 963 | } |
941 | 964 | ||
942 | static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) | 965 | static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) |
@@ -1107,7 +1130,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1107 | } | 1130 | } |
1108 | /* If ctime has changed we should definitely clear access+acl caches */ | 1131 | /* If ctime has changed we should definitely clear access+acl caches */ |
1109 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) | 1132 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) |
1110 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1133 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1111 | } else if (nfsi->change_attr != fattr->change_attr) { | 1134 | } else if (nfsi->change_attr != fattr->change_attr) { |
1112 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | 1135 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
1113 | inode->i_sb->s_id, inode->i_ino); | 1136 | inode->i_sb->s_id, inode->i_ino); |
@@ -1163,7 +1186,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1163 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | 1186 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); |
1164 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1187 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1165 | nfsi->attrtimeo_timestamp = now; | 1188 | nfsi->attrtimeo_timestamp = now; |
1166 | nfsi->last_updated = now; | 1189 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); |
1167 | } else { | 1190 | } else { |
1168 | if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { | 1191 | if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { |
1169 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) | 1192 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) |