| From 2159184ea01e4ae7d15f2017e296d4bc82d5aeb0 Mon Sep 17 00:00:00 2001 |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Thu, 28 May 2015 23:09:19 -0400 |
| Subject: d_walk() might skip too much |
| |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/dcache.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/fs/dcache.c |
| +++ b/fs/dcache.c |
| @@ -1179,13 +1179,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; |
| } |