aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-07-13 21:28:20 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-08-03 17:14:12 -0400
commit912a108da767ae75cc929d2854e698aff527ec5d (patch)
tree7ae1fda9f3512f9fabd1cc6d2467b4a9c416d745 /fs/nfs
parentf3324a2a94c229831cfd42d871902cd4a9bd5e0f (diff)
NFS: teach nfs_neg_need_reval to understand LOOKUP_RCU
This requires nfs_check_verifier to take an rcu_walk flag, and requires an rcu version of nfs_revalidate_inode which returns -ECHILD rather than making an RPC call. With this, nfs_lookup_revalidate can call nfs_neg_need_reval in RCU-walk mode. We can also move the LOOKUP_RCU check past the nfs_check_verifier() call in nfs_lookup_revalidate. If RCU_WALK prevents nfs_check_verifier or nfs_neg_need_reval from doing a full check, they return a status indicating that a revalidation is required. As this revalidation will not be possible in RCU_WALK mode, -ECHILD will ultimately be returned, which is the desired result. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c59
-rw-r--r--fs/nfs/inode.c9
2 files changed, 51 insertions, 17 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 8a3c36984fc4..dcd4fe5831d6 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -988,9 +988,13 @@ EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate);
988 * A check for whether or not the parent directory has changed. 988 * A check for whether or not the parent directory has changed.
989 * In the case it has, we assume that the dentries are untrustworthy 989 * In the case it has, we assume that the dentries are untrustworthy
990 * and may need to be looked up again. 990 * and may need to be looked up again.
991 * If rcu_walk prevents us from performing a full check, return 0.
991 */ 992 */
992static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) 993static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
994 int rcu_walk)
993{ 995{
996 int ret;
997
994 if (IS_ROOT(dentry)) 998 if (IS_ROOT(dentry))
995 return 1; 999 return 1;
996 if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) 1000 if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
@@ -998,7 +1002,11 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
998 if (!nfs_verify_change_attribute(dir, dentry->d_time)) 1002 if (!nfs_verify_change_attribute(dir, dentry->d_time))
999 return 0; 1003 return 0;
1000 /* Revalidate nfsi->cache_change_attribute before we declare a match */ 1004 /* Revalidate nfsi->cache_change_attribute before we declare a match */
1001 if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) 1005 if (rcu_walk)
1006 ret = nfs_revalidate_inode_rcu(NFS_SERVER(dir), dir);
1007 else
1008 ret = nfs_revalidate_inode(NFS_SERVER(dir), dir);
1009 if (ret < 0)
1002 return 0; 1010 return 0;
1003 if (!nfs_verify_change_attribute(dir, dentry->d_time)) 1011 if (!nfs_verify_change_attribute(dir, dentry->d_time))
1004 return 0; 1012 return 0;
@@ -1054,6 +1062,9 @@ out_force:
1054 * 1062 *
1055 * If parent mtime has changed, we revalidate, else we wait for a 1063 * If parent mtime has changed, we revalidate, else we wait for a
1056 * period corresponding to the parent's attribute cache timeout value. 1064 * period corresponding to the parent's attribute cache timeout value.
1065 *
1066 * If LOOKUP_RCU prevents us from performing a full check, return 1
1067 * suggesting a reval is needed.
1057 */ 1068 */
1058static inline 1069static inline
1059int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, 1070int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
@@ -1064,7 +1075,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
1064 return 0; 1075 return 0;
1065 if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) 1076 if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
1066 return 1; 1077 return 1;
1067 return !nfs_check_verifier(dir, dentry); 1078 return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
1068} 1079}
1069 1080
1070/* 1081/*
@@ -1101,11 +1112,11 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1101 inode = dentry->d_inode; 1112 inode = dentry->d_inode;
1102 1113
1103 if (!inode) { 1114 if (!inode) {
1104 if (flags & LOOKUP_RCU) 1115 if (nfs_neg_need_reval(dir, dentry, flags)) {
1105 return -ECHILD; 1116 if (flags & LOOKUP_RCU)
1106 1117 return -ECHILD;
1107 if (nfs_neg_need_reval(dir, dentry, flags))
1108 goto out_bad; 1118 goto out_bad;
1119 }
1109 goto out_valid_noent; 1120 goto out_valid_noent;
1110 } 1121 }
1111 1122
@@ -1120,16 +1131,21 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1120 if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) 1131 if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
1121 goto out_set_verifier; 1132 goto out_set_verifier;
1122 1133
1123 if (flags & LOOKUP_RCU)
1124 return -ECHILD;
1125
1126 /* Force a full look up iff the parent directory has changed */ 1134 /* Force a full look up iff the parent directory has changed */
1127 if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) { 1135 if (!nfs_is_exclusive_create(dir, flags) &&
1136 nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
1137
1138 if (flags & LOOKUP_RCU)
1139 return -ECHILD;
1140
1128 if (nfs_lookup_verify_inode(inode, flags)) 1141 if (nfs_lookup_verify_inode(inode, flags))
1129 goto out_zap_parent; 1142 goto out_zap_parent;
1130 goto out_valid; 1143 goto out_valid;
1131 } 1144 }
1132 1145
1146 if (flags & LOOKUP_RCU)
1147 return -ECHILD;
1148
1133 if (NFS_STALE(inode)) 1149 if (NFS_STALE(inode))
1134 goto out_bad; 1150 goto out_bad;
1135 1151
@@ -1566,14 +1582,23 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1566 struct dentry *parent; 1582 struct dentry *parent;
1567 struct inode *dir; 1583 struct inode *dir;
1568 1584
1569 if (flags & LOOKUP_RCU) 1585 if (flags & LOOKUP_RCU) {
1570 return -ECHILD; 1586 parent = rcu_dereference(dentry);
1571 1587 dir = ACCESS_ONCE(parent->d_inode);
1572 parent = dget_parent(dentry); 1588 if (!dir)
1573 dir = parent->d_inode; 1589 return -ECHILD;
1590 } else {
1591 parent = dget_parent(dentry);
1592 dir = parent->d_inode;
1593 }
1574 if (!nfs_neg_need_reval(dir, dentry, flags)) 1594 if (!nfs_neg_need_reval(dir, dentry, flags))
1575 ret = 1; 1595 ret = 1;
1576 dput(parent); 1596 else if (flags & LOOKUP_RCU)
1597 ret = -ECHILD;
1598 if (!(flags & LOOKUP_RCU))
1599 dput(parent);
1600 else if (parent != rcu_dereference(dentry))
1601 return -ECHILD;
1577 goto out; 1602 goto out;
1578 } 1603 }
1579 1604
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 9927913c97c2..147fd17e7920 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1002,6 +1002,15 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
1002} 1002}
1003EXPORT_SYMBOL_GPL(nfs_revalidate_inode); 1003EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
1004 1004
1005int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode)
1006{
1007 if (!(NFS_I(inode)->cache_validity &
1008 (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
1009 && !nfs_attribute_cache_expired(inode))
1010 return NFS_STALE(inode) ? -ESTALE : 0;
1011 return -ECHILD;
1012}
1013
1005static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) 1014static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
1006{ 1015{
1007 struct nfs_inode *nfsi = NFS_I(inode); 1016 struct nfs_inode *nfsi = NFS_I(inode);