summaryrefslogtreecommitdiffstats
path: root/freed-ora/current/master/deal-with-deadlock-in-d_walk.patch
diff options
context:
space:
mode:
Diffstat (limited to 'freed-ora/current/master/deal-with-deadlock-in-d_walk.patch')
-rw-r--r--freed-ora/current/master/deal-with-deadlock-in-d_walk.patch86
1 files changed, 86 insertions, 0 deletions
diff --git a/freed-ora/current/master/deal-with-deadlock-in-d_walk.patch b/freed-ora/current/master/deal-with-deadlock-in-d_walk.patch
new file mode 100644
index 000000000..fd0e21c33
--- /dev/null
+++ b/freed-ora/current/master/deal-with-deadlock-in-d_walk.patch
@@ -0,0 +1,86 @@
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sun, 26 Oct 2014 19:31:10 -0400
+Subject: [PATCH] deal with deadlock in d_walk()
+
+... by not hitting rename_retry for reasons other than rename having
+happened. In other words, do _not_ restart when finding that
+between unlocking the child and locking the parent the former got
+into __dentry_kill(). Skip the killed siblings instead...
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+---
+ fs/dcache.c | 31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/fs/dcache.c b/fs/dcache.c
+index c3ea5b765f6a..71acf8d6f2be 100644
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -495,7 +495,7 @@ static void __dentry_kill(struct dentry *dentry)
+ }
+ /* if it was on the hash then remove it */
+ __d_drop(dentry);
+- list_del(&dentry->d_child);
++ __list_del_entry(&dentry->d_child);
+ /*
+ * Inform d_walk() that we are no longer attached to the
+ * dentry tree
+@@ -1082,33 +1082,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);
+
+@@ -1118,6 +1116,9 @@ out_unlock:
+ return;
+
+ rename_retry:
++ spin_unlock(&this_parent->d_lock);
++ rcu_read_unlock();
++ BUG_ON(seq & 1);
+ if (!retry)
+ return;
+ seq = 1;
+--
+2.1.0
+
OpenPOWER on IntegriCloud