* [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
@ 2023-08-17 7:47 Chengfeng Ye
2023-08-21 21:02 ` Martin K. Petersen
2023-08-25 1:12 ` Martin K. Petersen
0 siblings, 2 replies; 3+ messages in thread
From: Chengfeng Ye @ 2023-08-17 7:47 UTC (permalink / raw)
To: hare, jejb, martin.petersen, bigeasy, dave, satishkh, sebaddel, kartilak
Cc: linux-scsi, linux-kernel, Chengfeng Ye
There is a long call chain that &fip->ctlr_lock is acquired by isr
fnic_isr_msix_wq_copy() under hard irq context. Thus other process
context code acquiring the lock should disable irq, otherwise
deadlock could happen if the irq preempt the execution while the
lock is held in process context on the same CPU.
[ISR]
fnic_isr_msix_wq_copy()
-> fnic_wq_copy_cmpl_handler()
-> fnic_fcpio_cmpl_handler()
-> fnic_fcpio_flogi_reg_cmpl_handler()
-> fnic_flush_tx()
-> fnic_send_frame()
-> fcoe_ctlr_els_send()
-> spin_lock_bh(&fip->ctlr_lock)
[Process Context]
1. fcoe_ctlr_timer_work()
-> fcoe_ctlr_flogi_send()
-> spin_lock_bh(&fip->ctlr_lock)
2. fcoe_ctlr_recv_work()
-> fcoe_ctlr_recv_handler()
-> fcoe_ctlr_recv_els()
-> fcoe_ctlr_announce()
-> spin_lock_bh(&fip->ctlr_lock)
3. fcoe_ctlr_recv_work()
-> fcoe_ctlr_recv_handler()
-> fcoe_ctlr_recv_els()
-> fcoe_ctlr_flogi_retry()
-> spin_lock_bh(&fip->ctlr_lock)
4. -> fcoe_xmit()
-> fcoe_ctlr_els_send()
-> spin_lock_bh(&fip->ctlr_lock)
spin_lock_bh() is not enough since fnic_isr_msix_wq_copy() is a
hardirq.
These flaws were found by an experimental static analysis tool I am
developing for irq-related deadlock.
The patch fix the potential deadlocks by spin_lock_irqsave() to
disable hard irq.
Fixes: 794d98e77f59 ("[SCSI] libfcoe: retry rejected FLOGI to another FCF if possible")
Signed-off-by: Chengfeng Ye <dg573847474@gmail.com>
---
Change in v2:
- Add fixes tag
---
drivers/scsi/fcoe/fcoe_ctlr.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 5c8d1ba3f8f3..19eee108db02 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -319,16 +319,17 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
+ unsigned long flags;
mutex_lock(&fip->ctlr_mutex);
- spin_lock_bh(&fip->ctlr_lock);
+ spin_lock_irqsave(&fip->ctlr_lock, flags);
kfree_skb(fip->flogi_req);
fip->flogi_req = NULL;
list_for_each_entry(fcf, &fip->fcfs, list)
fcf->flogi_sent = 0;
- spin_unlock_bh(&fip->ctlr_lock);
+ spin_unlock_irqrestore(&fip->ctlr_lock, flags);
sel = fip->sel_fcf;
if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr))
@@ -699,6 +700,7 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
{
struct fc_frame *fp;
struct fc_frame_header *fh;
+ unsigned long flags;
u16 old_xid;
u8 op;
u8 mac[ETH_ALEN];
@@ -732,11 +734,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
op = FIP_DT_FLOGI;
if (fip->mode == FIP_MODE_VN2VN)
break;
- spin_lock_bh(&fip->ctlr_lock);
+ spin_lock_irqsave(&fip->ctlr_lock, flags);
kfree_skb(fip->flogi_req);
fip->flogi_req = skb;
fip->flogi_req_send = 1;
- spin_unlock_bh(&fip->ctlr_lock);
+ spin_unlock_irqrestore(&fip->ctlr_lock, flags);
schedule_work(&fip->timer_work);
return -EINPROGRESS;
case ELS_FDISC:
@@ -1705,10 +1707,11 @@ static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
+ unsigned long flags;
int error;
mutex_lock(&fip->ctlr_mutex);
- spin_lock_bh(&fip->ctlr_lock);
+ spin_lock_irqsave(&fip->ctlr_lock, flags);
LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
fcf = fcoe_ctlr_select(fip);
if (!fcf || fcf->flogi_sent) {
@@ -1719,7 +1722,7 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
fcoe_ctlr_solicit(fip, NULL);
error = fcoe_ctlr_flogi_send_locked(fip);
}
- spin_unlock_bh(&fip->ctlr_lock);
+ spin_unlock_irqrestore(&fip->ctlr_lock, flags);
mutex_unlock(&fip->ctlr_mutex);
return error;
}
@@ -1736,8 +1739,9 @@ static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
+ unsigned long flags;
- spin_lock_bh(&fip->ctlr_lock);
+ spin_lock_irqsave(&fip->ctlr_lock, flags);
fcf = fip->sel_fcf;
if (!fcf || !fip->flogi_req_send)
goto unlock;
@@ -1764,7 +1768,7 @@ static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
} else /* XXX */
LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
unlock:
- spin_unlock_bh(&fip->ctlr_lock);
+ spin_unlock_irqrestore(&fip->ctlr_lock, flags);
}
/**
--
2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
2023-08-17 7:47 [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock Chengfeng Ye
@ 2023-08-21 21:02 ` Martin K. Petersen
2023-08-25 1:12 ` Martin K. Petersen
1 sibling, 0 replies; 3+ messages in thread
From: Martin K. Petersen @ 2023-08-21 21:02 UTC (permalink / raw)
To: Chengfeng Ye
Cc: hare, jejb, martin.petersen, bigeasy, dave, satishkh, sebaddel,
kartilak, linux-scsi, linux-kernel
Chengfeng,
> There is a long call chain that &fip->ctlr_lock is acquired by isr
> fnic_isr_msix_wq_copy() under hard irq context. Thus other process
> context code acquiring the lock should disable irq, otherwise deadlock
> could happen if the irq preempt the execution while the lock is held
> in process context on the same CPU.
Applied to 6.6/scsi-staging, thanks!
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
2023-08-17 7:47 [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock Chengfeng Ye
2023-08-21 21:02 ` Martin K. Petersen
@ 2023-08-25 1:12 ` Martin K. Petersen
1 sibling, 0 replies; 3+ messages in thread
From: Martin K. Petersen @ 2023-08-25 1:12 UTC (permalink / raw)
To: hare, jejb, bigeasy, dave, satishkh, sebaddel, kartilak, Chengfeng Ye
Cc: Martin K . Petersen, linux-scsi, linux-kernel
On Thu, 17 Aug 2023 07:47:08 +0000, Chengfeng Ye wrote:
> There is a long call chain that &fip->ctlr_lock is acquired by isr
> fnic_isr_msix_wq_copy() under hard irq context. Thus other process
> context code acquiring the lock should disable irq, otherwise
> deadlock could happen if the irq preempt the execution while the
> lock is held in process context on the same CPU.
>
> [ISR]
> fnic_isr_msix_wq_copy()
> -> fnic_wq_copy_cmpl_handler()
> -> fnic_fcpio_cmpl_handler()
> -> fnic_fcpio_flogi_reg_cmpl_handler()
> -> fnic_flush_tx()
> -> fnic_send_frame()
> -> fcoe_ctlr_els_send()
> -> spin_lock_bh(&fip->ctlr_lock)
>
> [...]
Applied to 6.6/scsi-queue, thanks!
[1/1] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock
https://git.kernel.org/mkp/scsi/c/1a1975551943
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-08-25 1:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17 7:47 [PATCH v2] scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock Chengfeng Ye
2023-08-21 21:02 ` Martin K. Petersen
2023-08-25 1:12 ` Martin K. Petersen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®