aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-06 09:17:24 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-09 16:53:59 -0400
commita4ff7401fbfa06fba3aac14db5b33c5b76298f2c (patch)
tree177712d205bb839152135e6bbeda92f23e4f0c85
parentdd9fbcb8e10349fbd640aaa5942455912004f284 (diff)
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>
-rw-r--r--fs/afs/dir.c20
-rw-r--r--fs/afs/fsclient.c1
-rw-r--r--fs/afs/inode.c1
-rw-r--r--fs/afs/internal.h1
4 files changed, 18 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)
1015 struct dentry *parent; 1015 struct dentry *parent;
1016 struct inode *inode; 1016 struct inode *inode;
1017 struct key *key; 1017 struct key *key;
1018 void *dir_version; 1018 long dir_version, de_version;
1019 int ret; 1019 int ret;
1020 1020
1021 if (flags & LOOKUP_RCU) 1021 if (flags & LOOKUP_RCU)
@@ -1059,9 +1059,19 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1059 goto out_bad_parent; 1059 goto out_bad_parent;
1060 } 1060 }
1061 1061
1062 dir_version = (void *) (unsigned long) dir->status.data_version; 1062 /* We only need to invalidate a dentry if the server's copy changed
1063 if (dentry->d_fsdata == dir_version) 1063 * behind our back. If we made the change, it's no problem. Note that
1064 goto out_valid; /* the dir contents are unchanged */ 1064 * on a 32-bit system, we only have 32 bits in the dentry to store the
1065 * version.
1066 */
1067 dir_version = (long)dir->status.data_version;
1068 de_version = (long)dentry->d_fsdata;
1069 if (de_version == dir_version)
1070 goto out_valid;
1071
1072 dir_version = (long)dir->invalid_before;
1073 if (de_version - dir_version >= 0)
1074 goto out_valid;
1065 1075
1066 _debug("dir modified"); 1076 _debug("dir modified");
1067 afs_stat_v(dir, n_reval); 1077 afs_stat_v(dir, n_reval);
@@ -1120,7 +1130,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1120 } 1130 }
1121 1131
1122out_valid: 1132out_valid:
1123 dentry->d_fsdata = dir_version; 1133 dentry->d_fsdata = (void *)dir_version;
1124 dput(parent); 1134 dput(parent);
1125 key_put(key); 1135 key_put(key);
1126 _leave(" = 1 [valid]"); 1136 _leave(" = 1 [valid]");
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index ff87fc6bb27f..f7570d229dcc 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -100,6 +100,7 @@ void afs_update_inode_from_status(struct afs_vnode *vnode,
100 (unsigned long long) status->data_version, 100 (unsigned long long) status->data_version,
101 vnode->fid.vid, vnode->fid.vnode, 101 vnode->fid.vid, vnode->fid.vnode,
102 (unsigned long long) *expected_version); 102 (unsigned long long) *expected_version);
103 vnode->invalid_before = status->data_version;
103 set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); 104 set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
104 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 105 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
105 } 106 }
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 2e32d475ec11..07f450513f3e 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -83,6 +83,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
83 83
84 inode->i_blocks = 0; 84 inode->i_blocks = 0;
85 inode->i_mapping->a_ops = &afs_fs_aops; 85 inode->i_mapping->a_ops = &afs_fs_aops;
86 vnode->invalid_before = vnode->status.data_version;
86 87
87 read_sequnlock_excl(&vnode->cb_lock); 88 read_sequnlock_excl(&vnode->cb_lock);
88 89
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ac3076c2a8e8..adf9b17d328c 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -479,6 +479,7 @@ struct afs_vnode {
479 struct afs_volume *volume; /* volume on which vnode resides */ 479 struct afs_volume *volume; /* volume on which vnode resides */
480 struct afs_fid fid; /* the file identifier for this inode */ 480 struct afs_fid fid; /* the file identifier for this inode */
481 struct afs_file_status status; /* AFS status info for this file */ 481 struct afs_file_status status; /* AFS status info for this file */
482 afs_dataversion_t invalid_before; /* Child dentries are invalid before this */
482#ifdef CONFIG_AFS_FSCACHE 483#ifdef CONFIG_AFS_FSCACHE
483 struct fscache_cookie *cache; /* caching cookie */ 484 struct fscache_cookie *cache; /* caching cookie */
484#endif 485#endif