scsi: mpi3mr: Use IRQ save variants of spinlock to protect chain frame allocation
authorRanjan Kumar <ranjan.kumar@broadcom.com>
Thu, 6 Apr 2023 10:18:19 +0000 (15:48 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 12 Apr 2023 01:17:56 +0000 (21:17 -0400)
Driver uses spin lock without irqsave when it needs to acquire a chain
frame. This is done to protect chain frame allocation from multiple
submission threads. If there is any I/O queued from an interrupt context,
and if that requires a chain frame, and if the chain lock is held by the CPU
which got interrupted, then there will be a possible deadlock.

Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Link: https://lore.kernel.org/r/20230406101819.10109-1-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpi3mr/mpi3mr_os.c

index 5c2fd09b94974b722b1567a41d6b01d0d8821865..d627355303d790de4c2e5e763ca8406ace2fc240 100644 (file)
@@ -3331,19 +3331,19 @@ static int mpi3mr_get_chain_idx(struct mpi3mr_ioc *mrioc)
 {
        u8 retry_count = 5;
        int cmd_idx = -1;
+       unsigned long flags;
 
+       spin_lock_irqsave(&mrioc->chain_buf_lock, flags);
        do {
-               spin_lock(&mrioc->chain_buf_lock);
                cmd_idx = find_first_zero_bit(mrioc->chain_bitmap,
                    mrioc->chain_buf_count);
                if (cmd_idx < mrioc->chain_buf_count) {
                        set_bit(cmd_idx, mrioc->chain_bitmap);
-                       spin_unlock(&mrioc->chain_buf_lock);
                        break;
                }
-               spin_unlock(&mrioc->chain_buf_lock);
                cmd_idx = -1;
        } while (retry_count--);
+       spin_unlock_irqrestore(&mrioc->chain_buf_lock, flags);
        return cmd_idx;
 }