diff options
author | Nick Piggin <npiggin@kernel.dk> | 2010-08-17 14:37:30 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-08-18 08:35:45 -0400 |
commit | 2e2e88ea8c3bd9e1bd6e42faf047a4ac3fbb3b2f (patch) | |
tree | 398f6de92d9e41419297354a26e25e0db8a693f6 | |
parent | 3a48ee8a4ad26c3a538b6fc11a86a8f80c3dce18 (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.c | 10 |
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; |
712 | found: | ||
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; |
714 | done: | 715 | done: |
@@ -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 | ||
778 | need_revalidate: | 772 | need_revalidate: |
779 | dentry = do_revalidate(dentry, nd); | 773 | dentry = do_revalidate(dentry, nd); |