[Devel] [PATCH RHEL7 COMMIT] cbt: bitmap corruption caused by ipi

Konstantin Khorenko khorenko at virtuozzo.com
Thu Oct 18 16:21:31 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.14.4.vz7.72.11
------>
commit 0a074588bfb8663fe52216edf9052181d38880b0
Author: Vasily Averin <vvs at virtuozzo.com>
Date:   Thu Oct 18 16:21:29 2018 +0300

    cbt: bitmap corruption caused by ipi
    
    IPI generated by cbt_flush_cache() can interrupt blk_cbt_add() in "bad" places
    and lead to bitmap corruption.
    
    CPU A                       CPU B
    blk_cbt_add()
    ...                         cbt_flush_cache()
       old = *ex;                submit IPI
       ex->start = start;
    
    interrupt
      __cbt_flush_cpu_cache
       if (ex->len)   <<< found non-changed len
         __blk_cbt_set(cbt, ex->start, ex->len, 0, 1); <<< set wrong bitmask
         ex->start += ex->len; <<< incorrectly adjusts ex->start
         ex->len = 0;
    return from interrupt back to blk_cbt_add()
       ex->len = len;   <<< set len and get wrong bitmask
    (because ex->start was changed in __cbt_flush_cpu_cache)
    
    Similar problem happens if IPI will be processed in middle of following block in blk_cbt_add()
    
            if (ex->start + ex->len == start) {
                    ex->len += len;
                    goto out_rcu;
            }
    
    Patch disables interrupts in specified places.
    
    https://jira.sw.ru/browse/PSBM-89323
    Signed-off-by: Vasily Averin <vvs at virtuozzo.com>
---
 block/blk-cbt.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/block/blk-cbt.c b/block/blk-cbt.c
index d83ee9e5a44a..0b5a8c165298 100644
--- a/block/blk-cbt.c
+++ b/block/blk-cbt.c
@@ -229,13 +229,16 @@ static void blk_cbt_add(struct request_queue *q, blkcnt_t start, blkcnt_t len)
 		goto out_rcu;
 	}
 	ex = this_cpu_ptr(cbt->cache);
+	local_irq_disable();
 	if (ex->start + ex->len == start) {
 		ex->len += len;
+		local_irq_enable();
 		goto out_rcu;
 	}
 	old = *ex;
 	ex->start = start;
 	ex->len = len;
+	local_irq_enable();
 
 	if (likely(old.len))
 		__blk_cbt_set(cbt, old.start, old.len, 1, 1, NULL, NULL);



More information about the Devel mailing list