public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] mtip32xx: mtip_async_complete() bug fixes
  2014-03-13 21:09 [PATCH] mtip32xx: mtip_async_complete() bug fixes Sam Bradshaw
@ 2014-03-13 21:02 ` Jens Axboe
  2014-03-13 21:33   ` Sam Bradshaw
  0 siblings, 1 reply; 4+ messages in thread
From: Jens Axboe @ 2014-03-13 21:02 UTC (permalink / raw)
  To: Sam Bradshaw
  Cc: linux-kernel, Felipe Franciosi, david.vrabel,
	Asai Thambi Samymuthu Pattrayasamy (asamymuthupa)

On 03/13/2014 03:09 PM, Sam Bradshaw wrote:
> This patch fixes 2 issues in the fast completion path:
> 1) Possible double completions / double dma_unmap_sg() calls due to lack
> of atomicity in the check and subsequent dereference of the upper layer
> callback function.  Fixed with cmpxchg before unmap and callback.
> 2) Regression in unaligned IO constraining workaround for p420m devices.
>   Fixed by checking if IO is unaligned and using proper semaphore if so.

Sam, what is this patch against? It doesn't apply to -rc6 and it doesn't 
apply to for-3.15/drivers (the latter would be preferred/required). It 
also seems to have line break issues.

-- 
Jens Axboe


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

* [PATCH] mtip32xx: mtip_async_complete() bug fixes
@ 2014-03-13 21:09 Sam Bradshaw
  2014-03-13 21:02 ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Sam Bradshaw @ 2014-03-13 21:09 UTC (permalink / raw)
  To: Jens Axboe
  Cc: linux-kernel, Felipe Franciosi, david.vrabel,
	Asai Thambi Samymuthu Pattrayasamy (asamymuthupa)

This patch fixes 2 issues in the fast completion path:
1) Possible double completions / double dma_unmap_sg() calls due to lack 
of atomicity in the check and subsequent dereference of the upper layer 
callback function.  Fixed with cmpxchg before unmap and callback.
2) Regression in unaligned IO constraining workaround for p420m devices. 
  Fixed by checking if IO is unaligned and using proper semaphore if so.

Bumped version to indicate presence of these fixes.

Signed-off-by: Sam Bradshaw <sbradshaw@micron.com>
diff --git a/drivers/block/mtip32xx/mtip32xx.c 
b/drivers/block/mtip32xx/mtip32xx.c
index b2012b7..624e9d9 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -252,38 +252,45 @@ static void mtip_async_complete(struct mtip_port 
*port,
  				void *data,
  				int status)
  {
-	struct mtip_cmd *command;
+	struct mtip_cmd *cmd;
  	struct driver_data *dd = data;
-	int cb_status = status ? -EIO : 0;
+	int unaligned, cb_status = status ? -EIO : 0;
+	void (*func)(void *, int);

  	if (unlikely(!dd) || unlikely(!port))
  		return;

-	command = &port->commands[tag];
+	cmd = &port->commands[tag];

  	if (unlikely(status == PORT_IRQ_TF_ERR)) {
  		dev_warn(&port->dd->pdev->dev,
  			"Command tag %d failed due to TFE\n", tag);
  	}

-	/* Unmap the DMA scatter list entries */
-	dma_unmap_sg(&dd->pdev->dev,
-		command->sg,
-		command->scatter_ents,
-		command->direction);
+	/* Clear the active flag */
+	atomic_set(&port->commands[tag].active, 0);

  	/* Upper layer callback */
-	if (likely(command->async_callback))
-		command->async_callback(command->async_data, cb_status);
+	func = cmd->async_callback;
+	if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) {

-	command->async_callback = NULL;
-	command->comp_func = NULL;
+		/* Unmap the DMA scatter list entries */
+		dma_unmap_sg(&dd->pdev->dev,
+			cmd->sg,
+			cmd->scatter_ents,
+			cmd->direction);

-	/* Clear the allocated and active bits for the command */
-	atomic_set(&port->commands[tag].active, 0);
-	release_slot(port, tag);
+		func(cmd->async_data, cb_status);
+		unaligned = cmd->unaligned;

-	up(&port->cmd_slot);
+		/* Clear the allocated bit for the command */
+		release_slot(port, tag);
+
+		if (unlikely(unaligned))
+			up(&port->cmd_slot_unal);
+		else
+			up(&port->cmd_slot);
+	}
  }

  /*
@@ -660,11 +667,12 @@ static void mtip_timeout_function(unsigned long 
int data)
  {
  	struct mtip_port *port = (struct mtip_port *) data;
  	struct host_to_dev_fis *fis;
-	struct mtip_cmd *command;
-	int tag, cmdto_cnt = 0;
+	struct mtip_cmd *cmd;
+	int unaligned, tag, cmdto_cnt = 0;
  	unsigned int bit, group;
  	unsigned int num_command_slots;
  	unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
+	void (*func)(void *, int);

  	if (unlikely(!port))
  		return;
@@ -694,8 +702,8 @@ static void mtip_timeout_function(unsigned long int 
data)
  			group = tag >> 5;
  			bit = tag & 0x1F;

-			command = &port->commands[tag];
-			fis = (struct host_to_dev_fis *) command->command;
+			cmd = &port->commands[tag];
+			fis = (struct host_to_dev_fis *) cmd->command;

  			set_bit(tag, tagaccum);
  			cmdto_cnt++;
@@ -709,27 +717,30 @@ static void mtip_timeout_function(unsigned long 
int data)
  			 */
  			writel(1 << bit, port->completed[group]);

