From: Greg Kroah-Hartman Date: Tue, 27 Jan 2015 18:34:03 +0000 (-0800) Subject: 3.10-stable patches X-Git-Tag: v3.10.67~42 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ac60d7ffdb628a113184684687c71a8c75dab8f;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: ipr-wait-for-aborted-command-responses.patch --- diff --git a/queue-3.10/ipr-wait-for-aborted-command-responses.patch b/queue-3.10/ipr-wait-for-aborted-command-responses.patch new file mode 100644 index 00000000000..a3c5d5ba8b2 --- /dev/null +++ b/queue-3.10/ipr-wait-for-aborted-command-responses.patch @@ -0,0 +1,183 @@ +From 6cdb08172bc89f0a39e1643c5e7eab362692fd1b Mon Sep 17 00:00:00 2001 +From: Brian King +Date: Thu, 30 Oct 2014 17:27:10 -0500 +Subject: ipr: wait for aborted command responses + +From: Brian King + +commit 6cdb08172bc89f0a39e1643c5e7eab362692fd1b upstream. + +Fixes a race condition in abort handling that was injected +when multiple interrupt support was added. When only a single +interrupt is present, the adapter guarantees it will send +responses for aborted commands prior to the response for the +abort command itself. With multiple interrupts, these responses +generally come back on different interrupts, so we need to +ensure the abort thread waits until the aborted command is +complete so we don't perform a double completion. This race +condition was being hit frequently in environments which +were triggering command timeouts, which was resulting in +a double completion causing a kernel oops. + +Signed-off-by: Brian King +Reviewed-by: Wendy Xiong +Tested-by: Wendy Xiong +Signed-off-by: Christoph Hellwig +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/ipr.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/scsi/ipr.h | 1 + 2 files changed, 93 insertions(+) + +--- a/drivers/scsi/ipr.c ++++ b/drivers/scsi/ipr.c +@@ -645,6 +645,7 @@ static void ipr_init_ipr_cmnd(struct ipr + ipr_reinit_ipr_cmnd(ipr_cmd); + ipr_cmd->u.scratch = 0; + ipr_cmd->sibling = NULL; ++ ipr_cmd->eh_comp = NULL; + ipr_cmd->fast_done = fast_done; + init_timer(&ipr_cmd->timer); + } +@@ -810,6 +811,8 @@ static void ipr_scsi_eh_done(struct ipr_ + + scsi_dma_unmap(ipr_cmd->scsi_cmd); + scsi_cmd->scsi_done(scsi_cmd); ++ if (ipr_cmd->eh_comp) ++ complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); + } + +@@ -4767,6 +4770,84 @@ static int ipr_slave_alloc(struct scsi_d + return rc; + } + ++/** ++ * ipr_match_lun - Match function for specified LUN ++ * @ipr_cmd: ipr command struct ++ * @device: device to match (sdev) ++ * ++ * Returns: ++ * 1 if command matches sdev / 0 if command does not match sdev ++ **/ ++static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device) ++{ ++ if (ipr_cmd->scsi_cmd && ipr_cmd->scsi_cmd->device == device) ++ return 1; ++ return 0; ++} ++ ++/** ++ * ipr_wait_for_ops - Wait for matching commands to complete ++ * @ipr_cmd: ipr command struct ++ * @device: device to match (sdev) ++ * @match: match function to use ++ * ++ * Returns: ++ * SUCCESS / FAILED ++ **/ ++static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, ++ int (*match)(struct ipr_cmnd *, void *)) ++{ ++ struct ipr_cmnd *ipr_cmd; ++ int wait; ++ unsigned long flags; ++ struct ipr_hrr_queue *hrrq; ++ signed long timeout = IPR_ABORT_TASK_TIMEOUT; ++ DECLARE_COMPLETION_ONSTACK(comp); ++ ++ ENTER; ++ do { ++ wait = 0; ++ ++ for_each_hrrq(hrrq, ioa_cfg) { ++ spin_lock_irqsave(hrrq->lock, flags); ++ list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { ++ if (match(ipr_cmd, device)) { ++ ipr_cmd->eh_comp = ∁ ++ wait++; ++ } ++ } ++ spin_unlock_irqrestore(hrrq->lock, flags); ++ } ++ ++ if (wait) { ++ timeout = wait_for_completion_timeout(&comp, timeout); ++ ++ if (!timeout) { ++ wait = 0; ++ ++ for_each_hrrq(hrrq, ioa_cfg) { ++ spin_lock_irqsave(hrrq->lock, flags); ++ list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { ++ if (match(ipr_cmd, device)) { ++ ipr_cmd->eh_comp = NULL; ++ wait++; ++ } ++ } ++ spin_unlock_irqrestore(hrrq->lock, flags); ++ } ++ ++ if (wait) ++ dev_err(&ioa_cfg->pdev->dev, "Timed out waiting for aborted commands\n"); ++ LEAVE; ++ return wait ? FAILED : SUCCESS; ++ } ++ } ++ } while (wait); ++ ++ LEAVE; ++ return SUCCESS; ++} ++ + static int ipr_eh_host_reset(struct scsi_cmnd *cmd) + { + struct ipr_ioa_cfg *ioa_cfg; +@@ -4985,11 +5066,17 @@ static int __ipr_eh_dev_reset(struct scs + static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) + { + int rc; ++ struct ipr_ioa_cfg *ioa_cfg; ++ ++ ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata; + + spin_lock_irq(cmd->device->host->host_lock); + rc = __ipr_eh_dev_reset(cmd); + spin_unlock_irq(cmd->device->host->host_lock); + ++ if (rc == SUCCESS) ++ rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); ++ + return rc; + } + +@@ -5167,13 +5254,18 @@ static int ipr_eh_abort(struct scsi_cmnd + { + unsigned long flags; + int rc; ++ struct ipr_ioa_cfg *ioa_cfg; + + ENTER; + ++ ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; ++ + spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); + rc = ipr_cancel_op(scsi_cmd); + spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); + ++ if (rc == SUCCESS) ++ rc = ipr_wait_for_ops(ioa_cfg, scsi_cmd->device, ipr_match_lun); + LEAVE; + return rc; + } +--- a/drivers/scsi/ipr.h ++++ b/drivers/scsi/ipr.h +@@ -1578,6 +1578,7 @@ struct ipr_cmnd { + struct scsi_device *sdev; + } u; + ++ struct completion *eh_comp; + struct ipr_hrr_queue *hrrq; + struct ipr_ioa_cfg *ioa_cfg; + }; diff --git a/queue-3.10/series b/queue-3.10/series index 483b06a7e0b..2ac186032bf 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -5,3 +5,4 @@ libata-prevent-hsm-state-change-race-between-isr-and-pio.patch alsa-usb-audio-add-mic-volume-fix-quirk-for-logitech-webcam-c210.patch scripts-recordmcount.pl-there-is-no-m32-gcc-option-on-super-h-anymore.patch drm-i915-fix-mutex-owner-inspection-race-under-debug_mutexes.patch +ipr-wait-for-aborted-command-responses.patch