summaryrefslogtreecommitdiffstats
path: root/fs/afs/dir.c
diff options
context:
space:
mode:
authorDavid Howells2018-04-06 15:17:24 +0200
committerDavid Howells2018-04-09 22:53:59 +0200
commita4ff7401fbfa06fba3aac14db5b33c5b76298f2c (patch)
tree177712d205bb839152135e6bbeda92f23e4f0c85 /fs/afs/dir.c
parentafs: Rearrange status mapping (diff)
downloadkernel-qcow2-linux-a4ff7401fbfa06fba3aac14db5b33c5b76298f2c.tar.gz
kernel-qcow2-linux-a4ff7401fbfa06fba3aac14db5b33c5b76298f2c.tar.xz
kernel-qcow2-linux-a4ff7401fbfa06fba3aac14db5b33c5b76298f2c.zip
afs: Keep track of invalid-before version for dentry coherency
Each afs dentry is tagged with the version that the parent directory was at last time it was validated and, currently, if this differs, the directory is scanned and the dentry is refreshed. However, this leads to an excessive amount of revalidation on directories that get modified on the client without conflict with another client. We know there's no conflict because the parent directory's data version number got incremented by exactly 1 on any create, mkdir, unlink, etc., therefore we can trust the current state of the unaffected dentries when we perform a local directory modification. Optimise by keeping track of the last version of the parent directory that was changed outside of the client in the parent directory's vnode and using that to validate the dentries rather than the current version. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/dir.c')
-rw-r--r--fs/afs/dir.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 538ca18efe0d..08b499504f63 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1015,7 +1015,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
struct dentry *parent;
struct inode *inode;
struct key *key;
- void *dir_version;
+ long dir_version, de_version;
int ret;
if (flags & LOOKUP_RCU)
@@ -1059,9 +1059,19 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
goto out_bad_parent;
}
- dir_version = (void *) (unsigned long) dir->status.data_version;
- if (dentry->d_fsdata == dir_version)
- goto out_valid; /* the dir contents are unchanged */
+ /* We only need to invalidate a dentry if the server's copy changed
+ * behind our back. If we made the change, it's no problem. Note that
+ * on a 32-bit system, we only have 32 bits in the dentry to store the
+ * version.
+ */
+ dir_version = (long)dir->status.data_version;
+ de_version = (long)dentry->d_fsdata;
+ if (de_version == dir_version)
+ goto out_valid;
+
+ dir_version = (long)dir->invalid_before;
+ if (de_version - dir_version >= 0)
+ goto out_valid;
_debug("dir modified");
afs_stat_v(dir, n_reval);
@@ -1120,7 +1130,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
}
out_valid:
- dentry->d_fsdata = dir_version;
+ dentry->d_fsdata = (void *)dir_version;
dput(parent);
key_put(key);
_leave(" = 1 [valid]");