From mboxrd@z Thu Jan 1 00:00:00 1970 From: Cong Wang Subject: [Patch 3.14 stable 16/16] lock_parent: don't step on stale ->d_parent of all-but-freed one Date: Thu, 6 Nov 2014 11:37:20 -0800 Message-ID: <1415302640-5876-17-git-send-email-xiyou.wangcong@gmail.com> References: <1415302640-5876-1-git-send-email-xiyou.wangcong@gmail.com> Cc: viro@zeniv.linux.org.uk, gregkh@linuxfoundation.org, linux-fsdevel@vger.kernel.org To: stable@vger.kernel.org Return-path: In-Reply-To: <1415302640-5876-1-git-send-email-xiyou.wangcong@gmail.com> Sender: stable-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org From: Al Viro 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 (cherry picked from commit c2338f2dc7c1e9f6202f370c64ffd7f44f3d4b51) --- fs/dcache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index c0f89ea..b4251db 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -531,10 +531,12 @@ static inline struct dentry *lock_parent(struct dentry *dentry) 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); -- 1.8.3.1