[Devel] [PATCH rh7] dcache: fix dentry leak when shrink races with kill
Vladimir Davydov
vdavydov at virtuozzo.com
Tue Jul 5 10:05:54 PDT 2016
dentry_kill() does not free a dentry in case it is on a shrink list -
see __dentry_kill() -> d_free(). Instead it just marks it
DCACHE_MAY_FREE, which will make the shrinker free it when it's done
with it. This is required to avoid use after free in
shrink_dentry_list(). This logic was back-ported by commit e33cae748d1a
("ms/dcache: dentry_kill(): don't try to remove from shrink list").
When back-porting this commit I occasionally missed a hunk for
shrink_dentry_list(). The hunk makes shrink_dentry_list() more carefully
check dentry->d_lock_ref.count, i.e. instead of merely checking if it's
0 or not, it makes it check if it's strictly greater than 0. W/o this
check a dentry might leak if shrink races with kill, because before
trying to free a dentry, dentry_kill() first calls
lockref_mark_dead(&dentry->d_lockref), which sets d_lockref.count to
-128, so that shrink_dentry_list() will silently skip the dentry instead
of freeing it.
This patch resurrects the missing hunk.
https://jira.sw.ru/browse/PSBM-49321
Fixes: e33cae748d1a ("ms/dcache: dentry_kill(): don't try to remove from shrink list")
Signed-off-by: Vladimir Davydov <vdavydov at virtuozzo.com>
---
fs/dcache.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 09ed486c9f1d..6433814a02d2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -874,7 +874,7 @@ static void shrink_dentry_list(struct list_head *list)
* We found an inuse dentry which was not removed from
* the LRU because of laziness during lookup. Do not free it.
*/
- if (dentry->d_lockref.count) {
+ if ((int)dentry->d_lockref.count > 0) {
spin_unlock(&dentry->d_lock);
if (parent)
spin_unlock(&parent->d_lock);
--
2.1.4
More information about the Devel
mailing list