summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-12-04 18:34:34 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-12-04 18:34:34 -0500
commit1cd9cb05f96e526f41bb4704caa95dc40ed08c5d (patch)
treebce7b634a76c12c695f4b69551709ec5c155f393
parent9310b224f2ecc8bb075b86d753a2f359e3e1ac85 (diff)
NFS: Only look at the change attribute cache state in nfs_check_verifier
When looking at whether or not our dcache is valid, we really don't care about the general state of the directory attribute cache. Instead, we we only care about the state of the change attribute. This fixes a performance issue when the client is responsible for changing the directory contents; a number of NFSv4 operations will atomically update the directory change attribute, but may not return all the other attributes. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/dir.c14
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--include/linux/nfs_fs.h1
3 files changed, 8 insertions, 9 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f5702457c052..7483722162fa 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1030,8 +1030,6 @@ EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate);
static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
int rcu_walk)
{
- int ret;
-
if (IS_ROOT(dentry))
return 1;
if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
@@ -1039,12 +1037,12 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
if (!nfs_verify_change_attribute(dir, dentry->d_time))
return 0;
/* Revalidate nfsi->cache_change_attribute before we declare a match */
- if (rcu_walk)
- ret = nfs_revalidate_inode_rcu(NFS_SERVER(dir), dir);
- else
- ret = nfs_revalidate_inode(NFS_SERVER(dir), dir);
- if (ret < 0)
- return 0;
+ if (nfs_mapping_need_revalidate_inode(dir)) {
+ if (rcu_walk)
+ return 0;
+ if (__nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+ return 0;
+ }
if (!nfs_verify_change_attribute(dir, dentry->d_time))
return 0;
return 1;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index df4d7ec348ed..7de345fd8e1e 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1112,7 +1112,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
return 0;
}
-static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
+bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
unsigned long cache_validity = NFS_I(inode)->cache_validity;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index db1002abc95e..cb631973839a 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -345,6 +345,7 @@ extern int nfs_attribute_cache_expired(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
+extern bool nfs_mapping_need_revalidate_inode(struct inode *inode);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_revalidate_mapping_rcu(struct inode *inode);
extern int nfs_setattr(struct dentry *, struct iattr *);