aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2010-08-17 14:37:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-18 08:35:45 -0400
commit2e2e88ea8c3bd9e1bd6e42faf047a4ac3fbb3b2f (patch)
tree398f6de92d9e41419297354a26e25e0db8a693f6
parent3a48ee8a4ad26c3a538b6fc11a86a8f80c3dce18 (diff)
fs: fix do_lookup false negative
fs: fix do_lookup false negative In do_lookup, if we initially find no dentry, we take the directory i_mutex and re-check the lookup. If we find a dentry there, then we revalidate it if needed. However if that revalidate asks for the dentry to be invalidated, we return -ENOENT from do_lookup. What should happen instead is an attempt to allocate and lookup a new dentry. This is probably not noticed because it is rare. It is only reached if a concurrent create races in first (in which case, the dentry probably won't be invalidated anyway), or if the racy __d_lookup has failed due to a false-negative (which is very rare). Fix this by removing code and have it use the normal reval path. Signed-off-by: Nick Piggin <npiggin@kernel.dk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c10
1 files changed, 2 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 17ea76bf2fbe..c2742b7dec59 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -709,6 +709,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
709 dentry = __d_lookup(nd->path.dentry, name); 709 dentry = __d_lookup(nd->path.dentry, name);
710 if (!dentry) 710 if (!dentry)
711 goto need_lookup; 711 goto need_lookup;
712found:
712 if (dentry->d_op && dentry->d_op->d_revalidate) 713 if (dentry->d_op && dentry->d_op->d_revalidate)
713 goto need_revalidate; 714 goto need_revalidate;
714done: 715done:
@@ -766,14 +767,7 @@ out_unlock:
766 * we waited on the semaphore. Need to revalidate. 767 * we waited on the semaphore. Need to revalidate.
767 */ 768 */
768 mutex_unlock(&dir->i_mutex); 769 mutex_unlock(&dir->i_mutex);
769 if (dentry->d_op && dentry->d_op->d_revalidate) { 770 goto found;
770 dentry = do_revalidate(dentry, nd);
771 if (!dentry)
772 dentry = ERR_PTR(-ENOENT);
773 }
774 if (IS_ERR(dentry))
775 goto fail;
776 goto done;
777 771
778need_revalidate: 772need_revalidate:
779 dentry = do_revalidate(dentry, nd); 773 dentry = do_revalidate(dentry, nd);