aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-01-31 08:16:24 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-02-03 18:35:05 -0500
commitc79ba787c11e767ffaf8d723923afda99ba6c63c (patch)
tree746cd4018ab4dd5b28368b8e9a4d4c23c8e5b7b0
parentef75c7974b383769ae5741cf930b8aa4dcaef395 (diff)
NFS: Dont clobber more uptodate values in nfs_set_verifier()
nfs_lookup_revalidate and friends are not serialised, so it is currently quite possible for the dentry to be revalidated, and then have the updated verifier replaced with an older value by another process. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/dir.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 062e108fac50..37c1dd642184 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -637,7 +637,7 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
637 * In the case it has, we assume that the dentries are untrustworthy 637 * In the case it has, we assume that the dentries are untrustworthy
638 * and may need to be looked up again. 638 * and may need to be looked up again.
639 */ 639 */
640static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) 640static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
641{ 641{
642 if (IS_ROOT(dentry)) 642 if (IS_ROOT(dentry))
643 return 1; 643 return 1;
@@ -652,6 +652,12 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
652 dentry->d_fsdata = (void *)verf; 652 dentry->d_fsdata = (void *)verf;
653} 653}
654 654
655static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
656{
657 if (time_after(verf, (unsigned long)dentry->d_fsdata))
658 nfs_set_verifier(dentry, verf);
659}
660
655/* 661/*
656 * Whenever an NFS operation succeeds, we know that the dentry 662 * Whenever an NFS operation succeeds, we know that the dentry
657 * is valid, so we update the revalidation timestamp. 663 * is valid, so we update the revalidation timestamp.
@@ -785,7 +791,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
785 goto out_bad; 791 goto out_bad;
786 792
787 nfs_renew_times(dentry); 793 nfs_renew_times(dentry);
788 nfs_set_verifier(dentry, verifier); 794 nfs_refresh_verifier(dentry, verifier);
789 out_valid: 795 out_valid:
790 unlock_kernel(); 796 unlock_kernel();
791 dput(parent); 797 dput(parent);
@@ -1085,7 +1091,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
1085 verifier = nfs_save_change_attribute(dir); 1091 verifier = nfs_save_change_attribute(dir);
1086 ret = nfs4_open_revalidate(dir, dentry, openflags, nd); 1092 ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
1087 if (!ret) 1093 if (!ret)
1088 nfs_set_verifier(dentry, verifier); 1094 nfs_refresh_verifier(dentry, verifier);
1089 unlock_kernel(); 1095 unlock_kernel();
1090out: 1096out:
1091 dput(parent); 1097 dput(parent);
@@ -1159,10 +1165,13 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
1159 dentry = alias; 1165 dentry = alias;
1160 } 1166 }
1161 1167
1162out_renew:
1163 nfs_renew_times(dentry); 1168 nfs_renew_times(dentry);
1164 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1169 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1165 return dentry; 1170 return dentry;
1171out_renew:
1172 nfs_renew_times(dentry);
1173 nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir));
1174 return dentry;
1166} 1175}
1167 1176
1168/* 1177/*
@@ -1700,7 +1709,7 @@ out:
1700 if (!error) { 1709 if (!error) {
1701 d_move(old_dentry, new_dentry); 1710 d_move(old_dentry, new_dentry);
1702 nfs_renew_times(new_dentry); 1711 nfs_renew_times(new_dentry);
1703 nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); 1712 nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir));
1704 } 1713 }
1705 1714
1706 /* new dentry created? */ 1715 /* new dentry created? */