-			/* Unmap the DMA scatter list entries */
-			dma_unmap_sg(&port->dd->pdev->dev,
-					command->sg,
-					command->scatter_ents,
-					command->direction);
+			/* Clear the active flag for the command */
+			atomic_set(&port->commands[tag].active, 0);

-			/* Call the async completion callback. */
-			if (likely(command->async_callback))
-				command->async_callback(command->async_data,
-							 -EIO);
-			command->async_callback = NULL;
-			command->comp_func = NULL;
+			func = cmd->async_callback;
+			if (func &&
+			    cmpxchg(&cmd->async_callback, func, 0) == func) {

-			/*
-			 * Clear the allocated bit and active tag for the
-			 * command.
-			 */
-			atomic_set(&port->commands[tag].active, 0);
-			release_slot(port, tag);
+				/* Unmap the DMA scatter list entries */
+				dma_unmap_sg(&port->dd->pdev->dev,
+						cmd->sg,
+						cmd->scatter_ents,
+						cmd->direction);

-			up(&port->cmd_slot);
+				func(cmd->async_data, -EIO);
+				unaligned = cmd->unaligned;
+
+				/* Clear the allocated bit for the command. */
+				release_slot(port, tag);
+
+				if (unaligned)
+					up(&port->cmd_slot_unal);
+				else
+					up(&port->cmd_slot);
+			}
  		}
  	}

diff --git a/drivers/block/mtip32xx/mtip32xx.h 
b/drivers/block/mtip32xx/mtip32xx.h
index 54174cb..ffb955e 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -92,7 +92,7 @@

  /* Driver name and version strings */
  #define MTIP_DRV_NAME		"mtip32xx"
-#define MTIP_DRV_VERSION	"1.3.0"
+#define MTIP_DRV_VERSION	"1.3.1"

  /* Maximum number of minor device numbers per device. */
  #define MTIP_MAX_MINORS		16


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

* Re: [PATCH] mtip32xx: mtip_async_complete() bug fixes
  2014-03-13 21:02 ` Jens Axboe
@ 2014-03-13 21:33   ` Sam Bradshaw
  2014-03-13 21:59     ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Sam Bradshaw @ 2014-03-13 21:33 UTC (permalink / raw)
  To: Jens Axboe
  Cc: linux-kernel, Felipe Franciosi, david.vrabel,
	Asai Thambi Samymuthu Pattrayasamy (asamymuthupa)

