[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20201218204354.586951-4-a.darwish@linutronix.de>
Date: Fri, 18 Dec 2020 21:43:46 +0100
From: "Ahmed S. Darwish" <a.darwish@...utronix.de>
To: "James E.J. Bottomley" <jejb@...ux.ibm.com>,
"Martin K. Petersen" <martin.petersen@...cle.com>,
Daniel Wagner <dwagner@...e.de>,
Jason Yan <yanaijie@...wei.com>,
John Garry <john.garry@...wei.com>,
Artur Paszkiewicz <artur.paszkiewicz@...el.com>,
Jack Wang <jinpu.wang@...ud.ionos.com>
Cc: linux-scsi@...r.kernel.org, LKML <linux-kernel@...r.kernel.org>,
Thomas Gleixner <tglx@...utronix.de>,
"Sebastian A. Siewior" <bigeasy@...utronix.de>,
"Ahmed S. Darwish" <a.darwish@...utronix.de>
Subject: [PATCH 03/11] scsi: mvsas: Pass gfp_t flags to libsas event notifiers
mvsas calls the non _gfp version of the libsas event notifiers API,
leading to the buggy call chains below:
mvsas/mv_sas.c :: mvs_work_queue() [process context]
spin_lock_irqsave(mvs_info::lock, )
-> sas_ha->notify_phy_event()
== libsas/sas_event.c :: sas_notify_phy_event()
-> sas_alloc_event()
-> in_interrupt() = false
-> invalid GFP_KERNEL allocation
-> sas_ha->notify_port_event()
== libsas/sas_event.c :: sas_notify_port_event()
-> sas_alloc_event()
-> in_interrupt() = false
-> invalid GFP_KERNEL allocation
Use the new event notifiers API instead, which requires callers to
explicitly pass the gfp_t memory allocation flags.
Below are context analysis for the modified functions:
=> mvs_bytes_dmaed():
Since it is invoked from both process and atomic contexts, let its
callers pass the gfp_t flags. Call chains:
scsi_scan.c: do_scsi_scan_host() [has msleep()]
-> shost->hostt->scan_start()
-> [mvsas/mv_init.c: Scsi_Host::scsi_host_template .scan_start = mvs_scan_start()]
-> mvsas/mv_sas.c: mvs_scan_start()
-> mvs_bytes_dmaed(..., GFP_KERNEL)
mvsas/mv_sas.c: mvs_work_queue()
spin_lock_irqsave(mvs_info::lock,)
-> mvs_bytes_dmaed(..., GFP_ATOMIC)
mvsas/mv_64xx.c: mvs_64xx_isr() || mvsas/mv_94xx.c: mvs_94xx_isr()
-> mvsas/mv_chips.h: mvs_int_full()
-> mvsas/mv_sas.c: mvs_int_port()
-> mvs_bytes_dmaed(..., GFP_ATOMIC);
=> mvs_work_queue():
Invoked from process context, but it calls all the libsas event notifier
APIs under a spin_lock_irqsave(). Pass GFP_ATOMIC.
Signed-off-by: Ahmed S. Darwish <a.darwish@...utronix.de>
Cc: stable@...r.kernel.org
Cc: John Garry <john.garry@...wei.com>
Cc: Jason Yan <yanaijie@...wei.com>
---
drivers/scsi/mvsas/mv_sas.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index a920eced92ec..30a34c5bdf6b 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -216,7 +216,7 @@ void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
}
-static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i, gfp_t gfp_flags)
{
struct mvs_phy *phy = &mvi->phy[i];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -230,7 +230,7 @@ static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
}
sas_ha = mvi->sas;
- sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+ sas_ha->notify_phy_event_gfp(sas_phy, PHYE_OOB_DONE, gfp_flags);
if (sas_phy->phy) {
struct sas_phy *sphy = sas_phy->phy;
@@ -262,8 +262,8 @@ static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
- mvi->sas->notify_port_event(sas_phy,
- PORTE_BYTES_DMAED);
+ mvi->sas->notify_port_event_gfp(sas_phy,
+ PORTE_BYTES_DMAED, gfp_flags);
}
void mvs_scan_start(struct Scsi_Host *shost)
@@ -279,7 +279,7 @@ void mvs_scan_start(struct Scsi_Host *shost)
for (j = 0; j < core_nr; j++) {
mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
for (i = 0; i < mvi->chip->n_phy; ++i)
- mvs_bytes_dmaed(mvi, i);
+ mvs_bytes_dmaed(mvi, i, GFP_KERNEL);
}
mvs_prv->scan_finished = 1;
}
@@ -1895,21 +1895,21 @@ static void mvs_work_queue(struct work_struct *work)
if (!(tmp & PHY_READY_MASK)) {
sas_phy_disconnected(sas_phy);
mvs_phy_disconnected(phy);
- sas_ha->notify_phy_event(sas_phy,
- PHYE_LOSS_OF_SIGNAL);
+ sas_ha->notify_phy_event_gfp(sas_phy,
+ PHYE_LOSS_OF_SIGNAL, GFP_ATOMIC);
mv_dprintk("phy%d Removed Device\n", phy_no);
} else {
MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
mvs_update_phyinfo(mvi, phy_no, 1);
- mvs_bytes_dmaed(mvi, phy_no);
+ mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC);
mvs_port_notify_formed(sas_phy, 0);
mv_dprintk("phy%d Attached Device\n", phy_no);
}
}
} else if (mwq->handler & EXP_BRCT_CHG) {
phy->phy_event &= ~EXP_BRCT_CHG;
- sas_ha->notify_port_event(sas_phy,
- PORTE_BROADCAST_RCVD);
+ sas_ha->notify_port_event_gfp(sas_phy,
+ PORTE_BROADCAST_RCVD, GFP_ATOMIC);
mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
}
list_del(&mwq->entry);
@@ -2026,7 +2026,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
mdelay(10);
}
- mvs_bytes_dmaed(mvi, phy_no);
+ mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC);
/* whether driver is going to handle hot plug */
if (phy->phy_event & PHY_PLUG_OUT) {
mvs_port_notify_formed(&phy->sas_phy, 0);
--
2.29.2
Powered by blists - more mailing lists