Commit 02377779 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
parents f9e6e6d2 19bc5f2a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -878,6 +878,9 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
		payload_size = sizeof(purex->els_frame_payload);
	}

	if (total_bytes > sizeof(item->iocb.iocb))
		total_bytes = sizeof(item->iocb.iocb);

	pending_bytes = total_bytes;
	no_bytes = (pending_bytes > payload_size) ? payload_size :
		   pending_bytes;
@@ -1163,6 +1166,10 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,

	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
	    - PURX_ELS_HEADER_SIZE;

	if (total_bytes > sizeof(item->iocb.iocb))
		total_bytes = sizeof(item->iocb.iocb);

	pending_bytes = total_bytes;
	entry_count = entry_count_remaining = purex->entry_count;
	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
+10 −1
Original line number Diff line number Diff line
@@ -282,11 +282,20 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
{
	struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
	struct Scsi_Host *shost = scmd->device->host;
	unsigned int busy = scsi_host_busy(shost);
	unsigned int busy;
	unsigned long flags;

	spin_lock_irqsave(shost->host_lock, flags);
	shost->host_failed++;
	spin_unlock_irqrestore(shost->host_lock, flags);
	/*
	 * The counting of busy requests needs to occur after adding to
	 * host_failed or after the lock acquire for adding to host_failed
	 * to prevent a race with host unbusy and missing an eh wakeup.
	 */
	busy = scsi_host_busy(shost);

	spin_lock_irqsave(shost->host_lock, flags);
	scsi_eh_wakeup(shost, busy);
	spin_unlock_irqrestore(shost->host_lock, flags);
}
+8 −0
Original line number Diff line number Diff line
@@ -376,6 +376,14 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
	rcu_read_lock();
	__clear_bit(SCMD_STATE_INFLIGHT, &cmd->state);
	if (unlikely(scsi_host_in_recovery(shost))) {
		/*
		 * Ensure the clear of SCMD_STATE_INFLIGHT is visible to
		 * other CPUs before counting busy requests. Otherwise,
		 * reordering can cause CPUs to race and miss an eh wakeup
		 * when no CPU sees all busy requests as done or timed out.
		 */
		smp_mb();

		unsigned int busy = scsi_host_busy(shost);

		spin_lock_irqsave(shost->host_lock, flags);
+2 −1
Original line number Diff line number Diff line
@@ -1144,7 +1144,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
	 * The current SCSI handling on the host side does
	 * not correctly handle:
	 * INQUIRY command with page code parameter set to 0x80
	 * MODE_SENSE command with cmd[2] == 0x1c
	 * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c
	 * MAINTENANCE_IN is not supported by HyperV FC passthrough
	 *
	 * 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,

	if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
	   (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) ||
	   (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) ||
	   (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN &&
	   hv_dev_is_fc(device))) {
		vstor_packet->vm_srb.scsi_status = 0;
+8 −2
Original line number Diff line number Diff line
@@ -741,8 +741,11 @@ void iscsit_dec_session_usage_count(struct iscsit_session *sess)
	spin_lock_bh(&sess->session_usage_lock);
	sess->session_usage_count--;

	if (!sess->session_usage_count && sess->session_waiting_on_uc)
	if (!sess->session_usage_count && sess->session_waiting_on_uc) {
		spin_unlock_bh(&sess->session_usage_lock);
		complete(&sess->session_waiting_on_uc_comp);
		return;
	}

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

	if (!conn->conn_usage_count && conn->conn_waiting_on_uc)
	if (!conn->conn_usage_count && conn->conn_waiting_on_uc) {
		spin_unlock_bh(&conn->conn_usage_lock);
		complete(&conn->conn_waiting_on_uc_comp);
		return;
	}

	spin_unlock_bh(&conn->conn_usage_lock);
}
Loading