linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] target: Bugfixes for .39-rc7
@ 2011-05-07  2:54 Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 1/3] target: Fix multi task->task_sg[] chaining logic bug Nicholas A. Bellinger
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2011-05-07  2:54 UTC (permalink / raw)
  To: linux-kernel, linux-scsi, James Bottomley
  Cc: Linus Torvalds, Christoph Hellwig, Kiran Patil, Robert W. Love,
	FUJITA Tomonori, Bart Van Assche, Hannes Reinecke, Mike Christie,
	Andy Grover, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

Hi James and Co,

My apologies for lateness with this bugfix series.  This series contains
three patches that should be considered critical target core bugfixes for
.39 that have been under stress testing in a couple of different labs
recently using lio-core-2.6.git/lio-4.1 (.39-rcX) and /lio-4.0 (.38.3)
branch code.

These are all important bugfixes that are required to run with in-flight
.40 HW target drivers in the upstream LIO tree.  This includes fixes for
the main transport_do_task_sg_chain() Data I/O mapping logic, and
task->task_sg[] shutdown path from MSI-X interrupt context.  These patches
apply for all of the following fabric drivers:

   tcm_fc(openfcoe) w/ ddp offload, tcm_qla2xxx, ib_srpt and ibmvscsis.

These patches address issues that are able to easily produce OOPsen with
small backstore max_sectors values, so please review+consider for .39 and
also queue into stable@kernel.org for .38.

The series is also available here for a direct pull:

  git://git.kernel.org/pub/scm/linux/kernel/git/nab/scsi-post-merge-2.6.git for-39-rc-fixes

and has been made against the following scsi-rc-fixes HEAD:

commit c055f5b2614b4f758ae6cc86733f31fa4c2c5844
Author: James Bottomley <James.Bottomley@suse.de>
Date:   Sun May 1 09:42:07 2011 -0500

    [SCSI] fix oops in scsi_run_queue()

Thanks!

--nab

Nicholas Bellinger (3):
  target: Fix multi task->task_sg[] chaining logic bug
  target: Fix interrupt context bug with stats_lock and
    core_tmr_alloc_req
  target: Fix bug with task_sg chained transport_free_dev_tasks release

 drivers/target/target_core_device.c    |    4 +-
 drivers/target/target_core_tmr.c       |    7 +++--
 drivers/target/target_core_transport.c |   39 ++++++++++++++++++++++---------
 include/target/target_core_base.h      |    1 +
 include/target/target_core_transport.h |    1 +
 5 files changed, 35 insertions(+), 17 deletions(-)

-- 
1.7.5.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] target: Fix multi task->task_sg[] chaining logic bug
  2011-05-07  2:54 [PATCH 0/3] target: Bugfixes for .39-rc7 Nicholas A. Bellinger
