From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch series converts the existing transport_generic_unmap() and transport_generic_write_same() code to be called directly from TCM code using transport_emulate_control_cdb(). It also converts the primary struct se_subsystem_api->do_discard() to accept an 'sector_t lba' and 'u32 range' that is passed from SCSI UNMAP/WRITE_SAME emulation down to generic block level discard logic in TCM/IBLOCK. This patch also makes emulate_tpu and emulate_tpws now disabled by default, even when the underlying struct block_device supports Discard during IBLOCK device creation. This means that these two attrs will need to be enabled on a per $HBA/$DEV/attrib/ basis to explictly activate SCSI UNMAP/WRITE_SAME support. Finally, this patch also drops the Generic Block Discard support in TCM/FILEIO as there is really not a safe way to do this yet. Thanks again to hch for his input on this item! Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx> Reported-by: Christoph Hellwig <hch@xxxxxx> --- drivers/target/target_core_device.c | 18 +++++ drivers/target/target_core_file.c | 127 +------------------------------- drivers/target/target_core_iblock.c | 41 ++--------- drivers/target/target_core_transport.c | 27 ++++--- include/target/target_core_transport.h | 9 +-- 5 files changed, 43 insertions(+), 179 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 070da98..5364259 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1231,6 +1231,15 @@ int se_dev_set_emulate_tpu(struct se_device *dev, int flag) printk(KERN_ERR "Illegal value %d\n", flag); return -1; } + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) { + printk(KERN_ERR "Generic Block Discard not supported\n"); + return -ENOSYS; + } + DEV_ATTRIB(dev)->emulate_tpu = flag; printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", dev, flag); @@ -1243,6 +1252,15 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag) printk(KERN_ERR "Illegal value %d\n", flag); return -1; } + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) { + printk(KERN_ERR "Generic Block Discard not supported\n"); + return -ENOSYS; + } + DEV_ATTRIB(dev)->emulate_tpws = flag; printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", dev, flag); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 3a68932..6c3f9e5 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -235,32 +235,6 @@ static struct se_device *fd_create_virtdevice( fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; fd_dev->fd_queue_depth = dev->queue_depth; - /* - * Check for QUEUE_FLAG_DISCARD and enable TCM TPE emulation - * if present for struct block_device backend - */ - if (S_ISBLK(inode->i_mode)) { - if (blk_queue_discard(bdev_get_queue(inode->i_bdev))) { - struct block_device *bd = inode->i_bdev; - struct request_queue *q = bdev_get_queue(bd); - - DEV_ATTRIB(dev)->max_unmap_lba_count = - q->limits.max_discard_sectors; - /* - * Currently hardcoded to 1 in Linux/SCSI code.. - */ - DEV_ATTRIB(dev)->max_unmap_block_desc_count = 1; - DEV_ATTRIB(dev)->unmap_granularity = - q->limits.discard_granularity; - DEV_ATTRIB(dev)->unmap_granularity_alignment = - q->limits.discard_alignment; - - DEV_ATTRIB(dev)->emulate_tpu = 1; - DEV_ATTRIB(dev)->emulate_tpws = 1; - printk(KERN_INFO "FILEIO: Enabling BLOCK Discard" - " for TPU=1 and TPWS=1 emulation\n"); - } - } printk(KERN_INFO "CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, @@ -358,91 +332,6 @@ static void *fd_allocate_request( return (void *)fd_req; } -static int fd_emulate_unmap(struct se_task *task) -{ - struct se_cmd *cmd = TASK_CMD(task); - struct fd_dev *fd_dev = task->se_dev->dev_ptr; - struct file *f = fd_dev->fd_file; - struct inode *i; - struct block_device *bd; - int ret; - - i = igrab(f->f_mapping->host); - if (!(i)) { - printk(KERN_ERR "FILEIO: Unable to locate inode for" - " backend for UNMAP\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - /* - * Currently for struct file w/o a struct block_device - * backend we return a success.. - */ - if (!(S_ISBLK(i->i_mode))) { - printk(KERN_WARNING "Ignoring UNMAP for non BD" - " backend for struct file\n"); - iput(i); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - bd = I_BDEV(f->f_mapping->host); - if (!(bd)) { - printk(KERN_ERR "FILEIO: Unable to locate struct" - " block_device for UNMAP\n"); - iput(i); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - /* - * Now call the transport_generic_unmap() -> blkdev_issue_discard() - * wrapper to translate SCSI UNMAP into Linux/BLOCK discards on - * LBA+Range descriptors in the UNMAP write paylaod. - */ - ret = transport_generic_unmap(cmd, bd); - iput(i); - - return ret; -} - -static int fd_emulate_write_same_unmap(struct se_task *task) -{ - struct se_cmd *cmd = TASK_CMD(task); - struct fd_dev *fd_dev = task->se_dev->dev_ptr; - struct file *f = fd_dev->fd_file; - struct inode *i; - struct block_device *bd; - int ret; - - i = igrab(f->f_mapping->host); - if (!(i)) { - printk(KERN_ERR "FILEIO: Unable to locate inode for" - " backend for WRITE_SAME\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - /* - * Currently for struct file w/o a struct block_device - * backend we return a success.. - */ - if (!(S_ISBLK(i->i_mode))) { - printk(KERN_WARNING "Ignoring WRITE_SAME for non BD" - " backend for struct file\n"); - iput(i); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - bd = I_BDEV(f->f_mapping->host); - if (!(bd)) { - printk(KERN_ERR "FILEIO: Unable to locate struct" - " block_device for WRITE_SAME\n"); - iput(i); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - ret = transport_generic_write_same(cmd, bd); - iput(i); - if (ret < 0) - return ret; - - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; -} - static inline int fd_iovec_alloc(struct fd_request *req) { req->fd_iovs = kzalloc(sizeof(struct iovec) * req->fd_sg_count, @@ -774,20 +663,6 @@ static int fd_do_task(struct se_task *task) return PYX_TRANSPORT_SENT_TO_TRANSPORT; } -static int fd_do_discard(struct se_task *task, enum blk_discard_type type) -{ - if (type == DISCARD_UNMAP) - return fd_emulate_unmap(task); - else if (type == DISCARD_WRITE_SAME_UNMAP) - return fd_emulate_write_same_unmap(task); - else { - printk(KERN_ERR "Unsupported discard_type_t: %d\n", type); - return -ENOSYS; - } - - return -ENOSYS; -} - /* fd_free_task(): (Part of se_subsystem_api_t template) * * @@ -1172,7 +1047,7 @@ static struct se_subsystem_api fileio_template = { .transport_complete = fd_transport_complete, .allocate_request = fd_allocate_request, .do_task = fd_do_task, - .do_discard = fd_do_discard, + .do_discard = NULL, .do_sync_cache = fd_emulate_sync_cache, .free_task = fd_free_task, .check_configfs_dev_params = fd_check_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index e740265..463f992 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -213,10 +213,8 @@ static struct se_device *iblock_create_virtdevice( DEV_ATTRIB(dev)->unmap_granularity_alignment = q->limits.discard_alignment; - DEV_ATTRIB(dev)->emulate_tpu = 1; - DEV_ATTRIB(dev)->emulate_tpws = 1; - printk(KERN_INFO "IBLOCK: Enabling BLOCK Discard support" - " for TPU=1 and TPWS=1 emulation\n"); + printk(KERN_INFO "IBLOCK: BLOCK Discard support available," + " disabled by default\n"); } return dev; @@ -392,22 +390,6 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( return blocks_long; } -static int iblock_emulate_write_same_unmap(struct se_task *task) -{ - struct iblock_dev *ibd = task->se_dev->dev_ptr; - struct block_device *bd = ibd->ibd_bd; - struct se_cmd *cmd = TASK_CMD(task); - int ret; - - ret = transport_generic_write_same(cmd, bd); - if (ret < 0) - return ret; - - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; -} - static int __iblock_do_sync_cache(struct se_device *dev) { struct iblock_dev *ib_dev = (struct iblock_dev *)dev->dev_ptr; @@ -532,22 +514,13 @@ static int iblock_do_task(struct se_task *task) return PYX_TRANSPORT_SENT_TO_TRANSPORT; } -static int iblock_do_discard(struct se_task *task, enum blk_discard_type type) +static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) { - struct iblock_dev *ibd = task->se_dev->dev_ptr; + struct iblock_dev *ibd = dev->dev_ptr; struct block_device *bd = ibd->ibd_bd; - struct se_cmd *cmd = TASK_CMD(task); - - if (type == DISCARD_UNMAP) - return transport_generic_unmap(cmd, bd); - else if (type == DISCARD_WRITE_SAME_UNMAP) - return iblock_emulate_write_same_unmap(task); - else { - printk(KERN_ERR "Unsupported discard_type_t: %d\n", type); - return -ENOSYS; - } - - return -ENOSYS; + int barrier = 0; + + return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); } static void iblock_free_task(struct se_task *task) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4a30fb9..44376a3 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -5475,14 +5475,15 @@ int transport_get_sense_data(struct se_cmd *cmd) * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -int transport_generic_unmap(struct se_cmd *cmd, struct block_device *bdev) +static int transport_generic_unmap(struct se_task *task) { + struct se_cmd *cmd = TASK_CMD(task); struct se_device *dev = SE_DEV(cmd); unsigned char *buf = T_TASK(cmd)->t_task_buf, *ptr = NULL; unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0]; sector_t lba; unsigned int size = cmd->data_length, range; - int barrier = 0, ret, offset = 8; /* First UNMAP block descriptor starts at 8 byte offset */ + int ret, offset = 8; /* First UNMAP block descriptor starts at 8 byte offset */ unsigned short dl, bd_dl; /* Skip over UNMAP header */ @@ -5499,7 +5500,7 @@ int transport_generic_unmap(struct se_cmd *cmd, struct block_device *bdev) printk(KERN_INFO "UNMAP: Using lba: %llu and range: %u\n", (unsigned long long)lba, range); - ret = blkdev_issue_discard(bdev, lba, range, GFP_KERNEL, barrier); + ret = TRANSPORT(dev)->do_discard(dev, lba, range); if (ret < 0) { printk(KERN_ERR "blkdev_issue_discard() failed: %d\n", ret); return -1; @@ -5509,20 +5510,22 @@ int transport_generic_unmap(struct se_cmd *cmd, struct block_device *bdev) size -= 16; } + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -EXPORT_SYMBOL(transport_generic_unmap); /* * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -int transport_generic_write_same(struct se_cmd *cmd, struct block_device *bdev) +static int transport_generic_write_same(struct se_task *task) { + struct se_cmd *cmd = TASK_CMD(task); struct se_device *dev = SE_DEV(cmd); sector_t lba; unsigned int range; - int barrier = 0, ret; + int ret; lba = T_TASK(cmd)->t_task_lba; range = (cmd->data_length / TRANSPORT(dev)->get_blocksize(dev)); @@ -5530,14 +5533,16 @@ int transport_generic_write_same(struct se_cmd *cmd, struct block_device *bdev) printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %u\n", (unsigned long long)lba, range); - ret = blkdev_issue_discard(bdev, lba, range, GFP_KERNEL, barrier); + ret = TRANSPORT(dev)->do_discard(dev, lba, range); if (ret < 0) { printk(KERN_INFO "blkdev_issue_discard() failed for WRITE_SAME\n"); return -1; } + + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } -EXPORT_SYMBOL(transport_generic_write_same); /* * Used by TCM subsystem plugins IBLOCK, FILEIO, and RAMDISK as a @@ -5610,7 +5615,7 @@ int transport_emulate_control_cdb(struct se_task *task) TRANSPORT(dev)->name); return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } - ret = TRANSPORT(dev)->do_discard(task, DISCARD_UNMAP); + ret = transport_generic_unmap(task); if (ret < 0) return ret; break; @@ -5620,7 +5625,7 @@ int transport_emulate_control_cdb(struct se_task *task) " for: %s\n", TRANSPORT(dev)->name); return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } - ret = TRANSPORT(dev)->do_discard(task, DISCARD_WRITE_SAME_UNMAP); + ret = transport_generic_write_same(task); if (ret < 0) return ret; break; @@ -5633,7 +5638,7 @@ int transport_emulate_control_cdb(struct se_task *task) " supported for: %s\n", TRANSPORT(dev)->name); return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; } - ret = TRANSPORT(dev)->do_discard(task, DISCARD_WRITE_SAME_UNMAP); + ret = transport_generic_write_same(task); if (ret < 0) return ret; break; diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index 1f29cf3..c156098 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h @@ -127,11 +127,6 @@ #define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs)) -enum blk_discard_type { - DISCARD_UNMAP, - DISCARD_WRITE_SAME_UNMAP, -}; - struct se_mem; struct se_subsystem_api; @@ -243,8 +238,6 @@ extern int transport_generic_emulate_modesense(struct se_cmd *, extern int transport_generic_emulate_request_sense(struct se_cmd *, unsigned char *); extern int transport_get_sense_data(struct se_cmd *); -extern int transport_generic_unmap(struct se_cmd *, struct block_device *); -extern int transport_generic_write_same(struct se_cmd *, struct block_device *); extern int transport_emulate_control_cdb(struct se_task *); extern struct se_cmd *transport_allocate_passthrough(unsigned char *, int, u32, void *, u32, u32, void *); @@ -471,7 +464,7 @@ struct se_subsystem_api { * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate * UNMAP and WRITE_SAME_* w/ UNMAP=1 <-> Linux/Block Discard */ - int (*do_discard)(struct se_task *, enum blk_discard_type); + int (*do_discard)(struct se_device *, sector_t, u32); /* * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate * SYNCHRONIZE_CACHE_* <-> Linux/Block blkdev_issue_flush() -- 1.5.6.5 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html