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