@ 2011-05-07  2:54 ` Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 2/3] target: Fix interrupt context bug with stats_lock and core_tmr_alloc_req Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 3/3] target: Fix bug with task_sg chained transport_free_dev_tasks release Nicholas A. Bellinger
  2 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2011-05-07  2:54 UTC (permalink / raw)
  To: linux-kernel, linux-scsi, James Bottomley
  Cc: Linus Torvalds, Christoph Hellwig, Kiran Patil, Robert W. Love,
	FUJITA Tomonori, Bart Van Assche, Hannes Reinecke, Mike Christie,
	Andy Grover, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch fixes a bug in transport_do_task_sg_chain() used by HW target
mode modules with sg_chain() to provide a single sg_next() walkable memory
layout for use with pci_map_sg() and friends.  This patch addresses an
issue with mapping multiple small block max_sector tasks across multiple
struct se_task->task_sg[] mappings for HW target mode operation.

This was causing OOPs with (cmd->t_task->t_tasks_no > 1) I/O traffic for
HW target drivers using transport_do_task_sg_chain(), and has been tested
so far with tcm_fc(openfcoe), tcm_qla2xxx, and ib_srpt fabrics with
t_tasks_no > 1 IBLOCK backends using a smaller max_sectors to trigger the
original issue.

Reported-by: Kiran Patil <kiran.patil@intel.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_transport.c |   26 +++++++++++++++-----------
 1 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 9583b23..fefe10a 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -4776,18 +4776,20 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
 				sg_end_cur->page_link &= ~0x02;
 
 				sg_chain(sg_head, task_sg_num, sg_head_cur);
-				sg_count += (task->task_sg_num + 1);
-			} else
 				sg_count += task->task_sg_num;
+				task_sg_num = (task->task_sg_num + 1);
+			} else {
+				sg_chain(sg_head, task_sg_num, sg_head_cur);
+				sg_count += task->task_sg_num;
+				task_sg_num = task->task_sg_num;
+			}
 
 			sg_head = sg_head_cur;
 			sg_link = sg_link_cur;
-			task_sg_num = task->task_sg_num;
 			continue;
 		}
 		sg_head = sg_first = &task->task_sg[0];
 		sg_link = &task->task_sg[task->task_sg_num];
-		task_sg_num = task->task_sg_num;
 		/*
 		 * Check for single task..
 		 */
@@ -4798,9 +4800,12 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
 			 */
 			sg_end = &task->task_sg[task->task_sg_num - 1];
 			sg_end->page_link &= ~0x02;
-			sg_count += (task->task_sg_num + 1);
-		} else
 			sg_count += task->task_sg_num;
+			task_sg_num = (task->task_sg_num + 1);
+		} else {
+			sg_count += task->task_sg_num;
+			task_sg_num = task->task_sg_num;
+		}
 	}
 	/*
 	 * Setup the starting pointer and total t_tasks_sg_linked_no including
@@ -4809,21 +4814,20 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
 	T_TASK(cmd)->t_tasks_sg_chained = sg_first;
 	T_TASK(cmd)->t_tasks_sg_chained_no = sg_count;
 
-	DEBUG_CMD_M("Setup T_TASK(cmd)->t_tasks_sg_chained: %p and"
-		" t_tasks_sg_chained_no: %u\n", T_TASK(cmd)->t_tasks_sg_chained,
+	DEBUG_CMD_M("Setup cmd: %p T_TASK(cmd)->t_tasks_sg_chained: %p and"
+		" t_tasks_sg_chained_no: %u\n", cmd, T_TASK(cmd)->t_tasks_sg_chained,
 		T_TASK(cmd)->t_tasks_sg_chained_no);
 
 	for_each_sg(T_TASK(cmd)->t_tasks_sg_chained, sg,
 			T_TASK(cmd)->t_tasks_sg_chained_no, i) {
 
-		DEBUG_CMD_M("SG: %p page: %p length: %d offset: %d\n",
-			sg, sg_page(sg), sg->length, sg->offset);
+		DEBUG_CMD_M("SG[%d]: %p page: %p length: %d offset: %d, magic: 0x%08x\n",
+			i, sg, sg_page(sg), sg->length, sg->offset, sg->sg_magic);
 		if (sg_is_chain(sg))
 			DEBUG_CMD_M("SG: %p sg_is_chain=1\n", sg);
 		if (sg_is_last(sg))
 			DEBUG_CMD_M("SG: %p sg_is_last=1\n", sg);
 	}
-
 }
 EXPORT_SYMBOL(transport_do_task_sg_chain);
 
-- 
1.7.5.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] target: Fix interrupt context bug with stats_lock and core_tmr_alloc_req
  2011-05-07  2:54 [PATCH 0/3] target: Bugfixes for .39-rc7 Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 1/3] target: Fix multi task->task_sg[] chaining logic bug Nicholas A. Bellinger
@ 2011-05-07  2:54 ` Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 3/3] target: Fix bug with task_sg chained transport_free_dev_tasks release Nicholas A. Bellinger
  2 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2011-05-07  2:54 UTC (permalink / raw)
  To: linux-kernel, linux-scsi, James Bottomley
  Cc: Linus Torvalds, Christoph Hellwig, Kiran Patil, Robert W. Love,
	FUJITA Tomonori, Bart Van Assche, Hannes Reinecke, Mike Christie,
	Andy Grover, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch fixes two bugs wrt to the interrupt context usage of target
