From fb418240ecbd721a1237da592c075993c1709955 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 9 May 2017 16:46:04 -0500 Subject: target: remove dead code Local variable _ret_ is assigned to a constant value and it is never updated again. Remove this variable and the dead code it guards. Addresses-Coverity-ID: 140761 Signed-off-by: Gustavo A. R. Silva Reviewed-by: Tyrel Datwyler Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_rd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 20253d04103f..d12967690054 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -554,7 +554,7 @@ static ssize_t rd_set_configfs_dev_params(struct se_device *dev, struct rd_dev *rd_dev = RD_DEV(dev); char *orig, *ptr, *opts; substring_t args[MAX_OPT_ARGS]; - int ret = 0, arg, token; + int arg, token; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -589,7 +589,7 @@ static ssize_t rd_set_configfs_dev_params(struct se_device *dev, } kfree(orig); - return (!ret) ? count : ret; + return count; } static ssize_t rd_show_configfs_dev_params(struct se_device *dev, char *b) -- cgit v1.2.3 From 12bdcbd539c6327c09da0503c674733cb2d82cb5 Mon Sep 17 00:00:00 2001 From: Byungchul Park Date: Fri, 12 May 2017 09:42:56 +0900 Subject: vhost/scsi: Don't reinvent the wheel but use existing llist API Although llist provides proper APIs, they are not used. Make them used. Signed-off-by: Byungchul Park Acked-by: Nicholas Bellinger Signed-off-by: Nicholas Bellinger --- drivers/vhost/scsi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index fd6c8b66f06f..679f8960db4b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -496,14 +496,12 @@ static void vhost_scsi_evt_work(struct vhost_work *work) struct vhost_scsi *vs = container_of(work, struct vhost_scsi, vs_event_work); struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; - struct vhost_scsi_evt *evt; + struct vhost_scsi_evt *evt, *t; struct llist_node *llnode; mutex_lock(&vq->mutex); llnode = llist_del_all(&vs->vs_event_list); - while (llnode) { - evt = llist_entry(llnode, struct vhost_scsi_evt, list); - llnode = llist_next(llnode); + llist_for_each_entry_safe(evt, t, llnode, list) { vhost_scsi_do_evt_work(vs, evt); vhost_scsi_free_evt(vs, evt); } @@ -529,10 +527,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) bitmap_zero(signal, VHOST_SCSI_MAX_VQ); llnode = llist_del_all(&vs->vs_completion_list); - while (llnode) { - cmd = llist_entry(llnode, struct vhost_scsi_cmd, - tvc_completion_list); - llnode = llist_next(llnode); + llist_for_each_entry(cmd, llnode, tvc_completion_list) { se_cmd = &cmd->tvc_se_cmd; pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, -- cgit v1.2.3 From 464fd6419c68bc6b1697e02f46b6d3dd57dfed28 Mon Sep 17 00:00:00 2001 From: Michael Cyr Date: Tue, 16 May 2017 17:49:21 -0500 Subject: ibmvscsis: Enable Logical Partition Migration Support Changes to support a new mechanism from phyp to better synchronize the logical partition migration (LPM) of the client partition. This includes a new VIOCTL to register that we support this new functionality, and 2 new Transport Event types, and finally another new VIOCTL to let phyp know once we're ready for the Suspend. Signed-off-by: Michael Cyr Signed-off-by: Bryant G. Ly Signed-off-by: Nicholas Bellinger --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 148 ++++++++++++++++++++++++++++--- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h | 25 +++++- drivers/scsi/ibmvscsi_tgt/libsrp.h | 5 +- 3 files changed, 162 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index abf6026645dd..35710524d059 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -155,6 +155,9 @@ static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi) qrc = h_free_crq(vscsi->dds.unit_id); switch (qrc) { case H_SUCCESS: + spin_lock_bh(&vscsi->intr_lock); + vscsi->flags &= ~PREP_FOR_SUSPEND_FLAGS; + spin_unlock_bh(&vscsi->intr_lock); break; case H_HARDWARE: @@ -422,6 +425,9 @@ static void ibmvscsis_disconnect(struct work_struct *work) new_state = vscsi->new_state; vscsi->new_state = 0; + vscsi->flags |= DISCONNECT_SCHEDULED; + vscsi->flags &= ~SCHEDULE_DISCONNECT; + pr_debug("disconnect: flags 0x%x, state 0x%hx\n", vscsi->flags, vscsi->state); @@ -802,6 +808,13 @@ static long ibmvscsis_establish_new_q(struct scsi_info *vscsi) long rc = ADAPT_SUCCESS; uint format; + rc = h_vioctl(vscsi->dds.unit_id, H_ENABLE_PREPARE_FOR_SUSPEND, 30000, + 0, 0, 0, 0); + if (rc == H_SUCCESS) + vscsi->flags |= PREP_FOR_SUSPEND_ENABLED; + else if (rc != H_NOT_FOUND) + pr_err("Error from Enable Prepare for Suspend: %ld\n", rc); + vscsi->flags &= PRESERVE_FLAG_FIELDS; vscsi->rsp_q_timer.timer_pops = 0; vscsi->debit = 0; @@ -950,6 +963,63 @@ static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi, } } +/** + * ibmvscsis_ready_for_suspend() - Helper function to call VIOCTL + * @vscsi: Pointer to our adapter structure + * @idle: Indicates whether we were called from adapter_idle. This + * is important to know if we need to do a disconnect, since if + * we're called from adapter_idle, we're still processing the + * current disconnect, so we can't just call post_disconnect. + * + * This function is called when the adapter is idle when phyp has sent + * us a Prepare for Suspend Transport Event. + * + * EXECUTION ENVIRONMENT: + * Process or interrupt environment called with interrupt lock held + */ +static long ibmvscsis_ready_for_suspend(struct scsi_info *vscsi, bool idle) +{ + long rc = 0; + struct viosrp_crq *crq; + + /* See if there is a Resume event in the queue */ + crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index; + + pr_debug("ready_suspend: flags 0x%x, state 0x%hx crq_valid:%x\n", + vscsi->flags, vscsi->state, (int)crq->valid); + + if (!(vscsi->flags & PREP_FOR_SUSPEND_ABORTED) && !(crq->valid)) { + rc = h_vioctl(vscsi->dds.unit_id, H_READY_FOR_SUSPEND, 0, 0, 0, + 0, 0); + if (rc) { + pr_err("Ready for Suspend Vioctl failed: %ld\n", rc); + rc = 0; + } + } else if (((vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE) && + (vscsi->flags & PREP_FOR_SUSPEND_ABORTED)) || + ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) || + (crq->format != RESUME_FROM_SUSP)))) { + if (idle) { + vscsi->state = ERR_DISCONNECT_RECONNECT; + ibmvscsis_reset_queue(vscsi); + rc = -1; + } else if (vscsi->state == CONNECTED) { + ibmvscsis_post_disconnect(vscsi, + ERR_DISCONNECT_RECONNECT, 0); + } + + vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE; + + if ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) || + (crq->format != RESUME_FROM_SUSP))) + pr_err("Invalid element in CRQ after Prepare for Suspend"); + } + + vscsi->flags &= ~(PREP_FOR_SUSPEND_PENDING | PREP_FOR_SUSPEND_ABORTED); + + return rc; +} + /** * ibmvscsis_trans_event() - Handle a Transport Event * @vscsi: Pointer to our adapter structure @@ -974,18 +1044,8 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi, case PARTNER_FAILED: case PARTNER_DEREGISTER: ibmvscsis_delete_client_info(vscsi, true); - break; - - default: - rc = ERROR; - dev_err(&vscsi->dev, "trans_event: invalid format %d\n", - (uint)crq->format); - ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, - RESPONSE_Q_DOWN); - break; - } - - if (rc == ADAPT_SUCCESS) { + if (crq->format == MIGRATED) + vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE; switch (vscsi->state) { case NO_QUEUE: case ERR_DISCONNECTED: @@ -1034,6 +1094,60 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi, vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT); break; } + break; + + case PREPARE_FOR_SUSPEND: + pr_debug("Prep for Suspend, crq status = 0x%x\n", + (int)crq->status); + switch (vscsi->state) { + case ERR_DISCONNECTED: + case WAIT_CONNECTION: + case CONNECTED: + ibmvscsis_ready_for_suspend(vscsi, false); + break; + case SRP_PROCESSING: + vscsi->resume_state = vscsi->state; + vscsi->flags |= PREP_FOR_SUSPEND_PENDING; + if (crq->status == CRQ_ENTRY_OVERWRITTEN) + vscsi->flags |= PREP_FOR_SUSPEND_OVERWRITE; + ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0); + break; + case NO_QUEUE: + case UNDEFINED: + case UNCONFIGURING: + case WAIT_ENABLED: + case ERR_DISCONNECT: + case ERR_DISCONNECT_RECONNECT: + case WAIT_IDLE: + pr_err("Invalid state for Prepare for Suspend Trans Event: 0x%x\n", + vscsi->state); + break; + } + break; + + case RESUME_FROM_SUSP: + pr_debug("Resume from Suspend, crq status = 0x%x\n", + (int)crq->status); + if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) { + vscsi->flags |= PREP_FOR_SUSPEND_ABORTED; + } else { + if ((crq->status == CRQ_ENTRY_OVERWRITTEN) || + (vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE)) { + ibmvscsis_post_disconnect(vscsi, + ERR_DISCONNECT_RECONNECT, + 0); + vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE; + } + } + break; + + default: + rc = ERROR; + dev_err(&vscsi->dev, "trans_event: invalid format %d\n", + (uint)crq->format); + ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, + RESPONSE_Q_DOWN); + break; } rc = vscsi->flags & SCHEDULE_DISCONNECT; @@ -1201,6 +1315,7 @@ static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi) static void ibmvscsis_adapter_idle(struct scsi_info *vscsi) { int free_qs = false; + long rc = 0; pr_debug("adapter_idle: flags 0x%x, state 0x%hx\n", vscsi->flags, vscsi->state); @@ -1240,7 +1355,14 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi) vscsi->rsp_q_timer.timer_pops = 0; vscsi->debit = 0; vscsi->credit = 0; - if (vscsi->flags & TRANS_EVENT) { + if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) { + vscsi->state = vscsi->resume_state; + vscsi->resume_state = 0; + rc = ibmvscsis_ready_for_suspend(vscsi, true); + vscsi->flags &= ~DISCONNECT_SCHEDULED; + if (rc) + break; + } else if (vscsi->flags & TRANS_EVENT) { vscsi->state = WAIT_CONNECTION; vscsi->flags &= PRESERVE_FLAG_FIELDS; } else { diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h index b4391a8de456..cc96c2731134 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h @@ -262,6 +262,14 @@ struct scsi_info { #define DISCONNECT_SCHEDULED 0x00800 /* remove function is sleeping */ #define CFG_SLEEPING 0x01000 + /* Register for Prepare for Suspend Transport Events */ +#define PREP_FOR_SUSPEND_ENABLED 0x02000 + /* Prepare for Suspend event sent */ +#define PREP_FOR_SUSPEND_PENDING 0x04000 + /* Resume from Suspend event sent */ +#define PREP_FOR_SUSPEND_ABORTED 0x08000 + /* Prepare for Suspend event overwrote another CRQ entry */ +#define PREP_FOR_SUSPEND_OVERWRITE 0x10000 u32 flags; /* adapter lock */ spinlock_t intr_lock; @@ -272,6 +280,7 @@ struct scsi_info { /* used in crq, to tag what iu the response is for */ u64 empty_iu_tag; uint new_state; + uint resume_state; /* control block for the response queue timer */ struct timer_cb rsp_q_timer; /* keep last client to enable proper accounting */ @@ -324,8 +333,13 @@ struct scsi_info { #define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \ ((VSCSI)->flags & BLOCK)) +#define PREP_FOR_SUSPEND_FLAGS (PREP_FOR_SUSPEND_ENABLED | \ + PREP_FOR_SUSPEND_PENDING | \ + PREP_FOR_SUSPEND_ABORTED | \ + PREP_FOR_SUSPEND_OVERWRITE) + /* flag bit that are not reset during disconnect */ -#define PRESERVE_FLAG_FIELDS 0 +#define PRESERVE_FLAG_FIELDS (PREP_FOR_SUSPEND_FLAGS) #define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf)) @@ -333,8 +347,15 @@ struct scsi_info { #define WRITE_CMD(cdb) (((cdb)[0] & 0x1F) == 0xA) #ifndef H_GET_PARTNER_INFO -#define H_GET_PARTNER_INFO 0x0000000000000008LL +#define H_GET_PARTNER_INFO 0x0000000000000008LL +#endif +#ifndef H_ENABLE_PREPARE_FOR_SUSPEND +#define H_ENABLE_PREPARE_FOR_SUSPEND 0x000000000000001DLL #endif +#ifndef H_READY_FOR_SUSPEND +#define H_READY_FOR_SUSPEND 0x000000000000001ELL +#endif + #define h_copy_rdma(l, sa, sb, da, db) \ plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db) diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.h b/drivers/scsi/ibmvscsi_tgt/libsrp.h index 4696f331453e..9fec55b36322 100644 --- a/drivers/scsi/ibmvscsi_tgt/libsrp.h +++ b/drivers/scsi/ibmvscsi_tgt/libsrp.h @@ -30,10 +30,13 @@ enum srp_trans_event { UNUSED_FORMAT = 0, PARTNER_FAILED = 1, PARTNER_DEREGISTER = 2, - MIGRATED = 6 + MIGRATED = 6, + PREPARE_FOR_SUSPEND = 9, + RESUME_FROM_SUSP = 0xA }; enum srp_status { + CRQ_ENTRY_OVERWRITTEN = 0x20, HEADER_DESCRIPTOR = 0xF1, PING = 0xF5, PING_RESPONSE = 0xF6 -- cgit v1.2.3 From 2237498f0b5c74768f688ebaf16eab2c708d5fdb Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 11 Apr 2017 22:21:47 -0700 Subject: target/iblock: Convert WRITE_SAME to blkdev_issue_zeroout The people who are actively using iblock_execute_write_same_direct() are doing so in the context of ESX VAAI BlockZero, together with EXTENDED_COPY and COMPARE_AND_WRITE primitives. In practice though I've not seen any users of IBLOCK WRITE_SAME for anything other than VAAI BlockZero, so just using blkdev_issue_zeroout() when available, and falling back to iblock_execute_write_same() if the WRITE_SAME buffer contains anything other than zeros should be OK. (Hook up max_write_zeroes_sectors to signal LBPRZ feature bit in target_configure_unmap_from_queue - nab) Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Cc: Christoph Hellwig Cc: Mike Christie Cc: Hannes Reinecke Cc: Jens Axboe Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_iblock.c | 44 +++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8add07f387f9..a5762e601fa1 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -851,7 +851,7 @@ bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, attrib->unmap_granularity = q->limits.discard_granularity / block_size; attrib->unmap_granularity_alignment = q->limits.discard_alignment / block_size; - attrib->unmap_zeroes_data = 0; + attrib->unmap_zeroes_data = (q->limits.max_write_zeroes_sectors); return true; } EXPORT_SYMBOL(target_configure_unmap_from_queue); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index bb069ebe4aa6..b2044133d747 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -86,6 +86,7 @@ static int iblock_configure_device(struct se_device *dev) struct block_device *bd = NULL; struct blk_integrity *bi; fmode_t mode; + unsigned int max_write_zeroes_sectors; int ret = -ENOMEM; if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { @@ -129,7 +130,11 @@ static int iblock_configure_device(struct se_device *dev) * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. */ - dev->dev_attrib.max_write_same_len = 0xFFFF; + max_write_zeroes_sectors = bdev_write_zeroes_sectors(bd); + if (max_write_zeroes_sectors) + dev->dev_attrib.max_write_same_len = max_write_zeroes_sectors; + else + dev->dev_attrib.max_write_same_len = 0xFFFF; if (blk_queue_nonrot(q)) dev->dev_attrib.is_nonrot = 1; @@ -415,28 +420,31 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) } static sense_reason_t -iblock_execute_write_same_direct(struct block_device *bdev, struct se_cmd *cmd) +iblock_execute_zero_out(struct block_device *bdev, struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct scatterlist *sg = &cmd->t_data_sg[0]; - struct page *page = NULL; - int ret; + unsigned char *buf, zero = 0x00, *p = &zero; + int rc, ret; - if (sg->offset) { - page = alloc_page(GFP_KERNEL); - if (!page) - return TCM_OUT_OF_RESOURCES; - sg_copy_to_buffer(sg, cmd->t_data_nents, page_address(page), - dev->dev_attrib.block_size); - } + buf = kmap(sg_page(sg)) + sg->offset; + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + /* + * Fall back to block_execute_write_same() slow-path if + * incoming WRITE_SAME payload does not contain zeros. + */ + rc = memcmp(buf, p, cmd->data_length); + kunmap(sg_page(sg)); + + if (rc) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = blkdev_issue_write_same(bdev, + ret = blkdev_issue_zeroout(bdev, target_to_linux_sector(dev, cmd->t_task_lba), target_to_linux_sector(dev, sbc_get_write_same_sectors(cmd)), - GFP_KERNEL, page ? page : sg_page(sg)); - if (page) - __free_page(page); + GFP_KERNEL, false); if (ret) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -472,8 +480,10 @@ iblock_execute_write_same(struct se_cmd *cmd) return TCM_INVALID_CDB_FIELD; } - if (bdev_write_same(bdev)) - return iblock_execute_write_same_direct(bdev, cmd); + if (bdev_write_zeroes_sectors(bdev)) { + if (!iblock_execute_zero_out(bdev, cmd)) + return 0; + } ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) -- cgit v1.2.3 From c17cd24959cdb12c855dc61e20c36fa25f21f3d3 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 1 Jun 2017 03:10:53 -0700 Subject: target/configfs: Kill se_device->dev_link_magic Instead of using a hardcoded magic value in se_device when verifying a target config_item symlink source during target_fabric_port_link(), go ahead and use target_core_dev_item_ops directly instead. Reviewed-by: Christoph Hellwig Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 +++++- drivers/target/target_core_device.c | 1 - drivers/target/target_core_fabric_configfs.c | 12 +++++++----- include/target/target_core_base.h | 2 -- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 0326607e5ab8..9b8abd55c21c 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2236,7 +2236,11 @@ static void target_core_dev_release(struct config_item *item) target_free_device(dev); } -static struct configfs_item_operations target_core_dev_item_ops = { +/* + * Used in target_core_fabric_configfs.c to verify valid se_device symlink + * within target_fabric_port_link() + */ +struct configfs_item_operations target_core_dev_item_ops = { .release = target_core_dev_release, }; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index a5762e601fa1..e4771cec108c 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -756,7 +756,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) if (!dev) return NULL; - dev->dev_link_magic = SE_DEV_LINK_MAGIC; dev->se_hba = hba; dev->transport = hba->backend->ops; dev->prot_length = sizeof(struct t10_pi_tuple); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index d1e6cab8e3d3..2cbaecd1669d 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -620,6 +620,8 @@ static struct configfs_attribute *target_fabric_port_attrs[] = { NULL, }; +extern struct configfs_item_operations target_core_dev_item_ops; + static int target_fabric_port_link( struct config_item *lun_ci, struct config_item *se_dev_ci) @@ -628,16 +630,16 @@ static int target_fabric_port_link( struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); struct se_portal_group *se_tpg; - struct se_device *dev = - container_of(to_config_group(se_dev_ci), struct se_device, dev_group); + struct se_device *dev; struct target_fabric_configfs *tf; int ret; - if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { - pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" - " %p to struct se_device: %p\n", se_dev_ci, dev); + if (!se_dev_ci->ci_type || + se_dev_ci->ci_type->ct_item_ops != &target_core_dev_item_ops) { + pr_err("Bad se_dev_ci, not a valid se_dev_ci pointer: %p\n", se_dev_ci); return -EFAULT; } + dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group); if (!(dev->dev_flags & DF_CONFIGURED)) { pr_err("se_device not configured yet, cannot port link\n"); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 0c1dce2ac6f0..c3c14d053122 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -746,8 +746,6 @@ struct se_dev_stat_grps { }; struct se_device { -#define SE_DEV_LINK_MAGIC 0xfeeddeef - u32 dev_link_magic; /* RELATIVE TARGET PORT IDENTIFER Counter */ u16 dev_rpti_counter; /* Used for SAM Task Attribute ordering */ -- cgit v1.2.3 From 9ae0e9ade56f23765366d2cfad24e65f28df977d Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 1 Jun 2017 03:11:18 -0700 Subject: target/configfs: Kill se_lun->lun_link_magic Instead of using a hardcoded magic value in se_lun when verifying a target config_item symlink source during target_fabric_mappedlun_link(), go ahead and use target_fabric_port_item_ops directly instead. Reviewed-by: Christoph Hellwig Cc: Mike Christie Cc: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_fabric_configfs.c | 13 ++++++++----- drivers/target/target_core_tpg.c | 1 - include/target/target_core_base.h | 2 -- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 2cbaecd1669d..e9e917cc6441 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -65,6 +65,8 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) pr_debug("Setup generic %s\n", __stringify(_name)); \ } +static struct configfs_item_operations target_fabric_port_item_ops; + /* Start of tfc_tpg_mappedlun_cit */ static int target_fabric_mappedlun_link( @@ -72,19 +74,20 @@ static int target_fabric_mappedlun_link( struct config_item *lun_ci) { struct se_dev_entry *deve; - struct se_lun *lun = container_of(to_config_group(lun_ci), - struct se_lun, lun_group); + struct se_lun *lun; struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), struct se_lun_acl, se_lun_group); struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; bool lun_access_ro; - if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { - pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" - " %p to struct lun: %p\n", lun_ci, lun); + if (!lun_ci->ci_type || + lun_ci->ci_type->ct_item_ops != &target_fabric_port_item_ops) { + pr_err("Bad lun_ci, not a valid lun_ci pointer: %p\n", lun_ci); return -EFAULT; } + lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); + /* * Ensure that the source port exists */ diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 310d9e55c6eb..36913734c6bc 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -576,7 +576,6 @@ struct se_lun *core_tpg_alloc_lun( return ERR_PTR(-ENOMEM); } lun->unpacked_lun = unpacked_lun; - lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_ref_comp); init_completion(&lun->lun_shutdown_comp); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c3c14d053122..47d9f381209f 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -701,8 +701,6 @@ struct scsi_port_stats { struct se_lun { u64 unpacked_lun; -#define SE_LUN_LINK_MAGIC 0xffff7771 - u32 lun_link_magic; bool lun_shutdown; bool lun_access_ro; u32 lun_index; -- cgit v1.2.3 From eceb4459df4a5b6127ae479280168847b9780b25 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 1 Jun 2017 20:21:33 -0700 Subject: iscsi-target: Avoid holding ->tpg_state_lock during param update As originally reported by Jia-Ju, iscsit_tpg_enable_portal_group() holds iscsi_portal_group->tpg_state_lock while updating AUTHMETHOD via iscsi_update_param_value(), which performs a GFP_KERNEL allocation. However, since iscsit_tpg_enable_portal_group() is already protected by iscsit_get_tpg() -> iscsi_portal_group->tpg_access_lock in it's parent caller, ->tpg_state_lock only needs to be held when setting TPG_STATE_ACTIVE. Reported-by: Jia-Ju Bai Reviewed-by: Jia-Ju Bai Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_tpg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 2e7e08dbda48..abaabbaebd88 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -311,11 +311,9 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; int ret; - spin_lock(&tpg->tpg_state_lock); if (tpg->tpg_state == TPG_STATE_ACTIVE) { pr_err("iSCSI target portal group: %hu is already" " active, ignoring request.\n", tpg->tpgt); - spin_unlock(&tpg->tpg_state_lock); return -EINVAL; } /* @@ -324,10 +322,8 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) * is enforced (as per default), and remove the NONE option. */ param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); - if (!param) { - spin_unlock(&tpg->tpg_state_lock); + if (!param) return -EINVAL; - } if (tpg->tpg_attrib.authentication) { if (!strcmp(param->value, NONE)) { @@ -341,6 +337,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) goto err; } + spin_lock(&tpg->tpg_state_lock); tpg->tpg_state = TPG_STATE_ACTIVE; spin_unlock(&tpg->tpg_state_lock); @@ -353,7 +350,6 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) return 0; err: - spin_unlock(&tpg->tpg_state_lock); return ret; } -- cgit v1.2.3 From 12f66e4a0f7b5624901ba4301210e026c9ddf78d Mon Sep 17 00:00:00 2001 From: Jiang Yi Date: Fri, 2 Jun 2017 11:45:09 +0800 Subject: target: reject COMPARE_AND_WRITE if emulate_caw is not set In struct se_dev_attrib, there is a field emulate_caw exposed as a /sys/kernel/config/target/core/$HBA/$DEV/attrib/. If this field is set zero, it means the corresponding struct se_device does not support the scsi cmd COMPARE_AND_WRITE In function sbc_parse_cdb(), go ahead and reject scsi COMPARE_AND_WRITE if emulate_caw is not set, because it has been explicitly disabled from user-space. (Make pr_err ratelimited - nab) Signed-off-by: Jiang Yi Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 4316f7b65fb7..ff4a6ec30adf 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1005,6 +1005,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) break; } case COMPARE_AND_WRITE: + if (!dev->dev_attrib.emulate_caw) { + pr_err_ratelimited("se_device %s/%s (vpd_unit_serial %s) reject" + " COMPARE_AND_WRITE\n", dev->se_hba->backend->ops->name, + dev->dev_group.cg_item.ci_name, dev->t10_wwn.unit_serial); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } sectors = cdb[13]; /* * Currently enforce COMPARE_AND_WRITE for a single sector -- cgit v1.2.3 From eeb64d239ea664592ff8f1bce5546209a6593df5 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 3 Jun 2017 06:41:03 -0700 Subject: target: Add support for TMR percpu reference counting This patch introduces TMR percpu reference counting using se_lun->lun_ref in transport_lookup_tmr_lun(), following how existing non TMR per se_lun reference counting works within transport_lookup_cmd_lun(). It also adds explicit transport_lun_remove_cmd() calls to drop the reference in the three tmr related locations that invoke transport_cmd_check_stop_to_fabric(); - target_tmr_work() during normal ->queue_tm_rsp() - target_complete_tmr_failure() during error ->queue_tm_rsp() - transport_generic_handle_tmr() during early failure Also, note the exception paths in transport_generic_free_cmd() and transport_cmd_finish_abort() already check SCF_SE_LUN_CMD, and will invoke transport_lun_remove_cmd() when necessary. Reviewed-by: Himanshu Madhani Reviewed-by: Quinn Tran Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 14 ++++++++++---- drivers/target/target_core_transport.c | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e4771cec108c..bf7a57953fa4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -168,11 +168,20 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) rcu_read_lock(); deve = target_nacl_find_deve(nacl, unpacked_lun); if (deve) { - se_cmd->se_lun = rcu_dereference(deve->se_lun); se_lun = rcu_dereference(deve->se_lun); + + if (!percpu_ref_tryget_live(&se_lun->lun_ref)) { + se_lun = NULL; + goto out_unlock; + } + + se_cmd->se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; + se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + se_cmd->lun_ref_active = true; } +out_unlock: rcu_read_unlock(); if (!se_lun) { @@ -182,9 +191,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) unpacked_lun); return -ENODEV; } - /* - * XXX: Add percpu se_lun->lun_ref reference count for TMR - */ se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); se_tmr->tmr_dev = rcu_dereference_raw(se_lun->lun_se_dev); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f1b3a46bdcaf..97a01f48068b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1590,6 +1590,7 @@ static void target_complete_tmr_failure(struct work_struct *work) se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); + transport_lun_remove_cmd(se_cmd); transport_cmd_check_stop_to_fabric(se_cmd); } @@ -3201,6 +3202,7 @@ static void target_tmr_work(struct work_struct *work) cmd->se_tfo->queue_tm_rsp(cmd); check_stop: + transport_lun_remove_cmd(cmd); transport_cmd_check_stop_to_fabric(cmd); } @@ -3223,6 +3225,7 @@ int transport_generic_handle_tmr( pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d" "ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function, cmd->se_tmr_req->ref_task_tag, cmd->tag); + transport_lun_remove_cmd(cmd); transport_cmd_check_stop_to_fabric(cmd); return 0; } -- cgit v1.2.3 From 5465e7d3b99bbaa823ae4f8e538543e7d6cdc530 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 3 Jun 2017 06:55:50 -0700 Subject: target: Add TARGET_SCF_LOOKUP_LUN_FROM_TAG support for ABORT_TASK This patch introduces support in target_submit_tmr() for locating a unpacked_lun from an existing se_cmd->tag during ABORT_TASK. When TARGET_SCF_LOOKUP_LUN_FROM_TAG is set, target_submit_tmr() will do the extra lookup via target_lookup_lun_from_tag() and subsequently invoke transport_lookup_tmr_lun() so a proper percpu se_lun->lun_ref is taken before workqueue dispatch into se_device->tmr_wq happens. Aside from the extra target_lookup_lun_from_tag(), the existing code-path remains unchanged. Reviewed-by: Himanshu Madhani Reviewed-by: Quinn Tran Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 53 ++++++++++++++++++++++++++++------ include/target/target_core_base.h | 3 +- 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 97a01f48068b..e045803921f8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1594,6 +1594,29 @@ static void target_complete_tmr_failure(struct work_struct *work) transport_cmd_check_stop_to_fabric(se_cmd); } +static bool target_lookup_lun_from_tag(struct se_session *se_sess, u64 tag, + u64 *unpacked_lun) +{ + struct se_cmd *se_cmd; + unsigned long flags; + bool ret = false; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { + if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) + continue; + + if (se_cmd->tag == tag) { + *unpacked_lun = se_cmd->orig_fe_lun; + ret = true; + break; + } + } + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + return ret; +} + /** * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd * for TMR CDBs @@ -1641,19 +1664,31 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, core_tmr_release_req(se_cmd->se_tmr_req); return ret; } + /* + * If this is ABORT_TASK with no explicit fabric provided LUN, + * go ahead and search active session tags for a match to figure + * out unpacked_lun for the original se_cmd. + */ + if (tm_type == TMR_ABORT_TASK && (flags & TARGET_SCF_LOOKUP_LUN_FROM_TAG)) { + if (!target_lookup_lun_from_tag(se_sess, tag, &unpacked_lun)) + goto failure; + } ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); - if (ret) { - /* - * For callback during failure handling, push this work off - * to process context with TMR_LUN_DOES_NOT_EXIST status. - */ - INIT_WORK(&se_cmd->work, target_complete_tmr_failure); - schedule_work(&se_cmd->work); - return 0; - } + if (ret) + goto failure; + transport_generic_handle_tmr(se_cmd); return 0; + + /* + * For callback during failure handling, push this work off + * to process context with TMR_LUN_DOES_NOT_EXIST status. + */ +failure: + INIT_WORK(&se_cmd->work, target_complete_tmr_failure); + schedule_work(&se_cmd->work); + return 0; } EXPORT_SYMBOL(target_submit_tmr); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 47d9f381209f..f835528e424e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -188,7 +188,8 @@ enum target_sc_flags_table { TARGET_SCF_BIDI_OP = 0x01, TARGET_SCF_ACK_KREF = 0x02, TARGET_SCF_UNKNOWN_SIZE = 0x04, - TARGET_SCF_USE_CPUID = 0x08, + TARGET_SCF_USE_CPUID = 0x08, + TARGET_SCF_LOOKUP_LUN_FROM_TAG = 0x10, }; /* fabric independent task management function values */ -- cgit v1.2.3 From eb5ae2335a84cccf45ec01602bc300c3e70486d0 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 3 Jun 2017 07:07:21 -0700 Subject: qla2xxx: Convert QLA_TGT_ABTS to TARGET_SCF_LOOKUP_LUN_FROM_TAG Following Himanshu's earlier patch to drop the redundant tag lookup within __qlt_24xx_handle_abts(), go ahead and drop this now QLA_TGT_ABTS can use TARGET_SCF_LOOKUP_LUN_FROM_TAG and have target_submit_tmr() do this from common code. Reviewed-by: Himanshu Madhani Acked-by: Himanshu Madhani Reviewed-by: Quinn Tran Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/qla_target.c | 39 +++++++++----------------------------- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 4 +++- 2 files changed, 12 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 0e03ca2ab3e5..401e245477d4 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1847,38 +1847,13 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct abts_recv_from_24xx *abts, struct fc_port *sess) { struct qla_hw_data *ha = vha->hw; - struct se_session *se_sess = sess->se_sess; struct qla_tgt_mgmt_cmd *mcmd; - struct se_cmd *se_cmd; - u32 lun = 0; int rc; - bool found_lun = false; - unsigned long flags; - - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { - struct qla_tgt_cmd *cmd = - container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - if (se_cmd->tag == abts->exchange_addr_to_abort) { - lun = cmd->unpacked_lun; - found_lun = true; - break; - } - } - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - /* cmd not in LIO lists, look in qla list */ - if (!found_lun) { - if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { - /* send TASK_ABORT response immediately */ - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false); - return 0; - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081, - "unable to find cmd in driver or LIO for tag 0x%x\n", - abts->exchange_addr_to_abort); - return -ENOENT; - } + if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { + /* send TASK_ABORT response immediately */ + qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false); + return 0; } ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, @@ -1899,7 +1874,11 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, mcmd->reset_count = vha->hw->chip_reset; mcmd->tmr_func = QLA_TGT_ABTS; - rc = ha->tgt.tgt_ops->handle_tmr(mcmd, lun, mcmd->tmr_func, + /* + * LUN is looked up by target-core internally based on the passed + * abts->exchange_addr_to_abort tag. + */ + rc = ha->tgt.tgt_ops->handle_tmr(mcmd, 0, mcmd->tmr_func, abts->exchange_addr_to_abort); if (rc != 0) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf052, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7443e4efa3ae..75aeb9fdfd06 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -601,11 +601,13 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, struct fc_port *sess = mcmd->sess; struct se_cmd *se_cmd = &mcmd->se_cmd; int transl_tmr_func = 0; + int flags = TARGET_SCF_ACK_KREF; switch (tmr_func) { case QLA_TGT_ABTS: pr_debug("%ld: ABTS received\n", sess->vha->host_no); transl_tmr_func = TMR_ABORT_TASK; + flags |= TARGET_SCF_LOOKUP_LUN_FROM_TAG; break; case QLA_TGT_2G_ABORT_TASK: pr_debug("%ld: 2G Abort Task received\n", sess->vha->host_no); @@ -638,7 +640,7 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, } return target_submit_tmr(se_cmd, sess->se_sess, NULL, lun, mcmd, - transl_tmr_func, GFP_ATOMIC, tag, TARGET_SCF_ACK_KREF); + transl_tmr_func, GFP_ATOMIC, tag, flags); } static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) -- cgit v1.2.3 From 3e182db787714b373d4b1a1fd7dba4a581e8e406 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:22 -0700 Subject: target: Use symbolic value for WRITE_VERIFY_16 Now that a symbolic value has been introduced for WRITE_VERIFY_16, use it. This patch does not change any functionality. References: commit c2d26f18dcbc ("target: Add WRITE_VERIFY_16") Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Cc: Bryant G. Ly Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index bf7a57953fa4..6403f44e6104 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1131,7 +1131,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, case WRITE_16: case WRITE_VERIFY: case WRITE_VERIFY_12: - case 0x8e: /* WRITE_VERIFY_16 */ + case WRITE_VERIFY_16: case COMPARE_AND_WRITE: case XDWRITEREAD_10: cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; -- cgit v1.2.3 From 9f2f342892e15f8600939ec8d06caf963ccff880 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:23 -0700 Subject: target: Remove se_device.dev_list The last user of se_device.dev_list was removed through commit 0fd97ccf45be ("target: kill struct se_subsystem_dev"). Hence also remove se_device.dev_list. Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 - include/target/target_core_base.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 6403f44e6104..1f54b397bd57 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -767,7 +767,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->prot_length = sizeof(struct t10_pi_tuple); dev->hba_index = hba->hba_index; - INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index f835528e424e..a3af69fcf75e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -816,8 +816,6 @@ struct se_device { unsigned char udev_path[SE_UDEV_PATH_LEN]; /* Pointer to template of function pointers for transport */ const struct target_backend_ops *transport; - /* Linked list for struct se_hba struct se_device list */ - struct list_head dev_list; struct se_lun xcopy_lun; /* Protection Information */ int prot_length; -- cgit v1.2.3 From f2b72d6a8eed0eb02e6346886514a27df1efe827 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:24 -0700 Subject: target: Fix transport_init_se_cmd() Avoid that aborting a command before it has been submitted onto a workqueue triggers the following warning: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 3 PID: 46 Comm: kworker/u8:1 Not tainted 4.12.0-rc2-dbg+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Workqueue: tmr-iblock target_tmr_work [target_core_mod] Call Trace: dump_stack+0x86/0xcf register_lock_class+0xe8/0x570 __lock_acquire+0xa1/0x11d0 lock_acquire+0x59/0x80 flush_work+0x42/0x2b0 __cancel_work_timer+0x10c/0x180 cancel_work_sync+0xb/0x10 core_tmr_lun_reset+0x352/0x740 [target_core_mod] target_tmr_work+0xd6/0x130 [target_core_mod] process_one_work+0x1ca/0x3f0 worker_thread+0x49/0x3b0 kthread+0x109/0x140 ret_from_fork+0x31/0x40 Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e045803921f8..d601616b9f12 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1239,6 +1239,7 @@ void transport_init_se_cmd( init_completion(&cmd->t_transport_stop_comp); init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); + INIT_WORK(&cmd->work, NULL); kref_init(&cmd->cmd_kref); cmd->se_tfo = tfo; -- cgit v1.2.3 From a85d667e58bddf73be84d1981b41eaac985ed216 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:27 -0700 Subject: target: Use {get,put}_unaligned_be*() instead of open coding these functions Introduce the function get_unaligned_be24(). Use {get,put}_unaligned_be*() where appropriate. This patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 8 +-- drivers/target/target_core_device.c | 8 +-- drivers/target/target_core_fabric_lib.c | 6 +- drivers/target/target_core_pr.c | 99 +++++++-------------------------- drivers/target/target_core_pscsi.c | 20 +++---- drivers/target/target_core_sbc.c | 59 +++++--------------- drivers/target/target_core_spc.c | 42 +++++++------- drivers/target/target_core_xcopy.c | 4 +- include/target/target_core_backend.h | 8 +++ 9 files changed, 83 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index fc4a9c303d55..a91b7c25ffd4 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -205,8 +205,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * TARGET PORT GROUP */ - buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff); - buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff); + put_unaligned_be16(tg_pt_gp->tg_pt_gp_id, &buf[off]); + off += 2; off++; /* Skip over Reserved */ /* @@ -235,8 +235,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * Set RELATIVE TARGET PORT IDENTIFIER */ - buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); - buf[off++] = (lun->lun_rtpi & 0xff); + put_unaligned_be16(lun->lun_rtpi, &buf[off]); + off += 2; rd_len += 4; } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1f54b397bd57..11c80c47b9d3 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1091,19 +1091,19 @@ passthrough_parse_cdb(struct se_cmd *cmd, TRANSPORT_FLAG_PASSTHROUGH_PGR)) { if (cdb[0] == PERSISTENT_RESERVE_IN) { cmd->execute_cmd = target_scsi3_emulate_pr_in; - size = (cdb[7] << 8) + cdb[8]; + size = get_unaligned_be16(&cdb[7]); return target_cmd_size_check(cmd, size); } if (cdb[0] == PERSISTENT_RESERVE_OUT) { cmd->execute_cmd = target_scsi3_emulate_pr_out; - size = (cdb[7] << 8) + cdb[8]; + size = get_unaligned_be16(&cdb[7]); return target_cmd_size_check(cmd, size); } if (cdb[0] == RELEASE || cdb[0] == RELEASE_10) { cmd->execute_cmd = target_scsi2_reservation_release; if (cdb[0] == RELEASE_10) - size = (cdb[7] << 8) | cdb[8]; + size = get_unaligned_be16(&cdb[7]); else size = cmd->data_length; return target_cmd_size_check(cmd, size); @@ -1111,7 +1111,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, if (cdb[0] == RESERVE || cdb[0] == RESERVE_10) { cmd->execute_cmd = target_scsi2_reservation_reserve; if (cdb[0] == RESERVE_10) - size = (cdb[7] << 8) | cdb[8]; + size = get_unaligned_be16(&cdb[7]); else size = cmd->data_length; return target_cmd_size_check(cmd, size); diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index cb6497ce4b61..508da345b73f 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -216,8 +217,7 @@ static int iscsi_get_pr_transport_id( if (padding != 0) len += padding; - buf[2] = ((len >> 8) & 0xff); - buf[3] = (len & 0xff); + put_unaligned_be16(len, &buf[2]); /* * Increment value for total payload + header length for * full status descriptor @@ -306,7 +306,7 @@ static char *iscsi_parse_pr_out_transport_id( */ if (out_tid_len) { /* The shift works thanks to integer promotion rules */ - add_len = (buf[2] << 8) | buf[3]; + add_len = get_unaligned_be16(&buf[2]); tid_len = strlen(&buf[4]); tid_len += 4; /* Add four bytes for iSCSI Transport ID header */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 129ca572673c..9921d4d6bb41 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1562,10 +1562,7 @@ core_scsi3_decode_spec_i_port( * first extract TransportID Parameter Data Length, and make sure * the value matches up to the SCSI expected data transfer length. */ - tpdl = (buf[24] & 0xff) << 24; - tpdl |= (buf[25] & 0xff) << 16; - tpdl |= (buf[26] & 0xff) << 8; - tpdl |= buf[27] & 0xff; + tpdl = get_unaligned_be32(&buf[24]); if ((tpdl + 28) != cmd->data_length) { pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header" @@ -3221,12 +3218,8 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, goto out_put_pr_reg; } - rtpi = (buf[18] & 0xff) << 8; - rtpi |= buf[19] & 0xff; - tid_len = (buf[20] & 0xff) << 24; - tid_len |= (buf[21] & 0xff) << 16; - tid_len |= (buf[22] & 0xff) << 8; - tid_len |= buf[23] & 0xff; + rtpi = get_unaligned_be16(&buf[18]); + tid_len = get_unaligned_be32(&buf[20]); transport_kunmap_data_sg(cmd); buf = NULL; @@ -3552,16 +3545,6 @@ out_put_pr_reg: return ret; } -static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3]; - __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - /* * See spc4r17 section 6.14 Table 170 */ @@ -3619,8 +3602,8 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) /* * From PERSISTENT_RESERVE_OUT parameter list (payload) */ - res_key = core_scsi3_extract_reservation_key(&buf[0]); - sa_res_key = core_scsi3_extract_reservation_key(&buf[8]); + res_key = get_unaligned_be64(&buf[0]); + sa_res_key = get_unaligned_be64(&buf[8]); /* * REGISTER_AND_MOVE uses a different SA parameter list containing * SCSI TransportIDs. @@ -3734,10 +3717,7 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd) if (!buf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (dev->t10_pr.pr_generation & 0xff); + put_unaligned_be32(dev->t10_pr.pr_generation, buf); spin_lock(&dev->t10_pr.registration_lock); list_for_each_entry(pr_reg, &dev->t10_pr.registration_list, @@ -3749,23 +3729,13 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd) if ((add_len + 8) > (cmd->data_length - 8)) break; - buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); - buf[off++] = (pr_reg->pr_res_key & 0xff); - + put_unaligned_be64(pr_reg->pr_res_key, &buf[off]); + off += 8; add_len += 8; } spin_unlock(&dev->t10_pr.registration_lock); - buf[4] = ((add_len >> 24) & 0xff); - buf[5] = ((add_len >> 16) & 0xff); - buf[6] = ((add_len >> 8) & 0xff); - buf[7] = (add_len & 0xff); + put_unaligned_be32(add_len, &buf[4]); transport_kunmap_data_sg(cmd); @@ -3796,10 +3766,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd) if (!buf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (dev->t10_pr.pr_generation & 0xff); + put_unaligned_be32(dev->t10_pr.pr_generation, &buf[0]); spin_lock(&dev->dev_reservation_lock); pr_reg = dev->dev_pr_res_holder; @@ -3807,10 +3774,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd) /* * Set the hardcoded Additional Length */ - buf[4] = ((add_len >> 24) & 0xff); - buf[5] = ((add_len >> 16) & 0xff); - buf[6] = ((add_len >> 8) & 0xff); - buf[7] = (add_len & 0xff); + put_unaligned_be32(add_len, &buf[4]); if (cmd->data_length < 22) goto err; @@ -3837,14 +3801,7 @@ core_scsi3_pri_read_reservation(struct se_cmd *cmd) else pr_res_key = pr_reg->pr_res_key; - buf[8] = ((pr_res_key >> 56) & 0xff); - buf[9] = ((pr_res_key >> 48) & 0xff); - buf[10] = ((pr_res_key >> 40) & 0xff); - buf[11] = ((pr_res_key >> 32) & 0xff); - buf[12] = ((pr_res_key >> 24) & 0xff); - buf[13] = ((pr_res_key >> 16) & 0xff); - buf[14] = ((pr_res_key >> 8) & 0xff); - buf[15] = (pr_res_key & 0xff); + put_unaligned_be64(pr_res_key, &buf[8]); /* * Set the SCOPE and TYPE */ @@ -3882,8 +3839,7 @@ core_scsi3_pri_report_capabilities(struct se_cmd *cmd) if (!buf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - buf[0] = ((add_len >> 8) & 0xff); - buf[1] = (add_len & 0xff); + put_unaligned_be16(add_len, &buf[0]); buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */ buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */ buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */ @@ -3947,10 +3903,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) if (!buf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (dev->t10_pr.pr_generation & 0xff); + put_unaligned_be32(dev->t10_pr.pr_generation, &buf[0]); spin_lock(&dev->dev_reservation_lock); if (dev->dev_pr_res_holder) { @@ -3992,14 +3945,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) /* * Set RESERVATION KEY */ - buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); - buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); - buf[off++] = (pr_reg->pr_res_key & 0xff); + put_unaligned_be64(pr_reg->pr_res_key, &buf[off]); + off += 8; off += 4; /* Skip Over Reserved area */ /* @@ -4041,8 +3988,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) if (!pr_reg->pr_reg_all_tg_pt) { u16 sep_rtpi = pr_reg->tg_pt_sep_rtpi; - buf[off++] = ((sep_rtpi >> 8) & 0xff); - buf[off++] = (sep_rtpi & 0xff); + put_unaligned_be16(sep_rtpi, &buf[off]); + off += 2; } else off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */ @@ -4062,10 +4009,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) /* * Set the ADDITIONAL DESCRIPTOR LENGTH */ - buf[off++] = ((desc_len >> 24) & 0xff); - buf[off++] = ((desc_len >> 16) & 0xff); - buf[off++] = ((desc_len >> 8) & 0xff); - buf[off++] = (desc_len & 0xff); + put_unaligned_be32(desc_len, &buf[off]); /* * Size of full desctipor header minus TransportID * containing $FABRIC_MOD specific) initiator device/port @@ -4082,10 +4026,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) /* * Set ADDITIONAL_LENGTH */ - buf[4] = ((add_len >> 24) & 0xff); - buf[5] = ((add_len >> 16) & 0xff); - buf[6] = ((add_len >> 8) & 0xff); - buf[7] = (add_len & 0xff); + put_unaligned_be32(add_len, &buf[4]); transport_kunmap_data_sg(cmd); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 3e4abb13f8ea..e0be4aa38328 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -168,7 +168,7 @@ static void pscsi_tape_read_blocksize(struct se_device *dev, /* * If MODE_SENSE still returns zero, set the default value to 1024. */ - sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]); + sdev->sector_size = get_unaligned_be24(&buf[9]); out_free: if (!sdev->sector_size) sdev->sector_size = 1024; @@ -209,8 +209,7 @@ pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn) cdb[0] = INQUIRY; cdb[1] = 0x01; /* Query VPD */ cdb[2] = 0x80; /* Unit Serial Number */ - cdb[3] = (INQUIRY_VPD_SERIAL_LEN >> 8) & 0xff; - cdb[4] = (INQUIRY_VPD_SERIAL_LEN & 0xff); + put_unaligned_be16(INQUIRY_VPD_SERIAL_LEN, &cdb[3]); ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL); @@ -245,8 +244,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev, cdb[0] = INQUIRY; cdb[1] = 0x01; /* Query VPD */ cdb[2] = 0x83; /* Device Identifier */ - cdb[3] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN >> 8) & 0xff; - cdb[4] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN & 0xff); + put_unaligned_be16(INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, &cdb[3]); ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, @@ -254,7 +252,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev, if (ret) goto out; - page_len = (buf[2] << 8) | buf[3]; + page_len = get_unaligned_be16(&buf[2]); while (page_len > 0) { /* Grab a pointer to the Identification descriptor */ page_83 = &buf[off]; @@ -669,19 +667,17 @@ after_mode_sense: } if (cdb[0] == MODE_SELECT) - bdl = (buf[3]); + bdl = buf[3]; else - bdl = (buf[6] << 8) | (buf[7]); + bdl = get_unaligned_be16(&buf[6]); if (!bdl) goto after_mode_select; if (cdb[0] == MODE_SELECT) - blocksize = (buf[9] << 16) | (buf[10] << 8) | - (buf[11]); + blocksize = get_unaligned_be24(&buf[9]); else - blocksize = (buf[13] << 16) | (buf[14] << 8) | - (buf[15]); + blocksize = get_unaligned_be24(&buf[13]); sd->sector_size = blocksize; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ff4a6ec30adf..ca42fba882db 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -71,14 +71,8 @@ sbc_emulate_readcapacity(struct se_cmd *cmd) else blocks = (u32)blocks_long; - buf[0] = (blocks >> 24) & 0xff; - buf[1] = (blocks >> 16) & 0xff; - buf[2] = (blocks >> 8) & 0xff; - buf[3] = blocks & 0xff; - buf[4] = (dev->dev_attrib.block_size >> 24) & 0xff; - buf[5] = (dev->dev_attrib.block_size >> 16) & 0xff; - buf[6] = (dev->dev_attrib.block_size >> 8) & 0xff; - buf[7] = dev->dev_attrib.block_size & 0xff; + put_unaligned_be32(blocks, &buf[0]); + put_unaligned_be32(dev->dev_attrib.block_size, &buf[4]); rbuf = transport_kmap_data_sg(cmd); if (rbuf) { @@ -102,18 +96,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) unsigned long long blocks = dev->transport->get_blocks(dev); memset(buf, 0, sizeof(buf)); - buf[0] = (blocks >> 56) & 0xff; - buf[1] = (blocks >> 48) & 0xff; - buf[2] = (blocks >> 40) & 0xff; - buf[3] = (blocks >> 32) & 0xff; - buf[4] = (blocks >> 24) & 0xff; - buf[5] = (blocks >> 16) & 0xff; - buf[6] = (blocks >> 8) & 0xff; - buf[7] = blocks & 0xff; - buf[8] = (dev->dev_attrib.block_size >> 24) & 0xff; - buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff; - buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff; - buf[11] = dev->dev_attrib.block_size & 0xff; + put_unaligned_be64(blocks, &buf[0]); + put_unaligned_be32(dev->dev_attrib.block_size, &buf[8]); /* * Set P_TYPE and PROT_EN bits for DIF support */ @@ -134,8 +118,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) if (dev->transport->get_alignment_offset_lbas) { u16 lalba = dev->transport->get_alignment_offset_lbas(dev); - buf[14] = (lalba >> 8) & 0x3f; - buf[15] = lalba & 0xff; + + put_unaligned_be16(lalba, &buf[14]); } /* @@ -262,18 +246,17 @@ static inline u32 transport_get_sectors_6(unsigned char *cdb) static inline u32 transport_get_sectors_10(unsigned char *cdb) { - return (u32)(cdb[7] << 8) + cdb[8]; + return get_unaligned_be16(&cdb[7]); } static inline u32 transport_get_sectors_12(unsigned char *cdb) { - return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; + return get_unaligned_be32(&cdb[6]); } static inline u32 transport_get_sectors_16(unsigned char *cdb) { - return (u32)(cdb[10] << 24) + (cdb[11] << 16) + - (cdb[12] << 8) + cdb[13]; + return get_unaligned_be32(&cdb[10]); } /* @@ -281,29 +264,23 @@ static inline u32 transport_get_sectors_16(unsigned char *cdb) */ static inline u32 transport_get_sectors_32(unsigned char *cdb) { - return (u32)(cdb[28] << 24) + (cdb[29] << 16) + - (cdb[30] << 8) + cdb[31]; + return get_unaligned_be32(&cdb[28]); } static inline u32 transport_lba_21(unsigned char *cdb) { - return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; + return get_unaligned_be24(&cdb[1]) & 0x1fffff; } static inline u32 transport_lba_32(unsigned char *cdb) { - return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + return get_unaligned_be32(&cdb[2]); } static inline unsigned long long transport_lba_64(unsigned char *cdb) { - unsigned int __v1, __v2; - - __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; + return get_unaligned_be64(&cdb[2]); } /* @@ -311,12 +288,7 @@ static inline unsigned long long transport_lba_64(unsigned char *cdb) */ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) { - unsigned int __v1, __v2; - - __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; - __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; + return get_unaligned_be64(&cdb[12]); } static sense_reason_t @@ -1051,8 +1023,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) cmd->t_task_cdb[1] & 0x1f); return TCM_INVALID_CDB_FIELD; } - size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; + size = get_unaligned_be32(&cdb[10]); break; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 2a91ed3ef380..f59ac7671031 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -287,8 +287,8 @@ check_t10_vend_desc: /* Skip over Obsolete field in RTPI payload * in Table 472 */ off += 2; - buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); - buf[off++] = (lun->lun_rtpi & 0xff); + put_unaligned_be16(lun->lun_rtpi, &buf[off]); + off += 2; len += 8; /* Header size + Designation descriptor */ /* * Target port group identifier, see spc4r17 @@ -316,8 +316,8 @@ check_t10_vend_desc: off++; /* Skip over Reserved */ buf[off++] = 4; /* DESIGNATOR LENGTH */ off += 2; /* Skip over Reserved Field */ - buf[off++] = ((tg_pt_gp_id >> 8) & 0xff); - buf[off++] = (tg_pt_gp_id & 0xff); + put_unaligned_be16(tg_pt_gp_id, &buf[off]); + off += 2; len += 8; /* Header size + Designation descriptor */ /* * Logical Unit Group identifier, see spc4r17 @@ -343,8 +343,8 @@ check_lu_gp: off++; /* Skip over Reserved */ buf[off++] = 4; /* DESIGNATOR LENGTH */ off += 2; /* Skip over Reserved Field */ - buf[off++] = ((lu_gp_id >> 8) & 0xff); - buf[off++] = (lu_gp_id & 0xff); + put_unaligned_be16(lu_gp_id, &buf[off]); + off += 2; len += 8; /* Header size + Designation descriptor */ /* * SCSI name string designator, see spc4r17 @@ -431,8 +431,7 @@ check_scsi_name: /* Header size + Designation descriptor */ len += (scsi_target_len + 4); } - buf[2] = ((len >> 8) & 0xff); - buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ + put_unaligned_be16(len, &buf[2]); /* Page Length for VPD 0x83 */ return 0; } EXPORT_SYMBOL(spc_emulate_evpd_83); @@ -1288,7 +1287,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = spc_emulate_modeselect; break; case MODE_SELECT_10: - *size = (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = spc_emulate_modeselect; break; case MODE_SENSE: @@ -1296,25 +1295,25 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = spc_emulate_modesense; break; case MODE_SENSE_10: - *size = (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = spc_emulate_modesense; break; case LOG_SELECT: case LOG_SENSE: - *size = (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be16(&cdb[7]); break; case PERSISTENT_RESERVE_IN: - *size = (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = target_scsi3_emulate_pr_in; break; case PERSISTENT_RESERVE_OUT: - *size = (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = target_scsi3_emulate_pr_out; break; case RELEASE: case RELEASE_10: if (cdb[0] == RELEASE_10) - *size = (cdb[7] << 8) | cdb[8]; + *size = get_unaligned_be16(&cdb[7]); else *size = cmd->data_length; @@ -1327,7 +1326,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) * Assume the passthrough or $FABRIC_MOD will tell us about it. */ if (cdb[0] == RESERVE_10) - *size = (cdb[7] << 8) | cdb[8]; + *size = get_unaligned_be16(&cdb[7]); else *size = cmd->data_length; @@ -1338,7 +1337,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = spc_emulate_request_sense; break; case INQUIRY: - *size = (cdb[3] << 8) + cdb[4]; + *size = get_unaligned_be16(&cdb[3]); /* * Do implicit HEAD_OF_QUEUE processing for INQUIRY. @@ -1349,7 +1348,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) break; case SECURITY_PROTOCOL_IN: case SECURITY_PROTOCOL_OUT: - *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + *size = get_unaligned_be32(&cdb[6]); break; case EXTENDED_COPY: *size = get_unaligned_be32(&cdb[10]); @@ -1361,19 +1360,18 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) break; case READ_ATTRIBUTE: case WRITE_ATTRIBUTE: - *size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; + *size = get_unaligned_be32(&cdb[10]); break; case RECEIVE_DIAGNOSTIC: case SEND_DIAGNOSTIC: - *size = (cdb[3] << 8) | cdb[4]; + *size = get_unaligned_be16(&cdb[3]); break; case WRITE_BUFFER: - *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + *size = get_unaligned_be24(&cdb[6]); break; case REPORT_LUNS: cmd->execute_cmd = spc_emulate_report_luns; - *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + *size = get_unaligned_be32(&cdb[6]); /* * Do implicit HEAD_OF_QUEUE processing for REPORT_LUNS * See spc4r17 section 5.3 diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index cac5a20a4de0..f12cf0c12531 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -311,9 +311,7 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op (unsigned long long)xop->dst_lba); if (dc != 0) { - xop->dbl = (desc[29] & 0xff) << 16; - xop->dbl |= (desc[30] & 0xff) << 8; - xop->dbl |= desc[31] & 0xff; + xop->dbl = get_unaligned_be24(&desc[29]); pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl); } diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index e475531565fd..b76071161cdc 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -2,6 +2,7 @@ #define TARGET_CORE_BACKEND_H #include +#include #include #define TRANSPORT_FLAG_PASSTHROUGH 0x1 @@ -109,4 +110,11 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb); bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, struct request_queue *q); + +/* Only use get_unaligned_be24() if reading p - 1 is allowed. */ +static inline uint32_t get_unaligned_be24(const uint8_t *const p) +{ + return get_unaligned_be32(p - 1) & 0xffffffU; +} + #endif /* TARGET_CORE_BACKEND_H */ -- cgit v1.2.3 From d877d7275be34ad70ce92bcbb4bb36cec77ed004 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:29 -0700 Subject: target: Fix a deadlock between the XCOPY code and iSCSI session shutdown Move the code for parsing an XCOPY command from the context of the iSCSI receiver thread to the context of the XCOPY workqueue. Keep the simple XCOPY checks in the context of the iSCSI receiver thread. Move the code for allocating and freeing struct xcopy_op from the code that parses an XCOPY command to its caller. This patch fixes the following deadlock: ====================================================== [ INFO: possible circular locking dependency detected ] 4.10.0-rc7-dbg+ #1 Not tainted ------------------------------------------------------- rmdir/13321 is trying to acquire lock: (&sess->cmdsn_mutex){+.+.+.}, at: [] iscsit_free_all_ooo_cmdsns+0x2d/0xb0 [iscsi_target_mod] but task is already holding lock: (&sb->s_type->i_mutex_key#14){++++++}, at: [] vfs_rmdir+0x50/0x140 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&sb->s_type->i_mutex_key#14){++++++}: lock_acquire+0x71/0x90 down_write+0x3f/0x70 configfs_depend_item+0x3a/0xb0 [configfs] target_depend_item+0x13/0x20 [target_core_mod] target_xcopy_locate_se_dev_e4+0xdd/0x1a0 [target_core_mod] target_do_xcopy+0x34b/0x970 [target_core_mod] __target_execute_cmd+0x22/0xa0 [target_core_mod] target_execute_cmd+0x233/0x2c0 [target_core_mod] iscsit_execute_cmd+0x208/0x270 [iscsi_target_mod] iscsit_sequence_cmd+0x10b/0x190 [iscsi_target_mod] iscsit_get_rx_pdu+0x37d/0xcd0 [iscsi_target_mod] iscsi_target_rx_thread+0x6e/0xa0 [iscsi_target_mod] kthread+0x102/0x140 ret_from_fork+0x31/0x40 -> #0 (&sess->cmdsn_mutex){+.+.+.}: __lock_acquire+0x10e6/0x1260 lock_acquire+0x71/0x90 mutex_lock_nested+0x5f/0x670 iscsit_free_all_ooo_cmdsns+0x2d/0xb0 [iscsi_target_mod] iscsit_close_session+0xac/0x200 [iscsi_target_mod] lio_tpg_close_session+0x9f/0xb0 [iscsi_target_mod] target_shutdown_sessions+0xc3/0xd0 [target_core_mod] core_tpg_del_initiator_node_acl+0x91/0x140 [target_core_mod] target_fabric_nacl_base_release+0x20/0x30 [target_core_mod] config_item_release+0x5a/0xc0 [configfs] config_item_put+0x1d/0x1f [configfs] configfs_rmdir+0x1a6/0x300 [configfs] vfs_rmdir+0xb7/0x140 do_rmdir+0x1f4/0x200 SyS_rmdir+0x11/0x20 entry_SYSCALL_64_fastpath+0x23/0xc6 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&sb->s_type->i_mutex_key#14); lock(&sess->cmdsn_mutex); lock(&sb->s_type->i_mutex_key#14); lock(&sess->cmdsn_mutex); *** DEADLOCK *** 3 locks held by rmdir/13321: #0: (sb_writers#10){.+.+.+}, at: [] mnt_want_write+0x1f/0x50 #1: (&default_group_class[depth - 1]#2/1){+.+.+.}, at: [] do_rmdir+0x15e/0x200 #2: (&sb->s_type->i_mutex_key#14){++++++}, at: [] vfs_rmdir+0x50/0x140 stack backtrace: CPU: 2 PID: 13321 Comm: rmdir Not tainted 4.10.0-rc7-dbg+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0x86/0xc3 print_circular_bug+0x1c7/0x220 __lock_acquire+0x10e6/0x1260 lock_acquire+0x71/0x90 mutex_lock_nested+0x5f/0x670 iscsit_free_all_ooo_cmdsns+0x2d/0xb0 [iscsi_target_mod] iscsit_close_session+0xac/0x200 [iscsi_target_mod] lio_tpg_close_session+0x9f/0xb0 [iscsi_target_mod] target_shutdown_sessions+0xc3/0xd0 [target_core_mod] core_tpg_del_initiator_node_acl+0x91/0x140 [target_core_mod] target_fabric_nacl_base_release+0x20/0x30 [target_core_mod] config_item_release+0x5a/0xc0 [configfs] config_item_put+0x1d/0x1f [configfs] configfs_rmdir+0x1a6/0x300 [configfs] vfs_rmdir+0xb7/0x140 do_rmdir+0x1f4/0x200 SyS_rmdir+0x11/0x20 entry_SYSCALL_64_fastpath+0x23/0xc6 Signed-off-by: Bart Van Assche Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 110 +++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index f12cf0c12531..56738a41e346 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -40,6 +40,8 @@ static struct workqueue_struct *xcopy_wq = NULL; +static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop); + static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) { int off = 0; @@ -779,13 +781,24 @@ static int target_xcopy_write_destination( static void target_xcopy_do_work(struct work_struct *work) { struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work); - struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev; struct se_cmd *ec_cmd = xop->xop_se_cmd; - sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba; + struct se_device *src_dev, *dst_dev; + sector_t src_lba, dst_lba, end_lba; unsigned int max_sectors; - int rc; - unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0; + int rc = 0; + unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0; + + if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE) + goto err_free; + if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev)) + goto err_free; + + src_dev = xop->src_dev; + dst_dev = xop->dst_dev; + src_lba = xop->src_lba; + dst_lba = xop->dst_lba; + nolb = xop->nolb; end_lba = src_lba + nolb; /* * Break up XCOPY I/O into hw_max_sectors sized I/O based on the @@ -853,6 +866,8 @@ static void target_xcopy_do_work(struct work_struct *work) out: xcopy_pt_undepend_remotedev(xop); + +err_free: kfree(xop); /* * Don't override an error scsi status if it has already been set @@ -865,48 +880,22 @@ out: target_complete_cmd(ec_cmd, ec_cmd->scsi_status); } -sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) +/* + * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing + * fails. + */ +static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop) { - struct se_device *dev = se_cmd->se_dev; - struct xcopy_op *xop = NULL; + struct se_cmd *se_cmd = xop->xop_se_cmd; unsigned char *p = NULL, *seg_desc; - unsigned int list_id, list_id_usage, sdll, inline_dl, sa; + unsigned int list_id, list_id_usage, sdll, inline_dl; sense_reason_t ret = TCM_INVALID_PARAMETER_LIST; int rc; unsigned short tdll; - if (!dev->dev_attrib.emulate_3pc) { - pr_err("EXTENDED_COPY operation explicitly disabled\n"); - return TCM_UNSUPPORTED_SCSI_OPCODE; - } - - sa = se_cmd->t_task_cdb[1] & 0x1f; - if (sa != 0x00) { - pr_err("EXTENDED_COPY(LID4) not supported\n"); - return TCM_UNSUPPORTED_SCSI_OPCODE; - } - - if (se_cmd->data_length == 0) { - target_complete_cmd(se_cmd, SAM_STAT_GOOD); - return TCM_NO_SENSE; - } - if (se_cmd->data_length < XCOPY_HDR_LEN) { - pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n", - se_cmd->data_length, XCOPY_HDR_LEN); - return TCM_PARAMETER_LIST_LENGTH_ERROR; - } - - xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); - if (!xop) { - pr_err("Unable to allocate xcopy_op\n"); - return TCM_OUT_OF_RESOURCES; - } - xop->xop_se_cmd = se_cmd; - p = transport_kmap_data_sg(se_cmd); if (!p) { pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n"); - kfree(xop); return TCM_OUT_OF_RESOURCES; } @@ -975,18 +964,57 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, rc * XCOPY_TARGET_DESC_LEN); transport_kunmap_data_sg(se_cmd); - - INIT_WORK(&xop->xop_work, target_xcopy_do_work); - queue_work(xcopy_wq, &xop->xop_work); return TCM_NO_SENSE; out: if (p) transport_kunmap_data_sg(se_cmd); - kfree(xop); return ret; } +sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) +{ + struct se_device *dev = se_cmd->se_dev; + struct xcopy_op *xop; + unsigned int sa; + + if (!dev->dev_attrib.emulate_3pc) { + pr_err("EXTENDED_COPY operation explicitly disabled\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + sa = se_cmd->t_task_cdb[1] & 0x1f; + if (sa != 0x00) { + pr_err("EXTENDED_COPY(LID4) not supported\n"); + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + if (se_cmd->data_length == 0) { + target_complete_cmd(se_cmd, SAM_STAT_GOOD); + return TCM_NO_SENSE; + } + if (se_cmd->data_length < XCOPY_HDR_LEN) { + pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n", + se_cmd->data_length, XCOPY_HDR_LEN); + return TCM_PARAMETER_LIST_LENGTH_ERROR; + } + + xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); + if (!xop) + goto err; + xop->xop_se_cmd = se_cmd; + INIT_WORK(&xop->xop_work, target_xcopy_do_work); + if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work))) + goto free; + return TCM_NO_SENSE; + +free: + kfree(xop); + +err: + return TCM_OUT_OF_RESOURCES; +} + static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd) { unsigned char *p; -- cgit v1.2.3 From 13fdd4458ed1b808946fd7baba657b6a51d3c72b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:35 -0700 Subject: IB/srpt: Make a debug statement in srpt_abort_cmd() more informative Do not only report the state of the I/O context before srpt_abort_cmd() was called but also the new state assigned by srpt_abort_cmd() Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Cc: Doug Ledford Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/srpt/ib_srpt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 1ced0731c140..402275be0931 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1157,8 +1157,8 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) } spin_unlock_irqrestore(&ioctx->spinlock, flags); - pr_debug("Aborting cmd with state %d and tag %lld\n", state, - ioctx->cmd.tag); + pr_debug("Aborting cmd with state %d -> %d and tag %lld\n", state, + ioctx->state, ioctx->cmd.tag); switch (state) { case SRPT_STATE_NEW: -- cgit v1.2.3 From 9f4ab18ac51dc87345a9cbd2527e6acf7a0a9335 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:36 -0700 Subject: xen/scsiback: Fix a TMR related use-after-free scsiback_release_cmd() must not dereference se_cmd->se_tmr_req because that memory is freed by target_free_cmd_mem() before scsiback_release_cmd() is called. Fix this use-after-free by inlining struct scsiback_tmr into struct vscsibk_pend. Signed-off-by: Bart Van Assche Reviewed-by: Juergen Gross Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Cc: xen-devel@lists.xenproject.org Cc: # 3.18+ Signed-off-by: Nicholas Bellinger --- drivers/xen/xen-scsiback.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index d6950e0802b7..980f32817305 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -134,9 +134,7 @@ struct vscsibk_pend { struct page *pages[VSCSI_MAX_GRANTS]; struct se_cmd se_cmd; -}; -struct scsiback_tmr { atomic_t tmr_complete; wait_queue_head_t tmr_wait; }; @@ -599,26 +597,20 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, struct scsiback_tpg *tpg = pending_req->v2p->tpg; struct scsiback_nexus *nexus = tpg->tpg_nexus; struct se_cmd *se_cmd = &pending_req->se_cmd; - struct scsiback_tmr *tmr; u64 unpacked_lun = pending_req->v2p->lun; int rc, err = FAILED; - tmr = kzalloc(sizeof(struct scsiback_tmr), GFP_KERNEL); - if (!tmr) { - target_put_sess_cmd(se_cmd); - goto err; - } - - init_waitqueue_head(&tmr->tmr_wait); + init_waitqueue_head(&pending_req->tmr_wait); rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess, &pending_req->sense_buffer[0], - unpacked_lun, tmr, act, GFP_KERNEL, + unpacked_lun, NULL, act, GFP_KERNEL, tag, TARGET_SCF_ACK_KREF); if (rc) goto err; - wait_event(tmr->tmr_wait, atomic_read(&tmr->tmr_complete)); + wait_event(pending_req->tmr_wait, + atomic_read(&pending_req->tmr_complete)); err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; @@ -626,9 +618,8 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, scsiback_do_resp_with_sense(NULL, err, 0, pending_req); transport_generic_free_cmd(&pending_req->se_cmd, 1); return; + err: - if (tmr) - kfree(tmr); scsiback_do_resp_with_sense(NULL, err, 0, pending_req); } @@ -1389,12 +1380,6 @@ static int scsiback_check_stop_free(struct se_cmd *se_cmd) static void scsiback_release_cmd(struct se_cmd *se_cmd) { struct se_session *se_sess = se_cmd->se_sess; - struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; - - if (se_tmr && se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) { - struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr; - kfree(tmr); - } percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); } @@ -1455,11 +1440,11 @@ static int scsiback_queue_status(struct se_cmd *se_cmd) static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd) { - struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; - struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr; + struct vscsibk_pend *pending_req = container_of(se_cmd, + struct vscsibk_pend, se_cmd); - atomic_set(&tmr->tmr_complete, 1); - wake_up(&tmr->tmr_wait); + atomic_set(&pending_req->tmr_complete, 1); + wake_up(&pending_req->tmr_wait); } static void scsiback_aborted_task(struct se_cmd *se_cmd) -- cgit v1.2.3 From e3eac12442c2678d64b655e9768bda1be65e0b68 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:37 -0700 Subject: xen/scsiback: Replace a waitqueue and a counter by a completion This patch simplifies the implementation of the scsiback driver but does not change its behavior. Signed-off-by: Bart Van Assche Reviewed-by: Juergen Gross Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Cc: xen-devel@lists.xenproject.org Signed-off-by: Nicholas Bellinger --- drivers/xen/xen-scsiback.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 980f32817305..4cb33a0916a8 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -135,8 +135,7 @@ struct vscsibk_pend { struct se_cmd se_cmd; - atomic_t tmr_complete; - wait_queue_head_t tmr_wait; + struct completion tmr_done; }; #define VSCSI_DEFAULT_SESSION_TAGS 128 @@ -600,7 +599,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, u64 unpacked_lun = pending_req->v2p->lun; int rc, err = FAILED; - init_waitqueue_head(&pending_req->tmr_wait); + init_completion(&pending_req->tmr_done); rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess, &pending_req->sense_buffer[0], @@ -609,8 +608,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, if (rc) goto err; - wait_event(pending_req->tmr_wait, - atomic_read(&pending_req->tmr_complete)); + wait_for_completion(&pending_req->tmr_done); err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; @@ -1443,8 +1441,7 @@ static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd) struct vscsibk_pend *pending_req = container_of(se_cmd, struct vscsibk_pend, se_cmd); - atomic_set(&pending_req->tmr_complete, 1); - wake_up(&pending_req->tmr_wait); + complete(&pending_req->tmr_done); } static void scsiback_aborted_task(struct se_cmd *se_cmd) -- cgit v1.2.3 From af90e84d1f535827f4c593436a807b1efa9f6f2b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:38 -0700 Subject: xen/scsiback: Make TMF processing slightly faster Target drivers must guarantee that struct se_cmd and struct se_tmr_req exist as long as target_tmr_work() is in progress. Since the last access by the LIO core is a call to .check_stop_free() and since the Xen scsiback .check_stop_free() drops a reference to the TMF, it is already guaranteed that the struct se_cmd that corresponds to the TMF exists as long as target_tmr_work() is in progress. Hence change the second argument of transport_generic_free_cmd() from 1 into 0. Signed-off-by: Bart Van Assche Reviewed-by: Juergen Gross Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Cc: xen-devel@lists.xenproject.org Signed-off-by: Nicholas Bellinger --- drivers/xen/xen-scsiback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 4cb33a0916a8..7bc88fd43cfc 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -614,7 +614,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, SUCCESS : FAILED; scsiback_do_resp_with_sense(NULL, err, 0, pending_req); - transport_generic_free_cmd(&pending_req->se_cmd, 1); + transport_generic_free_cmd(&pending_req->se_cmd, 0); return; err: -- cgit v1.2.3 From 03db016a1bf2d35f41c08aad2ca4f4f18eeda4be Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 2 Jun 2017 23:33:56 -0700 Subject: iscsi-target: Kill left-over iscsi_target_do_cleanup With commit 25cdda95fda7 in place to address the initial login PDU asynchronous socket close OOPs, go ahead and kill off the left-over iscsi_target_do_cleanup() and ->login_cleanup_work. Reported-by: Mike Christie Cc: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_nego.c | 24 ------------------------ include/target/iscsi/iscsi_target_core.h | 1 - 2 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 6f88b31242b0..96df63f1f795 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -655,28 +655,6 @@ err: iscsit_deaccess_np(np, tpg, tpg_np); } -static void iscsi_target_do_cleanup(struct work_struct *work) -{ - struct iscsi_conn *conn = container_of(work, - struct iscsi_conn, login_cleanup_work.work); - struct sock *sk = conn->sock->sk; - struct iscsi_login *login = conn->login; - struct iscsi_np *np = login->np; - struct iscsi_portal_group *tpg = conn->tpg; - struct iscsi_tpg_np *tpg_np = conn->tpg_np; - - pr_debug("Entering iscsi_target_do_cleanup\n"); - - cancel_delayed_work_sync(&conn->login_work); - conn->orig_state_change(sk); - - iscsi_target_restore_sock_callbacks(conn); - iscsi_target_login_drop(conn, login); - iscsit_deaccess_np(np, tpg, tpg_np); - - pr_debug("iscsi_target_do_cleanup done()\n"); -} - static void iscsi_target_sk_state_change(struct sock *sk) { struct iscsi_conn *conn; @@ -1082,7 +1060,6 @@ int iscsi_target_locate_portal( int sessiontype = 0, ret = 0, tag_num, tag_size; INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx); - INIT_DELAYED_WORK(&conn->login_cleanup_work, iscsi_target_do_cleanup); iscsi_target_set_sock_callbacks(conn); login->np = np; @@ -1331,7 +1308,6 @@ int iscsi_target_start_negotiation( if (ret < 0) { cancel_delayed_work_sync(&conn->login_work); - cancel_delayed_work_sync(&conn->login_cleanup_work); iscsi_target_restore_sock_callbacks(conn); iscsi_remove_failed_auth_entry(conn); } diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 5f17fb770477..7948fc68286b 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -560,7 +560,6 @@ struct iscsi_conn { #define LOGIN_FLAGS_INITIAL_PDU 8 unsigned long login_flags; struct delayed_work login_work; - struct delayed_work login_cleanup_work; struct iscsi_login *login; struct timer_list nopin_timer; struct timer_list nopin_response_timer; -- cgit v1.2.3 From c00e6220231542c6409780a3e9bfa44be7d94f3a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:28 -0700 Subject: target: Introduce a function that shows the command state Introduce target_show_cmd() and use it where appropriate. If transport_wait_for_tasks() takes too long, make it show the state of the command it is waiting for. (Add missing brackets around multi-line conditions - nab) Signed-off-by: Bart Van Assche Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_tmr.c | 18 ++--- drivers/target/target_core_transport.c | 122 +++++++++++++++++++++++++++++---- include/target/target_core_fabric.h | 1 + 3 files changed, 114 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 13f47bf4d16b..e22847bd79b9 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -355,20 +355,10 @@ static void core_tmr_drain_state_list( cmd = list_entry(drain_task_list.next, struct se_cmd, state_list); list_del_init(&cmd->state_list); - pr_debug("LUN_RESET: %s cmd: %p" - " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d" - "cdb: 0x%02x\n", - (preempt_and_abort_list) ? "Preempt" : "", cmd, - cmd->tag, 0, - cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, - cmd->t_task_cdb[0]); - pr_debug("LUN_RESET: ITT[0x%08llx] - pr_res_key: 0x%016Lx" - " -- CMD_T_ACTIVE: %d" - " CMD_T_STOP: %d CMD_T_SENT: %d\n", - cmd->tag, cmd->pr_res_key, - (cmd->transport_state & CMD_T_ACTIVE) != 0, - (cmd->transport_state & CMD_T_STOP) != 0, - (cmd->transport_state & CMD_T_SENT) != 0); + target_show_cmd("LUN_RESET: ", cmd); + pr_debug("LUN_RESET: ITT[0x%08llx] - %s pr_res_key: 0x%016Lx\n", + cmd->tag, (preempt_and_abort_list) ? "preempt" : "", + cmd->pr_res_key); /* * If the command may be queued onto a workqueue cancel it now. diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d601616b9f12..a5ecec8f3996 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1704,15 +1704,9 @@ void transport_generic_request_failure(struct se_cmd *cmd, if (transport_check_aborted_status(cmd, 1)) return; - pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx" - " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]); - pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n", - cmd->se_tfo->get_cmd_state(cmd), - cmd->t_state, sense_reason); - pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n", - (cmd->transport_state & CMD_T_ACTIVE) != 0, - (cmd->transport_state & CMD_T_STOP) != 0, - (cmd->transport_state & CMD_T_SENT) != 0); + pr_debug("-----[ Storage Engine Exception; sense_reason %d\n", + sense_reason); + target_show_cmd("-----[ ", cmd); /* * For SAM Task Attribute emulation for failed struct se_cmd @@ -2705,6 +2699,108 @@ int target_put_sess_cmd(struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_put_sess_cmd); +static const char *data_dir_name(enum dma_data_direction d) +{ + switch (d) { + case DMA_BIDIRECTIONAL: return "BIDI"; + case DMA_TO_DEVICE: return "WRITE"; + case DMA_FROM_DEVICE: return "READ"; + case DMA_NONE: return "NONE"; + } + + return "(?)"; +} + +static const char *cmd_state_name(enum transport_state_table t) +{ + switch (t) { + case TRANSPORT_NO_STATE: return "NO_STATE"; + case TRANSPORT_NEW_CMD: return "NEW_CMD"; + case TRANSPORT_WRITE_PENDING: return "WRITE_PENDING"; + case TRANSPORT_PROCESSING: return "PROCESSING"; + case TRANSPORT_COMPLETE: return "COMPLETE"; + case TRANSPORT_ISTATE_PROCESSING: + return "ISTATE_PROCESSING"; + case TRANSPORT_COMPLETE_QF_WP: return "COMPLETE_QF_WP"; + case TRANSPORT_COMPLETE_QF_OK: return "COMPLETE_QF_OK"; + case TRANSPORT_COMPLETE_QF_ERR: return "COMPLETE_QF_ERR"; + } + + return "(?)"; +} + +static void target_append_str(char **str, const char *txt) +{ + char *prev = *str; + + *str = *str ? kasprintf(GFP_ATOMIC, "%s,%s", *str, txt) : + kstrdup(txt, GFP_ATOMIC); + kfree(prev); +} + +/* + * Convert a transport state bitmask into a string. The caller is + * responsible for freeing the returned pointer. + */ +static char *target_ts_to_str(u32 ts) +{ + char *str = NULL; + + if (ts & CMD_T_ABORTED) + target_append_str(&str, "aborted"); + if (ts & CMD_T_ACTIVE) + target_append_str(&str, "active"); + if (ts & CMD_T_COMPLETE) + target_append_str(&str, "complete"); + if (ts & CMD_T_SENT) + target_append_str(&str, "sent"); + if (ts & CMD_T_STOP) + target_append_str(&str, "stop"); + if (ts & CMD_T_FABRIC_STOP) + target_append_str(&str, "fabric_stop"); + + return str; +} + +static const char *target_tmf_name(enum tcm_tmreq_table tmf) +{ + switch (tmf) { + case TMR_ABORT_TASK: return "ABORT_TASK"; + case TMR_ABORT_TASK_SET: return "ABORT_TASK_SET"; + case TMR_CLEAR_ACA: return "CLEAR_ACA"; + case TMR_CLEAR_TASK_SET: return "CLEAR_TASK_SET"; + case TMR_LUN_RESET: return "LUN_RESET"; + case TMR_TARGET_WARM_RESET: return "TARGET_WARM_RESET"; + case TMR_TARGET_COLD_RESET: return "TARGET_COLD_RESET"; + case TMR_UNKNOWN: break; + } + return "(?)"; +} + +void target_show_cmd(const char *pfx, struct se_cmd *cmd) +{ + char *ts_str = target_ts_to_str(cmd->transport_state); + const u8 *cdb = cmd->t_task_cdb; + struct se_tmr_req *tmf = cmd->se_tmr_req; + + if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { + pr_debug("%scmd %#02x:%#02x with tag %#llx dir %s i_state %d t_state %s len %d refcnt %d transport_state %s\n", + pfx, cdb[0], cdb[1], cmd->tag, + data_dir_name(cmd->data_direction), + cmd->se_tfo->get_cmd_state(cmd), + cmd_state_name(cmd->t_state), cmd->data_length, + kref_read(&cmd->cmd_kref), ts_str); + } else { + pr_debug("%stmf %s with tag %#llx ref_task_tag %#llx i_state %d t_state %s refcnt %d transport_state %s\n", + pfx, target_tmf_name(tmf->function), cmd->tag, + tmf->ref_task_tag, cmd->se_tfo->get_cmd_state(cmd), + cmd_state_name(cmd->t_state), + kref_read(&cmd->cmd_kref), ts_str); + } + kfree(ts_str); +} +EXPORT_SYMBOL(target_show_cmd); + /* target_sess_cmd_list_set_waiting - Flag all commands in * sess_cmd_list to complete cmd_wait_comp. Set * sess_tearing_down so no more commands are queued. @@ -2849,13 +2945,13 @@ __transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop, cmd->transport_state |= CMD_T_STOP; - pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d," - " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag, - cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); + target_show_cmd("wait_for_tasks: Stopping ", cmd); spin_unlock_irqrestore(&cmd->t_state_lock, *flags); - wait_for_completion(&cmd->t_transport_stop_comp); + while (!wait_for_completion_timeout(&cmd->t_transport_stop_comp, + 180 * HZ)) + target_show_cmd("wait for tasks: ", cmd); spin_lock_irqsave(&cmd->t_state_lock, *flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index d7dd1427fe0d..33d2e3e5773c 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -160,6 +160,7 @@ int target_get_sess_cmd(struct se_cmd *, bool); int target_put_sess_cmd(struct se_cmd *); void target_sess_cmd_list_set_waiting(struct se_session *); void target_wait_for_sess_cmds(struct se_session *); +void target_show_cmd(const char *pfx, struct se_cmd *cmd); int core_alua_check_nonop_delay(struct se_cmd *); -- cgit v1.2.3 From 4d3895d5ea43cf40fd707692263c6f0988fe8d70 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:39 -0700 Subject: target/tcm_loop: Merge struct tcm_loop_cmd and struct tcm_loop_tmr This patch simplifies the tcm_loop implementation but does not change any functionality. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 22 ++++++++-------------- drivers/target/loopback/tcm_loop.h | 7 ++----- 2 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 5091b31b3e56..79776b447b15 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -221,7 +221,6 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, struct se_portal_group *se_tpg; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_cmd *tl_cmd = NULL; - struct tcm_loop_tmr *tl_tmr = NULL; int ret = TMR_FUNCTION_FAILED, rc; /* @@ -240,12 +239,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, return ret; } - tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL); - if (!tl_tmr) { - pr_err("Unable to allocate memory for tl_tmr\n"); - goto release; - } - init_waitqueue_head(&tl_tmr->tl_tmr_wait); + init_waitqueue_head(&tl_cmd->tl_tmr_wait); se_cmd = &tl_cmd->tl_se_cmd; se_tpg = &tl_tpg->tl_se_tpg; @@ -257,7 +251,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, DMA_NONE, TCM_SIMPLE_TAG, &tl_cmd->tl_sense_buf[0]); - rc = core_tmr_alloc_req(se_cmd, tl_tmr, tmr, GFP_KERNEL); + rc = core_tmr_alloc_req(se_cmd, NULL, tmr, GFP_KERNEL); if (rc < 0) goto release; @@ -276,7 +270,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, * tcm_loop_queue_tm_rsp() to wake us up. */ transport_generic_handle_tmr(se_cmd); - wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete)); + wait_event(tl_cmd->tl_tmr_wait, atomic_read(&tl_cmd->tmr_complete)); /* * The TMR LUN_RESET has completed, check the response status and * then release allocations. @@ -287,7 +281,6 @@ release: transport_generic_free_cmd(se_cmd, 1); else kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); - kfree(tl_tmr); return ret; } @@ -669,14 +662,15 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd) static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) { - struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; - struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + /* * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead * and wake up the wait_queue_head_t in tcm_loop_device_reset() */ - atomic_set(&tl_tmr->tmr_complete, 1); - wake_up(&tl_tmr->tl_tmr_wait); + atomic_set(&tl_cmd->tmr_complete, 1); + wake_up(&tl_cmd->tl_tmr_wait); } static void tcm_loop_aborted_task(struct se_cmd *se_cmd) diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index a8a230b4e6b5..21340781568b 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -16,13 +16,10 @@ struct tcm_loop_cmd { /* The TCM I/O descriptor that is accessed via container_of() */ struct se_cmd tl_se_cmd; struct work_struct work; - /* Sense buffer that will be mapped into outgoing status */ - unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; -}; - -struct tcm_loop_tmr { atomic_t tmr_complete; wait_queue_head_t tl_tmr_wait; + /* Sense buffer that will be mapped into outgoing status */ + unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; }; struct tcm_loop_nexus { -- cgit v1.2.3 From d17203c41185a05ecd4d1fc647f16b17ab1b27ae Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:40 -0700 Subject: target/tcm_loop: Replace a waitqueue and a counter by a completion This patch simplifies the implementation of the tcm_loop driver but does not change its behavior. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 12 ++++-------- drivers/target/loopback/tcm_loop.h | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 79776b447b15..27f912747113 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -239,7 +239,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, return ret; } - init_waitqueue_head(&tl_cmd->tl_tmr_wait); + init_completion(&tl_cmd->tmr_done); se_cmd = &tl_cmd->tl_se_cmd; se_tpg = &tl_tpg->tl_se_tpg; @@ -270,7 +270,7 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, * tcm_loop_queue_tm_rsp() to wake us up. */ transport_generic_handle_tmr(se_cmd); - wait_event(tl_cmd->tl_tmr_wait, atomic_read(&tl_cmd->tmr_complete)); + wait_for_completion(&tl_cmd->tmr_done); /* * The TMR LUN_RESET has completed, check the response status and * then release allocations. @@ -665,12 +665,8 @@ static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, struct tcm_loop_cmd, tl_se_cmd); - /* - * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead - * and wake up the wait_queue_head_t in tcm_loop_device_reset() - */ - atomic_set(&tl_cmd->tmr_complete, 1); - wake_up(&tl_cmd->tl_tmr_wait); + /* Wake up tcm_loop_issue_tmr(). */ + complete(&tl_cmd->tmr_done); } static void tcm_loop_aborted_task(struct se_cmd *se_cmd) diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 21340781568b..3acc43c05117 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -16,8 +16,7 @@ struct tcm_loop_cmd { /* The TCM I/O descriptor that is accessed via container_of() */ struct se_cmd tl_se_cmd; struct work_struct work; - atomic_t tmr_complete; - wait_queue_head_t tl_tmr_wait; + struct completion tmr_done; /* Sense buffer that will be mapped into outgoing status */ unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; }; -- cgit v1.2.3 From 75f141aaf48e13812b4fee914a66f6fce28b543f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:41 -0700 Subject: target/tcm_loop: Use target_submit_tmr() instead of open-coding this function Use target_submit_tmr() instead of open-coding this function. The only functional change is that TMFs are now added to sess_cmd_list, something the current code does not do. This behavior change is a bug fix because it makes LUN RESETs wait for other TMFs that are in progress for the same LUN. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 27f912747113..8cf556b4c5ca 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -218,7 +218,6 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, { struct se_cmd *se_cmd = NULL; struct se_session *se_sess; - struct se_portal_group *se_tpg; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_cmd *tl_cmd = NULL; int ret = TMR_FUNCTION_FAILED, rc; @@ -242,40 +241,15 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, init_completion(&tl_cmd->tmr_done); se_cmd = &tl_cmd->tl_se_cmd; - se_tpg = &tl_tpg->tl_se_tpg; se_sess = tl_tpg->tl_nexus->se_sess; - /* - * Initialize struct se_cmd descriptor from target_core_mod infrastructure - */ - transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, - DMA_NONE, TCM_SIMPLE_TAG, - &tl_cmd->tl_sense_buf[0]); - rc = core_tmr_alloc_req(se_cmd, NULL, tmr, GFP_KERNEL); + rc = target_submit_tmr(se_cmd, se_sess, tl_cmd->tl_sense_buf, lun, + NULL, tmr, GFP_KERNEL, task, 0 /*flags*/); if (rc < 0) goto release; - - if (tmr == TMR_ABORT_TASK) - se_cmd->se_tmr_req->ref_task_tag = task; - - /* - * Locate the underlying TCM struct se_lun - */ - if (transport_lookup_tmr_lun(se_cmd, lun) < 0) { - ret = TMR_LUN_DOES_NOT_EXIST; - goto release; - } - /* - * Queue the TMR to TCM Core and sleep waiting for - * tcm_loop_queue_tm_rsp() to wake us up. - */ - transport_generic_handle_tmr(se_cmd); wait_for_completion(&tl_cmd->tmr_done); - /* - * The TMR LUN_RESET has completed, check the response status and - * then release allocations. - */ ret = se_cmd->se_tmr_req->response; + release: if (se_cmd) transport_generic_free_cmd(se_cmd, 1); -- cgit v1.2.3 From 4c1f0e65397f4e5768b955c32489d5b4b6b92a90 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:42 -0700 Subject: target/tcm_loop: Make TMF processing slightly faster Target drivers must guarantee that struct se_cmd and struct se_tmr_req exist as long as target_tmr_work() is in progress. This is why the tcm_loop driver today passes 1 as second argument to transport_generic_free_cmd() from inside the TMF code. Instead of making the TMF code wait, make the TMF code obtain two references (SCF_ACK_KREF) and drop one reference from inside the .check_stop_free() callback. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 8cf556b4c5ca..b6a913e38b30 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -51,19 +51,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd); */ static int tcm_loop_check_stop_free(struct se_cmd *se_cmd) { - /* - * Do not release struct se_cmd's containing a valid TMR - * pointer. These will be released directly in tcm_loop_device_reset() - * with transport_generic_free_cmd(). - */ - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - return 0; - /* - * Release the struct se_cmd, which will make a callback to release - * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() - */ - transport_generic_free_cmd(se_cmd, 0); - return 1; + return transport_generic_free_cmd(se_cmd, 0); } static void tcm_loop_release_cmd(struct se_cmd *se_cmd) @@ -244,18 +232,23 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, se_sess = tl_tpg->tl_nexus->se_sess; rc = target_submit_tmr(se_cmd, se_sess, tl_cmd->tl_sense_buf, lun, - NULL, tmr, GFP_KERNEL, task, 0 /*flags*/); + NULL, tmr, GFP_KERNEL, task, + TARGET_SCF_ACK_KREF); if (rc < 0) goto release; wait_for_completion(&tl_cmd->tmr_done); ret = se_cmd->se_tmr_req->response; + target_put_sess_cmd(se_cmd); + +out: + return ret; release: if (se_cmd) - transport_generic_free_cmd(se_cmd, 1); + transport_generic_free_cmd(se_cmd, 0); else kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); - return ret; + goto out; } static int tcm_loop_abort_task(struct scsi_cmnd *sc) -- cgit v1.2.3 From 4412a67131a037fa1d032bcd50270e9d336a775d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:43 -0700 Subject: target/iscsi: Remove second argument of __iscsit_free_cmd() Initialize .data_direction to DMA_NONE in iscsit_allocate_cmd() such that the second argument of __iscsit_free_cmd() can be left out. Note: this patch causes the first part of __iscsit_free_cmd() no longer to be skipped for TMFs. That's fine since no data segments are associated with TMFs. Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 4 +--- drivers/target/iscsi/iscsi_target_util.c | 29 +++++++++++++---------------- drivers/target/iscsi/iscsi_target_util.h | 2 +- 3 files changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 3fdca2cdd8da..735d4ff2d0ce 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -488,15 +488,13 @@ EXPORT_SYMBOL(iscsit_queue_rsp); void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) { - bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD); - spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node) && !(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP)) list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); - __iscsit_free_cmd(cmd, scsi_cmd, true); + __iscsit_free_cmd(cmd, true); } EXPORT_SYMBOL(iscsit_aborted_task); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 7d3e2fcc26a0..41b9e7cc08b8 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -167,6 +167,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) cmd->se_cmd.map_tag = tag; cmd->conn = conn; + cmd->data_direction = DMA_NONE; INIT_LIST_HEAD(&cmd->i_conn_node); INIT_LIST_HEAD(&cmd->datain_list); INIT_LIST_HEAD(&cmd->cmd_r2t_list); @@ -711,19 +712,16 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) } EXPORT_SYMBOL(iscsit_release_cmd); -void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, - bool check_queues) +void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues) { struct iscsi_conn *conn = cmd->conn; - if (scsi_cmd) { - if (cmd->data_direction == DMA_TO_DEVICE) { - iscsit_stop_dataout_timer(cmd); - iscsit_free_r2ts_from_list(cmd); - } - if (cmd->data_direction == DMA_FROM_DEVICE) - iscsit_free_all_datain_reqs(cmd); + if (cmd->data_direction == DMA_TO_DEVICE) { + iscsit_stop_dataout_timer(cmd); + iscsit_free_r2ts_from_list(cmd); } + if (cmd->data_direction == DMA_FROM_DEVICE) + iscsit_free_all_datain_reqs(cmd); if (conn && check_queues) { iscsit_remove_cmd_from_immediate_queue(cmd, conn); @@ -738,23 +736,22 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) { struct se_cmd *se_cmd = NULL; int rc; - bool op_scsi = false; + /* * Determine if a struct se_cmd is associated with * this struct iscsi_cmd. */ switch (cmd->iscsi_opcode) { case ISCSI_OP_SCSI_CMD: - op_scsi = true; /* * Fallthrough */ case ISCSI_OP_SCSI_TMFUNC: se_cmd = &cmd->se_cmd; - __iscsit_free_cmd(cmd, op_scsi, shutdown); + __iscsit_free_cmd(cmd, shutdown); rc = transport_generic_free_cmd(se_cmd, shutdown); if (!rc && shutdown && se_cmd->se_sess) { - __iscsit_free_cmd(cmd, op_scsi, shutdown); + __iscsit_free_cmd(cmd, shutdown); target_put_sess_cmd(se_cmd); } break; @@ -766,18 +763,18 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) */ if (cmd->se_cmd.se_tfo != NULL) { se_cmd = &cmd->se_cmd; - __iscsit_free_cmd(cmd, true, shutdown); + __iscsit_free_cmd(cmd, shutdown); rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); if (!rc && shutdown && se_cmd->se_sess) { - __iscsit_free_cmd(cmd, true, shutdown); + __iscsit_free_cmd(cmd, shutdown); target_put_sess_cmd(se_cmd); } break; } /* Fall-through */ default: - __iscsit_free_cmd(cmd, false, shutdown); + __iscsit_free_cmd(cmd, shutdown); iscsit_release_cmd(cmd); break; } diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 9e4197af8708..425160565d0c 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -37,7 +37,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); -extern void __iscsit_free_cmd(struct iscsi_cmd *, bool, bool); +extern void __iscsit_free_cmd(struct iscsi_cmd *, bool); extern void iscsit_free_cmd(struct iscsi_cmd *, bool); extern int iscsit_check_session_usage_count(struct iscsi_session *); extern void iscsit_dec_session_usage_count(struct iscsi_session *); -- cgit v1.2.3 From d1c26857cdec3e3bdb5cf7179411f6ce8cc0834c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:44 -0700 Subject: target/iscsi: Simplify iscsit_free_cmd() Since .se_tfo is only set if a command has been submitted to the LIO core, check .se_tfo instead of .iscsi_opcode. Since __iscsit_free_cmd() only affects SCSI commands but not TMFs, calling that function for TMFs does not change behavior. This patch does not change the behavior of iscsit_free_cmd(). Signed-off-by: Bart Van Assche Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_util.c | 39 ++++---------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 41b9e7cc08b8..1e36f83b5961 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -734,49 +734,18 @@ void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues) void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) { - struct se_cmd *se_cmd = NULL; + struct se_cmd *se_cmd = cmd->se_cmd.se_tfo ? &cmd->se_cmd : NULL; int rc; - /* - * Determine if a struct se_cmd is associated with - * this struct iscsi_cmd. - */ - switch (cmd->iscsi_opcode) { - case ISCSI_OP_SCSI_CMD: - /* - * Fallthrough - */ - case ISCSI_OP_SCSI_TMFUNC: - se_cmd = &cmd->se_cmd; - __iscsit_free_cmd(cmd, shutdown); + __iscsit_free_cmd(cmd, shutdown); + if (se_cmd) { rc = transport_generic_free_cmd(se_cmd, shutdown); if (!rc && shutdown && se_cmd->se_sess) { __iscsit_free_cmd(cmd, shutdown); target_put_sess_cmd(se_cmd); } - break; - case ISCSI_OP_REJECT: - /* - * Handle special case for REJECT when iscsi_add_reject*() has - * overwritten the original iscsi_opcode assignment, and the - * associated cmd->se_cmd needs to be released. - */ - if (cmd->se_cmd.se_tfo != NULL) { - se_cmd = &cmd->se_cmd; - __iscsit_free_cmd(cmd, shutdown); - - rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); - if (!rc && shutdown && se_cmd->se_sess) { - __iscsit_free_cmd(cmd, shutdown); - target_put_sess_cmd(se_cmd); - } - break; - } - /* Fall-through */ - default: - __iscsit_free_cmd(cmd, shutdown); + } else { iscsit_release_cmd(cmd); - break; } } EXPORT_SYMBOL(iscsit_free_cmd); -- cgit v1.2.3 From 8fa4011e0dd9423f1226f2f9769a1cf25c264468 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 23 May 2017 16:48:45 -0700 Subject: target/iscsi: Remove dead code from iscsit_process_scsi_cmd() If an iSCSI command is rejected before iscsit_process_scsi_cmd() is called, .reject_reason is set but iscsit_process_scsi_cmd() is not called. This means that the "if (cmd->reject_reason) ..." code in this function can be removed without changing the behavior of this function. Signed-off-by: Bart Van Assche Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 735d4ff2d0ce..74e4975dd1b1 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1249,12 +1249,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, * execution. These exceptions are processed in CmdSN order using * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below. */ - if (cmd->sense_reason) { - if (cmd->reject_reason) - return 0; - + if (cmd->sense_reason) return 1; - } /* * Call directly into transport_generic_new_cmd() to perform * the backend memory allocation. -- cgit v1.2.3 From e9447a46e9fba006ff9b0f4e40a4e38bf2d788db Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 15:45:49 -0500 Subject: ibmvscsis: Use tpgt passed in by user ibmvscsis always returned 0 for the tpg/tag, since it did not parse the value passed in by the user. When functions like ALUA members exports the value, it will be incorrect because targetcli/rtslib starts the tpg numbering at 1. Signed-off-by: Bryant G. Ly Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 35710524d059..522d547d9fea 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -3914,8 +3914,16 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, { struct ibmvscsis_tport *tport = container_of(wwn, struct ibmvscsis_tport, tport_wwn); + u16 tpgt; int rc; + if (strstr(name, "tpgt_") != name) + return ERR_PTR(-EINVAL); + rc = kstrtou16(name + 5, 0, &tpgt); + if (rc) + return ERR_PTR(rc); + tport->tport_tpgt = tpgt; + tport->releasing = false; rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg, -- cgit v1.2.3 From 9a8bb60650b3d6994bd19a3200941f029c95a7a0 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 09:28:48 -0500 Subject: tcmu: Support emulate_write_cache This will enable the toggling of write_cache in tcmu through targetcli-fb Signed-off-by: Bryant G. Ly Reviewed-By: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index beb5f098f32d..0c797cc69d9e 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1290,6 +1290,8 @@ static int tcmu_configure_device(struct se_device *dev) /* Other attributes can be configured in userspace */ if (!dev->dev_attrib.hw_max_sectors) dev->dev_attrib.hw_max_sectors = 128; + if (!dev->dev_attrib.emulate_write_cache) + dev->dev_attrib.emulate_write_cache = 0; dev->dev_attrib.hw_queue_depth = 128; /* @@ -1546,6 +1548,32 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag } CONFIGFS_ATTR(tcmu_, cmd_time_out); +static ssize_t tcmu_emulate_write_cache_show(struct config_item *item, + char *page) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + + return snprintf(page, PAGE_SIZE, "%i\n", da->emulate_write_cache); +} + +static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, + const char *page, size_t count) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + int val; + int ret; + + ret = kstrtouint(page, 0, &val); + if (ret < 0) + return ret; + + da->emulate_write_cache = val; + return count; +} +CONFIGFS_ATTR(tcmu_, emulate_write_cache); + static struct configfs_attribute **tcmu_attrs; static struct target_backend_ops tcmu_ops = { @@ -1682,6 +1710,8 @@ static int __init tcmu_module_init(void) tcmu_attrs[i] = passthrough_attrib_attrs[i]; } tcmu_attrs[i] = &tcmu_attr_cmd_time_out; + i++; + tcmu_attrs[i] = &tcmu_attr_emulate_write_cache; tcmu_ops.tb_dev_attrib_attrs = tcmu_attrs; ret = transport_backend_register(&tcmu_ops); -- cgit v1.2.3 From 1068be7bd4b05ca41a6a8de724f52a9c87861412 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 09:28:49 -0500 Subject: tcmu: Add netlink for device reconfiguration This gives tcmu the ability to handle events that can cause reconfiguration, such as resize, path changes, write_cache, etc... Signed-off-by: Bryant G. Ly Reviewed-By: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 12 ++++++++++++ include/uapi/linux/target_core_user.h | 1 + 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 0c797cc69d9e..ae918222284b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1562,6 +1562,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, { struct se_dev_attrib *da = container_of(to_config_group(item), struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); int val; int ret; @@ -1570,6 +1571,17 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, return ret; da->emulate_write_cache = val; + + /* Check if device has been configured before */ + if (tcmu_dev_configured(udev)) { + ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, + udev->uio_info.name, + udev->uio_info.uio_dev->minor); + if (ret) { + pr_err("Unable to reconfigure device\n"); + return ret; + } + } return count; } CONFIGFS_ATTR(tcmu_, emulate_write_cache); diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index af17b4154ef6..403a61faada0 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -130,6 +130,7 @@ enum tcmu_genl_cmd { TCMU_CMD_UNSPEC, TCMU_CMD_ADDED_DEVICE, TCMU_CMD_REMOVED_DEVICE, + TCMU_CMD_RECONFIG_DEVICE, __TCMU_CMD_MAX, }; #define TCMU_CMD_MAX (__TCMU_CMD_MAX - 1) -- cgit v1.2.3 From 801fc54d5d943e8a6a6bc26bc94fb9b90938ff68 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 09:28:50 -0500 Subject: tcmu: Make dev_size configurable via userspace Allow tcmu backstores to be able to set the device size after it has been configured via set attribute. Part of support in userspace to support certain backstores changing device size. Signed-off-by: Bryant G. Ly Reviewed-By: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index ae918222284b..c8c84b71dc91 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1548,6 +1548,44 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag } CONFIGFS_ATTR(tcmu_, cmd_time_out); +static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + + return snprintf(page, PAGE_SIZE, "%zu\n", udev->dev_size); +} + +static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, + size_t count) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + unsigned long val; + int ret; + + ret = kstrtoul(page, 0, &val); + if (ret < 0) + return ret; + udev->dev_size = val; + + /* Check if device has been configured before */ + if (tcmu_dev_configured(udev)) { + ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, + udev->uio_info.name, + udev->uio_info.uio_dev->minor); + if (ret) { + pr_err("Unable to reconfigure device\n"); + return ret; + } + } + + return count; +} +CONFIGFS_ATTR(tcmu_, dev_size); + static ssize_t tcmu_emulate_write_cache_show(struct config_item *item, char *page) { @@ -1586,6 +1624,13 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, } CONFIGFS_ATTR(tcmu_, emulate_write_cache); +struct configfs_attribute *tcmu_attrib_attrs[] = { + &tcmu_attr_cmd_time_out, + &tcmu_attr_dev_size, + &tcmu_attr_emulate_write_cache, + NULL, +}; + static struct configfs_attribute **tcmu_attrs; static struct target_backend_ops tcmu_ops = { @@ -1685,7 +1730,7 @@ static int unmap_thread_fn(void *data) static int __init tcmu_module_init(void) { - int ret, i, len = 0; + int ret, i, k, len = 0; BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); @@ -1710,7 +1755,10 @@ static int __init tcmu_module_init(void) for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) { len += sizeof(struct configfs_attribute *); } - len += sizeof(struct configfs_attribute *) * 2; + for (i = 0; tcmu_attrib_attrs[i] != NULL; i++) { + len += sizeof(struct configfs_attribute *); + } + len += sizeof(struct configfs_attribute *); tcmu_attrs = kzalloc(len, GFP_KERNEL); if (!tcmu_attrs) { @@ -1721,9 +1769,10 @@ static int __init tcmu_module_init(void) for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) { tcmu_attrs[i] = passthrough_attrib_attrs[i]; } - tcmu_attrs[i] = &tcmu_attr_cmd_time_out; - i++; - tcmu_attrs[i] = &tcmu_attr_emulate_write_cache; + for (k = 0; tcmu_attrib_attrs[k] != NULL; k++) { + tcmu_attrs[i] = tcmu_attrib_attrs[k]; + i++; + } tcmu_ops.tb_dev_attrib_attrs = tcmu_attrs; ret = transport_backend_register(&tcmu_ops); -- cgit v1.2.3 From ee01825220f01c0befea25f08325962fa9374ee2 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 09:28:51 -0500 Subject: tcmu: Make dev_config configurable This allows for userspace to change the device path after it has been created. Thus giving the user the ability to change the path. The use case for this is to allow for virtual optical to have media change. Signed-off-by: Bryant G. Ly Reviewed-By: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index c8c84b71dc91..7c6475731895 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1548,6 +1548,46 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag } CONFIGFS_ATTR(tcmu_, cmd_time_out); +static ssize_t tcmu_dev_path_show(struct config_item *item, char *page) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + + return snprintf(page, PAGE_SIZE, "%s\n", udev->dev_config); +} + +static ssize_t tcmu_dev_path_store(struct config_item *item, const char *page, + size_t count) +{ + struct se_dev_attrib *da = container_of(to_config_group(item), + struct se_dev_attrib, da_group); + struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + char *copy = NULL; + int ret; + + copy = kstrdup(page, GFP_KERNEL); + if (!copy) { + kfree(copy); + return -EINVAL; + } + strlcpy(udev->dev_config, copy, TCMU_CONFIG_LEN); + + /* Check if device has been configured before */ + if (tcmu_dev_configured(udev)) { + ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, + udev->uio_info.name, + udev->uio_info.uio_dev->minor); + if (ret) { + pr_err("Unable to reconfigure device\n"); + return ret; + } + } + + return count; +} +CONFIGFS_ATTR(tcmu_, dev_path); + static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) { struct se_dev_attrib *da = container_of(to_config_group(item), @@ -1626,6 +1666,7 @@ CONFIGFS_ATTR(tcmu_, emulate_write_cache); struct configfs_attribute *tcmu_attrib_attrs[] = { &tcmu_attr_cmd_time_out, + &tcmu_attr_dev_path, &tcmu_attr_dev_size, &tcmu_attr_emulate_write_cache, NULL, -- cgit v1.2.3 From 8a45885c1514cdae2ee64b5ac03ffc00a1a8a9d7 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Tue, 6 Jun 2017 09:28:52 -0500 Subject: tcmu: Add Type of reconfig into netlink This patch adds more info about the attribute being changed, so that usersapce can easily figure out what is happening. Signed-off-by: Bryant G. Ly Reviewed-By: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 20 ++++++++++++++------ include/uapi/linux/target_core_user.h | 8 ++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 7c6475731895..afc1fd6bacaf 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1176,7 +1176,8 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) return 0; } -static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int minor) +static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, + int minor, int type) { struct sk_buff *skb; void *msg_header; @@ -1198,6 +1199,10 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino if (ret < 0) goto free_skb; + ret = nla_put_u32(skb, TCMU_ATTR_TYPE, type); + if (ret < 0) + goto free_skb; + genlmsg_end(skb, msg_header); ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, @@ -1301,7 +1306,7 @@ static int tcmu_configure_device(struct se_device *dev) kref_get(&udev->kref); ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor); + udev->uio_info.uio_dev->minor, NO_RECONFIG); if (ret) goto err_netlink; @@ -1383,7 +1388,7 @@ static void tcmu_free_device(struct se_device *dev) if (tcmu_dev_configured(udev)) { tcmu_netlink_event(TCMU_CMD_REMOVED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor); + udev->uio_info.uio_dev->minor, NO_RECONFIG); uio_unregister_device(&udev->uio_info); } @@ -1577,7 +1582,8 @@ static ssize_t tcmu_dev_path_store(struct config_item *item, const char *page, if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor); + udev->uio_info.uio_dev->minor, + CONFIG_PATH); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; @@ -1615,7 +1621,8 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor); + udev->uio_info.uio_dev->minor, + CONFIG_SIZE); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; @@ -1654,7 +1661,8 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor); + udev->uio_info.uio_dev->minor, + CONFIG_WRITECACHE); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index 403a61faada0..5b00e3500005 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -139,8 +139,16 @@ enum tcmu_genl_attr { TCMU_ATTR_UNSPEC, TCMU_ATTR_DEVICE, TCMU_ATTR_MINOR, + TCMU_ATTR_TYPE, __TCMU_ATTR_MAX, }; #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1) +enum tcmu_reconfig_types { + NO_RECONFIG, + CONFIG_PATH, + CONFIG_SIZE, + CONFIG_WRITECACHE, +}; + #endif -- cgit v1.2.3 From 1d6ef276594a781686058802996e09c8550fd767 Mon Sep 17 00:00:00 2001 From: Jiang Yi Date: Sun, 25 Jun 2017 12:28:50 -0700 Subject: target: Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce This patch addresses a COMPARE_AND_WRITE se_device->caw_sem leak, that would be triggered during normal se_cmd shutdown or abort via __transport_wait_for_tasks(). This would occur because target_complete_cmd() would catch this early and do complete_all(&cmd->t_transport_stop_comp), but since target_complete_ok_work() or target_complete_failure_work() are never called to invoke se_cmd->transport_complete_callback(), the COMPARE_AND_WRITE specific callbacks never release caw_sem. To address this special case, go ahead and release caw_sem directly from target_complete_cmd(). (Remove '&& success' from check, to release caw_sem regardless of scsi_status - nab) Signed-off-by: Jiang Yi Cc: # 3.14+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a5ecec8f3996..28de421e3220 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -730,6 +730,15 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) if (cmd->transport_state & CMD_T_ABORTED || cmd->transport_state & CMD_T_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); + /* + * If COMPARE_AND_WRITE was stopped by __transport_wait_for_tasks(), + * release se_device->caw_sem obtained by sbc_compare_and_write() + * since target_complete_ok_work() or target_complete_failure_work() + * won't be called to invoke the normal CAW completion callbacks. + */ + if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) { + up(&dev->caw_sem); + } complete_all(&cmd->t_transport_stop_comp); return; } else if (!success) { -- cgit v1.2.3 From 07932a023af3cd728390ffdaeffb78e357123181 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 15 Jun 2017 15:05:31 +0800 Subject: tcmu: Fix module removal due to stuck unmap_thread thread again Because the unmap code just after the schdule() returned may take a long time and if the kthread_stop() is fired just when in this routine, the module removal maybe stuck too. Signed-off-by: Xiubo Li Reviewed-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index afc1fd6bacaf..a60a66d61146 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1707,7 +1707,7 @@ static int unmap_thread_fn(void *data) struct page *page; int i; - while (1) { + while (!kthread_should_stop()) { DEFINE_WAIT(__wait); prepare_to_wait(&unmap_wait, &__wait, TASK_INTERRUPTIBLE); -- cgit v1.2.3 From 5821783bcaa94f4a00d65effb3fb8937b08cb2ae Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 13 Jun 2017 14:29:09 +0100 Subject: tcmu: make array tcmu_attrib_attrs static const The array tcmu_attrib_attrs does not need to be in global scope, so make it static. Cleans up sparse warning: "symbol 'tcmu_attrib_attrs' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index a60a66d61146..6322269d9e85 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1672,7 +1672,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, } CONFIGFS_ATTR(tcmu_, emulate_write_cache); -struct configfs_attribute *tcmu_attrib_attrs[] = { +static struct configfs_attribute *tcmu_attrib_attrs[] = { &tcmu_attr_cmd_time_out, &tcmu_attr_dev_path, &tcmu_attr_dev_size, -- cgit v1.2.3 From fce50a2fa4e9c6e103915c351b6d4a98661341d6 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 29 Jun 2017 22:21:31 -0700 Subject: iser-target: Avoid isert_conn->cm_id dereference in isert_login_recv_done This patch fixes a NULL pointer dereference in isert_login_recv_done() of isert_conn->cm_id due to isert_cma_handler() -> isert_connect_error() resetting isert_conn->cm_id = NULL during a failed login attempt. As per Sagi, we will always see the completion of all recv wrs posted on the qp (given that we assigned a ->done handler), this is a FLUSH error completion, we just don't get to verify that because we deref NULL before. The issue here, was the assumption that dereferencing the connection cm_id is always safe, which is not true since: commit 4a579da2586bd3b79b025947ea24ede2bbfede62 Author: Sagi Grimberg Date: Sun Mar 29 15:52:04 2015 +0300 iser-target: Fix possible deadlock in RDMA_CM connection error As I see it, we have a direct reference to the isert_device from isert_conn which is the one-liner fix that we actually need like we do in isert_rdma_read_done() and isert_rdma_write_done(). Reported-by: Andrea Righi Tested-by: Andrea Righi Reviewed-by: Sagi Grimberg Cc: # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index fcbed35e95a8..0e662656ef42 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1452,7 +1452,7 @@ static void isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc) { struct isert_conn *isert_conn = wc->qp->qp_context; - struct ib_device *ib_dev = isert_conn->cm_id->device; + struct ib_device *ib_dev = isert_conn->device->ib_device; if (unlikely(wc->status != IB_WC_SUCCESS)) { isert_print_wc(wc, "login recv"); -- cgit v1.2.3 From 5f572526a18418258bfa137e3353656c25439500 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 30 Jun 2017 00:08:13 -0700 Subject: qla2xxx: Fix incorrect tcm_qla2xxx_free_cmd use during TMR ABORT This patch drops two incorrect usages of tcm_qla2xxx_free_cmd() during TMR ABORT within tcm_qla2xxx_handle_data_work() and tcm_qla2xxx_aborted_task(), which where attempting to dispatch into workqueue context to do tcm_qla2xxx_complete_free() and subsequently invoke transport_generic_free_cmd(). This is incorrect because during TMR ABORT target-core will drop the outstanding se_cmd->cmd_kref references once it has quiesced the se_cmd via transport_wait_for_tasks(), and in the case of qla2xxx it should not attempt to do it's own transport_generic_free_cmd() once the abort has occured. As reported by Pascal, this was originally manifesting as a BUG_ON(cmd->cmd_in_wq) in qlt_free_cmd() during TMR ABORT, with a LIO backend that had sufficently high enough WRITE latency to trigger a host side TMR ABORT_TASK. In addition, for the case in tcm_qla2xxx_write_pending_status() and tcm_qla2xxx_handle_data_work() that waits for outstanding FCP WRITE data transfer to complete before preceeding with a TMR ABORT, avoid se_cmd->t_transport_stop_comp that is already used by transport_wait_for_tasks() and use a qla2xxx internal struct completion instead. Reported-by: Pascal de Bruijn Tested-by: Pascal de Bruijn Acked-by: Himanshu Madhani Cc: Quinn Tran Cc: # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/qla_target.c | 4 ++++ drivers/scsi/qla2xxx/qla_target.h | 1 + drivers/scsi/qla2xxx/tcm_qla2xxx.c | 36 +++--------------------------------- 3 files changed, 8 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 401e245477d4..8f8ece900801 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4079,6 +4079,8 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; memset(cmd, 0, sizeof(struct qla_tgt_cmd)); + init_completion(&cmd->write_pending_abort_comp); + memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -5083,6 +5085,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); + init_completion(&cmd->write_pending_abort_comp); + memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->tgt = vha->vha_tgt.qla_tgt; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index d64420251194..939e93c5d3ae 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -868,6 +868,7 @@ struct qla_tgt_cmd { unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; spinlock_t cmd_lock; + struct completion write_pending_abort_comp; /* to save extra sess dereferences */ unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 75aeb9fdfd06..8c1bf9b14bb2 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -415,6 +415,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) { + struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); unsigned long flags; /* * Check for WRITE_PENDING status to determine if we need to wait for @@ -424,8 +425,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) if (se_cmd->t_state == TRANSPORT_WRITE_PENDING || se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, - 50); + wait_for_completion(&cmd->write_pending_abort_comp); return 0; } spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); @@ -501,7 +501,6 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. @@ -509,17 +508,6 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) */ cmd->cmd_in_wq = 0; - spin_lock_irqsave(&cmd->cmd_lock, flags); - cmd->data_work = 1; - if (cmd->aborted) { - cmd->data_work_free = 1; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - - tcm_qla2xxx_free_cmd(cmd); - return; - } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - cmd->vha->tgt_counters.qla_core_ret_ctio++; if (!cmd->write_data_transferred) { /* @@ -527,7 +515,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) * waiting upon completion in tcm_qla2xxx_write_pending_status() */ if (cmd->se_cmd.transport_state & CMD_T_ABORTED) { - complete(&cmd->se_cmd.t_transport_stop_comp); + complete(&cmd->write_pending_abort_comp); return; } @@ -753,31 +741,13 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) qlt_xmit_tm_rsp(mcmd); } -#define DATA_WORK_NOT_FREE(_cmd) (_cmd->data_work && !_cmd->data_work_free) static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - unsigned long flags; if (qlt_abort_cmd(cmd)) return; - - spin_lock_irqsave(&cmd->cmd_lock, flags); - if ((cmd->state == QLA_TGT_STATE_NEW)|| - ((cmd->state == QLA_TGT_STATE_DATA_IN) && - DATA_WORK_NOT_FREE(cmd))) { - cmd->data_work_free = 1; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - /* - * cmd has not reached fw, Use this trigger to free it. - */ - tcm_qla2xxx_free_cmd(cmd); - return; - } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - return; - } static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, -- cgit v1.2.3 From 2d76443e02f260d7a5bd0ede1851ae5534f0c68d Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 12 Jun 2017 01:34:28 -0500 Subject: tcmu: reconfigure netlink attr changes 1. TCMU_ATTR_TYPE is too generic when it describes only the reconfiguration type, so rename to TCMU_ATTR_RECONFIG_TYPE. 2. Only return the reconfig type when it is a TCMU_CMD_RECONFIG_DEVICE command. 3. CONFIG_* type is not needed. We can pass the value along with an ATTR to userspace, so it does not need to read sysfs/configfs. 4. Fix leak in tcmu_dev_path_store and rename to dev_config to reflect it is more than just a path that can be changed. 6. Don't update kernel struct value if netlink sending fails. Signed-off-by: Mike Christie Reviewed-by: "Bryant G. Ly" Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 73 +++++++++++++++++++++-------------- include/uapi/linux/target_core_user.h | 12 ++---- 2 files changed, 48 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 6322269d9e85..ca5b081295db 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1177,7 +1177,8 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) } static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, - int minor, int type) + int minor, int reconfig_attr, + const void *reconfig_data) { struct sk_buff *skb; void *msg_header; @@ -1199,9 +1200,27 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, if (ret < 0) goto free_skb; - ret = nla_put_u32(skb, TCMU_ATTR_TYPE, type); - if (ret < 0) - goto free_skb; + if (cmd == TCMU_CMD_RECONFIG_DEVICE) { + switch (reconfig_attr) { + case TCMU_ATTR_DEV_CFG: + ret = nla_put_string(skb, reconfig_attr, reconfig_data); + break; + case TCMU_ATTR_DEV_SIZE: + ret = nla_put_u64_64bit(skb, reconfig_attr, + *((u64 *)reconfig_data), + TCMU_ATTR_PAD); + break; + case TCMU_ATTR_WRITECACHE: + ret = nla_put_u8(skb, reconfig_attr, + *((u8 *)reconfig_data)); + break; + default: + BUG(); + } + + if (ret < 0) + goto free_skb; + } genlmsg_end(skb, msg_header); @@ -1306,7 +1325,7 @@ static int tcmu_configure_device(struct se_device *dev) kref_get(&udev->kref); ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor, NO_RECONFIG); + udev->uio_info.uio_dev->minor, 0, NULL); if (ret) goto err_netlink; @@ -1388,7 +1407,7 @@ static void tcmu_free_device(struct se_device *dev) if (tcmu_dev_configured(udev)) { tcmu_netlink_event(TCMU_CMD_REMOVED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor, NO_RECONFIG); + udev->uio_info.uio_dev->minor, 0, NULL); uio_unregister_device(&udev->uio_info); } @@ -1553,7 +1572,7 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag } CONFIGFS_ATTR(tcmu_, cmd_time_out); -static ssize_t tcmu_dev_path_show(struct config_item *item, char *page) +static ssize_t tcmu_dev_config_show(struct config_item *item, char *page) { struct se_dev_attrib *da = container_of(to_config_group(item), struct se_dev_attrib, da_group); @@ -1562,37 +1581,34 @@ static ssize_t tcmu_dev_path_show(struct config_item *item, char *page) return snprintf(page, PAGE_SIZE, "%s\n", udev->dev_config); } -static ssize_t tcmu_dev_path_store(struct config_item *item, const char *page, - size_t count) +static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, + size_t count) { struct se_dev_attrib *da = container_of(to_config_group(item), struct se_dev_attrib, da_group); struct tcmu_dev *udev = TCMU_DEV(da->da_dev); - char *copy = NULL; - int ret; + int ret, len; - copy = kstrdup(page, GFP_KERNEL); - if (!copy) { - kfree(copy); + len = strlen(page); + if (!len || len > TCMU_CONFIG_LEN - 1) return -EINVAL; - } - strlcpy(udev->dev_config, copy, TCMU_CONFIG_LEN); /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, udev->uio_info.uio_dev->minor, - CONFIG_PATH); + TCMU_ATTR_DEV_CFG, page); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; } } + strlcpy(udev->dev_config, page, TCMU_CONFIG_LEN); return count; } -CONFIGFS_ATTR(tcmu_, dev_path); +CONFIGFS_ATTR(tcmu_, dev_config); static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) { @@ -1609,26 +1625,25 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, struct se_dev_attrib *da = container_of(to_config_group(item), struct se_dev_attrib, da_group); struct tcmu_dev *udev = TCMU_DEV(da->da_dev); - unsigned long val; + u64 val; int ret; - ret = kstrtoul(page, 0, &val); + ret = kstrtou64(page, 0, &val); if (ret < 0) return ret; - udev->dev_size = val; /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, udev->uio_info.uio_dev->minor, - CONFIG_SIZE); + TCMU_ATTR_DEV_SIZE, &val); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; } } - + udev->dev_size = val; return count; } CONFIGFS_ATTR(tcmu_, dev_size); @@ -1648,33 +1663,33 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, struct se_dev_attrib *da = container_of(to_config_group(item), struct se_dev_attrib, da_group); struct tcmu_dev *udev = TCMU_DEV(da->da_dev); - int val; + u8 val; int ret; - ret = kstrtouint(page, 0, &val); + ret = kstrtou8(page, 0, &val); if (ret < 0) return ret; - da->emulate_write_cache = val; - /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, udev->uio_info.name, udev->uio_info.uio_dev->minor, - CONFIG_WRITECACHE); + TCMU_ATTR_WRITECACHE, &val); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; } } + + da->emulate_write_cache = val; return count; } CONFIGFS_ATTR(tcmu_, emulate_write_cache); static struct configfs_attribute *tcmu_attrib_attrs[] = { &tcmu_attr_cmd_time_out, - &tcmu_attr_dev_path, + &tcmu_attr_dev_config, &tcmu_attr_dev_size, &tcmu_attr_emulate_write_cache, NULL, diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index 5b00e3500005..4bfc9a1b635c 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -139,16 +139,12 @@ enum tcmu_genl_attr { TCMU_ATTR_UNSPEC, TCMU_ATTR_DEVICE, TCMU_ATTR_MINOR, - TCMU_ATTR_TYPE, + TCMU_ATTR_PAD, + TCMU_ATTR_DEV_CFG, + TCMU_ATTR_DEV_SIZE, + TCMU_ATTR_WRITECACHE, __TCMU_ATTR_MAX, }; #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1) -enum tcmu_reconfig_types { - NO_RECONFIG, - CONFIG_PATH, - CONFIG_SIZE, - CONFIG_WRITECACHE, -}; - #endif -- cgit v1.2.3 From 926347061ef1f4d3873829fd1960c6e4b965aa9f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:12 -0500 Subject: target: break up free_device callback With this patch free_device is now used to free what is allocated in the alloc_device callback and destroy_device tears down the resources that are setup in the configure_device callback. This patch will be needed in the next patch where tcmu needs to be able to look up the device in the destroy callback. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 ++ drivers/target/target_core_file.c | 7 ++++++- drivers/target/target_core_iblock.c | 8 ++++++-- drivers/target/target_core_pscsi.c | 7 ++++++- drivers/target/target_core_rd.c | 7 ++++++- drivers/target/target_core_user.c | 12 +++++++++--- include/target/target_core_backend.h | 1 + 7 files changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 11c80c47b9d3..16a701fed66b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -974,6 +974,8 @@ void target_free_device(struct se_device *dev) if (dev->dev_flags & DF_CONFIGURED) { destroy_workqueue(dev->tmr_wq); + dev->transport->destroy_device(dev); + mutex_lock(&g_device_mutex); list_del(&dev->g_dev_node); mutex_unlock(&g_device_mutex); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 73b8f93a5fef..50f235580546 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -236,6 +236,11 @@ static void fd_dev_call_rcu(struct rcu_head *p) } static void fd_free_device(struct se_device *dev) +{ + call_rcu(&dev->rcu_head, fd_dev_call_rcu); +} + +static void fd_destroy_device(struct se_device *dev) { struct fd_dev *fd_dev = FD_DEV(dev); @@ -243,7 +248,6 @@ static void fd_free_device(struct se_device *dev) filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } - call_rcu(&dev->rcu_head, fd_dev_call_rcu); } static int fd_do_rw(struct se_cmd *cmd, struct file *fd, @@ -826,6 +830,7 @@ static const struct target_backend_ops fileio_ops = { .detach_hba = fd_detach_hba, .alloc_device = fd_alloc_device, .configure_device = fd_configure_device, + .destroy_device = fd_destroy_device, .free_device = fd_free_device, .parse_cdb = fd_parse_cdb, .set_configfs_dev_params = fd_set_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index b2044133d747..a5e16f715392 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -189,6 +189,11 @@ static void iblock_dev_call_rcu(struct rcu_head *p) } static void iblock_free_device(struct se_device *dev) +{ + call_rcu(&dev->rcu_head, iblock_dev_call_rcu); +} + +static void iblock_destroy_device(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -196,8 +201,6 @@ static void iblock_free_device(struct se_device *dev) blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); if (ib_dev->ibd_bio_set != NULL) bioset_free(ib_dev->ibd_bio_set); - - call_rcu(&dev->rcu_head, iblock_dev_call_rcu); } static unsigned long long iblock_emulate_read_cap_with_block_size( @@ -858,6 +861,7 @@ static const struct target_backend_ops iblock_ops = { .detach_hba = iblock_detach_hba, .alloc_device = iblock_alloc_device, .configure_device = iblock_configure_device, + .destroy_device = iblock_destroy_device, .free_device = iblock_free_device, .parse_cdb = iblock_parse_cdb, .set_configfs_dev_params = iblock_set_configfs_dev_params, diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index e0be4aa38328..7d944b23aeee 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -563,6 +563,11 @@ static void pscsi_dev_call_rcu(struct rcu_head *p) } static void pscsi_free_device(struct se_device *dev) +{ + call_rcu(&dev->rcu_head, pscsi_dev_call_rcu); +} + +static void pscsi_destroy_device(struct se_device *dev) { struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; @@ -592,7 +597,6 @@ static void pscsi_free_device(struct se_device *dev) pdv->pdv_sd = NULL; } - call_rcu(&dev->rcu_head, pscsi_dev_call_rcu); } static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, @@ -1084,6 +1088,7 @@ static const struct target_backend_ops pscsi_ops = { .pmode_enable_hba = pscsi_pmode_enable_hba, .alloc_device = pscsi_alloc_device, .configure_device = pscsi_configure_device, + .destroy_device = pscsi_destroy_device, .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, .parse_cdb = pscsi_parse_cdb, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d12967690054..a6e8106abd6f 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -338,11 +338,15 @@ static void rd_dev_call_rcu(struct rcu_head *p) } static void rd_free_device(struct se_device *dev) +{ + call_rcu(&dev->rcu_head, rd_dev_call_rcu); +} + +static void rd_destroy_device(struct se_device *dev) { struct rd_dev *rd_dev = RD_DEV(dev); rd_release_device_space(rd_dev); - call_rcu(&dev->rcu_head, rd_dev_call_rcu); } static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) @@ -651,6 +655,7 @@ static const struct target_backend_ops rd_mcp_ops = { .detach_hba = rd_detach_hba, .alloc_device = rd_alloc_device, .configure_device = rd_configure_device, + .destroy_device = rd_destroy_device, .free_device = rd_free_device, .parse_cdb = rd_parse_cdb, .set_configfs_dev_params = rd_set_configfs_dev_params, diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index ca5b081295db..e58127b8db8a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1379,6 +1379,14 @@ static void tcmu_blocks_release(struct tcmu_dev *udev) } static void tcmu_free_device(struct se_device *dev) +{ + struct tcmu_dev *udev = TCMU_DEV(dev); + + /* release ref from init */ + kref_put(&udev->kref, tcmu_dev_kref_release); +} + +static void tcmu_destroy_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); struct tcmu_cmd *cmd; @@ -1411,9 +1419,6 @@ static void tcmu_free_device(struct se_device *dev) uio_unregister_device(&udev->uio_info); } - - /* release ref from init */ - kref_put(&udev->kref, tcmu_dev_kref_release); } enum { @@ -1705,6 +1710,7 @@ static struct target_backend_ops tcmu_ops = { .detach_hba = tcmu_detach_hba, .alloc_device = tcmu_alloc_device, .configure_device = tcmu_configure_device, + .destroy_device = tcmu_destroy_device, .free_device = tcmu_free_device, .parse_cdb = tcmu_parse_cdb, .set_configfs_dev_params = tcmu_set_configfs_dev_params, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index b76071161cdc..3dbcacd7e8d7 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -30,6 +30,7 @@ struct target_backend_ops { struct se_device *(*alloc_device)(struct se_hba *, const char *); int (*configure_device)(struct se_device *); + void (*destroy_device)(struct se_device *); void (*free_device)(struct se_device *device); ssize_t (*set_configfs_dev_params)(struct se_device *, -- cgit v1.2.3 From 0a5eee647b78e53da05e081362f42a11b4b674eb Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:13 -0500 Subject: target: use idr for se_device dev index In the next patches we will add tcmu netlink support that allows userspace to send commands to target_core_user. To execute operations on a se_device/tcmu_dev we need to be able to look up a dev by any old id. This patch replaces the se_device->dev_index with a idr created id. The next patches will also remove the g_device_list and replace it with the idr. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 30 ++++++++++++++++++++++++++---- include/target/target_core_base.h | 1 - 2 files changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 16a701fed66b..f10dfe7b1d54 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -51,6 +51,7 @@ DEFINE_MUTEX(g_device_mutex); LIST_HEAD(g_device_list); +static DEFINE_IDR(devices_idr); static struct se_hba *lun0_hba; /* not static, needed by tpg.c */ @@ -882,7 +883,7 @@ EXPORT_SYMBOL(target_to_linux_sector); int target_configure_device(struct se_device *dev) { struct se_hba *hba = dev->se_hba; - int ret; + int ret, id; if (dev->dev_flags & DF_CONFIGURED) { pr_err("se_dev->se_dev_ptr already set for storage" @@ -890,9 +891,26 @@ int target_configure_device(struct se_device *dev) return -EEXIST; } + /* + * Add early so modules like tcmu can use during its + * configuration. + */ + mutex_lock(&g_device_mutex); + /* + * Use cyclic to try and avoid collisions with devices + * that were recently removed. + */ + id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL); + mutex_unlock(&g_device_mutex); + if (id < 0) { + ret = -ENOMEM; + goto out; + } + dev->dev_index = id; + ret = dev->transport->configure_device(dev); if (ret) - goto out; + goto out_free_index; /* * XXX: there is not much point to have two different values here.. */ @@ -907,12 +925,11 @@ int target_configure_device(struct se_device *dev) dev->dev_attrib.hw_block_size); dev->dev_attrib.optimal_sectors = dev->dev_attrib.hw_max_sectors; - dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); dev->creation_time = get_jiffies_64(); ret = core_setup_alua(dev); if (ret) - goto out; + goto out_free_index; /* * Startup the struct se_device processing thread @@ -960,6 +977,10 @@ int target_configure_device(struct se_device *dev) out_free_alua: core_alua_free_lu_gp_mem(dev); +out_free_index: + mutex_lock(&g_device_mutex); + idr_remove(&devices_idr, dev->dev_index); + mutex_unlock(&g_device_mutex); out: se_release_vpd_for_dev(dev); return ret; @@ -977,6 +998,7 @@ void target_free_device(struct se_device *dev) dev->transport->destroy_device(dev); mutex_lock(&g_device_mutex); + idr_remove(&devices_idr, dev->dev_index); list_del(&dev->g_dev_node); mutex_unlock(&g_device_mutex); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index a3af69fcf75e..51a92f17352c 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -219,7 +219,6 @@ enum tcm_tmrsp_table { */ typedef enum { SCSI_INST_INDEX, - SCSI_DEVICE_INDEX, SCSI_AUTH_INTR_INDEX, SCSI_INDEX_TYPE_MAX } scsi_index_t; -- cgit v1.2.3 From 85441e6b8c97964a6da72135dc21f708adbdc4d8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:14 -0500 Subject: target: add helper to find se_device by dev_index This adds a helper to find a se_device by dev_index. It will be used in the next patches so tcmu's netlink interface can execute commands on specific devices. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 24 ++++++++++++++++++++++++ include/target/target_core_backend.h | 2 ++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index f10dfe7b1d54..de1131612ddc 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -880,6 +880,30 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb) } EXPORT_SYMBOL(target_to_linux_sector); +/** + * target_find_device - find a se_device by its dev_index + * @id: dev_index + * @do_depend: true if caller needs target_depend_item to be done + * + * If do_depend is true, the caller must do a target_undepend_item + * when finished using the device. + * + * If do_depend is false, the caller must be called in a configfs + * callback or during removal. + */ +struct se_device *target_find_device(int id, bool do_depend) +{ + struct se_device *dev; + + mutex_lock(&g_device_mutex); + dev = idr_find(&devices_idr, id); + if (dev && do_depend && target_depend_item(&dev->dev_group.cg_item)) + dev = NULL; + mutex_unlock(&g_device_mutex); + return dev; +} +EXPORT_SYMBOL(target_find_device); + int target_configure_device(struct se_device *dev) { struct se_hba *hba = dev->se_hba; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 3dbcacd7e8d7..1f2b7007f2df 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -106,6 +106,8 @@ bool target_lun_is_rdonly(struct se_cmd *); sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); +struct se_device *target_find_device(int id, bool do_depend); + bool target_sense_desc_format(struct se_device *dev); sector_t target_to_linux_sector(struct se_device *dev, sector_t lb); bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, -- cgit v1.2.3 From b3af66e24393f03ef81db17a11387d9e6174bd01 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:15 -0500 Subject: tcmu: perfom device add, del and reconfig synchronously This makes the device add, del reconfig operations sync. It fixes the issue where for add and reconfig, we do not know if userspace successfully completely the operation, so we leave invalid kernel structs or report incorrect status for the config/reconfig operations. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 213 ++++++++++++++++++++++++++++++---- include/uapi/linux/target_core_user.h | 7 ++ 2 files changed, 200 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index e58127b8db8a..e080cd1a8fde 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -87,6 +87,8 @@ /* Default maximum of the global data blocks(512K * PAGE_SIZE) */ #define TCMU_GLOBAL_MAX_BLOCKS (512 * 1024) +static u8 tcmu_kern_cmd_reply_supported; + static struct device *tcmu_root_device; struct tcmu_hba { @@ -95,6 +97,13 @@ struct tcmu_hba { #define TCMU_CONFIG_LEN 256 +struct tcmu_nl_cmd { + /* wake up thread waiting for reply */ + struct completion complete; + int cmd; + int status; +}; + struct tcmu_dev { struct list_head node; struct kref kref; @@ -135,6 +144,11 @@ struct tcmu_dev { struct timer_list timeout; unsigned int cmd_time_out; + spinlock_t nl_cmd_lock; + struct tcmu_nl_cmd curr_nl_cmd; + /* wake up threads waiting on curr_nl_cmd */ + wait_queue_head_t nl_cmd_wq; + char dev_config[TCMU_CONFIG_LEN]; }; @@ -178,16 +192,128 @@ static const struct genl_multicast_group tcmu_mcgrps[] = { [TCMU_MCGRP_CONFIG] = { .name = "config", }, }; +static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] = { + [TCMU_ATTR_DEVICE] = { .type = NLA_STRING }, + [TCMU_ATTR_MINOR] = { .type = NLA_U32 }, + [TCMU_ATTR_CMD_STATUS] = { .type = NLA_S32 }, + [TCMU_ATTR_DEVICE_ID] = { .type = NLA_U32 }, + [TCMU_ATTR_SUPP_KERN_CMD_REPLY] = { .type = NLA_U8 }, +}; + +static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) +{ + struct se_device *dev; + struct tcmu_dev *udev; + struct tcmu_nl_cmd *nl_cmd; + int dev_id, rc, ret = 0; + bool is_removed = (completed_cmd == TCMU_CMD_REMOVED_DEVICE); + + if (!info->attrs[TCMU_ATTR_CMD_STATUS] || + !info->attrs[TCMU_ATTR_DEVICE_ID]) { + printk(KERN_ERR "TCMU_ATTR_CMD_STATUS or TCMU_ATTR_DEVICE_ID not set, doing nothing\n"); + return -EINVAL; + } + + dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]); + rc = nla_get_s32(info->attrs[TCMU_ATTR_CMD_STATUS]); + + dev = target_find_device(dev_id, !is_removed); + if (!dev) { + printk(KERN_ERR "tcmu nl cmd %u/%u completion could not find device with dev id %u.\n", + completed_cmd, rc, dev_id); + return -ENODEV; + } + udev = TCMU_DEV(dev); + + spin_lock(&udev->nl_cmd_lock); + nl_cmd = &udev->curr_nl_cmd; + + pr_debug("genl cmd done got id %d curr %d done %d rc %d\n", dev_id, + nl_cmd->cmd, completed_cmd, rc); + + if (nl_cmd->cmd != completed_cmd) { + printk(KERN_ERR "Mismatched commands (Expecting reply for %d. Current %d).\n", + completed_cmd, nl_cmd->cmd); + ret = -EINVAL; + } else { + nl_cmd->status = rc; + } + + spin_unlock(&udev->nl_cmd_lock); + if (!is_removed) + target_undepend_item(&dev->dev_group.cg_item); + if (!ret) + complete(&nl_cmd->complete); + return ret; +} + +static int tcmu_genl_rm_dev_done(struct sk_buff *skb, struct genl_info *info) +{ + return tcmu_genl_cmd_done(info, TCMU_CMD_REMOVED_DEVICE); +} + +static int tcmu_genl_add_dev_done(struct sk_buff *skb, struct genl_info *info) +{ + return tcmu_genl_cmd_done(info, TCMU_CMD_ADDED_DEVICE); +} + +static int tcmu_genl_reconfig_dev_done(struct sk_buff *skb, + struct genl_info *info) +{ + return tcmu_genl_cmd_done(info, TCMU_CMD_RECONFIG_DEVICE); +} + +static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info) +{ + if (info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]) { + tcmu_kern_cmd_reply_supported = + nla_get_u8(info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]); + printk(KERN_INFO "tcmu daemon: command reply support %u.\n", + tcmu_kern_cmd_reply_supported); + } + + return 0; +} + +static const struct genl_ops tcmu_genl_ops[] = { + { + .cmd = TCMU_CMD_SET_FEATURES, + .flags = GENL_ADMIN_PERM, + .policy = tcmu_attr_policy, + .doit = tcmu_genl_set_features, + }, + { + .cmd = TCMU_CMD_ADDED_DEVICE_DONE, + .flags = GENL_ADMIN_PERM, + .policy = tcmu_attr_policy, + .doit = tcmu_genl_add_dev_done, + }, + { + .cmd = TCMU_CMD_REMOVED_DEVICE_DONE, + .flags = GENL_ADMIN_PERM, + .policy = tcmu_attr_policy, + .doit = tcmu_genl_rm_dev_done, + }, + { + .cmd = TCMU_CMD_RECONFIG_DEVICE_DONE, + .flags = GENL_ADMIN_PERM, + .policy = tcmu_attr_policy, + .doit = tcmu_genl_reconfig_dev_done, + }, +}; + /* Our generic netlink family */ static struct genl_family tcmu_genl_family __ro_after_init = { .module = THIS_MODULE, .hdrsize = 0, .name = "TCM-USER", - .version = 1, + .version = 2, .maxattr = TCMU_ATTR_MAX, .mcgrps = tcmu_mcgrps, .n_mcgrps = ARRAY_SIZE(tcmu_mcgrps), .netnsok = true, + .ops = tcmu_genl_ops, + .n_ops = ARRAY_SIZE(tcmu_genl_ops), }; #define tcmu_cmd_set_dbi_cur(cmd, index) ((cmd)->dbi_cur = (index)) @@ -989,6 +1115,9 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) setup_timer(&udev->timeout, tcmu_device_timedout, (unsigned long)udev); + init_waitqueue_head(&udev->nl_cmd_wq); + spin_lock_init(&udev->nl_cmd_lock); + return &udev->se_dev; } @@ -1176,9 +1305,54 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) return 0; } -static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, - int minor, int reconfig_attr, - const void *reconfig_data) +static void tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd) +{ + struct tcmu_nl_cmd *nl_cmd = &udev->curr_nl_cmd; + + if (!tcmu_kern_cmd_reply_supported) + return; +relock: + spin_lock(&udev->nl_cmd_lock); + + if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { + spin_unlock(&udev->nl_cmd_lock); + pr_debug("sleeping for open nl cmd\n"); + wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC)); + goto relock; + } + + memset(nl_cmd, 0, sizeof(*nl_cmd)); + nl_cmd->cmd = cmd; + init_completion(&nl_cmd->complete); + + spin_unlock(&udev->nl_cmd_lock); +} + +static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) +{ + struct tcmu_nl_cmd *nl_cmd = &udev->curr_nl_cmd; + int ret; + DEFINE_WAIT(__wait); + + if (!tcmu_kern_cmd_reply_supported) + return 0; + + pr_debug("sleeping for nl reply\n"); + wait_for_completion(&nl_cmd->complete); + + spin_lock(&udev->nl_cmd_lock); + nl_cmd->cmd = TCMU_CMD_UNSPEC; + ret = nl_cmd->status; + nl_cmd->status = 0; + spin_unlock(&udev->nl_cmd_lock); + + wake_up_all(&udev->nl_cmd_wq); + + return ret;; +} + +static int tcmu_netlink_event(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd, + int reconfig_attr, const void *reconfig_data) { struct sk_buff *skb; void *msg_header; @@ -1192,11 +1366,15 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, if (!msg_header) goto free_skb; - ret = nla_put_string(skb, TCMU_ATTR_DEVICE, name); + ret = nla_put_string(skb, TCMU_ATTR_DEVICE, udev->uio_info.name); if (ret < 0) goto free_skb; - ret = nla_put_u32(skb, TCMU_ATTR_MINOR, minor); + ret = nla_put_u32(skb, TCMU_ATTR_MINOR, udev->uio_info.uio_dev->minor); + if (ret < 0) + goto free_skb; + + ret = nla_put_u32(skb, TCMU_ATTR_DEVICE_ID, udev->se_dev.dev_index); if (ret < 0) goto free_skb; @@ -1224,12 +1402,15 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, genlmsg_end(skb, msg_header); + tcmu_init_genl_cmd_reply(udev, cmd); + ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, TCMU_MCGRP_CONFIG, GFP_KERNEL); - /* We don't care if no one is listening */ if (ret == -ESRCH) ret = 0; + if (!ret) + ret = tcmu_wait_genl_cmd_reply(udev); return ret; free_skb: @@ -1324,8 +1505,7 @@ static int tcmu_configure_device(struct se_device *dev) */ kref_get(&udev->kref); - ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor, 0, NULL); + ret = tcmu_netlink_event(udev, TCMU_CMD_ADDED_DEVICE, 0, NULL); if (ret) goto err_netlink; @@ -1414,8 +1594,7 @@ static void tcmu_destroy_device(struct se_device *dev) tcmu_blocks_release(udev); if (tcmu_dev_configured(udev)) { - tcmu_netlink_event(TCMU_CMD_REMOVED_DEVICE, udev->uio_info.name, - udev->uio_info.uio_dev->minor, 0, NULL); + tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL); uio_unregister_device(&udev->uio_info); } @@ -1600,9 +1779,7 @@ static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, - udev->uio_info.name, - udev->uio_info.uio_dev->minor, + ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, TCMU_ATTR_DEV_CFG, page); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -1639,9 +1816,7 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, - udev->uio_info.name, - udev->uio_info.uio_dev->minor, + ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, TCMU_ATTR_DEV_SIZE, &val); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -1677,9 +1852,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(TCMU_CMD_RECONFIG_DEVICE, - udev->uio_info.name, - udev->uio_info.uio_dev->minor, + ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, TCMU_ATTR_WRITECACHE, &val); if (ret) { pr_err("Unable to reconfigure device\n"); diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index 4bfc9a1b635c..24a1c4ec2248 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -131,6 +131,10 @@ enum tcmu_genl_cmd { TCMU_CMD_ADDED_DEVICE, TCMU_CMD_REMOVED_DEVICE, TCMU_CMD_RECONFIG_DEVICE, + TCMU_CMD_ADDED_DEVICE_DONE, + TCMU_CMD_REMOVED_DEVICE_DONE, + TCMU_CMD_RECONFIG_DEVICE_DONE, + TCMU_CMD_SET_FEATURES, __TCMU_CMD_MAX, }; #define TCMU_CMD_MAX (__TCMU_CMD_MAX - 1) @@ -143,6 +147,9 @@ enum tcmu_genl_attr { TCMU_ATTR_DEV_CFG, TCMU_ATTR_DEV_SIZE, TCMU_ATTR_WRITECACHE, + TCMU_ATTR_CMD_STATUS, + TCMU_ATTR_DEVICE_ID, + TCMU_ATTR_SUPP_KERN_CMD_REPLY, __TCMU_ATTR_MAX, }; #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1) -- cgit v1.2.3 From b1943fd454d1a2e2c8018a2f79a7023893619439 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:16 -0500 Subject: target: add helper to iterate over devices This adds a wrapper around idr_for_each so the xcopy code can loop over the devices in the next patch. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 45 +++++++++++++++++++++++++++++++++++ drivers/target/target_core_internal.h | 2 ++ 2 files changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index de1131612ddc..bd32a0c65961 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -904,6 +904,51 @@ struct se_device *target_find_device(int id, bool do_depend) } EXPORT_SYMBOL(target_find_device); +struct devices_idr_iter { + int (*fn)(struct se_device *dev, void *data); + void *data; +}; + +static int target_devices_idr_iter(int id, void *p, void *data) +{ + struct devices_idr_iter *iter = data; + struct se_device *dev = p; + + /* + * We add the device early to the idr, so it can be used + * by backend modules during configuration. We do not want + * to allow other callers to access partially setup devices, + * so we skip them here. + */ + if (!(dev->dev_flags & DF_CONFIGURED)) + return 0; + + return iter->fn(dev, iter->data); +} + +/** + * target_for_each_device - iterate over configured devices + * @fn: iterator function + * @data: pointer to data that will be passed to fn + * + * fn must return 0 to continue looping over devices. non-zero will break + * from the loop and return that value to the caller. + */ +int target_for_each_device(int (*fn)(struct se_device *dev, void *data), + void *data) +{ + struct devices_idr_iter iter; + int ret; + + iter.fn = fn; + iter.data = data; + + mutex_lock(&g_device_mutex); + ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter); + mutex_unlock(&g_device_mutex); + return ret; +} + int target_configure_device(struct se_device *dev) { struct se_hba *hba = dev->se_hba; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 0912de7c0cf8..1d3ac0238568 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -87,6 +87,8 @@ void core_dev_release_virtual_lun0(void); struct se_device *target_alloc_device(struct se_hba *hba, const char *name); int target_configure_device(struct se_device *dev); void target_free_device(struct se_device *); +int target_for_each_device(int (*fn)(struct se_device *dev, void *data), + void *data); /* target_core_configfs.c */ void target_setup_backend_cits(struct target_backend *); -- cgit v1.2.3 From 6906d008b4b06e42cad393ac25bec76fbf31fabd Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:17 -0500 Subject: xcopy: loop over devices using idr helper This converts the xcopy code to use the idr helper. The next patch will drop the g_device_list and make g_device_mutex local to the target_core_device.c file. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 70 ++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 56738a41e346..9ee89e00cd77 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -55,48 +55,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) return 0; } -static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, - struct se_device **found_dev) +struct xcopy_dev_search_info { + const unsigned char *dev_wwn; + struct se_device *found_dev; +}; + +static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev, + void *data) { - struct se_device *se_dev; + struct xcopy_dev_search_info *info = data; unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; int rc; - mutex_lock(&g_device_mutex); - list_for_each_entry(se_dev, &g_device_list, g_dev_node) { + if (!se_dev->dev_attrib.emulate_3pc) + return 0; - if (!se_dev->dev_attrib.emulate_3pc) - continue; + memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); + target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); - memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); - target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); + rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); + if (rc != 0) + return 0; - rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); - if (rc != 0) - continue; + info->found_dev = se_dev; + pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); - *found_dev = se_dev; - pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); + rc = target_depend_item(&se_dev->dev_group.cg_item); + if (rc != 0) { + pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n", + rc, se_dev); + return rc; + } - rc = target_depend_item(&se_dev->dev_group.cg_item); - if (rc != 0) { - pr_err("configfs_depend_item attempt failed:" - " %d for se_dev: %p\n", rc, se_dev); - mutex_unlock(&g_device_mutex); - return rc; - } + pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n", + se_dev, &se_dev->dev_group); + return 1; +} + +static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, + struct se_device **found_dev) +{ + struct xcopy_dev_search_info info; + int ret; - pr_debug("Called configfs_depend_item for se_dev: %p" - " se_dev->se_dev_group: %p\n", se_dev, - &se_dev->dev_group); + memset(&info, 0, sizeof(info)); + info.dev_wwn = dev_wwn; - mutex_unlock(&g_device_mutex); + ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info); + if (ret == 1) { + *found_dev = info.found_dev; return 0; + } else { + pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); + return -EINVAL; } - mutex_unlock(&g_device_mutex); - - pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); - return -EINVAL; } static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, -- cgit v1.2.3 From be50f538e9a5081c61a78faf58c5591c94064633 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:18 -0500 Subject: target: remove g_device_list g_device_list is no longer needed because we now use the idr code for lookups and seaches. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 30 ++++++++++++------------------ drivers/target/target_core_internal.h | 3 --- include/target/target_core_base.h | 1 - 3 files changed, 12 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index bd32a0c65961..3ae8fbf01bdf 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -49,8 +49,8 @@ #include "target_core_pr.h" #include "target_core_ua.h" -DEFINE_MUTEX(g_device_mutex); -LIST_HEAD(g_device_list); +DEFINE_MUTEX(device_mutex); +LIST_HEAD(device_list); static DEFINE_IDR(devices_idr); static struct se_hba *lun0_hba; @@ -773,7 +773,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) INIT_LIST_HEAD(&dev->delayed_cmd_list); INIT_LIST_HEAD(&dev->state_list); INIT_LIST_HEAD(&dev->qf_cmd_list); - INIT_LIST_HEAD(&dev->g_dev_node); spin_lock_init(&dev->execute_task_lock); spin_lock_init(&dev->delayed_cmd_lock); spin_lock_init(&dev->dev_reservation_lock); @@ -895,11 +894,11 @@ struct se_device *target_find_device(int id, bool do_depend) { struct se_device *dev; - mutex_lock(&g_device_mutex); + mutex_lock(&device_mutex); dev = idr_find(&devices_idr, id); if (dev && do_depend && target_depend_item(&dev->dev_group.cg_item)) dev = NULL; - mutex_unlock(&g_device_mutex); + mutex_unlock(&device_mutex); return dev; } EXPORT_SYMBOL(target_find_device); @@ -943,9 +942,9 @@ int target_for_each_device(int (*fn)(struct se_device *dev, void *data), iter.fn = fn; iter.data = data; - mutex_lock(&g_device_mutex); + mutex_lock(&device_mutex); ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter); - mutex_unlock(&g_device_mutex); + mutex_unlock(&device_mutex); return ret; } @@ -964,13 +963,13 @@ int target_configure_device(struct se_device *dev) * Add early so modules like tcmu can use during its * configuration. */ - mutex_lock(&g_device_mutex); + mutex_lock(&device_mutex); /* * Use cyclic to try and avoid collisions with devices * that were recently removed. */ id = idr_alloc_cyclic(&devices_idr, dev, 0, INT_MAX, GFP_KERNEL); - mutex_unlock(&g_device_mutex); + mutex_unlock(&device_mutex); if (id < 0) { ret = -ENOMEM; goto out; @@ -1036,10 +1035,6 @@ int target_configure_device(struct se_device *dev) hba->dev_count++; spin_unlock(&hba->device_lock); - mutex_lock(&g_device_mutex); - list_add_tail(&dev->g_dev_node, &g_device_list); - mutex_unlock(&g_device_mutex); - dev->dev_flags |= DF_CONFIGURED; return 0; @@ -1047,9 +1042,9 @@ int target_configure_device(struct se_device *dev) out_free_alua: core_alua_free_lu_gp_mem(dev); out_free_index: - mutex_lock(&g_device_mutex); + mutex_lock(&device_mutex); idr_remove(&devices_idr, dev->dev_index); - mutex_unlock(&g_device_mutex); + mutex_unlock(&device_mutex); out: se_release_vpd_for_dev(dev); return ret; @@ -1066,10 +1061,9 @@ void target_free_device(struct se_device *dev) dev->transport->destroy_device(dev); - mutex_lock(&g_device_mutex); + mutex_lock(&device_mutex); idr_remove(&devices_idr, dev->dev_index); - list_del(&dev->g_dev_node); - mutex_unlock(&g_device_mutex); + mutex_unlock(&device_mutex); spin_lock(&hba->device_lock); hba->dev_count--; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 1d3ac0238568..f30e8ac13386 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -56,9 +56,6 @@ struct target_fabric_configfs { extern struct t10_alua_lu_gp *default_lu_gp; /* target_core_device.c */ -extern struct mutex g_device_mutex; -extern struct list_head g_device_list; - int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev); struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 51a92f17352c..516764febeb7 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -796,7 +796,6 @@ struct se_device { struct list_head delayed_cmd_list; struct list_head state_list; struct list_head qf_cmd_list; - struct list_head g_dev_node; /* Pointer to associated SE HBA */ struct se_hba *se_hba; /* T10 Inquiry and VPD WWN Information */ -- cgit v1.2.3 From 531283ff7593f7059ced43c725d90cec3e5af549 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:19 -0500 Subject: tcmu: drop configured check in destroy destroy_device is only called if we have successfully run configure_device, so drop the duplicate tcmu_dev_configured check. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index e080cd1a8fde..d10aa0ac0918 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1593,11 +1593,9 @@ static void tcmu_destroy_device(struct se_device *dev) tcmu_blocks_release(udev); - if (tcmu_dev_configured(udev)) { - tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL); + tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL); - uio_unregister_device(&udev->uio_info); - } + uio_unregister_device(&udev->uio_info); } enum { -- cgit v1.2.3 From 9260695d65590f4711d1166eadbfcb0acfa0625a Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 23 Jun 2017 01:18:20 -0500 Subject: tcmu: fix multiple uio open/close sequences If the uio device is open and closed multiple times, the kref count will be off due to tcmu_release getting called multiple times for each close. This patch integrates Wenji Tang's patch to add a kref_get on open that now matches the kref_put done on tcmu_release and adds a kref_put in tcmu_destroy_device to match the kref_get done in succesful tcmu_configure_device calls. Signed-off-by: Mike Christie Cc: Wenji Tang Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index d10aa0ac0918..1e69b1b32558 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1269,6 +1269,7 @@ static int tcmu_open(struct uio_info *info, struct inode *inode) return -EBUSY; udev->inode = inode; + kref_get(&udev->kref); pr_debug("open\n"); @@ -1300,7 +1301,7 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags); pr_debug("close\n"); - /* release ref from configure */ + /* release ref from open */ kref_put(&udev->kref, tcmu_dev_kref_release); return 0; } @@ -1596,6 +1597,9 @@ static void tcmu_destroy_device(struct se_device *dev) tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL); uio_unregister_device(&udev->uio_info); + + /* release ref from configure */ + kref_put(&udev->kref, tcmu_dev_kref_release); } enum { -- cgit v1.2.3 From 9d62bc0e6d79b11e3298e831358155930fb8f5e3 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 30 Jun 2017 16:14:16 +0800 Subject: tcmu: Fix flushing cmd entry dcache page When feeding the tcmu's cmd ring, we need to flush the dcache page for the cmd entry to make sure these kernel stores are visible to user space mappings of that page. For the none PAD cmd entry, this will be flushed at the end of the tcmu_queue_cmd_ring(). Signed-off-by: Xiubo Li Reviewed-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1e69b1b32558..a8ff6b5fdec8 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -825,21 +825,21 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) size_t pad_size = head_to_end(cmd_head, udev->cmdr_size); entry = (void *) mb + CMDR_OFF + cmd_head; - tcmu_flush_dcache_range(entry, sizeof(*entry)); tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD); tcmu_hdr_set_len(&entry->hdr.len_op, pad_size); entry->hdr.cmd_id = 0; /* not used for PAD */ entry->hdr.kflags = 0; entry->hdr.uflags = 0; + tcmu_flush_dcache_range(entry, sizeof(*entry)); UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size); + tcmu_flush_dcache_range(mb, sizeof(*mb)); cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ WARN_ON(cmd_head != 0); } entry = (void *) mb + CMDR_OFF + cmd_head; - tcmu_flush_dcache_range(entry, sizeof(*entry)); tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD); entry->hdr.cmd_id = tcmu_cmd->cmd_id; entry->hdr.kflags = 0; -- cgit v1.2.3 From c82ff239ecf27dd5eddc91540f50321547a2d311 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 4 Jul 2017 09:44:19 +0100 Subject: target: make device_mutex and device_list static Variables device_mutex and device_list static are local to the source, so make them static. Cleans up sparse warnings: "symbol 'device_list' was not declared. Should it be static?" "symbol 'device_mutex' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 3ae8fbf01bdf..bbcef3bc66c8 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -49,8 +49,8 @@ #include "target_core_pr.h" #include "target_core_ua.h" -DEFINE_MUTEX(device_mutex); -LIST_HEAD(device_list); +static DEFINE_MUTEX(device_mutex); +static LIST_HEAD(device_list); static DEFINE_IDR(devices_idr); static struct se_hba *lun0_hba; -- cgit v1.2.3 From 9fe36984501035f2878aa10d83e79bfc07b7ad7e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:38 -0500 Subject: target: do not require a transport_complete for SCF_TRANSPORT_TASK_SENSE tcmu needs to pass raw sense to target_complete_cmd, but a a transport_complete callout is akward to implement for it. This moves the check for SCF_TRANSPORT_TASK_SENSE so any backend can pass sense. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 28de421e3220..a8f943e325eb 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -719,9 +719,9 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) dev->transport->transport_complete(cmd, cmd->t_data_sg, transport_get_sense_buffer(cmd)); - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) - success = 1; } + if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) + success = 1; /* * Check for case where an explicit ABORT_TASK has been received -- cgit v1.2.3 From c6d66aba98a39cfed206c5c61f0a604ba09b26ce Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:39 -0500 Subject: target: add helper to copy sense to se_cmd buffer This adds a helper to copy sense from backend module buffer to the se_cmd's sense buffer. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 18 ++++++++++++++++++ include/target/target_core_backend.h | 2 ++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a8f943e325eb..341025a3cbb7 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -704,6 +704,24 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) return cmd->sense_buffer; } +void transport_copy_sense_to_cmd(struct se_cmd *cmd, unsigned char *sense) +{ + unsigned char *cmd_sense_buf; + unsigned long flags; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + cmd_sense_buf = transport_get_sense_buffer(cmd); + if (!cmd_sense_buf) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return; + } + + cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; + memcpy(cmd_sense_buf, sense, cmd->scsi_sense_length); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); +} +EXPORT_SYMBOL(transport_copy_sense_to_cmd); + void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) { struct se_device *dev = cmd->se_dev; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 1f2b7007f2df..3757f5f54e03 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -73,6 +73,8 @@ void target_backend_unregister(const struct target_backend_ops *); void target_complete_cmd(struct se_cmd *, u8); void target_complete_cmd_with_length(struct se_cmd *, u8, int); +void transport_copy_sense_to_cmd(struct se_cmd *, unsigned char *); + sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd); sense_reason_t spc_emulate_inquiry_std(struct se_cmd *, unsigned char *); -- cgit v1.2.3 From 406f74c20dc258f8258b64d16d159c3fff06a506 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:40 -0500 Subject: tcmu: fix sense handling during completion We were just copying the sense to the cmd sense_buffer and did not implement a transport_complete or set the SCF_TRANSPORT_TASK_SENSE, so the sense was ignored. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index a8ff6b5fdec8..cbbfba0c1352 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -956,8 +956,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * cmd->se_cmd); entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { - memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, - se_cmd->scsi_sense_length); + transport_copy_sense_to_cmd(se_cmd, entry->rsp.sense_buffer); } else if (se_cmd->se_cmd_flags & SCF_BIDI) { /* Get Data-In buffer before clean up */ gather_data_area(udev, cmd, true); -- cgit v1.2.3 From dce6ce8cfb842c333094c3eb2e3ea66b1edb02ad Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:41 -0500 Subject: pscsi: finish cmd processing from pscsi_req_done This patch performs the pscsi_transport_complete operations from pscsi_req_done. It looks like the only difference the transport_complete callout provides is that it is called under t_state_lock which seems to only be needed for the SCF_TRANSPORT_TASK_SENSE bit handling. We can now use transport_copy_sense_to_cmd to handle the se_cmd sense bits, and we can then drop the code where we have to copy the request info to the pscsi_plugin_task for transport_complete use. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pscsi.c | 38 ++++++++++++++++---------------------- drivers/target/target_core_pscsi.h | 4 ---- 2 files changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 7d944b23aeee..fb40f64072f6 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -599,12 +599,11 @@ static void pscsi_destroy_device(struct se_device *dev) } } -static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, - unsigned char *sense_buffer) +static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status, + unsigned char *req_sense) { struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev); struct scsi_device *sd = pdv->pdv_sd; - int result; struct pscsi_plugin_task *pt = cmd->priv; unsigned char *cdb; /* @@ -615,7 +614,6 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, return; cdb = &pt->pscsi_cdb[0]; - result = pt->pscsi_result; /* * Hack to make sure that Write-Protect modepage is set if R/O mode is * forced. @@ -624,7 +622,7 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, goto after_mode_sense; if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && - (status_byte(result) << 1) == SAM_STAT_GOOD) { + scsi_status == SAM_STAT_GOOD) { bool read_only = target_lun_is_rdonly(cmd); if (read_only) { @@ -659,12 +657,12 @@ after_mode_sense: * storage engine. */ if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) && - (status_byte(result) << 1) == SAM_STAT_GOOD) { + scsi_status == SAM_STAT_GOOD) { unsigned char *buf; u16 bdl; u32 blocksize; - buf = sg_virt(&sg[0]); + buf = sg_virt(&cmd->t_data_sg[0]); if (!buf) { pr_err("Unable to get buf for scatterlist\n"); goto after_mode_select; @@ -687,10 +685,8 @@ after_mode_sense: } after_mode_select: - if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) { - memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER); - cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; - } + if (scsi_status == SAM_STAT_CHECK_CONDITION) + transport_copy_sense_to_cmd(cmd, req_sense); } enum { @@ -1049,30 +1045,29 @@ static void pscsi_req_done(struct request *req, int uptodate) { struct se_cmd *cmd = req->end_io_data; struct pscsi_plugin_task *pt = cmd->priv; + int result = scsi_req(req)->result; + u8 scsi_status = status_byte(result) << 1; - pt->pscsi_result = scsi_req(req)->result; - pt->pscsi_resid = scsi_req(req)->resid_len; - - cmd->scsi_status = status_byte(pt->pscsi_result) << 1; - if (cmd->scsi_status) { + if (scsi_status) { pr_debug("PSCSI Status Byte exception at cmd: %p CDB:" " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0], - pt->pscsi_result); + result); } - switch (host_byte(pt->pscsi_result)) { + pscsi_complete_cmd(cmd, scsi_status, scsi_req(req)->sense); + + switch (host_byte(result)) { case DID_OK: - target_complete_cmd(cmd, cmd->scsi_status); + target_complete_cmd(cmd, scsi_status); break; default: pr_debug("PSCSI Host Byte exception at cmd: %p CDB:" " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0], - pt->pscsi_result); + result); target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); break; } - memcpy(pt->pscsi_sense, scsi_req(req)->sense, TRANSPORT_SENSE_BUFFER); __blk_put_request(req->q, req); kfree(pt); } @@ -1090,7 +1085,6 @@ static const struct target_backend_ops pscsi_ops = { .configure_device = pscsi_configure_device, .destroy_device = pscsi_destroy_device, .free_device = pscsi_free_device, - .transport_complete = pscsi_transport_complete, .parse_cdb = pscsi_parse_cdb, .set_configfs_dev_params = pscsi_set_configfs_dev_params, .show_configfs_dev_params = pscsi_show_configfs_dev_params, diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index 8a02fa47c7e8..b86fb0e1b783 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -23,10 +23,6 @@ struct scsi_device; struct Scsi_Host; struct pscsi_plugin_task { - unsigned char pscsi_sense[TRANSPORT_SENSE_BUFFER]; - int pscsi_direction; - int pscsi_result; - u32 pscsi_resid; unsigned char pscsi_cdb[0]; } ____cacheline_aligned; -- cgit v1.2.3 From 1a444175486026c1a280507f8d82094909acddd2 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:42 -0500 Subject: target: remove transport_complete transport_complete is no longer used, so drop the code. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 ------ include/target/target_core_backend.h | 4 ---- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 341025a3cbb7..b9122a56784e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -732,12 +732,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) spin_lock_irqsave(&cmd->t_state_lock, flags); - - if (dev && dev->transport->transport_complete) { - dev->transport->transport_complete(cmd, - cmd->t_data_sg, - transport_get_sense_buffer(cmd)); - } if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) success = 1; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 3757f5f54e03..e150e391878b 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -37,10 +37,6 @@ struct target_backend_ops { const char *, ssize_t); ssize_t (*show_configfs_dev_params)(struct se_device *, char *); - void (*transport_complete)(struct se_cmd *cmd, - struct scatterlist *, - unsigned char *); - sense_reason_t (*parse_cdb)(struct se_cmd *cmd); u32 (*get_device_type)(struct se_device *); sector_t (*get_blocks)(struct se_device *); -- cgit v1.2.3 From 402242c904432207515e3ccb4126ff0dcfba89ca Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 31 May 2017 15:52:43 -0500 Subject: target: fix SAM_STAT_BUSY/TASK_SET_FULL handling If the scsi status was not SAM_STAT_GOOD or there was no transport sense, we would ignore the scsi status and do a generic not ready LUN communication failure check condition failure. The problem is that LUN COMM failure is treated as a hard error sometimes and will cause apps to get IO errors instead of the OS's SCSI layer retrying. For example, the tcmu daemon will return SAM_STAT_QUEUE_FULL when memory runs low and can still make progress but wants the initiator to reduce the work load. Windows will fail this error directly the app instead of retrying. This patch is based on Nick's "target/iblock: Use -EAGAIN/-ENOMEM to propigate SAM BUSY/TASK_SET_FULL" patch here: http://comments.gmane.org/gmane.linux.scsi.target.devel/11301 but instead of only setting SAM_STAT_GOOD, SAM_STAT_TASK_SET_FULL and SAM_STAT_BUSY as success, it sets all non check condition status as success so they are passed back to the initiator, so passthrough type backends can return all SCSI status codes. Since only passthrough uses this, I was not sure if we wanted to add checks for non-passthrough and specific codes. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b9122a56784e..8735243edf04 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -725,15 +725,23 @@ EXPORT_SYMBOL(transport_copy_sense_to_cmd); void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) { struct se_device *dev = cmd->se_dev; - int success = scsi_status == GOOD; + int success; unsigned long flags; cmd->scsi_status = scsi_status; - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) + switch (cmd->scsi_status) { + case SAM_STAT_CHECK_CONDITION: + if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) + success = 1; + else + success = 0; + break; + default: success = 1; + break; + } /* * Check for case where an explicit ABORT_TASK has been received -- cgit v1.2.3 From e5dc9a7055c98bcd7b03f9735d5f2ec2b7f0d897 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 28 Jun 2017 14:58:56 +0900 Subject: target: Use macro for WRITE_VERIFY_32 operation codes Add WRITE_VERIFY_32 definition to scsi prototypes and use this macro definition isntead of the hard coded value. (Drop WRITE_VERIFY_16 that's already part of another patch - nab) Signed-off-by: Damien Le Moal Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- include/scsi/scsi_proto.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index bbcef3bc66c8..1c7c57a3c52e 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1226,7 +1226,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, switch (get_unaligned_be16(&cdb[8])) { case READ_32: case WRITE_32: - case 0x0c: /* WRITE_VERIFY_32 */ + case WRITE_VERIFY_32: case XDWRITEREAD_32: cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index ce78ec8e367d..5e3fe037938e 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -161,6 +161,7 @@ #define READ_32 0x09 #define VERIFY_32 0x0a #define WRITE_32 0x0b +#define WRITE_VERIFY_32 0x0c #define WRITE_SAME_32 0x0d /* Values for T10/04-262r7 */ -- cgit v1.2.3 From 016a5fec19e191ed1d45f75d8bfbefdec3f2dada Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 28 Jun 2017 14:58:57 +0900 Subject: target: pscsi: Introduce TYPE_ZBC support TYPE_ZBC host managed zoned block devices are also block devices despite the non-standard device type (14h). Handle them similarly to regular TYPE_DISK devices. Signed-off-by: Damien Le Moal Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pscsi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index fb40f64072f6..b71d22ebc9bf 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -382,7 +382,7 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd) spin_unlock_irq(sh->host_lock); /* * Claim exclusive struct block_device access to struct scsi_device - * for TYPE_DISK using supplied udev_path + * for TYPE_DISK and TYPE_ZBC using supplied udev_path */ bd = blkdev_get_by_path(dev->udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv); @@ -400,8 +400,9 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd) return ret; } - pr_debug("CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%llu\n", - phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun); + pr_debug("CORE_PSCSI[%d] - Added TYPE_%s for %d:%d:%d:%llu\n", + phv->phv_host_id, sd->type == TYPE_DISK ? "DISK" : "ZBC", + sh->host_no, sd->channel, sd->id, sd->lun); return 0; } @@ -520,6 +521,7 @@ static int pscsi_configure_device(struct se_device *dev) */ switch (sd->type) { case TYPE_DISK: + case TYPE_ZBC: ret = pscsi_create_type_disk(dev, sd); break; default: @@ -576,9 +578,11 @@ static void pscsi_destroy_device(struct se_device *dev) if (sd) { /* * Release exclusive pSCSI internal struct block_device claim for - * struct scsi_device with TYPE_DISK from pscsi_create_type_disk() + * struct scsi_device with TYPE_DISK or TYPE_ZBC + * from pscsi_create_type_disk() */ - if ((sd->type == TYPE_DISK) && pdv->pdv_bd) { + if ((sd->type == TYPE_DISK || sd->type == TYPE_ZBC) && + pdv->pdv_bd) { blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); pdv->pdv_bd = NULL; @@ -1000,7 +1004,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) req->end_io_data = cmd; scsi_req(req)->cmd_len = scsi_command_size(pt->pscsi_cdb); scsi_req(req)->cmd = &pt->pscsi_cdb[0]; - if (pdv->pdv_sd->type == TYPE_DISK) + if (pdv->pdv_sd->type == TYPE_DISK || + pdv->pdv_sd->type == TYPE_ZBC) req->timeout = PS_TIMEOUT_DISK; else req->timeout = PS_TIMEOUT_OTHER; -- cgit v1.2.3 From de8c5221aa003935d6d31becf5850b247dff14a1 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Fri, 7 Jul 2017 14:20:00 -0500 Subject: tcmu: Fix dev_config_store Currently when there is a reconfig, the uio_info->name does not get updated to reflect the change in the dev_config name change. On restart tcmu-runner there will be a mismatch between the dev_config string in uio and the tcmu structure that contains the string. When this occurs it'll reload the one in uio and you lose the reconfigured device path. v2: Created a helper function for the updating of uio_info Signed-off-by: Bryant G. Ly Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index cbbfba0c1352..2f1fa927682e 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1418,19 +1418,14 @@ free_skb: return ret; } -static int tcmu_configure_device(struct se_device *dev) +static int tcmu_update_uio_info(struct tcmu_dev *udev) { - struct tcmu_dev *udev = TCMU_DEV(dev); struct tcmu_hba *hba = udev->hba->hba_ptr; struct uio_info *info; - struct tcmu_mailbox *mb; - size_t size; - size_t used; - int ret = 0; + size_t size, used; char *str; info = &udev->uio_info; - size = snprintf(NULL, 0, "tcm-user/%u/%s/%s", hba->host_id, udev->name, udev->dev_config); size += 1; /* for \0 */ @@ -1439,12 +1434,27 @@ static int tcmu_configure_device(struct se_device *dev) return -ENOMEM; used = snprintf(str, size, "tcm-user/%u/%s", hba->host_id, udev->name); - if (udev->dev_config[0]) snprintf(str + used, size - used, "/%s", udev->dev_config); info->name = str; + return 0; +} + +static int tcmu_configure_device(struct se_device *dev) +{ + struct tcmu_dev *udev = TCMU_DEV(dev); + struct uio_info *info; + struct tcmu_mailbox *mb; + int ret = 0; + + ret = tcmu_update_uio_info(udev); + if (ret) + return ret; + + info = &udev->uio_info; + udev->mb_addr = vzalloc(CMDR_SIZE); if (!udev->mb_addr) { ret = -ENOMEM; @@ -1786,6 +1796,12 @@ static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, pr_err("Unable to reconfigure device\n"); return ret; } + strlcpy(udev->dev_config, page, TCMU_CONFIG_LEN); + + ret = tcmu_update_uio_info(udev); + if (ret) + return ret; + return count; } strlcpy(udev->dev_config, page, TCMU_CONFIG_LEN); -- cgit v1.2.3 From 388fe6996bf658146e70c0df986981eae4be0385 Mon Sep 17 00:00:00 2001 From: Tang Wenji Date: Sat, 8 Jul 2017 11:15:44 +0800 Subject: target: Fix cmd size for PR-OUT in passthrough_parse_cdb The cmd size should be 4bytes form byte5 to byte8 when CDB opcode is PERSISTENT_RESERVE_OUT in SPC3 and SPC4 (Also fix up the same in spc_parse_cdb - MNC) Signed-off-by: Tang Wenji Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_spc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1c7c57a3c52e..e8dd6da164b2 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1183,7 +1183,7 @@ passthrough_parse_cdb(struct se_cmd *cmd, } if (cdb[0] == PERSISTENT_RESERVE_OUT) { cmd->execute_cmd = target_scsi3_emulate_pr_out; - size = get_unaligned_be16(&cdb[7]); + size = get_unaligned_be32(&cdb[5]); return target_cmd_size_check(cmd, size); } diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index f59ac7671031..cb0461a10808 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1307,7 +1307,7 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = target_scsi3_emulate_pr_in; break; case PERSISTENT_RESERVE_OUT: - *size = get_unaligned_be16(&cdb[7]); + *size = get_unaligned_be32(&cdb[5]); cmd->execute_cmd = target_scsi3_emulate_pr_out; break; case RELEASE: -- cgit v1.2.3 From 7ee0031786dc3762f61d0ec9171bb75d56a5ac76 Mon Sep 17 00:00:00 2001 From: Tang Wenji Date: Sat, 8 Jul 2017 11:28:25 +0800 Subject: target: Fix return sense reason in target_scsi3_emulate_pr_out The sense reason should be TCM_PARAMETER_LIST_LENGTH_ERROR when parmeter length error. Also the cdb[1] & 0x1f has been assigned to local variable sa, so use sa instead of it. Signed-off-by: Tang Wenji Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 9921d4d6bb41..6d5def64db61 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -3585,7 +3585,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - return TCM_INVALID_PARAMETER_LIST; + return TCM_PARAMETER_LIST_LENGTH_ERROR; } /* @@ -3629,7 +3629,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) /* * SPEC_I_PT=1 is only valid for Service action: REGISTER */ - if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) + if (spec_i_pt && (sa != PRO_REGISTER)) return TCM_INVALID_PARAMETER_LIST; /* @@ -3641,11 +3641,11 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) * the sense key set to ILLEGAL REQUEST, and the additional sense * code set to PARAMETER LIST LENGTH ERROR. */ - if (!spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && + if (!spec_i_pt && (sa != PRO_REGISTER_AND_MOVE) && (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - return TCM_INVALID_PARAMETER_LIST; + return TCM_PARAMETER_LIST_LENGTH_ERROR; } /* @@ -3685,7 +3685,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd) break; default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" - " action: 0x%02x\n", cdb[1] & 0x1f); + " action: 0x%02x\n", sa); return TCM_INVALID_CDB_FIELD; } -- cgit v1.2.3 From c17d5d5f51f72f24e0e17a4450ae5010bf6962d9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 10 Jul 2017 14:53:31 -0500 Subject: target: export lio pgr/alua support as device attr Older kernels could crash or hang if the user write/read some ALUA files with pscsi and tcmu backends. This patch exports if LIO supports executing PGR and ALUA scsi commands/checks for the se_device, so userspace can easily test. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 9b8abd55c21c..7e87d952bb7a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1085,6 +1085,24 @@ static ssize_t block_size_store(struct config_item *item, return count; } +static ssize_t alua_support_show(struct config_item *item, char *page) +{ + struct se_dev_attrib *da = to_attrib(item); + u8 flags = da->da_dev->transport->transport_flags; + + return snprintf(page, PAGE_SIZE, "%d\n", + flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ? 0 : 1); +} + +static ssize_t pgr_support_show(struct config_item *item, char *page) +{ + struct se_dev_attrib *da = to_attrib(item); + u8 flags = da->da_dev->transport->transport_flags; + + return snprintf(page, PAGE_SIZE, "%d\n", + flags & TRANSPORT_FLAG_PASSTHROUGH_PGR ? 0 : 1); +} + CONFIGFS_ATTR(, emulate_model_alias); CONFIGFS_ATTR(, emulate_dpo); CONFIGFS_ATTR(, emulate_fua_write); @@ -1116,6 +1134,8 @@ CONFIGFS_ATTR(, unmap_granularity); CONFIGFS_ATTR(, unmap_granularity_alignment); CONFIGFS_ATTR(, unmap_zeroes_data); CONFIGFS_ATTR(, max_write_same_len); +CONFIGFS_ATTR_RO(, alua_support); +CONFIGFS_ATTR_RO(, pgr_support); /* * dev_attrib attributes for devices using the target core SBC/SPC @@ -1154,6 +1174,8 @@ struct configfs_attribute *sbc_attrib_attrs[] = { &attr_unmap_granularity_alignment, &attr_unmap_zeroes_data, &attr_max_write_same_len, + &attr_alua_support, + &attr_pgr_support, NULL, }; EXPORT_SYMBOL(sbc_attrib_attrs); @@ -1168,6 +1190,8 @@ struct configfs_attribute *passthrough_attrib_attrs[] = { &attr_hw_block_size, &attr_hw_max_sectors, &attr_hw_queue_depth, + &attr_alua_support, + &attr_pgr_support, NULL, }; EXPORT_SYMBOL(passthrough_attrib_attrs); -- cgit v1.2.3 From b3743c71b7c33a126d6d8942bb268775987400ec Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 11 Jul 2017 17:59:43 +0800 Subject: tcmu: Fix possbile memory leak / OOPs when recalculating cmd base size For all the entries allocated from the ring cmd area, the memory is something like the stack memory, which will always reserve the old data, so the entry->req.iov_bidi_cnt maybe none zero. On some environments, the crash could be reproduce very easy and some not. The following is the crash core trace as reported by Damien: [ 240.143969] CPU: 0 PID: 1285 Comm: iscsi_trx Not tainted 4.12.0-rc1+ #3 [ 240.150607] Hardware name: ASUS All Series/H87-PRO, BIOS 2104 10/28/2014 [ 240.157331] task: ffff8807de4f5800 task.stack: ffffc900047dc000 [ 240.163270] RIP: 0010:memcpy_erms+0x6/0x10 [ 240.167377] RSP: 0018:ffffc900047dfc68 EFLAGS: 00010202 [ 240.172621] RAX: ffffc9065db85540 RBX: ffff8807f7980000 RCX: 0000000000000010 [ 240.179771] RDX: 0000000000000010 RSI: ffff8807de574fe0 RDI: ffffc9065db85540 [ 240.186930] RBP: ffffc900047dfd30 R08: ffff8807de41b000 R09: 0000000000000000 [ 240.194088] R10: 0000000000000040 R11: ffff8807e9b726f0 R12: 00000006565726b0 [ 240.201246] R13: ffffc90007612ea0 R14: 000000065657d540 R15: 0000000000000000 [ 240.208397] FS: 0000000000000000(0000) GS:ffff88081fa00000(0000) knlGS:0000000000000000 [ 240.216510] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 240.222280] CR2: ffffc9065db85540 CR3: 0000000001c0f000 CR4: 00000000001406f0 [ 240.229430] Call Trace: [ 240.231887] ? tcmu_queue_cmd+0x83c/0xa80 [ 240.235916] ? target_check_reservation+0xcd/0x6f0 [ 240.240725] __target_execute_cmd+0x27/0xa0 [ 240.244918] target_execute_cmd+0x232/0x2c0 [ 240.249124] ? __local_bh_enable_ip+0x64/0xa0 [ 240.253499] iscsit_execute_cmd+0x20d/0x270 [ 240.257693] iscsit_sequence_cmd+0x110/0x190 [ 240.261985] iscsit_get_rx_pdu+0x360/0xc80 [ 240.267565] ? iscsi_target_rx_thread+0x54/0xd0 [ 240.273571] iscsi_target_rx_thread+0x9a/0xd0 [ 240.279413] kthread+0x113/0x150 [ 240.284120] ? iscsi_target_tx_thread+0x1e0/0x1e0 [ 240.290297] ? kthread_create_on_node+0x40/0x40 [ 240.296297] ret_from_fork+0x2e/0x40 [ 240.301332] Code: 90 90 90 90 90 eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 [ 240.321751] RIP: memcpy_erms+0x6/0x10 RSP: ffffc900047dfc68 [ 240.328838] CR2: ffffc9065db85540 [ 240.333667] ---[ end trace b7e5354cfb54d08b ]--- To fix this, just memset all the entry memory before using it, and also to be more readable we adjust the bidi code. Fixed: fe25cc34795(tcmu: Recalculate the tcmu_cmd size to save cmd area memories) Reported-by: Bryant G. Ly Tested-by: Bryant G. Ly Reported-by: Damien Le Moal Tested-by: Damien Le Moal Reviewed-by: Mike Christie Signed-off-by: Xiubo Li Cc: # 4.12+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 2f1fa927682e..3b25ef3d5596 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -563,7 +563,7 @@ static int scatter_data_area(struct tcmu_dev *udev, to_offset = get_block_offset_user(udev, dbi, block_remaining); offset = DATA_BLOCK_SIZE - block_remaining; - to = (void *)(unsigned long)to + offset; + to += offset; if (*iov_cnt != 0 && to_offset == iov_tail(udev, *iov)) { @@ -636,7 +636,7 @@ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, copy_bytes = min_t(size_t, sg_remaining, block_remaining); offset = DATA_BLOCK_SIZE - block_remaining; - from = (void *)(unsigned long)from + offset; + from += offset; tcmu_flush_dcache_range(from, copy_bytes); memcpy(to + sg->length - sg_remaining, from, copy_bytes); @@ -840,10 +840,9 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) } entry = (void *) mb + CMDR_OFF + cmd_head; + memset(entry, 0, command_size); tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD); entry->hdr.cmd_id = tcmu_cmd->cmd_id; - entry->hdr.kflags = 0; - entry->hdr.uflags = 0; /* Handle allocating space from the data area */ tcmu_cmd_reset_dbi_cur(tcmu_cmd); @@ -862,11 +861,10 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } entry->req.iov_cnt = iov_cnt; - entry->req.iov_dif_cnt = 0; /* Handle BIDI commands */ + iov_cnt = 0; if (se_cmd->se_cmd_flags & SCF_BIDI) { - iov_cnt = 0; iov++; ret = scatter_data_area(udev, tcmu_cmd, se_cmd->t_bidi_data_sg, @@ -879,8 +877,8 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) pr_err("tcmu: alloc and scatter bidi data failed\n"); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - entry->req.iov_bidi_cnt = iov_cnt; } + entry->req.iov_bidi_cnt = iov_cnt; /* * Recalaulate the command's base size and size according -- cgit v1.2.3 From daf78c305148c5a52f75a7fd88461ffa7066aec6 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 11 Jul 2017 18:06:41 +0800 Subject: tcmu: clean up the code and with one small fix Remove useless blank line and code and at the same time add one error path to catch the errors. Reviewed-by: Mike Christie Signed-off-by: Xiubo Li Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 3b25ef3d5596..80ee130f8253 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -342,7 +342,6 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev, page = radix_tree_lookup(&udev->data_blocks, dbi); if (!page) { - if (atomic_add_return(1, &global_db_count) > TCMU_GLOBAL_MAX_BLOCKS) { atomic_dec(&global_db_count); @@ -352,14 +351,11 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev, /* try to get new page from the mm */ page = alloc_page(GFP_KERNEL); if (!page) - return false; + goto err_alloc; ret = radix_tree_insert(&udev->data_blocks, dbi, page); - if (ret) { - __free_page(page); - return false; - } - + if (ret) + goto err_insert; } if (dbi > udev->dbi_max) @@ -369,6 +365,11 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev, tcmu_cmd_set_dbi(tcmu_cmd, dbi); return true; +err_insert: + __free_page(page); +err_alloc: + atomic_dec(&global_db_count); + return false; } static bool tcmu_get_empty_blocks(struct tcmu_dev *udev, @@ -527,7 +528,7 @@ static inline size_t get_block_offset_user(struct tcmu_dev *dev, DATA_BLOCK_SIZE - remaining; } -static inline size_t iov_tail(struct tcmu_dev *udev, struct iovec *iov) +static inline size_t iov_tail(struct iovec *iov) { return (size_t)iov->iov_base + iov->iov_len; } @@ -566,7 +567,7 @@ static int scatter_data_area(struct tcmu_dev *udev, to += offset; if (*iov_cnt != 0 && - to_offset == iov_tail(udev, *iov)) { + to_offset == iov_tail(*iov)) { (*iov)->iov_len += copy_bytes; } else { new_iov(iov, iov_cnt, udev); @@ -722,10 +723,7 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, struct tcmu_cmd *cmd, } } - if (!tcmu_get_empty_blocks(udev, cmd)) - return false; - - return true; + return tcmu_get_empty_blocks(udev, cmd); } static inline size_t tcmu_cmd_get_base_cmd_size(size_t iov_cnt) -- cgit v1.2.3 From 55dd8cf2163e1866d9497c4f361d6ed42b3a192b Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 11 Jul 2017 10:50:00 -0700 Subject: Revert "qla2xxx: Fix incorrect tcm_qla2xxx_free_cmd use during TMR ABORT" This reverts commit 5f572526a18418258bfa137e3353656c25439500. As reported by Pascal here: http://www.spinics.net/lists/target-devel/msg15808.html there still appears to be another issue related to this change to drop the original bogus tcm_qla2xxx_free_cmd() usage from tcm_qla2xxx_handle_data_work() and tcm_qla2xxx_aborted_task(). So revert this for now, until Pascal can verify with further debug in place to understand what's going on. Reported-by: Pascal de Bruijn Cc: Pascal de Bruijn Cc: Himanshu Madhani Cc: Quinn Tran Cc: # 3.10+ Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/qla_target.c | 4 ---- drivers/scsi/qla2xxx/qla_target.h | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 8f8ece900801..401e245477d4 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4079,8 +4079,6 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; memset(cmd, 0, sizeof(struct qla_tgt_cmd)); - init_completion(&cmd->write_pending_abort_comp); - memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -5085,8 +5083,6 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); - init_completion(&cmd->write_pending_abort_comp); - memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->tgt = vha->vha_tgt.qla_tgt; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 939e93c5d3ae..d64420251194 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -868,7 +868,6 @@ struct qla_tgt_cmd { unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; spinlock_t cmd_lock; - struct completion write_pending_abort_comp; /* to save extra sess dereferences */ unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 8c1bf9b14bb2..75aeb9fdfd06 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -415,7 +415,6 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) { - struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); unsigned long flags; /* * Check for WRITE_PENDING status to determine if we need to wait for @@ -425,7 +424,8 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) if (se_cmd->t_state == TRANSPORT_WRITE_PENDING || se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - wait_for_completion(&cmd->write_pending_abort_comp); + wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, + 50); return 0; } spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); @@ -501,6 +501,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); + unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. @@ -508,6 +509,17 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) */ cmd->cmd_in_wq = 0; + spin_lock_irqsave(&cmd->cmd_lock, flags); + cmd->data_work = 1; + if (cmd->aborted) { + cmd->data_work_free = 1; + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + + tcm_qla2xxx_free_cmd(cmd); + return; + } + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + cmd->vha->tgt_counters.qla_core_ret_ctio++; if (!cmd->write_data_transferred) { /* @@ -515,7 +527,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work) * waiting upon completion in tcm_qla2xxx_write_pending_status() */ if (cmd->se_cmd.transport_state & CMD_T_ABORTED) { - complete(&cmd->write_pending_abort_comp); + complete(&cmd->se_cmd.t_transport_stop_comp); return; } @@ -741,13 +753,31 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) qlt_xmit_tm_rsp(mcmd); } +#define DATA_WORK_NOT_FREE(_cmd) (_cmd->data_work && !_cmd->data_work_free) static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); + unsigned long flags; if (qlt_abort_cmd(cmd)) return; + + spin_lock_irqsave(&cmd->cmd_lock, flags); + if ((cmd->state == QLA_TGT_STATE_NEW)|| + ((cmd->state == QLA_TGT_STATE_DATA_IN) && + DATA_WORK_NOT_FREE(cmd))) { + cmd->data_work_free = 1; + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + /* + * cmd has not reached fw, Use this trigger to free it. + */ + tcm_qla2xxx_free_cmd(cmd); + return; + } + spin_unlock_irqrestore(&cmd->cmd_lock, flags); + return; + } static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, -- cgit v1.2.3 From 138d351eefb727ab9e41a3dc5f112ceb4f6e59f2 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 7 Jul 2017 14:45:49 -0700 Subject: iscsi-target: Add login_keys_workaround attribute for non RFC initiators This patch re-introduces part of a long standing login workaround that was recently dropped by: commit 1c99de981f30b3e7868b8d20ce5479fa1c0fea46 Author: Nicholas Bellinger Date: Sun Apr 2 13:36:44 2017 -0700 iscsi-target: Drop work-around for legacy GlobalSAN initiator Namely, the workaround for FirstBurstLength ended up being required by Mellanox Flexboot PXE boot ROMs as reported by Robert. So this patch re-adds the work-around for FirstBurstLength within iscsi_check_proposer_for_optional_reply(), and makes the key optional to respond when the initiator does not propose, nor respond to it. Also as requested by Arun, this patch introduces a new TPG attribute named 'login_keys_workaround' that controls the use of both the FirstBurstLength workaround, as well as the two other existing workarounds for gPXE iSCSI boot client. By default, the workaround is enabled with login_keys_workaround=1, since Mellanox FlexBoot requires it, and Arun has verified the Qlogic MSFT initiator already proposes FirstBurstLength, so it's uneffected by this re-adding this part of the original work-around. Reported-by: Robert LeBlanc Cc: Robert LeBlanc Reviewed-by: Arun Easi Cc: # 3.1+ Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_configfs.c | 2 ++ drivers/target/iscsi/iscsi_target_nego.c | 6 ++-- drivers/target/iscsi/iscsi_target_parameters.c | 41 ++++++++++++++++++-------- drivers/target/iscsi/iscsi_target_parameters.h | 2 +- drivers/target/iscsi/iscsi_target_tpg.c | 19 ++++++++++++ drivers/target/iscsi/iscsi_target_tpg.h | 1 + include/target/iscsi/iscsi_target_core.h | 9 ++++++ 7 files changed, 64 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 535a8e06a401..0dd4c45f7575 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -781,6 +781,7 @@ DEF_TPG_ATTRIB(default_erl); DEF_TPG_ATTRIB(t10_pi); DEF_TPG_ATTRIB(fabric_prot_type); DEF_TPG_ATTRIB(tpg_enabled_sendtargets); +DEF_TPG_ATTRIB(login_keys_workaround); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_attr_authentication, @@ -796,6 +797,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_attr_t10_pi, &iscsi_tpg_attrib_attr_fabric_prot_type, &iscsi_tpg_attrib_attr_tpg_enabled_sendtargets, + &iscsi_tpg_attrib_attr_login_keys_workaround, NULL, }; diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 96df63f1f795..7a6751fecd32 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -864,7 +864,8 @@ static int iscsi_target_handle_csg_zero( SENDER_TARGET, login->rsp_buf, &login->rsp_length, - conn->param_list); + conn->param_list, + conn->tpg->tpg_attrib.login_keys_workaround); if (ret < 0) return -1; @@ -934,7 +935,8 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log SENDER_TARGET, login->rsp_buf, &login->rsp_length, - conn->param_list); + conn->param_list, + conn->tpg->tpg_attrib.login_keys_workaround); if (ret < 0) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, ISCSI_LOGIN_STATUS_INIT_ERR); diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index fce627628200..caab1045742d 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -765,7 +765,8 @@ static int iscsi_check_for_auth_key(char *key) return 0; } -static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param) +static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param, + bool keys_workaround) { if (IS_TYPE_BOOL_AND(param)) { if (!strcmp(param->value, NO)) @@ -773,19 +774,31 @@ static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param) } else if (IS_TYPE_BOOL_OR(param)) { if (!strcmp(param->value, YES)) SET_PSTATE_REPLY_OPTIONAL(param); - /* - * Required for gPXE iSCSI boot client - */ - if (!strcmp(param->name, IMMEDIATEDATA)) - SET_PSTATE_REPLY_OPTIONAL(param); + + if (keys_workaround) { + /* + * Required for gPXE iSCSI boot client + */ + if (!strcmp(param->name, IMMEDIATEDATA)) + SET_PSTATE_REPLY_OPTIONAL(param); + } } else if (IS_TYPE_NUMBER(param)) { if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) SET_PSTATE_REPLY_OPTIONAL(param); - /* - * Required for gPXE iSCSI boot client - */ - if (!strcmp(param->name, MAXCONNECTIONS)) - SET_PSTATE_REPLY_OPTIONAL(param); + + if (keys_workaround) { + /* + * Required for Mellanox Flexboot PXE boot ROM + */ + if (!strcmp(param->name, FIRSTBURSTLENGTH)) + SET_PSTATE_REPLY_OPTIONAL(param); + + /* + * Required for gPXE iSCSI boot client + */ + if (!strcmp(param->name, MAXCONNECTIONS)) + SET_PSTATE_REPLY_OPTIONAL(param); + } } else if (IS_PHASE_DECLARATIVE(param)) SET_PSTATE_REPLY_OPTIONAL(param); } @@ -1422,7 +1435,8 @@ int iscsi_encode_text_output( u8 sender, char *textbuf, u32 *length, - struct iscsi_param_list *param_list) + struct iscsi_param_list *param_list, + bool keys_workaround) { char *output_buf = NULL; struct iscsi_extra_response *er; @@ -1458,7 +1472,8 @@ int iscsi_encode_text_output( *length += 1; output_buf = textbuf + *length; SET_PSTATE_PROPOSER(param); - iscsi_check_proposer_for_optional_reply(param); + iscsi_check_proposer_for_optional_reply(param, + keys_workaround); pr_debug("Sending key: %s=%s\n", param->name, param->value); } diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index 9962ccf0ccd7..c47b73f57528 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -46,7 +46,7 @@ extern int iscsi_extract_key_value(char *, char **, char **); extern int iscsi_update_param_value(struct iscsi_param *, char *); extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *); extern int iscsi_encode_text_output(u8, u8, char *, u32 *, - struct iscsi_param_list *); + struct iscsi_param_list *, bool); extern int iscsi_check_negotiated_keys(struct iscsi_param_list *); extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *, struct iscsi_param_list *); diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index abaabbaebd88..594d07a1e995 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -227,6 +227,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->t10_pi = TA_DEFAULT_T10_PI; a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE; a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS; + a->login_keys_workaround = TA_DEFAULT_LOGIN_KEYS_WORKAROUND; } int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) @@ -895,3 +896,21 @@ int iscsit_ta_tpg_enabled_sendtargets( return 0; } + +int iscsit_ta_login_keys_workaround( + struct iscsi_portal_group *tpg, + u32 flag) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((flag != 0) && (flag != 1)) { + pr_err("Illegal value %d\n", flag); + return -EINVAL; + } + + a->login_keys_workaround = flag; + pr_debug("iSCSI_TPG[%hu] - TPG enabled bit for login keys workaround: %s ", + tpg->tpgt, (a->login_keys_workaround) ? "ON" : "OFF"); + + return 0; +} diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index ceba29851167..59fd3cabe89d 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -48,5 +48,6 @@ extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32); extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32); extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32); extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32); +extern int iscsit_ta_login_keys_workaround(struct iscsi_portal_group *, u32); #endif /* ISCSI_TARGET_TPG_H */ diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 7948fc68286b..0ca1fb08805b 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -66,6 +66,14 @@ struct sock; #define TA_DEFAULT_FABRIC_PROT_TYPE 0 /* TPG status needs to be enabled to return sendtargets discovery endpoint info */ #define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1 +/* + * Used to control the sending of keys with optional to respond state bit, + * as a workaround for non RFC compliant initiators,that do not propose, + * nor respond to specific keys required for login to complete. + * + * See iscsi_check_proposer_for_optional_reply() for more details. + */ +#define TA_DEFAULT_LOGIN_KEYS_WORKAROUND 1 #define ISCSI_IOV_DATA_BUFFER 5 @@ -768,6 +776,7 @@ struct iscsi_tpg_attrib { u8 t10_pi; u32 fabric_prot_type; u32 tpg_enabled_sendtargets; + u32 login_keys_workaround; struct iscsi_portal_group *tpg; }; -- cgit v1.2.3