From: Greg Kroah-Hartman Date: Thu, 12 Jun 2014 22:28:32 +0000 (-0700) Subject: 3.15-stable patches X-Git-Tag: v3.4.94~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=564b4cdc35d12aeefe49e5b897a375e5f0f18f66;p=thirdparty%2Fkernel%2Fstable-queue.git 3.15-stable patches added patches: lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch --- diff --git a/queue-3.15/lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch b/queue-3.15/lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch new file mode 100644 index 00000000000..751f30ff0fd --- /dev/null +++ b/queue-3.15/lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch @@ -0,0 +1,44 @@ +From c2338f2dc7c1e9f6202f370c64ffd7f44f3d4b51 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Thu, 12 Jun 2014 00:29:13 -0400 +Subject: lock_parent: don't step on stale ->d_parent of all-but-freed one + +From: Al Viro + +commit c2338f2dc7c1e9f6202f370c64ffd7f44f3d4b51 upstream. + +Dentry that had been through (or into) __dentry_kill() might be seen +by shrink_dentry_list(); that's normal, it'll be taken off the shrink +list and freed if __dentry_kill() has already finished. The problem +is, its ->d_parent might be pointing to already freed dentry, so +lock_parent() needs to be careful. + +We need to check that dentry hasn't already gone into __dentry_kill() +*and* grab rcu_read_lock() before dropping ->d_lock - the latter makes +sure that whatever we see in ->d_parent after dropping ->d_lock it +won't be freed until we drop rcu_read_lock(). + +Signed-off-by: Al Viro +Cc: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dcache.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -532,10 +532,12 @@ static inline struct dentry *lock_parent + struct dentry *parent = dentry->d_parent; + if (IS_ROOT(dentry)) + return NULL; ++ if (unlikely((int)dentry->d_lockref.count < 0)) ++ return NULL; + if (likely(spin_trylock(&parent->d_lock))) + return parent; +- spin_unlock(&dentry->d_lock); + rcu_read_lock(); ++ spin_unlock(&dentry->d_lock); + again: + parent = ACCESS_ONCE(dentry->d_parent); + spin_lock(&parent->d_lock); diff --git a/queue-3.15/series b/queue-3.15/series index bdbdc84c6e0..f82ec47cda3 100644 --- a/queue-3.15/series +++ b/queue-3.15/series @@ -1 +1,2 @@ fs-userns-change-inode_capable-to-capable_wrt_inode_uidgid.patch +lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch