]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Nov 2012 13:41:39 +0000 (14:41 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Nov 2012 13:41:39 +0000 (14:41 +0100)
added patches:
iscsi-target-fix-missed-wakeup-race-in-tx-thread.patch
rt2800-validate-step-value-for-temperature-compensation.patch
target-avoid-integer-overflow-in-se_dev_align_max_sectors.patch
target-don-t-return-success-from-module_init-if-setup-fails.patch
target-fix-incorrect-usage-of-nested-irq-spinlocks-in-abort_task-path.patch

queue-3.4/iscsi-target-fix-missed-wakeup-race-in-tx-thread.patch [new file with mode: 0644]
queue-3.4/rt2800-validate-step-value-for-temperature-compensation.patch [new file with mode: 0644]
queue-3.4/series
queue-3.4/target-avoid-integer-overflow-in-se_dev_align_max_sectors.patch [new file with mode: 0644]
queue-3.4/target-don-t-return-success-from-module_init-if-setup-fails.patch [new file with mode: 0644]
queue-3.4/target-fix-incorrect-usage-of-nested-irq-spinlocks-in-abort_task-path.patch [new file with mode: 0644]

diff --git a/queue-3.4/iscsi-target-fix-missed-wakeup-race-in-tx-thread.patch b/queue-3.4/iscsi-target-fix-missed-wakeup-race-in-tx-thread.patch
new file mode 100644 (file)
index 0000000..ba25976
--- /dev/null
@@ -0,0 +1,130 @@
+From d5627acba9ae584cf4928af19f7ddf5f6837de32 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Wed, 31 Oct 2012 09:16:46 -0700
+Subject: iscsi-target: Fix missed wakeup race in TX thread
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit d5627acba9ae584cf4928af19f7ddf5f6837de32 upstream.
+
+The sleeping code in iscsi_target_tx_thread() is susceptible to the classic
+missed wakeup race:
+
+ - TX thread finishes handle_immediate_queue() and handle_response_queue(),
+   thinks both queues are empty.
+ - Another thread adds a queue entry and does wake_up_process(), which does
+   nothing because the TX thread is still awake.
+ - TX thread does schedule_timeout() and sleeps forever.
+
+In practice this can kill an iSCSI connection if for example an initiator
+does single-threaded writes and the target misses the wakeup window when
+queueing an R2T; in this case the connection will be stuck until the
+initiator loses patience and does some task management operation (or kills
+the connection entirely).
+
+Fix this by converting to wait_event_interruptible(), which does not
+suffer from this sort of race.
+
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Cc: Andy Grover <agrover@redhat.com>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/iscsi/iscsi_target.c       |    4 +++-
+ drivers/target/iscsi/iscsi_target_core.h  |    1 +
+ drivers/target/iscsi/iscsi_target_login.c |    1 +
+ drivers/target/iscsi/iscsi_target_util.c  |   22 ++++++++++++++++++++--
+ drivers/target/iscsi/iscsi_target_util.h  |    1 +
+ 5 files changed, 26 insertions(+), 3 deletions(-)
+
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -3514,7 +3514,9 @@ restart:
+                */
+               iscsit_thread_check_cpumask(conn, current, 1);
+-              schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
++              wait_event_interruptible(conn->queues_wq,
++                                       !iscsit_conn_all_queues_empty(conn) ||
++                                       ts->status == ISCSI_THREAD_SET_RESET);
+               if ((ts->status == ISCSI_THREAD_SET_RESET) ||
+                    signal_pending(current))
+--- a/drivers/target/iscsi/iscsi_target_core.h
++++ b/drivers/target/iscsi/iscsi_target_core.h
+@@ -491,6 +491,7 @@ struct iscsi_tmr_req {
+ };
+ struct iscsi_conn {
++      wait_queue_head_t       queues_wq;
+       /* Authentication Successful for this connection */
+       u8                      auth_complete;
+       /* State connection is currently in */
+--- a/drivers/target/iscsi/iscsi_target_login.c
++++ b/drivers/target/iscsi/iscsi_target_login.c
+@@ -45,6 +45,7 @@ extern spinlock_t sess_idr_lock;
+ static int iscsi_login_init_conn(struct iscsi_conn *conn)
+ {
++      init_waitqueue_head(&conn->queues_wq);
+       INIT_LIST_HEAD(&conn->conn_list);
+       INIT_LIST_HEAD(&conn->conn_cmd_list);
+       INIT_LIST_HEAD(&conn->immed_queue_list);
+--- a/drivers/target/iscsi/iscsi_target_util.c
++++ b/drivers/target/iscsi/iscsi_target_util.c
+@@ -656,7 +656,7 @@ void iscsit_add_cmd_to_immediate_queue(
+       atomic_set(&conn->check_immediate_queue, 1);
+       spin_unlock_bh(&conn->immed_queue_lock);
+-      wake_up_process(conn->thread_set->tx_thread);
++      wake_up(&conn->queues_wq);
+ }
+ struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
+@@ -730,7 +730,7 @@ void iscsit_add_cmd_to_response_queue(
+       atomic_inc(&cmd->response_queue_count);
+       spin_unlock_bh(&conn->response_queue_lock);
+-      wake_up_process(conn->thread_set->tx_thread);
++      wake_up(&conn->queues_wq);
+ }
+ struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
+@@ -784,6 +784,24 @@ static void iscsit_remove_cmd_from_respo
+       }
+ }
++bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
++{
++      bool empty;
++
++      spin_lock_bh(&conn->immed_queue_lock);
++      empty = list_empty(&conn->immed_queue_list);
++      spin_unlock_bh(&conn->immed_queue_lock);
++
++      if (!empty)
++              return empty;
++
++      spin_lock_bh(&conn->response_queue_lock);
++      empty = list_empty(&conn->response_queue_list);
++      spin_unlock_bh(&conn->response_queue_lock);
++
++      return empty;
++}
++
+ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
+ {
+       struct iscsi_queue_req *qr, *qr_tmp;
+--- a/drivers/target/iscsi/iscsi_target_util.h
++++ b/drivers/target/iscsi/iscsi_target_util.h
+@@ -28,6 +28,7 @@ extern struct iscsi_queue_req *iscsit_ge
+ extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
+ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *);
+ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
++extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
+ extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
+ extern void iscsit_release_cmd(struct iscsi_cmd *);
+ extern void iscsit_free_cmd(struct iscsi_cmd *);
diff --git a/queue-3.4/rt2800-validate-step-value-for-temperature-compensation.patch b/queue-3.4/rt2800-validate-step-value-for-temperature-compensation.patch
new file mode 100644 (file)
index 0000000..5d41a67
--- /dev/null
@@ -0,0 +1,34 @@
+From bf7e1abe434ba9e22e8dc04a4cba4ab504b788b8 Mon Sep 17 00:00:00 2001
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+Date: Thu, 25 Oct 2012 09:51:39 +0200
+Subject: rt2800: validate step value for temperature compensation
+
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+
+commit bf7e1abe434ba9e22e8dc04a4cba4ab504b788b8 upstream.
+
+Some hardware has correct (!= 0xff) value of tssi_bounds[4] in the
+EEPROM, but step is equal to 0xff. This results on ridiculous delta
+calculations and completely broke TX power settings.
+
+Reported-and-tested-by: Pavel Lucik <pavel.lucik@gmail.com>
+Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/rt2x00/rt2800lib.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -2235,7 +2235,7 @@ static int rt2800_get_gain_calibration_d
+       /*
+        * Check if temperature compensation is supported.
+        */
+-      if (tssi_bounds[4] == 0xff)
++      if (tssi_bounds[4] == 0xff || step == 0xff)
+               return 0;
+       /*
index 462ec612a996f5c3c851cc9a876e12f8b95b4f7d..465996b8f07ca39be6a06445a8b568453bd2a52e 100644 (file)
@@ -3,3 +3,8 @@ xen-mmu-use-xen-specific-tlb-flush-instead-of-the-generic-one.patch
 input-tsc40-remove-wrong-announcement-of-pressure-support.patch
 ath9k-fix-stale-pointers-potentially-causing-access-to-free-d-skbs.patch
 ath9k-test-for-tid-only-in-blockacks-while-checking-tx-status.patch
+rt2800-validate-step-value-for-temperature-compensation.patch
+target-don-t-return-success-from-module_init-if-setup-fails.patch
+target-avoid-integer-overflow-in-se_dev_align_max_sectors.patch
+iscsi-target-fix-missed-wakeup-race-in-tx-thread.patch
+target-fix-incorrect-usage-of-nested-irq-spinlocks-in-abort_task-path.patch
diff --git a/queue-3.4/target-avoid-integer-overflow-in-se_dev_align_max_sectors.patch b/queue-3.4/target-avoid-integer-overflow-in-se_dev_align_max_sectors.patch
new file mode 100644 (file)
index 0000000..a7b4605
--- /dev/null
@@ -0,0 +1,58 @@
+From 3e03989b5868acf69a391a424dc71fcd6cc48167 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Wed, 31 Oct 2012 09:16:45 -0700
+Subject: target: Avoid integer overflow in se_dev_align_max_sectors()
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit 3e03989b5868acf69a391a424dc71fcd6cc48167 upstream.
+
+The expression (max_sectors * block_size) might overflow a u32
+(indeed, since iblock sets max_hw_sectors to UINT_MAX, it is
+guaranteed to overflow and end up with a much-too-small result in many
+common cases).  Fix this by doing an equivalent calculation that
+doesn't require multiplication.
+
+While we're touching this code, avoid splitting a printk format across
+two lines and use pr_info(...) instead of printk(KERN_INFO ...).
+
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_device.c |   18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/target/target_core_device.c
++++ b/drivers/target/target_core_device.c
+@@ -826,20 +826,20 @@ int se_dev_check_shutdown(struct se_devi
+ u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
+ {
+-      u32 tmp, aligned_max_sectors;
++      u32 aligned_max_sectors;
++      u32 alignment;
+       /*
+        * Limit max_sectors to a PAGE_SIZE aligned value for modern
+        * transport_allocate_data_tasks() operation.
+        */
+-      tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
+-      aligned_max_sectors = (tmp / block_size);
+-      if (max_sectors != aligned_max_sectors) {
+-              printk(KERN_INFO "Rounding down aligned max_sectors from %u"
+-                              " to %u\n", max_sectors, aligned_max_sectors);
+-              return aligned_max_sectors;
+-      }
++      alignment = max(1ul, PAGE_SIZE / block_size);
++      aligned_max_sectors = rounddown(max_sectors, alignment);
+-      return max_sectors;
++      if (max_sectors != aligned_max_sectors)
++              pr_info("Rounding down aligned max_sectors from %u to %u\n",
++                      max_sectors, aligned_max_sectors);
++
++      return aligned_max_sectors;
+ }
+ void se_dev_set_default_attribs(
diff --git a/queue-3.4/target-don-t-return-success-from-module_init-if-setup-fails.patch b/queue-3.4/target-don-t-return-success-from-module_init-if-setup-fails.patch
new file mode 100644 (file)
index 0000000..2091d8a
--- /dev/null
@@ -0,0 +1,35 @@
+From 0d0f9dfb31e0a6c92063e235417b42df185b3275 Mon Sep 17 00:00:00 2001
+From: Roland Dreier <roland@purestorage.com>
+Date: Wed, 31 Oct 2012 09:16:44 -0700
+Subject: target: Don't return success from module_init() if setup fails
+
+From: Roland Dreier <roland@purestorage.com>
+
+commit 0d0f9dfb31e0a6c92063e235417b42df185b3275 upstream.
+
+If the call to core_dev_release_virtual_lun0() fails, then nothing
+sets ret to anything other than 0, so even though everything is
+torn down and freed, target_core_init_configfs() will seem to succeed
+and the module will be loaded.  Fix this by passing the return value
+on up the chain.
+
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_configfs.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/target/target_core_configfs.c
++++ b/drivers/target/target_core_configfs.c
+@@ -3197,7 +3197,8 @@ static int __init target_core_init_confi
+       if (ret < 0)
+               goto out;
+-      if (core_dev_setup_virtual_lun0() < 0)
++      ret = core_dev_setup_virtual_lun0();
++      if (ret < 0)
+               goto out;
+       return 0;
diff --git a/queue-3.4/target-fix-incorrect-usage-of-nested-irq-spinlocks-in-abort_task-path.patch b/queue-3.4/target-fix-incorrect-usage-of-nested-irq-spinlocks-in-abort_task-path.patch
new file mode 100644 (file)
index 0000000..a1074fd
--- /dev/null
@@ -0,0 +1,43 @@
+From ab74b3d62f05192bf8fb8f169e7999d1183b2e08 Mon Sep 17 00:00:00 2001
+From: Steve Hodgson <steve@purestorage.com>
+Date: Wed, 31 Oct 2012 10:24:02 -0700
+Subject: target: Fix incorrect usage of nested IRQ spinlocks in ABORT_TASK path
+
+From: Steve Hodgson <steve@purestorage.com>
+
+commit ab74b3d62f05192bf8fb8f169e7999d1183b2e08 upstream.
+
+This patch changes core_tmr_abort_task() to use spin_lock -> spin_unlock
+around se_cmd->t_state_lock while spin_lock_irqsave is held via
+se_sess->sess_cmd_lock.
+
+Signed-off-by: Steve Hodgson <steve@purestorage.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/target/target_core_tmr.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/target/target_core_tmr.c
++++ b/drivers/target/target_core_tmr.c
+@@ -140,15 +140,15 @@ void core_tmr_abort_task(
+               printk("ABORT_TASK: Found referenced %s task_tag: %u\n",
+                       se_cmd->se_tfo->get_fabric_name(), ref_tag);
+-              spin_lock_irq(&se_cmd->t_state_lock);
++              spin_lock(&se_cmd->t_state_lock);
+               if (se_cmd->transport_state & CMD_T_COMPLETE) {
+                       printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag);
+-                      spin_unlock_irq(&se_cmd->t_state_lock);
++                      spin_unlock(&se_cmd->t_state_lock);
+                       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+                       goto out;
+               }
+               se_cmd->transport_state |= CMD_T_ABORTED;
+-              spin_unlock_irq(&se_cmd->t_state_lock);
++              spin_unlock(&se_cmd->t_state_lock);
+               list_del_init(&se_cmd->se_cmd_list);
+               kref_get(&se_cmd->cmd_kref);