aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-05-28 23:09:19 -0400
committerBen Hutchings <ben@decadent.org.uk>2015-08-07 00:32:13 +0100
commit60593faea74ea54e84cb638f9cc59e32d8268f37 (patch)
tree4e41dcc156c1d3b334df27459ea1ddfb26c1bcd8 /fs
parenta5045e0fee1a7b2cf132afb94977d4c8d781bd04 (diff)
downloadkernel_samsung_smdk4412-60593faea74ea54e84cb638f9cc59e32d8268f37.zip
kernel_samsung_smdk4412-60593faea74ea54e84cb638f9cc59e32d8268f37.tar.gz
kernel_samsung_smdk4412-60593faea74ea54e84cb638f9cc59e32d8268f37.tar.bz2
d_walk() might skip too much
commit 2159184ea01e4ae7d15f2017e296d4bc82d5aeb0 upstream. when we find that a child has died while we'd been trying to ascend, we should go into the first live sibling itself, rather than its sibling. Off-by-one in question had been introduced in "deal with deadlock in d_walk()" and the fix needs to be backported to all branches this one has been backported to. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> [bwh: Backported to 3.2: apply to the 3 copies of this logic we ended up with] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c24
1 files changed, 12 insertions, 12 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 8bc98af..8a35300 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1016,13 +1016,13 @@ ascend:
/* might go back up the wrong parent if we have had a rename */
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_child.next;
- while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ /* go into the first sibling still alive */
+ do {
+ next = child->d_child.next;
if (next == &this_parent->d_subdirs)
goto ascend;
child = list_entry(next, struct dentry, d_child);
- next = next->next;
- }
+ } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
rcu_read_unlock();
goto resume;
}
@@ -1142,13 +1142,13 @@ ascend:
/* might go back up the wrong parent if we have had a rename */
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_child.next;
- while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ /* go into the first sibling still alive */
+ do {
+ next = child->d_child.next;
if (next == &this_parent->d_subdirs)
goto ascend;
child = list_entry(next, struct dentry, d_child);
- next = next->next;
- }
+ } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
rcu_read_unlock();
goto resume;
}
@@ -2938,13 +2938,13 @@ ascend:
/* might go back up the wrong parent if we have had a rename */
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_child.next;
- while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ /* go into the first sibling still alive */
+ do {
+ next = child->d_child.next;
if (next == &this_parent->d_subdirs)
goto ascend;
child = list_entry(next, struct dentry, d_child);
- next = next->next;
- }
+ } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
rcu_read_unlock();
goto resume;
}