Re: [PATCH 1/2] target/sbc: Remove sbc_check_valid_sectors()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Christoph,

On Tue, 2014-06-10 at 17:53 +0200, Christophe Vu-Brugier wrote:
> A similar check is performed at the end of sbc_parse_cdb() and is now
> enforced if the SYNCHRONIZE CACHE command has a non zero logical block
> address or number of blocks.
> 
> Signed-off-by: Christophe Vu-Brugier <cvubrugier@xxxxxxxx>
> ---
> I think that the check performed in sbc_check_valid_sectors() was
> wrong because it used cmd->data_length instead of using the number of
> sectors from the CDB.
> 
>  drivers/target/target_core_sbc.c | 47 ++++++++--------------------------------
>  1 file changed, 9 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
> index e022959..aaec147 100644
> --- a/drivers/target/target_core_sbc.c
> +++ b/drivers/target/target_core_sbc.c
> @@ -176,24 +176,6 @@ static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
>  	return cmd->se_dev->dev_attrib.block_size * sectors;
>  }
>  
> -static int sbc_check_valid_sectors(struct se_cmd *cmd)
> -{
> -	struct se_device *dev = cmd->se_dev;
> -	unsigned long long end_lba;
> -	u32 sectors;
> -
> -	sectors = cmd->data_length / dev->dev_attrib.block_size;
> -	end_lba = dev->transport->get_blocks(dev) + 1;
> -
> -	if (cmd->t_task_lba + sectors > end_lba) {
> -		pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n",
> -			cmd->t_task_lba, sectors, end_lba);
> -		return -EINVAL;
> -	}
> -
> -	return 0;
> -}
> -
>  static inline u32 transport_get_sectors_6(unsigned char *cdb)
>  {
>  	/*
> @@ -680,6 +662,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  	unsigned int size;
>  	u32 sectors = 0;
>  	sense_reason_t ret;
> +	bool lba_check = false;
>  
>  	switch (cdb[0]) {
>  	case READ_6:
> @@ -877,15 +860,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  		break;
>  	case SYNCHRONIZE_CACHE:
>  	case SYNCHRONIZE_CACHE_16:
> -		if (!ops->execute_sync_cache) {
> -			size = 0;
> -			cmd->execute_cmd = sbc_emulate_noop;
> -			break;
> -		}
> -
> -		/*
> -		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
> -		 */
>  		if (cdb[0] == SYNCHRONIZE_CACHE) {
>  			sectors = transport_get_sectors_10(cdb);
>  			cmd->t_task_lba = transport_lba_32(cdb);
> @@ -893,18 +867,15 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  			sectors = transport_get_sectors_16(cdb);
>  			cmd->t_task_lba = transport_lba_64(cdb);
>  		}
> -
>  		size = sbc_get_size(cmd, sectors);
> -
> -		/*
> -		 * Check to ensure that LBA + Range does not exceed past end of
> -		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
> -		 */
> -		if (cmd->t_task_lba || sectors) {
> -			if (sbc_check_valid_sectors(cmd) < 0)
> -				return TCM_ADDRESS_OUT_OF_RANGE;
> +		if (cmd->t_task_lba || sectors)
> +			lba_check = true;
> +		if (ops->execute_sync_cache)
> +			cmd->execute_cmd = ops->execute_sync_cache;
> +		else {
> +			size = 0;
> +			cmd->execute_cmd = sbc_emulate_noop;
>  		}
> -		cmd->execute_cmd = ops->execute_sync_cache;
>  		break;
>  	case UNMAP:
>  		if (!ops->execute_unmap)
> @@ -971,7 +942,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
>  	if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd)
>  		return TCM_UNSUPPORTED_SCSI_OPCODE;
>  
> -	if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
> +	if ((cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) || lba_check) {
>  		unsigned long long end_lba;
>  
>  		if (sectors > dev->dev_attrib.fabric_max_sectors) {

So one potential issue here..

Now that lba_check = true is set for SYNCHRONIZE_CACHE and causes the
fabric_max_sectors + hw_max_sectors checks to kick in from above, it's
possible for a SYNCHRONIZE_CACHE to fail when the sector size exceeds
these *_max_sectors checks.

IIRC, this is why these checks where separate to begin with..

So instead of adding lba_check, how about adding a goto to jump to the
shared end_lba check, bypassing the two _*max_sectors checks..?

Here is an updated version of your original patch that is being applied
to target-pending/for-next now.

Please review.

--nab

>From d1794cacd8b35fe91050de6edb0b61329a61b059 Mon Sep 17 00:00:00 2001
From: Christophe Vu-Brugier <cvubrugier@xxxxxxxx>
Date: Tue, 10 Jun 2014 17:53:21 +0200
Subject: [PATCH] target/sbc: Remove sbc_check_valid_sectors()

A similar check is performed at the end of sbc_parse_cdb() and is now
enforced if the SYNCHRONIZE CACHE command's backend supports
->execute_sync_cache().

(Add check_lba goto to avoid *_max_sectors checks - nab)

Signed-off-by: Christophe Vu-Brugier <cvubrugier@xxxxxxxx>
Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/target/target_core_sbc.c |   45 +++++---------------------------------
 1 file changed, 6 insertions(+), 39 deletions(-)

diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 06f8ecd..56dfec8 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -176,24 +176,6 @@ static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
 	return cmd->se_dev->dev_attrib.block_size * sectors;
 }
 
-static int sbc_check_valid_sectors(struct se_cmd *cmd)
-{
-	struct se_device *dev = cmd->se_dev;
-	unsigned long long end_lba;
-	u32 sectors;
-
-	sectors = cmd->data_length / dev->dev_attrib.block_size;
-	end_lba = dev->transport->get_blocks(dev) + 1;
-
-	if (cmd->t_task_lba + sectors > end_lba) {
-		pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n",
-			cmd->t_task_lba, sectors, end_lba);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static inline u32 transport_get_sectors_6(unsigned char *cdb)
 {
 	/*
@@ -888,15 +870,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 		break;
 	case SYNCHRONIZE_CACHE:
 	case SYNCHRONIZE_CACHE_16:
-		if (!ops->execute_sync_cache) {
-			size = 0;
-			cmd->execute_cmd = sbc_emulate_noop;
-			break;
-		}
-
-		/*
-		 * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
-		 */
 		if (cdb[0] == SYNCHRONIZE_CACHE) {
 			sectors = transport_get_sectors_10(cdb);
 			cmd->t_task_lba = transport_lba_32(cdb);
@@ -904,18 +877,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 			sectors = transport_get_sectors_16(cdb);
 			cmd->t_task_lba = transport_lba_64(cdb);
 		}
-
-		size = sbc_get_size(cmd, sectors);
-
-		/*
-		 * Check to ensure that LBA + Range does not exceed past end of
-		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
-		 */
-		if (cmd->t_task_lba || sectors) {
-			if (sbc_check_valid_sectors(cmd) < 0)
-				return TCM_ADDRESS_OUT_OF_RANGE;
+		if (ops->execute_sync_cache) {
+			cmd->execute_cmd = ops->execute_sync_cache;
+			goto check_lba;
 		}
-		cmd->execute_cmd = ops->execute_sync_cache;
+		size = 0;
+		cmd->execute_cmd = sbc_emulate_noop;
 		break;
 	case UNMAP:
 		if (!ops->execute_unmap)
@@ -999,7 +966,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 				dev->dev_attrib.hw_max_sectors);
 			return TCM_INVALID_CDB_FIELD;
 		}
-
+check_lba:
 		end_lba = dev->transport->get_blocks(dev) + 1;
 		if (cmd->t_task_lba + sectors > end_lba) {
 			pr_err("cmd exceeds last lba %llu "
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux