diff mbox series

[1/3] megaraid_sas: fix concurrent access to ISR between IRQ polling and real interrupt

Message ID 20210929124022.24605-2-sumit.saxena@broadcom.com (mailing list archive)
State Accepted
Headers show
Series megaraid_sas: Driver version update to 07.719.03.00-rc1 | expand

Commit Message

Sumit Saxena Sept. 29, 2021, 12:40 p.m. UTC
IRQ polling thread calls ISR after enable_irq() to handle any missed IO
completion. atomic flag "in_used" was added to have the synchronization
between the IRQ polling thread and the interrupt context.
There is a bug around it leading to a race condition.

Below is the sequence:
-IRQ polling thread accesses ISR, fetches the reply descriptor.
-Real interrupt arrives and pre-empts polling thread(see enable_irq()
 is already called).
-Interrupt context picks the same reply descriptor as fetched by polling
 thread, processes it, and exits.
-Polling thread resumes and processes the descriptor which is already
 processed by interrupt thread leads to kernel crash.

Setting the "in_used" flag before fetching the reply descriptor ensures
synchronized access to ISR.

Link: https://www.spinics.net/lists/linux-scsi/msg159440.html
Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
Fixes: 9bedd36e9146 (scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs)
---
 drivers/scsi/megaraid/megaraid_sas_fusion.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 26d0cf9353dd..eb5ceb75a15e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -3530,6 +3530,9 @@  complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
 	if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
 		return IRQ_HANDLED;
 
+	if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1))
+		return 0;
+
 	desc = fusion->reply_frames_desc[MSIxIndex] +
 				fusion->last_reply_idx[MSIxIndex];
 
@@ -3540,11 +3543,11 @@  complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
 	reply_descript_type = reply_desc->ReplyFlags &
 		MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
 
-	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
+		if (irq_context)
+			atomic_dec(&irq_context->in_used);
 		return IRQ_NONE;
-
-	if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1))
-		return 0;
+	}
 
 	num_completed = 0;