On 03/13/2014 02:02 PM, Jens Axboe wrote:
> On 03/13/2014 03:09 PM, Sam Bradshaw wrote:
>> This patch fixes 2 issues in the fast completion path:
>> 1) Possible double completions / double dma_unmap_sg() calls due to lack
>> of atomicity in the check and subsequent dereference of the upper layer
>> callback function. Fixed with cmpxchg before unmap and callback.
>> 2) Regression in unaligned IO constraining workaround for p420m devices.
>> Fixed by checking if IO is unaligned and using proper semaphore if so.
> 
> Sam, what is this patch against? It doesn't apply to -rc6 and it doesn't 
> apply to for-3.15/drivers (the latter would be preferred/required). It 
> also seems to have line break issues.
> 

It's against for-3.15/drivers.  Sorry about the breaks; if I remove them
does it apply cleanly?


diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index b2012b7..624e9d9 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -252,38 +252,45 @@ static void mtip_async_complete(struct mtip_port *port,
 				void *data,
 				int status)
 {
-	struct mtip_cmd *command;
+	struct mtip_cmd *cmd;
 	struct driver_data *dd = data;
-	int cb_status = status ? -EIO : 0;
+	int unaligned, cb_status = status ? -EIO : 0;
+	void (*func)(void *, int);
 
 	if (unlikely(!dd) || unlikely(!port))
 		return;
 
-	command = &port->commands[tag];
+	cmd = &port->commands[tag];
 
 	if (unlikely(status == PORT_IRQ_TF_ERR)) {
 		dev_warn(&port->dd->pdev->dev,
 			"Command tag %d failed due to TFE\n", tag);
 	}
 
-	/* Unmap the DMA scatter list entries */
-	dma_unmap_sg(&dd->pdev->dev,
-		command->sg,
-		command->scatter_ents,
-		command->direction);
+	/* Clear the active flag */
+	atomic_set(&port->commands[tag].active, 0);
 
 	/* Upper layer callback */
-	if (likely(command->async_callback))
-		command->async_callback(command->async_data, cb_status);
+	func = cmd->async_callback;
+	if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) {
 
-	command->async_callback = NULL;
-	command->comp_func = NULL;
+		/* Unmap the DMA scatter list entries */
+		dma_unmap_sg(&dd->pdev->dev,
+			cmd->sg,
+			cmd->scatter_ents,
+			cmd->direction);
 
-	/* Clear the allocated and active bits for the command */
-	atomic_set(&port->commands[tag].active, 0);
-	release_slot(port, tag);
+		func(cmd->async_data, cb_status);
+		unaligned = cmd->unaligned;
 
-	up(&port->cmd_slot);
+		/* Clear the allocated bit for the command */
+		release_slot(port, tag);
+
+		if (unlikely(unaligned))
+			up(&port->cmd_slot_unal);
+		else
+			up(&port->cmd_slot);
+	}
 }
 
 /*
@@ -660,11 +667,12 @@ static void mtip_timeout_function(unsigned long int data)
 {
 	struct mtip_port *port = (struct mtip_port *) data;
 	struct host_to_dev_fis *fis;
-	struct mtip_cmd *command;
-	int tag, cmdto_cnt = 0;
+	struct mtip_cmd *cmd;
+	int unaligned, tag, cmdto_cnt = 0;
 	unsigned int bit, group;
 	unsigned int num_command_slots;
 	unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
+	void (*func)(void *, int);
 
 	if (unlikely(!port))
 		return;
@@ -694,8 +702,8 @@ static void mtip_timeout_function(unsigned long int data)
 			group = tag >> 5;
 			bit = tag & 0x1F;
 
-			command = &port->commands[tag];
-			fis = (struct host_to_dev_fis *) command->command;
+			cmd = &port->commands[tag];
+			fis = (struct host_to_dev_fis *) cmd->command;
 
 			set_bit(tag, tagaccum);
 			cmdto_cnt++;
@@ -709,27 +717,30 @@ static void mtip_timeout_function(unsigned long int data)
 			 */
 			writel(1 << bit, port->completed[group]);
 
