diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-05-31 08:45:08 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-05-31 08:45:08 -0700 |
| commit | 13bd441bb98e9cc91f9fb4449415e0519a0de7a9 (patch) | |
| tree | 25041ee4cfae04300db785d0aa69308ae4446335 /drivers/scsi | |
| parent | 9cf1afe6de1dc9dfced6070328626830794bac9d (diff) | |
| parent | 85db7391310b1304d2dc8ae3b0b12105a9567147 (diff) | |
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley:
"Two core changes, the only one of significance being the change to
kick queues in SDEV_CANCEL which had a small window for stuck
requests.
The major driver fixes are the one to the FC transport class to widen
the FPIN counter to counter a theoretical (and privileged) fabric
traffic injection attack and the other is an iscsi fix where a
malicious target could trick the kernel into an output buffer overrun.
Both the driver fixes were AI assisted"
* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
scsi: target: iscsi: Validate CHAP_R length before base64 decode
scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf
scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd()
scsi: fcoe: Reject FIP descriptors with zero fip_dlen in CVL walker
scsi: scsi_transport_fc: Widen FPIN pname walker counter to u32
scsi: scsi_debug: Add missing newline in scsi_debug_device_reset()
scsi: megaraid_sas: Fix NULL pointer dereference on firmware duplicate completion
scsi: devinfo: Add BLIST_NO_RSOC for Promise VTrak E310f
scsi: core: Run queues for all non-SDEV_DEL devices from scsi_run_host_queues
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/fcoe/fcoe_ctlr.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 9 | ||||
| -rw-r--r-- | drivers/scsi/scsi_debug.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/scsi_devinfo.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 27 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 77 |
6 files changed, 78 insertions, 40 deletions
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 02cd4410efca..496ddd45f74d 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1385,7 +1385,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, while (rlen >= sizeof(*desc)) { dlen = desc->fip_dlen * FIP_BPW; - if (dlen > rlen) + if (dlen < sizeof(*desc) || dlen > rlen) goto err; /* Drop CVL if there are duplicate critical descriptors */ if ((desc->fip_dtype < 32) && diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 2699e4e09b5b..056cbe50e19e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3612,6 +3612,15 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, complete(&cmd_fusion->done); break; case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ + /* + * Firmware can send stale/duplicate completions for + * commands already returned to the pool. scmd_local + * would be NULL for such cases. Skip processing to + * avoid NULL pointer access. + */ + if (!scmd_local) + break; + /* Update load balancing info */ if (fusion->load_balance_info && (megasas_priv(cmd_fusion->scmd)->status & diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1515495fd9ea..040c5e1e713a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6953,7 +6953,7 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) ++num_dev_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "doing device reset"); + sdev_printk(KERN_INFO, sdp, "doing device reset\n"); scsi_debug_stop_all_queued(sdp); if (devip) { diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 68a992494b12..c6defe1c3152 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -218,6 +218,7 @@ static struct { {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"Promise", "VTrak E310f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "", NULL, BLIST_SPARSELUN}, {"QEMU", "QEMU CD-ROM", NULL, BLIST_SKIP_VPD_PAGES}, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6e8c7a42603e..85eef401925a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -575,10 +575,33 @@ void scsi_requeue_run_queue(struct work_struct *work) void scsi_run_host_queues(struct Scsi_Host *shost) { - struct scsi_device *sdev; + struct scsi_device *sdev, *prev = NULL; + unsigned long flags; - shost_for_each_device(sdev, shost) + spin_lock_irqsave(shost->host_lock, flags); + __shost_for_each_device(sdev, shost) { + /* + * Only skip devices so deep into removal they will never need + * another kick to their queues. Thus scsi_device_get() cannot + * be used as it would skip devices in SDEV_CANCEL state which + * may need a queue kick. + */ + if (sdev->sdev_state == SDEV_DEL || + !get_device(&sdev->sdev_gendev)) + continue; + spin_unlock_irqrestore(shost->host_lock, flags); + + if (prev) + put_device(&prev->sdev_gendev); scsi_run_queue(sdev->request_queue); + + prev = sdev; + + spin_lock_irqsave(shost->host_lock, flags); + } + spin_unlock_irqrestore(shost->host_lock, flags); + if (prev) + put_device(&prev->sdev_gendev); } static void scsi_uninit_cmd(struct scsi_cmnd *cmd) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index dce95e361daf..173ed6373f04 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -737,6 +737,37 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats) } } +static void +fc_fpin_pname_stats_update(struct Scsi_Host *shost, + struct fc_rport *attach_rport, u16 event_type, + u32 desc_len, u32 fixed_len, u32 pname_count, + __be64 *pname_list, + void (*stats_update)(u16 event_type, + struct fc_fpin_stats *stats)) +{ + u32 i; + struct fc_rport *rport; + u64 wwpn; + + if (desc_len < fixed_len) + pname_count = 0; + else + pname_count = min(pname_count, (desc_len - fixed_len) / + sizeof(pname_list[0])); + + for (i = 0; i < pname_count; i++) { + wwpn = be64_to_cpu(pname_list[i]); + rport = fc_find_rport_by_wwpn(shost, wwpn); + if (rport && + (rport->roles & FC_PORT_ROLE_FCP_TARGET || + rport->roles & FC_PORT_ROLE_NVME_TARGET)) { + if (rport == attach_rport) + continue; + stats_update(event_type, &rport->fpin_stats); + } + } +} + /* * fc_fpin_li_stats_update - routine to update Link Integrity * event statistics. @@ -747,13 +778,11 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats) static void fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) { - u8 i; struct fc_rport *rport = NULL; struct fc_rport *attach_rport = NULL; struct fc_host_attrs *fc_host = shost_to_fc_host(shost); struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv; u16 event_type = be16_to_cpu(li_desc->event_type); - u64 wwpn; rport = fc_find_rport_by_wwpn(shost, be64_to_cpu(li_desc->attached_wwpn)); @@ -764,22 +793,11 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) fc_li_stats_update(event_type, &attach_rport->fpin_stats); } - if (be32_to_cpu(li_desc->pname_count) > 0) { - for (i = 0; - i < be32_to_cpu(li_desc->pname_count); - i++) { - wwpn = be64_to_cpu(li_desc->pname_list[i]); - rport = fc_find_rport_by_wwpn(shost, wwpn); - if (rport && - (rport->roles & FC_PORT_ROLE_FCP_TARGET || - rport->roles & FC_PORT_ROLE_NVME_TARGET)) { - if (rport == attach_rport) - continue; - fc_li_stats_update(event_type, - &rport->fpin_stats); - } - } - } + fc_fpin_pname_stats_update(shost, attach_rport, event_type, + be32_to_cpu(li_desc->desc_len), + FC_TLV_DESC_LENGTH_FROM_SZ(*li_desc), + be32_to_cpu(li_desc->pname_count), + li_desc->pname_list, fc_li_stats_update); if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn)) fc_li_stats_update(event_type, &fc_host->fpin_stats); @@ -827,13 +845,11 @@ static void fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv) { - u8 i; struct fc_rport *rport = NULL; struct fc_rport *attach_rport = NULL; struct fc_fn_peer_congn_desc *pc_desc = (struct fc_fn_peer_congn_desc *)tlv; u16 event_type = be16_to_cpu(pc_desc->event_type); - u64 wwpn; rport = fc_find_rport_by_wwpn(shost, be64_to_cpu(pc_desc->attached_wwpn)); @@ -844,22 +860,11 @@ fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost, fc_cn_stats_update(event_type, &attach_rport->fpin_stats); } - if (be32_to_cpu(pc_desc->pname_count) > 0) { - for (i = 0; - i < be32_to_cpu(pc_desc->pname_count); - i++) { - wwpn = be64_to_cpu(pc_desc->pname_list[i]); - rport = fc_find_rport_by_wwpn(shost, wwpn); - if (rport && - (rport->roles & FC_PORT_ROLE_FCP_TARGET || - rport->roles & FC_PORT_ROLE_NVME_TARGET)) { - if (rport == attach_rport) - continue; - fc_cn_stats_update(event_type, - &rport->fpin_stats); - } - } - } + fc_fpin_pname_stats_update(shost, attach_rport, event_type, + be32_to_cpu(pc_desc->desc_len), + FC_TLV_DESC_LENGTH_FROM_SZ(*pc_desc), + be32_to_cpu(pc_desc->pname_count), + pc_desc->pname_list, fc_cn_stats_update); } /* |
