blk_cbt_release() can be called both from soft irq and from
non-interrupt context, so spin_lock should be used with irqsave.

Example of the call from softirq context (taken from google):

 blk_release_queue
  kobject_cleanup
   kobject_put
    blk_put_queue
     blkg_free
      __blkg_release
       rcu_do_batch
        rcu_core
         rcu_core_si
          __do_softirq

blk_cbt_release() is called by the blk_release_queue()
which is the .release() callback of struct kobj_type.

Example of the call from non-irq context:

blk_cbt_release
 cbt_ioc_stop (even mutex is taken there => non-irq context)
  blk_cbt_ioctl
   blkdev_ioctl
    block_ioctl

Fixes: acdc18e4d1aa ("cbt: introduce changed block tracking")

Signed-off-by: Konstantin Khorenko <khore...@virtuozzo.com>
---
 block/blk-cbt.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/block/blk-cbt.c b/block/blk-cbt.c
index a6e1558835f1..432697f009dc 100644
--- a/block/blk-cbt.c
+++ b/block/blk-cbt.c
@@ -524,15 +524,16 @@ void blk_cbt_release(struct request_queue *q)
 {
        struct cbt_info *cbt;
        int in_use = 0;
+       unsigned long flags;
 
        cbt = q->cbt;
        if (!cbt)
                return;
-       spin_lock(&cbt->lock);
+       spin_lock_irqsave(&cbt->lock, flags);
        set_bit(CBT_DEAD, &cbt->flags);
        rcu_assign_pointer(q->cbt, NULL);
        in_use = cbt->count;
-       spin_unlock(&cbt->lock);
+       spin_unlock_irqrestore(&cbt->lock, flags);
        if (!in_use)
                call_rcu(&cbt->rcu, &cbt_release_callback);
 }
-- 
2.24.3

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to