]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Jan 2015 18:34:03 +0000 (10:34 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Jan 2015 18:34:03 +0000 (10:34 -0800)
added patches:
ipr-wait-for-aborted-command-responses.patch

queue-3.10/ipr-wait-for-aborted-command-responses.patch [new file with mode: 0644]
queue-3.10/series

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 (file)
index 0000000..a3c5d5b
--- /dev/null
@@ -0,0 +1,183 @@
+From 6cdb08172bc89f0a39e1643c5e7eab362692fd1b Mon Sep 17 00:00:00 2001
+From: Brian King <brking@linux.vnet.ibm.com>
+Date: Thu, 30 Oct 2014 17:27:10 -0500
+Subject: ipr: wait for aborted command responses
+
+From: Brian King <brking@linux.vnet.ibm.com>
+
+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 <brking@linux.vnet.ibm.com>
+Reviewed-by: Wendy Xiong <wenxiong@linux.vnet.ibm.com>
+Tested-by: Wendy Xiong <wenxiong@linux.vnet.ibm.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 = &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;
+ };
index 483b06a7e0bb4a0945c5732749e1a6aef7cce107..2ac186032bfa5dc3870f37c5f63c7ceac24a643c 100644 (file)
@@ -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