diff options
author | Jari Ruusu <jariruusu@users.sourceforge.net> | 2015-06-13 19:01:31 +0300 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2015-12-22 13:45:54 +0900 |
commit | 98f3861da760d33926cec5c42f16d969a497e990 (patch) | |
tree | 5e041dc85bdb878290ae688e4bf549cf626ebb90 /fs | |
parent | 3f4bdfae6aeb32fc41816fe4df2486c80db5ecbd (diff) | |
download | linux-3.10-artik-98f3861da760d33926cec5c42f16d969a497e990.tar.gz linux-3.10-artik-98f3861da760d33926cec5c42f16d969a497e990.tar.bz2 linux-3.10-artik-98f3861da760d33926cec5c42f16d969a497e990.zip |
d_walk() might skip too much
When Al Viro's VFS deadlock fix "deal with deadlock in d_walk()" was
backported to 3.10.y 3.4.y and 3.2.y stable kernel brances, the deadlock fix
was copied to 3 different places. Later, a bug in that code was discovered.
Al Viro's fix involved fixing only one part of code in mainline kernel. That
fix is called "d_walk() might skip too much".
3.10.y 3.4.y and 3.2.y stable kernel brances need that later fix copied to 3
different places. Greg Kroah-Hartman included Al Viro's "d_walk() might skip
too much" fix only once in 3.10.80 kernel, leaving 2 more places without a
fix.
The patch below was not written by me. I only applied Al Viro's "d_walk()
might skip too much" fix 2 more times to 3.10.80 kernel, and cheched that
the fixes went to correct places. With this patch applied, all 3 places that
I am aware of 3.10.y stable branch are now fixed.
Signed-off-by: Jari Ruusu <jariruusu@users.sourceforge.net>
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index e2800926ae0..38c4a302fab 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1053,13 +1053,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; } @@ -2977,13 +2977,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; } |