core with HW target mode drivers.  It first converts the usage of struct
se_device->stats_lock in transport_get_lun_for_cmd() and core_tmr_lun_reset()
to properly use spin_lock_irq() to address an BUG with CONFIG_LOCKDEP_SUPPORT=y
enabled.

This patch also adds a 'in_interrupt()' check to allow GFP_ATOMIC usage from
core_tmr_alloc_req() to fix a 'sleeping in interrupt context' BUG with HW
target fabrics that require this logic to function.

Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_device.c |    4 ++--
 drivers/target/target_core_tmr.c    |    7 ++++---
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index d25e208..fc10ed4 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -150,13 +150,13 @@ out:
 
 	{
 	struct se_device *dev = se_lun->lun_se_dev;
-	spin_lock(&dev->stats_lock);
+	spin_lock_irq(&dev->stats_lock);
 	dev->num_cmds++;
 	if (se_cmd->data_direction == DMA_TO_DEVICE)
 		dev->write_bytes += se_cmd->data_length;
 	else if (se_cmd->data_direction == DMA_FROM_DEVICE)
 		dev->read_bytes += se_cmd->data_length;
-	spin_unlock(&dev->stats_lock);
+	spin_unlock_irq(&dev->stats_lock);
 	}
 
 	/*
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 4a10983..59b8b9c 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -55,7 +55,8 @@ struct se_tmr_req *core_tmr_alloc_req(
 {
 	struct se_tmr_req *tmr;
 
-	tmr = kmem_cache_zalloc(se_tmr_req_cache, GFP_KERNEL);
+	tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ?
+					GFP_ATOMIC : GFP_KERNEL);
 	if (!(tmr)) {
 		printk(KERN_ERR "Unable to allocate struct se_tmr_req\n");
 		return ERR_PTR(-ENOMEM);
@@ -398,9 +399,9 @@ int core_tmr_lun_reset(
 		printk(KERN_INFO "LUN_RESET: SCSI-2 Released reservation\n");
 	}
 
-	spin_lock(&dev->stats_lock);
+	spin_lock_irq(&dev->stats_lock);
 	dev->num_resets++;
-	spin_unlock(&dev->stats_lock);
+	spin_unlock_irq(&dev->stats_lock);
 
 	DEBUG_LR("LUN_RESET: %s for [%s] Complete\n",
 			(preempt_and_abort_list) ? "Preempt" : "TMR",
-- 
1.7.5.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] target: Fix bug with task_sg chained transport_free_dev_tasks release
  2011-05-07  2:54 [PATCH 0/3] target: Bugfixes for .39-rc7 Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 1/3] target: Fix multi task->task_sg[] chaining logic bug Nicholas A. Bellinger
  2011-05-07  2:54 ` [PATCH 2/3] target: Fix interrupt context bug with stats_lock and core_tmr_alloc_req Nicholas A. Bellinger
@ 2011-05-07  2:54 ` Nicholas A. Bellinger
  2 siblings, 0 replies; 4+ messages in thread
From: Nicholas A. Bellinger @ 2011-05-07  2:54 UTC (permalink / raw)
  To: linux-kernel, linux-scsi, James Bottomley
  Cc: Linus Torvalds, Christoph Hellwig, Kiran Patil, Robert W. Love,
	FUJITA Tomonori, Bart Van Assche, Hannes Reinecke, Mike Christie,
	Andy Grover, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch addresses a bug in the target core release path for HW
operation where transport_free_dev_tasks() was incorrectly being called
from transport_lun_remove_cmd() while releasing a se_cmd reference and
calling struct target_core_fabric_ops->queue_data_in().

This would result in a OOPs with HW target mode when the release of
se_task->task_sg[] would happen before pci_unmap_sg() can be called in
HW target mode fabric module code.  This patch addresses the issue by
moving transport_free_dev_tasks() from transport_lun_remove_cmd() into
transport_generic_free_cmd(), and adding TRANSPORT_FREE_CMD_INTR and
transport_generic_free_cmd_intr() to allow se_cmd descriptor release
to happen fromfrom within transport_processing_thread() process context
when release of se_cmd is not possible from HW interrupt context.

Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_transport.c |   13 ++++++++++++-
 include/target/target_core_base.h      |    1 +
 include/target/target_core_transport.h |    1 +
 3 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index fefe10a..3eeb3e2 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -762,7 +762,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
 	transport_all_task_dev_remove_state(cmd);
 	spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
 
-	transport_free_dev_tasks(cmd);
 
 check_lun:
 	spin_lock_irqsave(&lun->lun_cmd_lock, flags);
@@ -2058,6 +2057,13 @@ int transport_generic_handle_tmr(
 }
 EXPORT_SYMBOL(transport_generic_handle_tmr);
 
+void transport_generic_free_cmd_intr(
+	struct se_cmd *cmd)
+{
+	transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
+}
+EXPORT_SYMBOL(transport_generic_free_cmd_intr);
+
 static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
 {
 	struct se_task *task, *task_tmp;
@@ -5301,6 +5307,8 @@ void transport_generic_free_cmd(
 		if (wait_for_tasks && cmd->transport_wait_for_tasks)
 			cmd->transport_wait_for_tasks(cmd, 0, 0);
 
+		transport_free_dev_tasks(cmd);
+
 		transport_generic_remove(cmd, release_to_pool,
 				session_reinstatement);
 	}
@@ -6136,6 +6144,9 @@ get_cmd:
 		case TRANSPORT_REMOVE:
 			transport_generic_remove(cmd, 1, 0);
 			break;
+		case TRANSPORT_FREE_CMD_INTR:
+			transport_generic_free_cmd(cmd, 0, 1, 0);
+			break;
 		case TRANSPORT_PROCESS_TMR:
 			transport_generic_do_tmr(cmd);
 			break;
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 1d3b5b2..561ac99 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -98,6 +98,7 @@ enum transport_state_table {
 	TRANSPORT_REMOVE	= 14,
 	TRANSPORT_FREE		= 15,
 	TRANSPORT_NEW_CMD_MAP	= 16,
+	TRANSPORT_FREE_CMD_INTR = 17,
 };
 
 /* Used for struct se_cmd->se_cmd_flags */
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
index 59aa464..24a1c6c 100644
--- a/include/target/target_core_transport.h
+++ b/include/target/target_core_transport.h
@@ -172,6 +172,7 @@ extern int transport_generic_handle_cdb_map(struct se_cmd *);
 extern int transport_generic_handle_data(struct se_cmd *);
 extern void transport_new_cmd_failure(struct se_cmd *);
 extern int transport_generic_handle_tmr(struct se_cmd *);
+extern void transport_generic_free_cmd_intr(struct se_cmd *);
 extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
 extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]);
 extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
-- 
1.7.5.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-05-07  2:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-07  2:54 [PATCH 0/3] target: Bugfixes for .39-rc7 Nicholas A. Bellinger
2011-05-07  2:54 ` [PATCH 1/3] target: Fix multi task->task_sg[] chaining logic bug Nicholas A. Bellinger
2011-05-07  2:54 ` [PATCH 2/3] target: Fix interrupt context bug with stats_lock and core_tmr_alloc_req Nicholas A. Bellinger
2011-05-07  2:54 ` [PATCH 3/3] target: Fix bug with task_sg chained transport_free_dev_tasks release Nicholas A. Bellinger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).