Commit e7dcc514 authored by Sumit Saxena's avatar Sumit Saxena Committed by Martin K. Petersen

scsi: megaraid_sas: Fix concurrent access to ISR between IRQ polling and real interrupt

IRQ polling thread calls ISR after enable_irq() to handle any missed I/O
completion. The 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 (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
Link: https://lore.kernel.org/r/20210929124022.24605-2-sumit.saxena@broadcom.com
Fixes: 9bedd36e ("scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs")
Signed-off-by: default avatarSumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d4996c6e
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment