Skip to content

Commit 0237777

Browse files
committed
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "Only one core change, the rest are drivers. The core change reorders some state operations in the error handler to try to prevent missed wake ups of the error handler (which can halt error processing and effectively freeze the entire system)" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: qla2xxx: Sanitize payload size to prevent member overflow scsi: target: iscsi: Fix use-after-free in iscsit_dec_session_usage_count() scsi: target: iscsi: Fix use-after-free in iscsit_dec_conn_usage_count() scsi: core: Wake up the error handler when final completions race against each other scsi: storvsc: Process unsupported MODE_SENSE_10 scsi: xen: scsiback: Fix potential memory leak in scsiback_remove()
2 parents f9e6e6d + 19bc5f2 commit 0237777

File tree

6 files changed

+36
-4
lines changed

6 files changed

+36
-4
lines changed

drivers/scsi/qla2xxx/qla_isr.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,9 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
878878
payload_size = sizeof(purex->els_frame_payload);
879879
}
880880

881+
if (total_bytes > sizeof(item->iocb.iocb))
882+
total_bytes = sizeof(item->iocb.iocb);
883+
881884
pending_bytes = total_bytes;
882885
no_bytes = (pending_bytes > payload_size) ? payload_size :
883886
pending_bytes;
@@ -1163,6 +1166,10 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
11631166

11641167
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
11651168
- PURX_ELS_HEADER_SIZE;
1169+
1170+
if (total_bytes > sizeof(item->iocb.iocb))
1171+
total_bytes = sizeof(item->iocb.iocb);
1172+
11661173
pending_bytes = total_bytes;
11671174
entry_count = entry_count_remaining = purex->entry_count;
11681175
no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ?

drivers/scsi/scsi_error.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,20 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
282282
{
283283
struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
284284
struct Scsi_Host *shost = scmd->device->host;
285-
unsigned int busy = scsi_host_busy(shost);
285+
unsigned int busy;
286286
unsigned long flags;
287287

288288
spin_lock_irqsave(shost->host_lock, flags);
289289
shost->host_failed++;
290+
spin_unlock_irqrestore(shost->host_lock, flags);
291+
/*
292+
* The counting of busy requests needs to occur after adding to
293+
* host_failed or after the lock acquire for adding to host_failed
294+
* to prevent a race with host unbusy and missing an eh wakeup.
295+
*/
296+
busy = scsi_host_busy(shost);
297+
298+
spin_lock_irqsave(shost->host_lock, flags);
290299
scsi_eh_wakeup(shost, busy);
291300
spin_unlock_irqrestore(shost->host_lock, flags);
292301
}

drivers/scsi/scsi_lib.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,14 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
376376
rcu_read_lock();
377377
__clear_bit(SCMD_STATE_INFLIGHT, &cmd->state);
378378
if (unlikely(scsi_host_in_recovery(shost))) {
379+
/*
380+
* Ensure the clear of SCMD_STATE_INFLIGHT is visible to
381+
* other CPUs before counting busy requests. Otherwise,
382+
* reordering can cause CPUs to race and miss an eh wakeup
383+
* when no CPU sees all busy requests as done or timed out.
384+
*/
385+
smp_mb();
386+
379387
unsigned int busy = scsi_host_busy(shost);
380388

381389
spin_lock_irqsave(shost->host_lock, flags);

drivers/scsi/storvsc_drv.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
11441144
* The current SCSI handling on the host side does
11451145
* not correctly handle:
11461146
* INQUIRY command with page code parameter set to 0x80
1147-
* MODE_SENSE command with cmd[2] == 0x1c
1147+
* MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c
11481148
* MAINTENANCE_IN is not supported by HyperV FC passthrough
11491149
*
11501150
* Setup srb and scsi status so this won't be fatal.
@@ -1154,6 +1154,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
11541154

11551155
if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
11561156
(stor_pkt->vm_srb.cdb[0] == MODE_SENSE) ||
1157+
(stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) ||
11571158
(stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN &&
11581159
hv_dev_is_fc(device))) {
11591160
vstor_packet->vm_srb.scsi_status = 0;

drivers/target/iscsi/iscsi_target_util.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,11 @@ void iscsit_dec_session_usage_count(struct iscsit_session *sess)
741741
spin_lock_bh(&sess->session_usage_lock);
742742
sess->session_usage_count--;
743743

744-
if (!sess->session_usage_count && sess->session_waiting_on_uc)
744+
if (!sess->session_usage_count && sess->session_waiting_on_uc) {
745+
spin_unlock_bh(&sess->session_usage_lock);
745746
complete(&sess->session_waiting_on_uc_comp);
747+
return;
748+
}
746749

747750
spin_unlock_bh(&sess->session_usage_lock);
748751
}
@@ -810,8 +813,11 @@ void iscsit_dec_conn_usage_count(struct iscsit_conn *conn)
810813
spin_lock_bh(&conn->conn_usage_lock);
811814
conn->conn_usage_count--;
812815

813-
if (!conn->conn_usage_count && conn->conn_waiting_on_uc)
816+
if (!conn->conn_usage_count && conn->conn_waiting_on_uc) {
817+
spin_unlock_bh(&conn->conn_usage_lock);
814818
complete(&conn->conn_waiting_on_uc_comp);
819+
return;
820+
}
815821

816822
spin_unlock_bh(&conn->conn_usage_lock);
817823
}

drivers/xen/xen-scsiback.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,7 @@ static void scsiback_remove(struct xenbus_device *dev)
12621262
gnttab_page_cache_shrink(&info->free_pages, 0);
12631263

12641264
dev_set_drvdata(&dev->dev, NULL);
1265+
kfree(info);
12651266
}
12661267

12671268
static int scsiback_probe(struct xenbus_device *dev,

0 commit comments

Comments
 (0)