-			/* Unmap the DMA scatter list entries */
-			dma_unmap_sg(&port->dd->pdev->dev,
-					command->sg,
-					command->scatter_ents,
-					command->direction);
+			/* Clear the active flag for the command */
+			atomic_set(&port->commands[tag].active, 0);
 
-			/* Call the async completion callback. */
-			if (likely(command->async_callback))
-				command->async_callback(command->async_data,
-							 -EIO);
-			command->async_callback = NULL;
-			command->comp_func = NULL;
+			func = cmd->async_callback;
+			if (func &&
+			    cmpxchg(&cmd->async_callback, func, 0) == func) {
 
-			/*
-			 * Clear the allocated bit and active tag for the
-			 * command.
-			 */
-			atomic_set(&port->commands[tag].active, 0);
-			release_slot(port, tag);
+				/* Unmap the DMA scatter list entries */
+				dma_unmap_sg(&port->dd->pdev->dev,
+						cmd->sg,
+						cmd->scatter_ents,
+						cmd->direction);
 
-			up(&port->cmd_slot);
+				func(cmd->async_data, -EIO);
+				unaligned = cmd->unaligned;
+
+				/* Clear the allocated bit for the command. */
+				release_slot(port, tag);
+
+				if (unaligned)
+					up(&port->cmd_slot_unal);
+				else
+					up(&port->cmd_slot);
+			}
 		}
 	}
 
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index 54174cb..ffb955e 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -92,7 +92,7 @@
 
 /* Driver name and version strings */
 #define MTIP_DRV_NAME		"mtip32xx"
-#define MTIP_DRV_VERSION	"1.3.0"
+#define MTIP_DRV_VERSION	"1.3.1"
 
 /* Maximum number of minor device numbers per device. */
 #define MTIP_MAX_MINORS		16

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

* Re: [PATCH] mtip32xx: mtip_async_complete() bug fixes
  2014-03-13 21:33   ` Sam Bradshaw
@ 2014-03-13 21:59     ` Jens Axboe
  0 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2014-03-13 21:59 UTC (permalink / raw)
  To: Sam Bradshaw
  Cc: linux-kernel, Felipe Franciosi, david.vrabel,
	Asai Thambi Samymuthu Pattrayasamy (asamymuthupa)

On 03/13/2014 03:33 PM, Sam Bradshaw wrote:
> On 03/13/2014 02:02 PM, Jens Axboe wrote:
>> On 03/13/2014 03:09 PM, Sam Bradshaw wrote:
>>> This patch fixes 2 issues in the fast completion path:
>>> 1) Possible double completions / double dma_unmap_sg() calls due to lack
>>> of atomicity in the check and subsequent dereference of the upper layer
>>> callback function. Fixed with cmpxchg before unmap and callback.
>>> 2) Regression in unaligned IO constraining workaround for p420m devices.
>>> Fixed by checking if IO is unaligned and using proper semaphore if so.
>>
>> Sam, what is this patch against? It doesn't apply to -rc6 and it doesn't
>> apply to for-3.15/drivers (the latter would be preferred/required). It
>> also seems to have line break issues.
>>
>
> It's against for-3.15/drivers.  Sorry about the breaks; if I remove them
> does it apply cleanly?

Yep, this one is much better. Thanks!

-- 
Jens Axboe


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

end of thread, other threads:[~2014-03-13 21:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-13 21:09 [PATCH] mtip32xx: mtip_async_complete() bug fixes Sam Bradshaw
2014-03-13 21:02 ` Jens Axboe
2014-03-13 21:33   ` Sam Bradshaw
2014-03-13 21:59     ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox