mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
lock_parent() needs to recheck if dentry got __dentry_kill'ed under it
commit 3b821409632ab778d46e807516b457dfa72736ed upstream. In case when dentry passed to lock_parent() is protected from freeing only by the fact that it's on a shrink list and trylock of parent fails, we could get hit by __dentry_kill() (and subsequent dentry_kill(parent)) between unlocking dentry and locking presumed parent. We need to recheck that dentry is alive once we lock both it and parent *and* postpone rcu_read_unlock() until after that point. Otherwise we could return a pointer to struct dentry that already is rcu-scheduled for freeing, with ->d_lock held on it; caller's subsequent attempt to unlock it can end up with memory corruption. Cc: stable@vger.kernel.org # 3.12+, counting backports Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e693f1331c
commit
b071bce3ff
11
fs/dcache.c
11
fs/dcache.c
@ -644,11 +644,16 @@ again:
|
|||||||
spin_unlock(&parent->d_lock);
|
spin_unlock(&parent->d_lock);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
if (parent != dentry) {
|
||||||
if (parent != dentry)
|
|
||||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
else
|
if (unlikely(dentry->d_lockref.count < 0)) {
|
||||||
|
spin_unlock(&parent->d_lock);
|
||||||
|
parent = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
parent = NULL;
|
parent = NULL;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user