From e6b248c29ccfc4927d541f901472497c1775cf0b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 15 Mar 2011 16:42:30 -0700 Subject: [PATCH] .38 patches --- ...unction-for-duplicated-functionality.patch | 146 ++++++++++++++++++ queue-2.6.38/series | 2 + ...lyrename-regression-in-kernel-2.6.38.patch | 56 +++++++ 3 files changed, 204 insertions(+) create mode 100644 queue-2.6.38/dcache.c-create-helper-function-for-duplicated-functionality.patch create mode 100644 queue-2.6.38/series create mode 100644 queue-2.6.38/vfs-fix-the-nfs-sillyrename-regression-in-kernel-2.6.38.patch diff --git a/queue-2.6.38/dcache.c-create-helper-function-for-duplicated-functionality.patch b/queue-2.6.38/dcache.c-create-helper-function-for-duplicated-functionality.patch new file mode 100644 index 00000000000..124978df738 --- /dev/null +++ b/queue-2.6.38/dcache.c-create-helper-function-for-duplicated-functionality.patch @@ -0,0 +1,146 @@ +From c826cb7dfce80512c26c984350077a25046bd215 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Tue, 15 Mar 2011 15:29:21 -0700 +Subject: dcache.c: create helper function for duplicated functionality + +From: Linus Torvalds + +commit c826cb7dfce80512c26c984350077a25046bd215 upstream. + +This creates a helper function for he "try to ascend into the parent +directory" case, which was written out in triplicate before. With all +the locking and subtle sequence number stuff, we really don't want to +duplicate that kind of code. + +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dcache.c | 88 +++++++++++++++++++++++++----------------------------------- + 1 file changed, 37 insertions(+), 51 deletions(-) + +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1012,6 +1012,34 @@ void shrink_dcache_for_umount(struct sup + } + + /* ++ * This tries to ascend one level of parenthood, but ++ * we can race with renaming, so we need to re-check ++ * the parenthood after dropping the lock and check ++ * that the sequence number still matches. ++ */ ++static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) ++{ ++ struct dentry *new = old->d_parent; ++ ++ rcu_read_lock(); ++ spin_unlock(&old->d_lock); ++ spin_lock(&new->d_lock); ++ ++ /* ++ * might go back up the wrong parent if we have had a rename ++ * or deletion ++ */ ++ if (new != old->d_parent || ++ (!locked && read_seqretry(&rename_lock, seq))) { ++ spin_unlock(&new->d_lock); ++ new = NULL; ++ } ++ rcu_read_unlock(); ++ return new; ++} ++ ++ ++/* + * Search for at least 1 mount point in the dentry's subdirs. + * We descend to the next level whenever the d_subdirs + * list is non-empty and continue searching. +@@ -1066,24 +1094,10 @@ resume: + * All done at this level ... ascend and resume the search. + */ + if (this_parent != parent) { +- struct dentry *tmp; +- struct dentry *child; +- +- tmp = this_parent->d_parent; +- rcu_read_lock(); +- spin_unlock(&this_parent->d_lock); +- child = this_parent; +- this_parent = tmp; +- 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 || +- (!locked && read_seqretry(&rename_lock, seq))) { +- spin_unlock(&this_parent->d_lock); +- rcu_read_unlock(); ++ struct dentry *child = this_parent; ++ this_parent = try_to_ascend(this_parent, locked, seq); ++ if (!this_parent) + goto rename_retry; +- } +- rcu_read_unlock(); + next = child->d_u.d_child.next; + goto resume; + } +@@ -1181,24 +1195,10 @@ resume: + * All done at this level ... ascend and resume the search. + */ + if (this_parent != parent) { +- struct dentry *tmp; +- struct dentry *child; +- +- tmp = this_parent->d_parent; +- rcu_read_lock(); +- spin_unlock(&this_parent->d_lock); +- child = this_parent; +- this_parent = tmp; +- 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 || +- (!locked && read_seqretry(&rename_lock, seq))) { +- spin_unlock(&this_parent->d_lock); +- rcu_read_unlock(); ++ struct dentry *child = this_parent; ++ this_parent = try_to_ascend(this_parent, locked, seq); ++ if (!this_parent) + goto rename_retry; +- } +- rcu_read_unlock(); + next = child->d_u.d_child.next; + goto resume; + } +@@ -2942,28 +2942,14 @@ resume: + spin_unlock(&dentry->d_lock); + } + if (this_parent != root) { +- struct dentry *tmp; +- struct dentry *child; +- +- tmp = this_parent->d_parent; ++ struct dentry *child = this_parent; + if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { + this_parent->d_flags |= DCACHE_GENOCIDE; + this_parent->d_count--; + } +- rcu_read_lock(); +- spin_unlock(&this_parent->d_lock); +- child = this_parent; +- this_parent = tmp; +- 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 || +- (!locked && read_seqretry(&rename_lock, seq))) { +- spin_unlock(&this_parent->d_lock); +- rcu_read_unlock(); ++ this_parent = try_to_ascend(this_parent, locked, seq); ++ if (!this_parent) + goto rename_retry; +- } +- rcu_read_unlock(); + next = child->d_u.d_child.next; + goto resume; + } diff --git a/queue-2.6.38/series b/queue-2.6.38/series new file mode 100644 index 00000000000..bfc22de4065 --- /dev/null +++ b/queue-2.6.38/series @@ -0,0 +1,2 @@ +dcache.c-create-helper-function-for-duplicated-functionality.patch +vfs-fix-the-nfs-sillyrename-regression-in-kernel-2.6.38.patch diff --git a/queue-2.6.38/vfs-fix-the-nfs-sillyrename-regression-in-kernel-2.6.38.patch b/queue-2.6.38/vfs-fix-the-nfs-sillyrename-regression-in-kernel-2.6.38.patch new file mode 100644 index 00000000000..c66e6e7e77f --- /dev/null +++ b/queue-2.6.38/vfs-fix-the-nfs-sillyrename-regression-in-kernel-2.6.38.patch @@ -0,0 +1,56 @@ +From c83ce989cb5ff86575821992ea82c4df5c388ebc Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Tue, 15 Mar 2011 13:36:43 -0400 +Subject: VFS: Fix the nfs sillyrename regression in kernel 2.6.38 + +From: Trond Myklebust + +commit c83ce989cb5ff86575821992ea82c4df5c388ebc upstream. + +The new vfs locking scheme introduced in 2.6.38 breaks NFS sillyrename +because the latter relies on being able to determine the parent +directory of the dentry in the ->iput() callback in order to send the +appropriate unlink rpc call. + +Looking at the code that cares about races with dput(), there doesn't +seem to be anything that specifically uses d_parent as a test for +whether or not there is a race: + - __d_lookup_rcu(), __d_lookup() all test for d_hashed() after d_parent + - shrink_dcache_for_umount() is safe since nothing else can rearrange + the dentries in that super block. + - have_submount(), select_parent() and d_genocide() can test for a + deletion if we set the DCACHE_DISCONNECTED flag when the dentry + is removed from the parent's d_subdirs list. + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dcache.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -296,8 +296,12 @@ static struct dentry *d_kill(struct dent + __releases(parent->d_lock) + __releases(dentry->d_inode->i_lock) + { +- dentry->d_parent = NULL; + list_del(&dentry->d_u.d_child); ++ /* ++ * Inform try_to_ascend() that we are no longer attached to the ++ * dentry tree ++ */ ++ dentry->d_flags |= DCACHE_DISCONNECTED; + if (parent) + spin_unlock(&parent->d_lock); + dentry_iput(dentry); +@@ -1030,6 +1034,7 @@ static struct dentry *try_to_ascend(stru + * or deletion + */ + if (new != old->d_parent || ++ (old->d_flags & DCACHE_DISCONNECTED) || + (!locked && read_seqretry(&rename_lock, seq))) { + spin_unlock(&new->d_lock); + new = NULL; -- 2.47.3