aboutsummaryrefslogtreecommitdiff
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorShannon Zhao <shannon.zhao@linaro.org>2015-05-26 20:43:27 +0800
committerShannon Zhao <shannon.zhao@linaro.org>2015-05-26 20:50:44 +0800
commit7e04a8803c644b0e1d90b59da24a6e1925082730 (patch)
tree3b3c82501cc06506f2596435365099973ca81fba /fs/dcache.c
parenta524c44bc75336d0b9d9b45ceb30e19354ff780e (diff)
parent13253707013a08ce5a279ebd029fa10230172458 (diff)
Merge branch 'linux-3.14.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into linux-linaro-lsk-v3.14
Conflicts: arch/arm/include/asm/kvm_mmu.h arch/arm/kvm/mmu.c arch/arm64/include/asm/kvm_arm.h arch/arm64/include/asm/kvm_mmu.h arch/arm64/kvm/sys_regs.c virt/kvm/arm/vgic.c
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 1b349b56839f..7a944f62c435 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -435,7 +435,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
__releases(parent->d_lock)
__releases(dentry->d_inode->i_lock)
{
- list_del(&dentry->d_child);
+ __list_del_entry(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -1123,33 +1123,31 @@ resume:
/*
* All done at this level ... ascend and resume the search.
*/
+ rcu_read_lock();
+ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
this_parent = child->d_parent;
- rcu_read_lock();
spin_unlock(&child->d_lock);
spin_lock(&this_parent->d_lock);
- /*
- * might go back up the wrong parent if we have had a rename
- * or deletion
- */
- if (this_parent != child->d_parent ||
- (child->d_flags & DCACHE_DENTRY_KILLED) ||
- need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
- rcu_read_unlock();
+ /* might go back up the wrong parent if we have had a rename. */
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
}
rcu_read_unlock();
- next = child->d_child.next;
goto resume;
}
- if (need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
- }
+ rcu_read_unlock();
if (finish)
finish(data);
@@ -1159,6 +1157,9 @@ out_unlock:
return;
rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
+ BUG_ON(seq & 1);
if (!retry)
return;
seq = 1;