From 564b4cdc35d12aeefe49e5b897a375e5f0f18f66 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Jun 2014 15:28:32 -0700 Subject: [PATCH] 3.15-stable patches added patches: lock_parent-don-t-step-on-stale-d_parent-of-all-but-freed-one.patch --- ...-stale-d_parent-of-all-but-freed-one.patch | 44 +++++++++++++++++++ queue-3.15/series | 1 + 2 files changed, 45 insertions(+) create mode 100644 queue-3.15/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 -- 2.47.3