diff options
author | Asias He | 2013-02-25 14:03:46 +0800 |
---|---|---|
committer | Nicholas Bellinger | 2013-04-25 01:05:24 -0700 |
commit | 86d7182985d25900929adce14fffd729cc8c6fb8 (patch) | |
tree | 8e5e755c5badf3a09b5b0c4e6c2f76c72c080dcf | |
parent | dbc21c5abbeb4419da5a54157c4b7a0ec0dee185 (diff) |
target: Add sbc_execute_unmap() helper
iblock_execute_unmap() and fd_execute_unmap share a lot of code.
Add sbc_execute_unmap() helper to remove duplicated code for
iblock_execute_unmap() and fd_execute_unmap().
Cc: Christoph Hellwig <hch@lst.de>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Asias He <asias@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_file.c | 82 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.c | 81 | ||||
-rw-r--r-- | drivers/target/target_core_sbc.c | 85 | ||||
-rw-r--r-- | include/target/target_core_backend.h | 4 |
4 files changed, 97 insertions, 155 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index d5b84fac31c7..9063c31df9e1 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -480,8 +480,9 @@ fd_execute_write_same(struct se_cmd *cmd) } static sense_reason_t -fd_do_unmap(struct se_cmd *cmd, struct file *file, sector_t lba, sector_t nolb) +fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) { + struct file *file = priv; struct inode *inode = file->f_mapping->host; int ret; @@ -542,84 +543,9 @@ fd_execute_write_same_unmap(struct se_cmd *cmd) static sense_reason_t fd_execute_unmap(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - struct fd_dev *fd_dev = FD_DEV(dev); - struct file *file = fd_dev->fd_file; - unsigned char *buf, *ptr = NULL; - sector_t lba; - int size; - u32 range; - sense_reason_t ret = 0; - int dl, bd_dl; - - /* We never set ANC_SUP */ - if (cmd->t_task_cdb[1]) - return TCM_INVALID_CDB_FIELD; - - if (cmd->data_length == 0) { - target_complete_cmd(cmd, SAM_STAT_GOOD); - return 0; - } - - if (cmd->data_length < 8) { - pr_warn("UNMAP parameter list length %u too small\n", - cmd->data_length); - return TCM_PARAMETER_LIST_LENGTH_ERROR; - } - - buf = transport_kmap_data_sg(cmd); - if (!buf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - dl = get_unaligned_be16(&buf[0]); - bd_dl = get_unaligned_be16(&buf[2]); + struct file *file = FD_DEV(cmd->se_dev)->fd_file; - size = cmd->data_length - 8; - if (bd_dl > size) - pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", - cmd->data_length, bd_dl); - else - size = bd_dl; - - if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { - ret = TCM_INVALID_PARAMETER_LIST; - goto err; - } - - /* First UNMAP block descriptor starts at 8 byte offset */ - ptr = &buf[8]; - pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" - " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - - while (size >= 16) { - lba = get_unaligned_be64(&ptr[0]); - range = get_unaligned_be32(&ptr[8]); - pr_debug("UNMAP: Using lba: %llu and range: %u\n", - (unsigned long long)lba, range); - - if (range > dev->dev_attrib.max_unmap_lba_count) { - ret = TCM_INVALID_PARAMETER_LIST; - goto err; - } - - if (lba + range > dev->transport->get_blocks(dev) + 1) { - ret = TCM_ADDRESS_OUT_OF_RANGE; - goto err; - } - - ret = fd_do_unmap(cmd, file, lba, range); - if (ret) - goto err; - - ptr += 16; - size -= 16; - } - -err: - transport_kunmap_data_sg(cmd); - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; + return sbc_execute_unmap(cmd, fd_do_unmap, file); } static sense_reason_t diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 96a9b620e89a..07f5f94634bb 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -380,9 +380,10 @@ iblock_execute_sync_cache(struct se_cmd *cmd) } static sense_reason_t -iblock_do_unmap(struct se_cmd *cmd, struct block_device *bdev, +iblock_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) { + struct block_device *bdev = priv; int ret; ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); @@ -397,83 +398,9 @@ iblock_do_unmap(struct se_cmd *cmd, struct block_device *bdev, static sense_reason_t iblock_execute_unmap(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - struct iblock_dev *ib_dev = IBLOCK_DEV(dev); - unsigned char *buf, *ptr = NULL; - sector_t lba; - int size; - u32 range; - sense_reason_t ret = 0; - int dl, bd_dl; - - /* We never set ANC_SUP */ - if (cmd->t_task_cdb[1]) - return TCM_INVALID_CDB_FIELD; - - if (cmd->data_length == 0) { - target_complete_cmd(cmd, SAM_STAT_GOOD); - return 0; - } - - if (cmd->data_length < 8) { - pr_warn("UNMAP parameter list length %u too small\n", - cmd->data_length); - return TCM_PARAMETER_LIST_LENGTH_ERROR; - } - - buf = transport_kmap_data_sg(cmd); - if (!buf) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - dl = get_unaligned_be16(&buf[0]); - bd_dl = get_unaligned_be16(&buf[2]); - - size = cmd->data_length - 8; - if (bd_dl > size) - pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", - cmd->data_length, bd_dl); - else - size = bd_dl; - - if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { - ret = TCM_INVALID_PARAMETER_LIST; - goto err; - } - - /* First UNMAP block descriptor starts at 8 byte offset */ - ptr = &buf[8]; - pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" - " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - - while (size >= 16) { - lba = get_unaligned_be64(&ptr[0]); - range = get_unaligned_be32(&ptr[8]); - pr_debug("UNMAP: Using lba: %llu and range: %u\n", - (unsigned long long)lba, range); - - if (range > dev->dev_attrib.max_unmap_lba_count) { - ret = TCM_INVALID_PARAMETER_LIST; - goto err; - } - - if (lba + range > dev->transport->get_blocks(dev) + 1) { - ret = TCM_ADDRESS_OUT_OF_RANGE; - goto err; - } - - ret = iblock_do_unmap(cmd, ib_dev->ibd_bd, lba, range); - if (ret) - goto err; - - ptr += 16; - size -= 16; - } + struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; -err: - transport_kunmap_data_sg(cmd); - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; + return sbc_execute_unmap(cmd, iblock_do_unmap, bdev); } static sense_reason_t diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 60d4b5185f32..bbc5b0ee2bdc 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -596,3 +596,88 @@ u32 sbc_get_device_type(struct se_device *dev) return TYPE_DISK; } EXPORT_SYMBOL(sbc_get_device_type); + +sense_reason_t +sbc_execute_unmap(struct se_cmd *cmd, + sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *, + sector_t, sector_t), + void *priv) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf, *ptr = NULL; + sector_t lba; + int size; + u32 range; + sense_reason_t ret = 0; + int dl, bd_dl; + + /* We never set ANC_SUP */ + if (cmd->t_task_cdb[1]) + return TCM_INVALID_CDB_FIELD; + + if (cmd->data_length == 0) { + target_complete_cmd(cmd, SAM_STAT_GOOD); + return 0; + } + + if (cmd->data_length < 8) { + pr_warn("UNMAP parameter list length %u too small\n", + cmd->data_length); + return TCM_PARAMETER_LIST_LENGTH_ERROR; + } + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + dl = get_unaligned_be16(&buf[0]); + bd_dl = get_unaligned_be16(&buf[2]); + + size = cmd->data_length - 8; + if (bd_dl > size) + pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", + cmd->data_length, bd_dl); + else + size = bd_dl; + + if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { + ret = TCM_INVALID_PARAMETER_LIST; + goto err; + } + + /* First UNMAP block descriptor starts at 8 byte offset */ + ptr = &buf[8]; + pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" + " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); + + while (size >= 16) { + lba = get_unaligned_be64(&ptr[0]); + range = get_unaligned_be32(&ptr[8]); + pr_debug("UNMAP: Using lba: %llu and range: %u\n", + (unsigned long long)lba, range); + + if (range > dev->dev_attrib.max_unmap_lba_count) { + ret = TCM_INVALID_PARAMETER_LIST; + goto err; + } + + if (lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } + + ret = do_unmap_fn(cmd, priv, lba, range); + if (ret) + goto err; + + ptr += 16; + size -= 16; + } + +err: + transport_kunmap_data_sg(cmd); + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; +} +EXPORT_SYMBOL(sbc_execute_unmap); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index b128c20770bc..ffa2696d64dc 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -60,6 +60,10 @@ sense_reason_t sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops); u32 sbc_get_device_rev(struct se_device *dev); u32 sbc_get_device_type(struct se_device *dev); sector_t sbc_get_write_same_sectors(struct se_cmd *cmd); +sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, + sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv, + sector_t lba, sector_t nolb), + void *priv); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); |