diff options
| author | Ranjan Kumar <ranjan.kumar@broadcom.com> | 2026-09-16 13:57:03 +0530 |
|---|---|---|
| committer | Martin K. Petersen (Oracle) <mkp@kernel.org> | 2026-09-16 22:14:23 -0400 |
| commit | 29e3f0856e8544ca185be3403518a102e0ca29fc (patch) | |
| tree | 4fa7e50f80936755c1e3a5d1b96cf2810559818a /drivers/scsi | |
| parent | 59f8c361872df3df9c47ad612a4562cd08441cc5 (diff) | |
| download | linux-next-29e3f0856e8544ca185be3403518a102e0ca29fc.tar.gz linux-next-29e3f0856e8544ca185be3403518a102e0ca29fc.zip | |
scsi: mpi3mr: Fix SAS port allocation and registration error handling
During SAS port creation, the driver does not verify successful port
allocation before attempting registration, which can lead to a NULL pointer
dereference. Additionally, if registration fails, the allocated port is not
freed, resulting in a memory leak.
Fix this by adding a NULL check after allocation and freeing the port when
registration fails.
Additional fixes in the error handling path include:
1. Fixing similar missing NULL checks for rphy allocations.
2. Cleaning up after a failed rphy registration tried to remove a device
that was never added, causing a crash. The rphy is now freed directly
instead.
3. A failed rphy registration left the target device with a dangling
pointer and a stuck pending flag. Both are now cleared.
4. Phys removed on error kept an internal flag set, permanently blocking
them from being added to a port again. Now cleared alongside the list
removal.
5. Could block in the SCSI mid-layer after a stop or reset had already
begun, the same ABBA deadlock class fixed elsewhere. The port
allocation path now stops before that call once that is detected.
6. The same reset check on the port removal path caused a memory leak and
a kernel BUG() on rediscovery.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=8
Closes: https://sashiko.dev/#/patchset/20260708183305.244485-1-ranjan.kumar@broadcom.com?part=8
Closes: https://sashiko.dev/#/patchset/20260724102505.115136-1-ranjan.kumar@broadcom.com?part=8
Closes: https://sashiko.dev/#/patchset/20260805110634.346670-1-ranjan.kumar@broadcom.com?part=8
Co-developed-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Link: https://patch.msgid.link/20260916082705.44712-9-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/mpi3mr/mpi3mr_transport.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index be794fe8eb7d..0dacfae6fa9d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -1436,9 +1436,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, } port = sas_port_alloc_num(mr_sas_node->parent_dev); + if (!port) { + ioc_err(mrioc, "failure at %s:%d/%s() (sas_port_alloc)!\n", + __FILE__, __LINE__, __func__); + goto out_fail; + } if ((sas_port_add(port))) { ioc_err(mrioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + sas_port_free(port); goto out_fail; } @@ -1458,14 +1464,32 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, mr_sas_port->port = port; if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) { rphy = sas_end_device_alloc(port); + if (!rphy) { + ioc_err(mrioc, "failure at %s:%d/%s() (sas_end_device_alloc)!\n", + __FILE__, __LINE__, __func__); + sas_port_delete(port); + goto out_fail; + } tgtdev->dev_spec.sas_sata_inf.rphy = rphy; } else { rphy = sas_expander_alloc(port, mr_sas_port->remote_identify.device_type); + if (!rphy) { + ioc_err(mrioc, "failure at %s:%d/%s() (sas_expander_alloc)!\n", + __FILE__, __LINE__, __func__); + sas_port_delete(port); + goto out_fail; + } } rphy->identify = mr_sas_port->remote_identify; spin_lock_irqsave(&mrioc->fwevt_lock, flags); + if (mrioc->stop_drv_processing || mrioc->reset_in_progress) { + spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); + sas_rphy_free(rphy); + sas_port_delete(port); + goto out_fail; + } if (mrioc->current_event) mrioc->current_event->pending_at_sml = 1; spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); @@ -1473,6 +1497,18 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, if ((sas_rphy_add(rphy))) { ioc_err(mrioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + spin_lock_irqsave(&mrioc->fwevt_lock, flags); + if (mrioc->current_event) { + mrioc->current_event->pending_at_sml = 0; + discard = mrioc->current_event->discard; + } + spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); + if (discard) + mpi3mr_print_device_event_notice(mrioc, true); + sas_rphy_unlink(rphy); + sas_rphy_free(rphy); + sas_port_delete(port); + goto out_fail; } if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) { tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0; @@ -1511,9 +1547,17 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, return mr_sas_port; out_fail: + if (tgtdev) { + tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0; + tgtdev->dev_spec.sas_sata_inf.rphy = NULL; + mpi3mr_tgtdev_put(tgtdev); + } + list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list, - port_siblings) + port_siblings) { + mr_sas_phy->phy_belongs_to_port = 0; list_del(&mr_sas_phy->port_siblings); + } kfree(mr_sas_port); return NULL; } |
