[Devel] [PATCH RHEL7 COMMIT] tcache: teach tcache_get_node() to handle cleancache_get_page/cleancache_invalidate_inode races

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jul 6 06:38:03 PDT 2015


The commit is pushed to "branch-rh7-3.10.0-123.1.2-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-123.1.2.vz7.5.24
------>
commit aaa1d051161262d1507712a6e7aa6c01051502f1
Author: Vladimir Davydov <vdavydov at parallels.com>
Date:   Mon Jul 6 17:38:03 2015 +0400

    tcache: teach tcache_get_node() to handle cleancache_get_page/cleancache_invalidate_inode races
    
    The BUG is triggered if tcache_get_node is about to return an
    invalidated node. This actually can happen if cleancache_get_page races
    with cleancache_invalidate_inode as follows, e.g. while concurrent
    direct reads/writes are performed:
    
    CPU0                                    CPU1
    ----                                    ----
    cleancache_get_page                     cleancache_invalidate_inode
     tcache_cleancache_get_page              tcache_cleancache_invalidate_inode
      tcache_get_node_and_pool                tcache_invalidate_node
       tcache_get_node
        spin_lock_irqsave(&tree->lock, flags)
        node = <lookup in the tree>
        spin_unlock_irqrestore(&tree->lock, flags)
                                              spin_lock_irq(&tree->lock)
                                              <remove node from the tree>
                                              spin_unlock_irq(&tree->lock)
                                              tcache_invalidate_node_pages
                                               spin_lock_irq(&node->tree_lock)
                                               node->invalidated = true
        BUG_ON(node->invalidated);
    
    Instead of panicking we should drop the page further in
    cleancache_get_page.
    
    https://jira.sw.ru/browse/PSBM-34620
    
    Signed-off-by: Vladimir Davydov <vdavydov at parallels.com>
---
 mm/tcache.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/mm/tcache.c b/mm/tcache.c
index e83ad05..8de3339 100644
--- a/mm/tcache.c
+++ b/mm/tcache.c
@@ -418,7 +418,6 @@ retry:
 
 	if (node) {
 		BUG_ON(node->pool != pool);
-		BUG_ON(node->invalidated);
 		if (node != new_node)
 			kfree(new_node);
 		return node;
@@ -866,6 +865,10 @@ static int tcache_cleancache_get_page(int pool_id,
 	node = tcache_get_node_and_pool(pool_id, &key, false);
 	if (node) {
 		cache_page = tcache_detach_page(node, index);
+		if (unlikely(cache_page && node->invalidated)) {
+			put_page(cache_page);
+			cache_page = NULL;
+		}
 		tcache_put_node_and_pool(node);
 	}
 



More information about the Devel mailing list