[Devel] [PATCH RHEL7 COMMIT] dcache: fix dentry leak when shrink races with kill

Vladimir Davydov vdavydov at virtuozzo.com
Thu Jul 7 07:33:14 PDT 2016


The commit is pushed to "branch-rh7-3.10.0-327.18.2.vz7.14.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.18.2.vz7.14.23
------>
commit 88b8ca0fe3055767d9b92495b3e28f587b923d04
Author: Vladimir Davydov <vdavydov at virtuozzo.com>
Date:   Thu Jul 7 18:33:13 2016 +0400

    dcache: fix dentry leak when shrink races with kill
    
    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);


More information about the Devel mailing list