]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 26 Aug 2013 18:56:04 +0000 (11:56 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 26 Aug 2013 18:56:04 +0000 (11:56 -0700)
added patches:
hostap-copying-wrong-data-prism2_ioctl_giwaplist.patch
libata-apply-behavioral-quirks-to-sil3826-pmp.patch
scsi-zfcp-fix-lock-imbalance-by-reworking-request-queue-locking.patch
zfcp-fix-schedule-inside-lock-in-scsi_device-list-loops.patch

queue-3.0/hostap-copying-wrong-data-prism2_ioctl_giwaplist.patch [new file with mode: 0644]
queue-3.0/libata-apply-behavioral-quirks-to-sil3826-pmp.patch [new file with mode: 0644]
queue-3.0/scsi-zfcp-fix-lock-imbalance-by-reworking-request-queue-locking.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/zfcp-fix-schedule-inside-lock-in-scsi_device-list-loops.patch [new file with mode: 0644]

diff --git a/queue-3.0/hostap-copying-wrong-data-prism2_ioctl_giwaplist.patch b/queue-3.0/hostap-copying-wrong-data-prism2_ioctl_giwaplist.patch
new file mode 100644 (file)
index 0000000..ca5359f
--- /dev/null
@@ -0,0 +1,34 @@
+From 909bd5926d474e275599094acad986af79671ac9 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Fri, 9 Aug 2013 12:52:31 +0300
+Subject: Hostap: copying wrong data prism2_ioctl_giwaplist()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 909bd5926d474e275599094acad986af79671ac9 upstream.
+
+We want the data stored in "addr" and "qual", but the extra ampersands
+mean we are copying stack data instead.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/hostap/hostap_ioctl.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/hostap/hostap_ioctl.c
++++ b/drivers/net/wireless/hostap/hostap_ioctl.c
+@@ -521,9 +521,9 @@ static int prism2_ioctl_giwaplist(struct
+       data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
+-      memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
++      memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
+       data->flags = 1; /* has quality information */
+-      memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
++      memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
+              sizeof(struct iw_quality) * data->length);
+       kfree(addr);
diff --git a/queue-3.0/libata-apply-behavioral-quirks-to-sil3826-pmp.patch b/queue-3.0/libata-apply-behavioral-quirks-to-sil3826-pmp.patch
new file mode 100644 (file)
index 0000000..a7fd1f8
--- /dev/null
@@ -0,0 +1,66 @@
+From 8ffff94d20b7eb446e848e0046107d51b17a20a8 Mon Sep 17 00:00:00 2001
+From: Terry Suereth <terry.suereth@gmail.com>
+Date: Sat, 17 Aug 2013 15:53:12 -0400
+Subject: libata: apply behavioral quirks to sil3826 PMP
+
+From: Terry Suereth <terry.suereth@gmail.com>
+
+commit 8ffff94d20b7eb446e848e0046107d51b17a20a8 upstream.
+
+Fixing support for the Silicon Image 3826 port multiplier, by applying
+to it the same quirks applied to the Silicon Image 3726.  Specifically
+fixes the repeated timeout/reset process which previously afflicted
+the 3726, as described from line 290.  Slightly based on notes from:
+
+https://bugzilla.redhat.com/show_bug.cgi?id=890237
+
+Signed-off-by: Terry Suereth <terry.suereth@gmail.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/ata/libata-pmp.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/ata/libata-pmp.c
++++ b/drivers/ata/libata-pmp.c
+@@ -288,24 +288,24 @@ static int sata_pmp_configure(struct ata
+       /* Disable sending Early R_OK.
+        * With "cached read" HDD testing and multiple ports busy on a SATA
+-       * host controller, 3726 PMP will very rarely drop a deferred
++       * host controller, 3x26 PMP will very rarely drop a deferred
+        * R_OK that was intended for the host. Symptom will be all
+        * 5 drives under test will timeout, get reset, and recover.
+        */
+-      if (vendor == 0x1095 && devid == 0x3726) {
++      if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
+               u32 reg;
+               err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
+               if (err_mask) {
+                       rc = -EIO;
+-                      reason = "failed to read Sil3726 Private Register";
++                      reason = "failed to read Sil3x26 Private Register";
+                       goto fail;
+               }
+               reg &= ~0x1;
+               err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
+               if (err_mask) {
+                       rc = -EIO;
+-                      reason = "failed to write Sil3726 Private Register";
++                      reason = "failed to write Sil3x26 Private Register";
+                       goto fail;
+               }
+       }
+@@ -383,8 +383,8 @@ static void sata_pmp_quirks(struct ata_p
+       u16 devid = sata_pmp_gscr_devid(gscr);
+       struct ata_link *link;
+-      if (vendor == 0x1095 && devid == 0x3726) {
+-              /* sil3726 quirks */
++      if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
++              /* sil3x26 quirks */
+               ata_for_each_link(link, ap, EDGE) {
+                       /* link reports offline after LPM */
+                       link->flags |= ATA_LFLAG_NO_LPM;
diff --git a/queue-3.0/scsi-zfcp-fix-lock-imbalance-by-reworking-request-queue-locking.patch b/queue-3.0/scsi-zfcp-fix-lock-imbalance-by-reworking-request-queue-locking.patch
new file mode 100644 (file)
index 0000000..dd7620b
--- /dev/null
@@ -0,0 +1,158 @@
+From d79ff142624e1be080ad8d09101f7004d79c36e1 Mon Sep 17 00:00:00 2001
+From: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+Date: Thu, 22 Aug 2013 17:45:36 +0200
+Subject: SCSI: zfcp: fix lock imbalance by reworking request queue locking
+
+From: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+
+commit d79ff142624e1be080ad8d09101f7004d79c36e1 upstream.
+
+This patch adds wait_event_interruptible_lock_irq_timeout(), which is a
+straight-forward descendant of wait_event_interruptible_timeout() and
+wait_event_interruptible_lock_irq().
+
+The zfcp driver used to call wait_event_interruptible_timeout()
+in combination with some intricate and error-prone locking. Using
+wait_event_interruptible_lock_irq_timeout() as a replacement
+nicely cleans up that locking.
+
+This rework removes a situation that resulted in a locking imbalance
+in zfcp_qdio_sbal_get():
+
+BUG: workqueue leaked lock or atomic: events/1/0xffffff00/10
+    last function: zfcp_fc_wka_port_offline+0x0/0xa0 [zfcp]
+
+It was introduced by commit c2af7545aaff3495d9bf9a7608c52f0af86fb194
+"[SCSI] zfcp: Do not wait for SBALs on stopped queue", which had a new
+code path related to ZFCP_STATUS_ADAPTER_QDIOUP that took an early exit
+without a required lock being held. The problem occured when a
+special, non-SCSI I/O request was being submitted in process context,
+when the adapter's queues had been torn down. In this case the bug
+surfaced when the Fibre Channel port connection for a well-known address
+was closed during a concurrent adapter shut-down procedure, which is a
+rare constellation.
+
+This patch also fixes these warnings from the sparse tool (make C=1):
+
+drivers/s390/scsi/zfcp_qdio.c:224:12: warning: context imbalance in
+ 'zfcp_qdio_sbal_check' - wrong count at exit
+drivers/s390/scsi/zfcp_qdio.c:244:5: warning: context imbalance in
+ 'zfcp_qdio_sbal_get' - unexpected unlock
+
+Last but not least, we get rid of that crappy lock-unlock-lock
+sequence at the beginning of the critical section.
+
+It is okay to call zfcp_erp_adapter_reopen() with req_q_lock held.
+
+Reported-by: Mikulas Patocka <mpatocka@redhat.com>
+Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com>
+Signed-off-by: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/s390/scsi/zfcp_qdio.c |    8 +----
+ include/linux/wait.h          |   57 ++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 6 deletions(-)
+
+--- a/drivers/s390/scsi/zfcp_qdio.c
++++ b/drivers/s390/scsi/zfcp_qdio.c
+@@ -199,11 +199,9 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_
+ static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
+ {
+-      spin_lock_irq(&qdio->req_q_lock);
+       if (atomic_read(&qdio->req_q_free) ||
+           !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+               return 1;
+-      spin_unlock_irq(&qdio->req_q_lock);
+       return 0;
+ }
+@@ -221,9 +219,8 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio
+ {
+       long ret;
+-      spin_unlock_irq(&qdio->req_q_lock);
+-      ret = wait_event_interruptible_timeout(qdio->req_q_wq,
+-                             zfcp_qdio_sbal_check(qdio), 5 * HZ);
++      ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq,
++                     zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ);
+       if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+               return -EIO;
+@@ -237,7 +234,6 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio
+               zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
+       }
+-      spin_lock_irq(&qdio->req_q_lock);
+       return -EIO;
+ }
+--- a/include/linux/wait.h
++++ b/include/linux/wait.h
+@@ -530,6 +530,63 @@ do {                                                                      \
+        ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1))
++#define __wait_event_interruptible_lock_irq_timeout(wq, condition,    \
++                                                  lock, ret)          \
++do {                                                                  \
++      DEFINE_WAIT(__wait);                                            \
++                                                                      \
++      for (;;) {                                                      \
++              prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);      \
++              if (condition)                                          \
++                      break;                                          \
++              if (signal_pending(current)) {                          \
++                      ret = -ERESTARTSYS;                             \
++                      break;                                          \
++              }                                                       \
++              spin_unlock_irq(&lock);                                 \
++              ret = schedule_timeout(ret);                            \
++              spin_lock_irq(&lock);                                   \
++              if (!ret)                                               \
++                      break;                                          \
++      }                                                               \
++      finish_wait(&wq, &__wait);                                      \
++} while (0)
++
++/**
++ * wait_event_interruptible_lock_irq_timeout - sleep until a condition gets true or a timeout elapses.
++ *            The condition is checked under the lock. This is expected
++ *            to be called with the lock taken.
++ * @wq: the waitqueue to wait on
++ * @condition: a C expression for the event to wait for
++ * @lock: a locked spinlock_t, which will be released before schedule()
++ *      and reacquired afterwards.
++ * @timeout: timeout, in jiffies
++ *
++ * The process is put to sleep (TASK_INTERRUPTIBLE) until the
++ * @condition evaluates to true or signal is received. The @condition is
++ * checked each time the waitqueue @wq is woken up.
++ *
++ * wake_up() has to be called after changing any variable that could
++ * change the result of the wait condition.
++ *
++ * This is supposed to be called while holding the lock. The lock is
++ * dropped before going to sleep and is reacquired afterwards.
++ *
++ * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it
++ * was interrupted by a signal, and the remaining jiffies otherwise
++ * if the condition evaluated to true before the timeout elapsed.
++ */
++#define wait_event_interruptible_lock_irq_timeout(wq, condition, lock,        \
++                                                timeout)              \
++({                                                                    \
++      int __ret = timeout;                                            \
++                                                                      \
++      if (!(condition))                                               \
++              __wait_event_interruptible_lock_irq_timeout(            \
++                                      wq, condition, lock, __ret);    \
++      __ret;                                                          \
++})
++
+ #define __wait_event_killable(wq, condition, ret)                     \
+ do {                                                                  \
index 2f2a79fa179115dc6f63c07270316532052f641a..6f9d602d27418d762ba8401de50d74759c077fd2 100644 (file)
@@ -3,3 +3,7 @@ xen-events-initialize-local-per-cpu-mask-for-all-possible-events.patch
 of-fdt-fix-memory-initialization-for-expanded-dt.patch
 nilfs2-remove-double-bio_put-in-nilfs_end_bio_write-for-bio_eopnotsupp-error.patch
 nilfs2-fix-issue-with-counting-number-of-bio-requests-for-bio_eopnotsupp-error-detection.patch
+hostap-copying-wrong-data-prism2_ioctl_giwaplist.patch
+libata-apply-behavioral-quirks-to-sil3826-pmp.patch
+scsi-zfcp-fix-lock-imbalance-by-reworking-request-queue-locking.patch
+zfcp-fix-schedule-inside-lock-in-scsi_device-list-loops.patch
diff --git a/queue-3.0/zfcp-fix-schedule-inside-lock-in-scsi_device-list-loops.patch b/queue-3.0/zfcp-fix-schedule-inside-lock-in-scsi_device-list-loops.patch
new file mode 100644 (file)
index 0000000..4abbbab
--- /dev/null
@@ -0,0 +1,170 @@
+From 924dd584b198a58aa7cb3efefd8a03326550ce8f Mon Sep 17 00:00:00 2001
+From: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+Date: Thu, 22 Aug 2013 17:45:37 +0200
+Subject: SCSI: zfcp: fix schedule-inside-lock in scsi_device list loops
+
+From: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+
+commit 924dd584b198a58aa7cb3efefd8a03326550ce8f upstream.
+
+BUG: sleeping function called from invalid context at kernel/workqueue.c:2752
+in_atomic(): 1, irqs_disabled(): 1, pid: 360, name: zfcperp0.0.1700
+CPU: 1 Not tainted 3.9.3+ #69
+Process zfcperp0.0.1700 (pid: 360, task: 0000000075b7e080, ksp: 000000007476bc30)
+<snip>
+Call Trace:
+([<00000000001165de>] show_trace+0x106/0x154)
+ [<00000000001166a0>] show_stack+0x74/0xf4
+ [<00000000006ff646>] dump_stack+0xc6/0xd4
+ [<000000000017f3a0>] __might_sleep+0x128/0x148
+ [<000000000015ece8>] flush_work+0x54/0x1f8
+ [<00000000001630de>] __cancel_work_timer+0xc6/0x128
+ [<00000000005067ac>] scsi_device_dev_release_usercontext+0x164/0x23c
+ [<0000000000161816>] execute_in_process_context+0x96/0xa8
+ [<00000000004d33d8>] device_release+0x60/0xc0
+ [<000000000048af48>] kobject_release+0xa8/0x1c4
+ [<00000000004f4bf2>] __scsi_iterate_devices+0xfa/0x130
+ [<000003ff801b307a>] zfcp_erp_strategy+0x4da/0x1014 [zfcp]
+ [<000003ff801b3caa>] zfcp_erp_thread+0xf6/0x2b0 [zfcp]
+ [<000000000016b75a>] kthread+0xf2/0xfc
+ [<000000000070c9de>] kernel_thread_starter+0x6/0xc
+ [<000000000070c9d8>] kernel_thread_starter+0x0/0xc
+
+Apparently, the ref_count for some scsi_device drops down to zero,
+triggering device removal through execute_in_process_context(), while
+the lldd error recovery thread iterates through a scsi device list.
+Unfortunately, execute_in_process_context() decides to immediately
+execute that device removal function, instead of scheduling asynchronous
+execution, since it detects process context and thinks it is safe to do
+so. But almost all calls to shost_for_each_device() in our lldd are
+inside spin_lock_irq, even in thread context. Obviously, schedule()
+inside spin_lock_irq sections is a bad idea.
+
+Change the lldd to use the proper iterator function,
+__shost_for_each_device(), in combination with required locking.
+
+Occurences that need to be changed include all calls in zfcp_erp.c,
+since those might be executed in zfcp error recovery thread context
+with a lock held.
+
+Other occurences of shost_for_each_device() in zfcp_fsf.c do not
+need to be changed (no process context, no surrounding locking).
+
+The problem was introduced in Linux 2.6.37 by commit
+b62a8d9b45b971a67a0f8413338c230e3117dff5
+"[SCSI] zfcp: Use SCSI device data zfcp_scsi_dev instead of zfcp_unit".
+
+Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Signed-off-by: Martin Peschke <mpeschke@linux.vnet.ibm.com>
+Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/s390/scsi/zfcp_erp.c |   29 ++++++++++++++++++++++-------
+ 1 file changed, 22 insertions(+), 7 deletions(-)
+
+--- a/drivers/s390/scsi/zfcp_erp.c
++++ b/drivers/s390/scsi/zfcp_erp.c
+@@ -102,10 +102,13 @@ static void zfcp_erp_action_dismiss_port
+       if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
+               zfcp_erp_action_dismiss(&port->erp_action);
+-      else
+-              shost_for_each_device(sdev, port->adapter->scsi_host)
++      else {
++              spin_lock(port->adapter->scsi_host->host_lock);
++              __shost_for_each_device(sdev, port->adapter->scsi_host)
+                       if (sdev_to_zfcp(sdev)->port == port)
+                               zfcp_erp_action_dismiss_lun(sdev);
++              spin_unlock(port->adapter->scsi_host->host_lock);
++      }
+ }
+ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
+@@ -592,9 +595,11 @@ static void _zfcp_erp_lun_reopen_all(str
+ {
+       struct scsi_device *sdev;
+-      shost_for_each_device(sdev, port->adapter->scsi_host)
++      spin_lock(port->adapter->scsi_host->host_lock);
++      __shost_for_each_device(sdev, port->adapter->scsi_host)
+               if (sdev_to_zfcp(sdev)->port == port)
+                       _zfcp_erp_lun_reopen(sdev, clear, id, 0);
++      spin_unlock(port->adapter->scsi_host->host_lock);
+ }
+ static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
+@@ -1435,8 +1440,10 @@ void zfcp_erp_set_adapter_status(struct
+               atomic_set_mask(common_mask, &port->status);
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
+-      shost_for_each_device(sdev, adapter->scsi_host)
++      spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
++      __shost_for_each_device(sdev, adapter->scsi_host)
+               atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
++      spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
+ }
+ /**
+@@ -1470,11 +1477,13 @@ void zfcp_erp_clear_adapter_status(struc
+       }
+       read_unlock_irqrestore(&adapter->port_list_lock, flags);
+-      shost_for_each_device(sdev, adapter->scsi_host) {
++      spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
++      __shost_for_each_device(sdev, adapter->scsi_host) {
+               atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
+               if (clear_counter)
+                       atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
+       }
++      spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
+ }
+ /**
+@@ -1488,16 +1497,19 @@ void zfcp_erp_set_port_status(struct zfc
+ {
+       struct scsi_device *sdev;
+       u32 common_mask = mask & ZFCP_COMMON_FLAGS;
++      unsigned long flags;
+       atomic_set_mask(mask, &port->status);
+       if (!common_mask)
+               return;
+-      shost_for_each_device(sdev, port->adapter->scsi_host)
++      spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
++      __shost_for_each_device(sdev, port->adapter->scsi_host)
+               if (sdev_to_zfcp(sdev)->port == port)
+                       atomic_set_mask(common_mask,
+                                       &sdev_to_zfcp(sdev)->status);
++      spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
+ }
+ /**
+@@ -1512,6 +1524,7 @@ void zfcp_erp_clear_port_status(struct z
+       struct scsi_device *sdev;
+       u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+       u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
++      unsigned long flags;
+       atomic_clear_mask(mask, &port->status);
+@@ -1521,13 +1534,15 @@ void zfcp_erp_clear_port_status(struct z
+       if (clear_counter)
+               atomic_set(&port->erp_counter, 0);
+-      shost_for_each_device(sdev, port->adapter->scsi_host)
++      spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
++      __shost_for_each_device(sdev, port->adapter->scsi_host)
+               if (sdev_to_zfcp(sdev)->port == port) {
+                       atomic_clear_mask(common_mask,
+                                         &sdev_to_zfcp(sdev)->status);
+                       if (clear_counter)
+                               atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
+               }
++      spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
+ }
+ /**