[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