From 9554c1be48b437f192234eebb89f124ba3ef0e25 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Thu, 7 Jun 2018 02:31:36 -0400 Subject: scsi: tcmu: remove useless code and clean up the code style. Since the TCMU_RING_SIZE macro is not using here will discard it and at the same time clean up the code style. Signed-off-by: Xiubo Li Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 7f96dfa32b9c..e4a76f9771ce 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -83,14 +83,10 @@ #define DATA_BLOCK_SIZE PAGE_SIZE #define DATA_BLOCK_SHIFT PAGE_SHIFT #define DATA_BLOCK_BITS_DEF (256 * 1024) -#define DATA_SIZE (DATA_BLOCK_BITS * DATA_BLOCK_SIZE) #define TCMU_MBS_TO_BLOCKS(_mbs) (_mbs << (20 - DATA_BLOCK_SHIFT)) #define TCMU_BLOCKS_TO_MBS(_blocks) (_blocks >> (20 - DATA_BLOCK_SHIFT)) -/* The total size of the ring is 8M + 256K * PAGE_SIZE */ -#define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) - /* * Default number of global data blocks(512K * PAGE_SIZE) * when the unmap thread will be started. @@ -283,7 +279,7 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) 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; + return -EINVAL; } dev_id = nla_get_u32(info->attrs[TCMU_ATTR_DEVICE_ID]); @@ -313,7 +309,7 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) spin_unlock(&udev->nl_cmd_lock); if (!is_removed) - target_undepend_item(&dev->dev_group.cg_item); + target_undepend_item(&dev->dev_group.cg_item); if (!ret) complete(&nl_cmd->complete); return ret; -- cgit v1.2.3 From 83c2b54b9295a5fc0d9c8f1751aaf8099d1760f6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 12 Jun 2018 12:05:43 -0700 Subject: scsi: target: Abstract tag freeing Introduce target_free_tag() and convert all drivers to use it. Signed-off-by: Matthew Wilcox Reviewed-by: Jens Axboe Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 4 ++-- drivers/target/iscsi/iscsi_target_util.c | 2 +- drivers/target/sbp/sbp_target.c | 2 +- drivers/target/tcm_fc/tfc_cmd.c | 4 ++-- drivers/usb/gadget/function/f_tcm.c | 2 +- drivers/vhost/scsi.c | 2 +- drivers/xen/xen-scsiback.c | 4 +--- include/target/target_core_base.h | 5 +++++ 8 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/target') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 0fea2e2326be..11274317118a 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3783,7 +3783,7 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) return; } cmd->jiffies_at_free = get_jiffies_64(); - percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); + target_free_tag(sess->se_sess, &cmd->se_cmd); } EXPORT_SYMBOL(qlt_free_cmd); @@ -4146,7 +4146,7 @@ out_term: qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); qlt_decr_num_pend_cmds(vha); - percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); + target_free_tag(sess->se_sess, &cmd->se_cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); spin_lock_irqsave(&ha->tgt.sess_lock, flags); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 4435bf374d2d..7e98697cfb8e 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -711,7 +711,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) kfree(cmd->iov_data); kfree(cmd->text_in_ptr); - percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag); + target_free_tag(sess->se_sess, se_cmd); } EXPORT_SYMBOL(iscsit_release_cmd); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index fb1003921d85..679ae29d25ab 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1460,7 +1460,7 @@ static void sbp_free_request(struct sbp_target_request *req) kfree(req->pg_tbl); kfree(req->cmd_buf); - percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); + target_free_tag(se_sess, se_cmd); } static void sbp_mgt_agent_process(struct work_struct *work) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index ec372860106f..13e4efbe1ce7 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -92,7 +92,7 @@ static void ft_free_cmd(struct ft_cmd *cmd) if (fr_seq(fp)) fc_seq_release(fr_seq(fp)); fc_frame_free(fp); - percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); + target_free_tag(sess->se_sess, &cmd->se_cmd); ft_sess_put(sess); /* undo get from lookup at recv */ } @@ -461,7 +461,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) cmd->sess = sess; cmd->seq = fc_seq_assign(lport, fp); if (!cmd->seq) { - percpu_ida_free(&se_sess->sess_tag_pool, tag); + target_free_tag(se_sess, &cmd->se_cmd); goto busy; } cmd->req_frame = fp; /* hold frame during cmd */ diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index d78dbb73bde8..9f670d9224b9 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1288,7 +1288,7 @@ static void usbg_release_cmd(struct se_cmd *se_cmd) struct se_session *se_sess = se_cmd->se_sess; kfree(cmd->data_buf); - percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); + target_free_tag(se_sess, se_cmd); } static u32 usbg_sess_get_index(struct se_session *se_sess) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 17fcd3b2e686..7aaf0e5512ed 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -324,7 +324,7 @@ static void vhost_scsi_release_cmd(struct se_cmd *se_cmd) } vhost_scsi_put_inflight(tv_cmd->inflight); - percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); + target_free_tag(se_sess, se_cmd); } static u32 vhost_scsi_sess_get_index(struct se_session *se_sess) diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 7bc88fd43cfc..ec6635258ed8 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1377,9 +1377,7 @@ 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; - - percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); + target_free_tag(se_cmd->se_sess, se_cmd); } static u32 scsiback_sess_get_index(struct se_session *se_sess) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 922a39f45abc..260c2f3e9460 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -934,4 +934,9 @@ static inline void atomic_dec_mb(atomic_t *v) smp_mb__after_atomic(); } +static inline void target_free_tag(struct se_session *sess, struct se_cmd *cmd) +{ + percpu_ida_free(&sess->sess_tag_pool, cmd->map_tag); +} + #endif /* TARGET_CORE_BASE_H */ -- cgit v1.2.3 From 10e9cbb6b531117be0c4a79f2c7fa9a45a0dd532 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 12 Jun 2018 12:05:44 -0700 Subject: scsi: target: Convert target drivers to use sbitmap The sbitmap and the percpu_ida perform essentially the same task, allocating tags for commands. The sbitmap outperforms the percpu_ida as documented here: https://lkml.org/lkml/2014/4/22/553 The sbitmap interface is a little harder to use, but being able to remove the percpu_ida code and getting better performance justifies the additional complexity. Signed-off-by: Matthew Wilcox Acked-by: Felipe Balbi # f_tcm Reviewed-by: Jens Axboe Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 10 ++++++---- drivers/target/iscsi/iscsi_target_util.c | 33 +++++++++++++++++++++++++++++--- drivers/target/sbp/sbp_target.c | 5 +++-- drivers/target/target_core_transport.c | 5 +++-- drivers/target/tcm_fc/tfc_cmd.c | 6 +++--- drivers/usb/gadget/function/f_tcm.c | 5 +++-- drivers/vhost/scsi.c | 6 +++--- drivers/xen/xen-scsiback.c | 5 +++-- include/target/iscsi/iscsi_target_core.h | 1 + include/target/target_core_base.h | 7 ++++--- 10 files changed, 59 insertions(+), 24 deletions(-) (limited to 'drivers/target') diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 11274317118a..3de11153d1d3 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4277,9 +4277,9 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, { struct se_session *se_sess = sess->se_sess; struct qla_tgt_cmd *cmd; - int tag; + int tag, cpu; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) return NULL; @@ -4292,6 +4292,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, qlt_incr_num_pend_cmds(vha); cmd->vha = vha; cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; cmd->sess = sess; cmd->loop_id = sess->loop_id; cmd->conf_compl_supported = sess->conf_compl_supported; @@ -5294,7 +5295,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct fc_port *sess; struct se_session *se_sess; struct qla_tgt_cmd *cmd; - int tag; + int tag, cpu; unsigned long flags; if (unlikely(tgt->tgt_stop)) { @@ -5326,7 +5327,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, se_sess = sess->se_sess; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) return; @@ -5357,6 +5358,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; cmd->qpair = ha->base_qpair; + cmd->se_cmd.map_cpu = cpu; if (qfull) { cmd->q_full = 1; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 7e98697cfb8e..8cfcf9033507 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -17,7 +17,7 @@ ******************************************************************************/ #include -#include +#include #include /* ipv6_addr_equal() */ #include #include @@ -147,6 +147,30 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) spin_unlock_bh(&cmd->r2t_lock); } +static int iscsit_wait_for_tag(struct se_session *se_sess, int state, int *cpup) +{ + int tag = -1; + DEFINE_WAIT(wait); + struct sbq_wait_state *ws; + + if (state == TASK_RUNNING) + return tag; + + ws = &se_sess->sess_tag_pool.ws[0]; + for (;;) { + prepare_to_wait_exclusive(&ws->wait, &wait, state); + if (signal_pending_state(state, current)) + break; + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, cpup); + if (tag >= 0) + break; + schedule(); + } + + finish_wait(&ws->wait, &wait); + return tag; +} + /* * May be called from software interrupt (timer) context for allocating * iSCSI NopINs. @@ -155,9 +179,11 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) { struct iscsi_cmd *cmd; struct se_session *se_sess = conn->sess->se_sess; - int size, tag; + int size, tag, cpu; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); + if (tag < 0) + tag = iscsit_wait_for_tag(se_sess, state, &cpu); if (tag < 0) return NULL; @@ -166,6 +192,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) memset(cmd, 0, size); cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; cmd->conn = conn; cmd->data_direction = DMA_NONE; INIT_LIST_HEAD(&cmd->i_conn_node); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 679ae29d25ab..42b21f2ac8b0 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -926,15 +926,16 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess, { struct se_session *se_sess = sess->se_sess; struct sbp_target_request *req; - int tag; + int tag, cpu; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) return ERR_PTR(-ENOMEM); req = &((struct sbp_target_request *)se_sess->sess_cmd_map)[tag]; memset(req, 0, sizeof(*req)); req->se_cmd.map_tag = tag; + req->se_cmd.map_cpu = cpu; req->se_cmd.tag = next_orb; return req; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ee5081ba5313..89dd475d0a8f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -260,7 +260,8 @@ int transport_alloc_session_tags(struct se_session *se_sess, } } - rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num); + rc = sbitmap_queue_init_node(&se_sess->sess_tag_pool, tag_num, -1, + false, GFP_KERNEL, NUMA_NO_NODE); if (rc < 0) { pr_err("Unable to init se_sess->sess_tag_pool," " tag_num: %u\n", tag_num); @@ -547,7 +548,7 @@ void transport_free_session(struct se_session *se_sess) target_put_nacl(se_nacl); } if (se_sess->sess_cmd_map) { - percpu_ida_destroy(&se_sess->sess_tag_pool); + sbitmap_queue_free(&se_sess->sess_tag_pool); kvfree(se_sess->sess_cmd_map); } kmem_cache_free(se_sess_cache, se_sess); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 13e4efbe1ce7..a183d4da7db2 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -448,9 +447,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) struct ft_cmd *cmd; struct fc_lport *lport = sess->tport->lport; struct se_session *se_sess = sess->se_sess; - int tag; + int tag, cpu; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) goto busy; @@ -458,6 +457,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) memset(cmd, 0, sizeof(struct ft_cmd)); cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; cmd->sess = sess; cmd->seq = fc_seq_assign(lport, fp); if (!cmd->seq) { diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 9f670d9224b9..5003e857dce7 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1071,15 +1071,16 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, { struct se_session *se_sess = tv_nexus->tvn_se_sess; struct usbg_cmd *cmd; - int tag; + int tag, cpu; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) return ERR_PTR(-ENOMEM); cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag]; memset(cmd, 0, sizeof(*cmd)); cmd->se_cmd.map_tag = tag; + cmd->se_cmd.map_cpu = cpu; cmd->se_cmd.tag = cmd->tag = scsi_tag; cmd->fu = fu; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 7aaf0e5512ed..ebaf831285ea 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -46,7 +46,6 @@ #include #include #include -#include #include "vhost.h" @@ -567,7 +566,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, struct se_session *se_sess; struct scatterlist *sg, *prot_sg; struct page **pages; - int tag; + int tag, cpu; tv_nexus = tpg->tpg_nexus; if (!tv_nexus) { @@ -576,7 +575,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, } se_sess = tv_nexus->tvn_se_sess; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) { pr_err("Unable to obtain tag for vhost_scsi_cmd\n"); return ERR_PTR(-ENOMEM); @@ -591,6 +590,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, cmd->tvc_prot_sgl = prot_sg; cmd->tvc_upages = pages; cmd->tvc_se_cmd.map_tag = tag; + cmd->tvc_se_cmd.map_cpu = cpu; cmd->tvc_tag = scsi_tag; cmd->tvc_lun = lun; cmd->tvc_task_attr = task_attr; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index ec6635258ed8..764dd9aa0131 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -654,9 +654,9 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring struct scsiback_nexus *nexus = tpg->tpg_nexus; struct se_session *se_sess = nexus->tvn_se_sess; struct vscsibk_pend *req; - int tag, i; + int tag, cpu, i; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); if (tag < 0) { pr_err("Unable to obtain tag for vscsiif_request\n"); return ERR_PTR(-ENOMEM); @@ -665,6 +665,7 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring req = &((struct vscsibk_pend *)se_sess->sess_cmd_map)[tag]; memset(req, 0, sizeof(*req)); req->se_cmd.map_tag = tag; + req->se_cmd.map_cpu = cpu; for (i = 0; i < VSCSI_MAX_GRANTS; i++) req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index cf5f3fff1f1a..f2e6abea8490 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -4,6 +4,7 @@ #include /* enum dma_data_direction */ #include /* struct list_head */ +#include #include /* struct sockaddr_storage */ #include /* u8 */ #include /* itt_t */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 260c2f3e9460..448f291125c2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -4,7 +4,7 @@ #include /* struct config_group */ #include /* enum dma_data_direction */ -#include /* struct percpu_ida */ +#include #include #include /* struct semaphore */ #include @@ -455,6 +455,7 @@ struct se_cmd { int sam_task_attr; /* Used for se_sess->sess_tag_pool */ unsigned int map_tag; + int map_cpu; /* Transport protocol dependent state, see transport_state_table */ enum transport_state_table t_state; /* See se_cmd_flags_table */ @@ -608,7 +609,7 @@ struct se_session { struct list_head sess_wait_list; spinlock_t sess_cmd_lock; void *sess_cmd_map; - struct percpu_ida sess_tag_pool; + struct sbitmap_queue sess_tag_pool; }; struct se_device; @@ -936,7 +937,7 @@ static inline void atomic_dec_mb(atomic_t *v) static inline void target_free_tag(struct se_session *sess, struct se_cmd *cmd) { - percpu_ida_free(&sess->sess_tag_pool, cmd->map_tag); + sbitmap_queue_clear(&sess->sess_tag_pool, cmd->map_tag, cmd->map_cpu); } #endif /* TARGET_CORE_BASE_H */ -- cgit v1.2.3 From 0297e962907d98ece34188cb267d3313812b6e42 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:18 -0500 Subject: scsi: tcmu: delete unused __wait When this code changed, this was never cleaned up. Signed-off-by: Mike Christie Tested-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index e4a76f9771ce..898a5619f2d6 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1564,7 +1564,6 @@ 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; -- cgit v1.2.3 From 3228691ffec134353cb5bf6fb4342283e0243412 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:19 -0500 Subject: scsi: tcmu: track nl commands The next patch is going to fix the hung nl command issue so this adds a list of outstanding nl commands that we can later abort when the daemon is restarted. Signed-off-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 68 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 29 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 898a5619f2d6..73a57681e312 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -103,9 +103,16 @@ struct tcmu_hba { #define TCMU_CONFIG_LEN 256 +static DEFINE_MUTEX(tcmu_nl_cmd_mutex); +static LIST_HEAD(tcmu_nl_cmd_list); + +struct tcmu_dev; + struct tcmu_nl_cmd { /* wake up thread waiting for reply */ struct completion complete; + struct list_head nl_list; + struct tcmu_dev *udev; int cmd; int status; }; @@ -157,7 +164,6 @@ struct tcmu_dev { struct list_head timedout_entry; - 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; @@ -270,11 +276,9 @@ static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] = { static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) { - struct se_device *dev; - struct tcmu_dev *udev; + struct tcmu_dev *udev = NULL; 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]) { @@ -285,33 +289,36 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) 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; + mutex_lock(&tcmu_nl_cmd_mutex); + list_for_each_entry(nl_cmd, &tcmu_nl_cmd_list, nl_list) { + if (nl_cmd->udev->se_dev.dev_index == dev_id) { + udev = nl_cmd->udev; + break; + } } - udev = TCMU_DEV(dev); - spin_lock(&udev->nl_cmd_lock); - nl_cmd = &udev->curr_nl_cmd; + if (!udev) { + pr_err(KERN_ERR "tcmu nl cmd %u/%d completion could not find device with dev id %u.\n", + completed_cmd, rc, dev_id); + ret = -ENODEV; + goto unlock; + } + list_del(&nl_cmd->nl_list); - pr_debug("genl cmd done got id %d curr %d done %d rc %d\n", dev_id, - nl_cmd->cmd, completed_cmd, rc); + pr_debug("%s genl cmd done got id %d curr %d done %d rc %d\n", + udev->name, 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); + pr_err("Mismatched commands on %s (Expecting reply for %d. Current %d).\n", + udev->name, completed_cmd, nl_cmd->cmd); ret = -EINVAL; - } else { - nl_cmd->status = rc; + goto unlock; } - spin_unlock(&udev->nl_cmd_lock); - if (!is_removed) - target_undepend_item(&dev->dev_group.cg_item); - if (!ret) - complete(&nl_cmd->complete); + nl_cmd->status = rc; + complete(&nl_cmd->complete); +unlock: + mutex_unlock(&tcmu_nl_cmd_mutex); return ret; } @@ -1258,7 +1265,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) timer_setup(&udev->cmd_timer, tcmu_cmd_timedout, 0); init_waitqueue_head(&udev->nl_cmd_wq); - spin_lock_init(&udev->nl_cmd_lock); INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL); @@ -1544,10 +1550,10 @@ static void tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd) return; relock: - spin_lock(&udev->nl_cmd_lock); + mutex_lock(&tcmu_nl_cmd_mutex); if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { - spin_unlock(&udev->nl_cmd_lock); + mutex_unlock(&tcmu_nl_cmd_mutex); pr_debug("sleeping for open nl cmd\n"); wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC)); goto relock; @@ -1555,9 +1561,13 @@ relock: memset(nl_cmd, 0, sizeof(*nl_cmd)); nl_cmd->cmd = cmd; + nl_cmd->udev = udev; init_completion(&nl_cmd->complete); + INIT_LIST_HEAD(&nl_cmd->nl_list); + + list_add_tail(&nl_cmd->nl_list, &tcmu_nl_cmd_list); - spin_unlock(&udev->nl_cmd_lock); + mutex_unlock(&tcmu_nl_cmd_mutex); } static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) @@ -1574,11 +1584,11 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) pr_debug("sleeping for nl reply\n"); wait_for_completion(&nl_cmd->complete); - spin_lock(&udev->nl_cmd_lock); + mutex_lock(&tcmu_nl_cmd_mutex); nl_cmd->cmd = TCMU_CMD_UNSPEC; ret = nl_cmd->status; nl_cmd->status = 0; - spin_unlock(&udev->nl_cmd_lock); + mutex_unlock(&tcmu_nl_cmd_mutex); wake_up_all(&udev->nl_cmd_wq); -- cgit v1.2.3 From 9de3a1ef032a5ad5d7b642d625b6bd362b1989d6 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:20 -0500 Subject: scsi: tcmu: simplify nl interface Just return EBUSY if a nl request comes in while processing one. The upper layers do not support sending multiple create/remove requests at the same time (you cannot have a create and remove at the same time or do multiple creates or removes at the same time) and doing a reconfig while a create/remove is still executing does not make sense. Signed-off-by: Mike Christie Tested-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 73a57681e312..9835ea3c4dcc 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -165,8 +165,6 @@ struct tcmu_dev { struct list_head timedout_entry; 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]; @@ -1264,8 +1262,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) timer_setup(&udev->qfull_timer, tcmu_qfull_timedout, 0); timer_setup(&udev->cmd_timer, tcmu_cmd_timedout, 0); - init_waitqueue_head(&udev->nl_cmd_wq); - INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL); return &udev->se_dev; @@ -1539,24 +1535,23 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) return 0; } -static void tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd) +static int 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; + return 0; if (udev->nl_reply_supported <= 0) - return; + return 0; -relock: mutex_lock(&tcmu_nl_cmd_mutex); if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { mutex_unlock(&tcmu_nl_cmd_mutex); - pr_debug("sleeping for open nl cmd\n"); - wait_event(udev->nl_cmd_wq, (nl_cmd->cmd == TCMU_CMD_UNSPEC)); - goto relock; + pr_warn("netlink cmd %d already executing on %s\n", + nl_cmd->cmd, udev->name); + return -EBUSY; } memset(nl_cmd, 0, sizeof(*nl_cmd)); @@ -1568,6 +1563,7 @@ relock: list_add_tail(&nl_cmd->nl_list, &tcmu_nl_cmd_list); mutex_unlock(&tcmu_nl_cmd_mutex); + return 0; } static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) @@ -1590,8 +1586,6 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) nl_cmd->status = 0; mutex_unlock(&tcmu_nl_cmd_mutex); - wake_up_all(&udev->nl_cmd_wq); - return ret; } @@ -1642,7 +1636,11 @@ static int tcmu_netlink_event_send(struct tcmu_dev *udev, genlmsg_end(skb, msg_header); - tcmu_init_genl_cmd_reply(udev, cmd); + ret = tcmu_init_genl_cmd_reply(udev, cmd); + if (ret) { + nlmsg_free(skb); + return ret; + } ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, TCMU_MCGRP_CONFIG, GFP_KERNEL); -- cgit v1.2.3 From 06add777bd0aa764a2252e80c46ecc55ddc29dd1 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:21 -0500 Subject: scsi: tcmu: misc nl code cleanup Some misc cleanup of the nl rework patches. 1. Fix space instead of tabs use and extra newline 2. Drop initializing variables to 0 when not needed 3. Just pass the skb_buff and msg_header pointers to tcmu_netlink_event_send. Signed-off-by: Mike Christie Tested-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9835ea3c4dcc..2a2e9e4e7593 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1628,11 +1628,9 @@ free_skb: static int tcmu_netlink_event_send(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd, - struct sk_buff **buf, void **hdr) + struct sk_buff *skb, void *msg_header) { - int ret = 0; - struct sk_buff *skb = *buf; - void *msg_header = *hdr; + int ret; genlmsg_end(skb, msg_header); @@ -1644,7 +1642,7 @@ static int tcmu_netlink_event_send(struct tcmu_dev *udev, ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, TCMU_MCGRP_CONFIG, GFP_KERNEL); - /* We don't care if no one is listening */ + /* We don't care if no one is listening */ if (ret == -ESRCH) ret = 0; if (!ret) @@ -1662,9 +1660,8 @@ static int tcmu_send_dev_add_event(struct tcmu_dev *udev) &msg_header); if (ret < 0) return ret; - return tcmu_netlink_event_send(udev, TCMU_CMD_ADDED_DEVICE, &skb, - &msg_header); - + return tcmu_netlink_event_send(udev, TCMU_CMD_ADDED_DEVICE, skb, + msg_header); } static int tcmu_send_dev_remove_event(struct tcmu_dev *udev) @@ -1678,7 +1675,7 @@ static int tcmu_send_dev_remove_event(struct tcmu_dev *udev) if (ret < 0) return ret; return tcmu_netlink_event_send(udev, TCMU_CMD_REMOVED_DEVICE, - &skb, &msg_header); + skb, msg_header); } static int tcmu_update_uio_info(struct tcmu_dev *udev) @@ -2197,7 +2194,7 @@ static int tcmu_send_dev_config_event(struct tcmu_dev *udev, return ret; } return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, - &skb, &msg_header); + skb, msg_header); } @@ -2259,7 +2256,7 @@ static int tcmu_send_dev_size_event(struct tcmu_dev *udev, u64 size) return ret; } return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, - &skb, &msg_header); + skb, msg_header); } static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, @@ -2341,7 +2338,7 @@ static int tcmu_send_emulate_write_cache(struct tcmu_dev *udev, u8 val) return ret; } return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, - &skb, &msg_header); + skb, msg_header); } static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, -- cgit v1.2.3 From bdaeedc1bea9e833196b5c7eb0ffd74edf9c863e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:22 -0500 Subject: scsi: tcmu: add module wide block/reset_netlink support This patch based on Xiubo's patches adds 2 tcmu attr to block and reset the netlink interface. It's used during userspace daemon reinitialization after the daemon has crashed while there is outstanding nl requests. The daemon can block the nl interface, kill outstanding requests in the kernel and then reopen the netlink socket and unblock it to allow new requests. [mkp: typo] Signed-off-by: Mike Christie Tested-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 100 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 2a2e9e4e7593..95559811d6cc 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -94,6 +94,7 @@ #define TCMU_GLOBAL_MAX_BLOCKS_DEF (512 * 1024) static u8 tcmu_kern_cmd_reply_supported; +static u8 tcmu_netlink_blocked; static struct device *tcmu_root_device; @@ -255,6 +256,92 @@ MODULE_PARM_DESC(global_max_data_area_mb, "Max MBs allowed to be allocated to all the tcmu device's " "data areas."); +static int tcmu_get_block_netlink(char *buffer, + const struct kernel_param *kp) +{ + return sprintf(buffer, "%s\n", tcmu_netlink_blocked ? + "blocked" : "unblocked"); +} + +static int tcmu_set_block_netlink(const char *str, + const struct kernel_param *kp) +{ + int ret; + u8 val; + + ret = kstrtou8(str, 0, &val); + if (ret < 0) + return ret; + + if (val > 1) { + pr_err("Invalid block netlink value %u\n", val); + return -EINVAL; + } + + tcmu_netlink_blocked = val; + return 0; +} + +static const struct kernel_param_ops tcmu_block_netlink_op = { + .set = tcmu_set_block_netlink, + .get = tcmu_get_block_netlink, +}; + +module_param_cb(block_netlink, &tcmu_block_netlink_op, NULL, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(block_netlink, "Block new netlink commands."); + +static int tcmu_fail_netlink_cmd(struct tcmu_nl_cmd *nl_cmd) +{ + struct tcmu_dev *udev = nl_cmd->udev; + + if (!tcmu_netlink_blocked) { + pr_err("Could not reset device's netlink interface. Netlink is not blocked.\n"); + return -EBUSY; + } + + if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { + pr_debug("Aborting nl cmd %d on %s\n", nl_cmd->cmd, udev->name); + nl_cmd->status = -EINTR; + list_del(&nl_cmd->nl_list); + complete(&nl_cmd->complete); + } + return 0; +} + +static int tcmu_set_reset_netlink(const char *str, + const struct kernel_param *kp) +{ + struct tcmu_nl_cmd *nl_cmd, *tmp_cmd; + int ret; + u8 val; + + ret = kstrtou8(str, 0, &val); + if (ret < 0) + return ret; + + if (val != 1) { + pr_err("Invalid reset netlink value %u\n", val); + return -EINVAL; + } + + mutex_lock(&tcmu_nl_cmd_mutex); + list_for_each_entry_safe(nl_cmd, tmp_cmd, &tcmu_nl_cmd_list, nl_list) { + ret = tcmu_fail_netlink_cmd(nl_cmd); + if (ret) + break; + } + mutex_unlock(&tcmu_nl_cmd_mutex); + + return ret; +} + +static const struct kernel_param_ops tcmu_reset_netlink_op = { + .set = tcmu_set_reset_netlink, +}; + +module_param_cb(reset_netlink, &tcmu_reset_netlink_op, NULL, S_IWUSR); +MODULE_PARM_DESC(reset_netlink, "Reset netlink commands."); + /* multicast group */ enum tcmu_multicast_groups { TCMU_MCGRP_CONFIG, @@ -303,8 +390,9 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) } list_del(&nl_cmd->nl_list); - pr_debug("%s genl cmd done got id %d curr %d done %d rc %d\n", - udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc); + pr_debug("%s genl cmd done got id %d curr %d done %d rc %d stat %d\n", + udev->name, dev_id, nl_cmd->cmd, completed_cmd, rc, + nl_cmd->status); if (nl_cmd->cmd != completed_cmd) { pr_err("Mismatched commands on %s (Expecting reply for %d. Current %d).\n", @@ -1547,6 +1635,13 @@ static int tcmu_init_genl_cmd_reply(struct tcmu_dev *udev, int cmd) mutex_lock(&tcmu_nl_cmd_mutex); + if (tcmu_netlink_blocked) { + mutex_unlock(&tcmu_nl_cmd_mutex); + pr_warn("Failing nl cmd %d on %s. Interface is blocked.\n", cmd, + udev->name); + return -EAGAIN; + } + if (nl_cmd->cmd != TCMU_CMD_UNSPEC) { mutex_unlock(&tcmu_nl_cmd_mutex); pr_warn("netlink cmd %d already executing on %s\n", @@ -1583,7 +1678,6 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) mutex_lock(&tcmu_nl_cmd_mutex); nl_cmd->cmd = TCMU_CMD_UNSPEC; ret = nl_cmd->status; - nl_cmd->status = 0; mutex_unlock(&tcmu_nl_cmd_mutex); return ret; -- cgit v1.2.3 From e2607484370ea1b3595a3c51485e66e0cbd17341 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 22 Jun 2018 16:40:23 -0500 Subject: scsi: target: remove target_find_device target_find_device is no longer used, so remove it. Signed-off-by: Mike Christie Tested-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_device.c | 24 ------------------------ include/target/target_core_backend.h | 2 -- 2 files changed, 26 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e27db4d45a9d..a9ad6ecb1812 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -879,30 +879,6 @@ 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(&device_mutex); - dev = idr_find(&devices_idr, id); - if (dev && do_depend && target_depend_item(&dev->dev_group.cg_item)) - dev = NULL; - mutex_unlock(&device_mutex); - return dev; -} -EXPORT_SYMBOL(target_find_device); - struct devices_idr_iter { int (*fn)(struct se_device *dev, void *data); void *data; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 34a15d59ed88..c3ac47255218 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -106,8 +106,6 @@ 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 0c218e16a8501cfda30f498217b434976cb62fc5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 26 Jun 2018 11:47:20 -0500 Subject: scsi: tcmu: Don't pass KERN_ERR to pr_err Fix warning: smatch warnings: drivers/target/target_core_user.c:301 tcmu_genl_cmd_done() warn: KERN_* level not at start of string Signed-off-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 95559811d6cc..847707a700cf 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -383,7 +383,7 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd) } if (!udev) { - pr_err(KERN_ERR "tcmu nl cmd %u/%d completion could not find device with dev id %u.\n", + pr_err("tcmu nl cmd %u/%d completion could not find device with dev id %u.\n", completed_cmd, rc, dev_id); ret = -ENODEV; goto unlock; -- cgit v1.2.3 From 6f3bf5a2fa4a53c8dbb5b7b3d3d93bf85acaa2eb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:48 -0700 Subject: scsi: target: Use config_item_name() instead of open-coding it Some target code uses config_item_name() while other code accesses .ci_name directly. Make the target code consistent by switching to config_item_name(). Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 4 ++-- drivers/target/target_core_sbc.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 5ccef7d597fa..93d3ff34b614 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -263,8 +263,8 @@ static struct config_group *target_core_register_fabric( &tf->tf_discovery_cit); configfs_add_default_group(&tf->tf_disc_group, &tf->tf_group); - pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" - " %s\n", tf->tf_group.cg_item.ci_name); + pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric: %s\n", + config_item_name(&tf->tf_group.cg_item)); return &tf->tf_group; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index b054682e974f..ebac2b49b9c6 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -978,9 +978,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) } 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); + pr_err_ratelimited("se_device %s/%s (vpd_unit_serial %s) reject COMPARE_AND_WRITE\n", + dev->se_hba->backend->ops->name, + config_item_name(&dev->dev_group.cg_item), + dev->t10_wwn.unit_serial); return TCM_UNSUPPORTED_SCSI_OPCODE; } sectors = cdb[13]; -- cgit v1.2.3 From 36d4cb460bcbe2a1323732a6e4bb9dd783284368 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 28 Jun 2018 13:48:57 -0500 Subject: scsi: target: Avoid that EXTENDED COPY commands trigger lock inversion The approach for adding a device to the devices_idr data structure and for removing it is as follows: * &dev->dev_group.cg_item is initialized before a device is added to devices_idr. * If the reference count of a device drops to zero then target_free_device() removes the device from devices_idr. * All devices_idr manipulations are protected by device_mutex. This means that increasing the reference count of a device is sufficient to prevent removal from devices_idr and also that it is safe access dev_group.cg_item for any device that is referenced by devices_idr. Use this to modify target_find_device() and target_for_each_device() such that these functions no longer introduce a dependency between device_mutex and the configfs root inode mutex. Note: it is safe to pass a NULL pointer to config_item_put() and also to config_item_get_unless_zero(). This patch prevents that lockdep reports the following complaint: ====================================================== WARNING: possible circular locking dependency detected 4.12.0-rc1-dbg+ #1 Not tainted ------------------------------------------------------ rmdir/12053 is trying to acquire lock: (device_mutex#2){+.+.+.}, at: [] target_free_device+0xae/0xf0 [target_core_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+0x59/0x80 down_write+0x36/0x70 configfs_depend_item+0x3a/0xb0 [configfs] target_depend_item+0x13/0x20 [target_core_mod] target_xcopy_locate_se_dev_e4_iter+0x87/0x100 [target_core_mod] target_devices_idr_iter+0x16/0x20 [target_core_mod] idr_for_each+0x39/0xc0 target_for_each_device+0x36/0x50 [target_core_mod] target_xcopy_locate_se_dev_e4+0x28/0x80 [target_core_mod] target_xcopy_do_work+0x2e9/0xdd0 [target_core_mod] process_one_work+0x1ca/0x3f0 worker_thread+0x49/0x3b0 kthread+0x109/0x140 ret_from_fork+0x31/0x40 -> #0 (device_mutex#2){+.+.+.}: __lock_acquire+0x101f/0x11d0 lock_acquire+0x59/0x80 __mutex_lock+0x7e/0x950 mutex_lock_nested+0x16/0x20 target_free_device+0xae/0xf0 [target_core_mod] target_core_dev_release+0x10/0x20 [target_core_mod] config_item_put+0x6e/0xb0 [configfs] configfs_rmdir+0x1a6/0x300 [configfs] vfs_rmdir+0xb7/0x140 do_rmdir+0x1f4/0x200 SyS_rmdir+0x11/0x20 entry_SYSCALL_64_fastpath+0x23/0xc2 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&sb->s_type->i_mutex_key#14); lock(device_mutex#2); lock(&sb->s_type->i_mutex_key#14); lock(device_mutex#2); *** DEADLOCK *** 3 locks held by rmdir/12053: #0: (sb_writers#10){.+.+.+}, at: [] mnt_want_write+0x1f/0x50 #1: (&sb->s_type->i_mutex_key#14/1){+.+.+.}, at: [] do_rmdir+0x15e/0x200 #2: (&sb->s_type->i_mutex_key#14){++++++}, at: [] vfs_rmdir+0x50/0x140 stack backtrace: CPU: 3 PID: 12053 Comm: rmdir Not tainted 4.12.0-rc1-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/0xcf print_circular_bug+0x1c7/0x220 __lock_acquire+0x101f/0x11d0 lock_acquire+0x59/0x80 __mutex_lock+0x7e/0x950 mutex_lock_nested+0x16/0x20 target_free_device+0xae/0xf0 [target_core_mod] target_core_dev_release+0x10/0x20 [target_core_mod] config_item_put+0x6e/0xb0 [configfs] configfs_rmdir+0x1a6/0x300 [configfs] vfs_rmdir+0xb7/0x140 do_rmdir+0x1f4/0x200 SyS_rmdir+0x11/0x20 entry_SYSCALL_64_fastpath+0x23/0xc2 Signed-off-by: Bart Van Assche [Rebased to handle conflict withe target_find_device removal] Signed-off-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_device.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index a9ad6ecb1812..e5c90afb40e6 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -880,14 +880,20 @@ sector_t target_to_linux_sector(struct se_device *dev, sector_t lb) EXPORT_SYMBOL(target_to_linux_sector); struct devices_idr_iter { + struct config_item *prev_item; int (*fn)(struct se_device *dev, void *data); void *data; }; static int target_devices_idr_iter(int id, void *p, void *data) + __must_hold(&device_mutex) { struct devices_idr_iter *iter = data; struct se_device *dev = p; + int ret; + + config_item_put(iter->prev_item); + iter->prev_item = NULL; /* * We add the device early to the idr, so it can be used @@ -898,7 +904,15 @@ static int target_devices_idr_iter(int id, void *p, void *data) if (!(dev->dev_flags & DF_CONFIGURED)) return 0; - return iter->fn(dev, iter->data); + iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item); + if (!iter->prev_item) + return 0; + mutex_unlock(&device_mutex); + + ret = iter->fn(dev, iter->data); + + mutex_lock(&device_mutex); + return ret; } /** @@ -912,15 +926,13 @@ static int target_devices_idr_iter(int id, void *p, void *data) int target_for_each_device(int (*fn)(struct se_device *dev, void *data), void *data) { - struct devices_idr_iter iter; + struct devices_idr_iter iter = { .fn = fn, .data = data }; int ret; - iter.fn = fn; - iter.data = data; - mutex_lock(&device_mutex); ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter); mutex_unlock(&device_mutex); + config_item_put(iter.prev_item); return ret; } -- cgit v1.2.3 From 3eeff1984051e45448765e49b712c6bfee1de378 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:50 -0700 Subject: scsi: target: Move a list_del_init() statement This patch does not change any functionality but makes the next patch easier to read. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 89dd475d0a8f..5e8329c5ddd0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2697,6 +2697,7 @@ static void target_release_cmd_kref(struct kref *kref) if (se_sess) { spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + list_del_init(&se_cmd->se_cmd_list); spin_lock(&se_cmd->t_state_lock); fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) && @@ -2704,13 +2705,11 @@ static void target_release_cmd_kref(struct kref *kref) spin_unlock(&se_cmd->t_state_lock); if (se_cmd->cmd_wait_set || fabric_stop) { - list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); target_free_cmd_mem(se_cmd); complete(&se_cmd->cmd_wait_comp); return; } - list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -- cgit v1.2.3 From 317f89712d7aa4acc2d93df27b753d4489826cc5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:51 -0700 Subject: scsi: target: Rename transport_init_session() into transport_alloc_session() Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_login.c | 2 +- drivers/target/target_core_transport.c | 26 ++++++++++++++++++++++---- include/target/target_core_fabric.h | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 99501785cdc1..923b1a9fc3dc 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -369,7 +369,7 @@ static int iscsi_login_zero_tsih_s1( return -ENOMEM; } - sess->se_sess = transport_init_session(TARGET_PROT_NORMAL); + sess->se_sess = transport_alloc_session(TARGET_PROT_NORMAL); if (IS_ERR(sess->se_sess)) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 5e8329c5ddd0..880e07f40099 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -224,7 +224,11 @@ void transport_subsystem_check_init(void) sub_api_initialized = 1; } -struct se_session *transport_init_session(enum target_prot_op sup_prot_ops) +/** + * transport_alloc_session - allocate a session object and initialize it + * @sup_prot_ops: bitmask that defines which T10-PI modes are supported. + */ +struct se_session *transport_alloc_session(enum target_prot_op sup_prot_ops) { struct se_session *se_sess; @@ -243,8 +247,15 @@ struct se_session *transport_init_session(enum target_prot_op sup_prot_ops) return se_sess; } -EXPORT_SYMBOL(transport_init_session); +EXPORT_SYMBOL(transport_alloc_session); +/** + * transport_alloc_session_tags - allocate target driver private data + * @se_sess: Session pointer. + * @tag_num: Maximum number of in-flight commands between initiator and target. + * @tag_size: Size in bytes of the private data a target driver associates with + * each command. + */ int transport_alloc_session_tags(struct se_session *se_sess, unsigned int tag_num, unsigned int tag_size) { @@ -274,6 +285,13 @@ int transport_alloc_session_tags(struct se_session *se_sess, } EXPORT_SYMBOL(transport_alloc_session_tags); +/** + * transport_init_session_tags - allocate a session and target driver private data + * @tag_num: Maximum number of in-flight commands between initiator and target. + * @tag_size: Size in bytes of the private data a target driver associates with + * each command. + * @sup_prot_ops: bitmask that defines which T10-PI modes are supported. + */ struct se_session *transport_init_session_tags(unsigned int tag_num, unsigned int tag_size, enum target_prot_op sup_prot_ops) @@ -292,7 +310,7 @@ struct se_session *transport_init_session_tags(unsigned int tag_num, return ERR_PTR(-EINVAL); } - se_sess = transport_init_session(sup_prot_ops); + se_sess = transport_alloc_session(sup_prot_ops); if (IS_ERR(se_sess)) return se_sess; @@ -402,7 +420,7 @@ target_alloc_session(struct se_portal_group *tpg, if (tag_num != 0) sess = transport_init_session_tags(tag_num, tag_size, prot_op); else - sess = transport_init_session(prot_op); + sess = transport_alloc_session(prot_op); if (IS_ERR(sess)) return sess; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index b297aa0d9651..010df9d5b977 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -115,7 +115,7 @@ struct se_session *target_alloc_session(struct se_portal_group *, int (*callback)(struct se_portal_group *, struct se_session *, void *)); -struct se_session *transport_init_session(enum target_prot_op); +struct se_session *transport_alloc_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); struct se_session *transport_init_session_tags(unsigned int, unsigned int, -- cgit v1.2.3 From d1bff07f387c05cfaba1ea505fc2ee5eac6b2c21 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:52 -0700 Subject: scsi: target: Introduce transport_init_session() Other than initializing xcopy_pt_sess.sess_wait_list, this patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 22 +++++++++++++++++----- drivers/target/target_core_xcopy.c | 5 +---- include/target/target_core_fabric.h | 1 + 3 files changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 880e07f40099..595b2f12ca6a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -224,6 +224,22 @@ void transport_subsystem_check_init(void) sub_api_initialized = 1; } +/** + * transport_init_session - initialize a session object + * @se_sess: Session object pointer. + * + * The caller must have zero-initialized @se_sess before calling this function. + */ +void transport_init_session(struct se_session *se_sess) +{ + INIT_LIST_HEAD(&se_sess->sess_list); + INIT_LIST_HEAD(&se_sess->sess_acl_list); + INIT_LIST_HEAD(&se_sess->sess_cmd_list); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + spin_lock_init(&se_sess->sess_cmd_lock); +} +EXPORT_SYMBOL(transport_init_session); + /** * transport_alloc_session - allocate a session object and initialize it * @sup_prot_ops: bitmask that defines which T10-PI modes are supported. @@ -238,11 +254,7 @@ struct se_session *transport_alloc_session(enum target_prot_op sup_prot_ops) " se_sess_cache\n"); return ERR_PTR(-ENOMEM); } - INIT_LIST_HEAD(&se_sess->sess_list); - INIT_LIST_HEAD(&se_sess->sess_acl_list); - INIT_LIST_HEAD(&se_sess->sess_cmd_list); - INIT_LIST_HEAD(&se_sess->sess_wait_list); - spin_lock_init(&se_sess->sess_cmd_lock); + transport_init_session(se_sess); se_sess->sup_prot_ops = sup_prot_ops; return se_sess; diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 9ee89e00cd77..2718a933c0c6 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -497,10 +497,7 @@ int target_xcopy_setup_pt(void) INIT_LIST_HEAD(&xcopy_pt_nacl.acl_list); INIT_LIST_HEAD(&xcopy_pt_nacl.acl_sess_list); memset(&xcopy_pt_sess, 0, sizeof(struct se_session)); - INIT_LIST_HEAD(&xcopy_pt_sess.sess_list); - INIT_LIST_HEAD(&xcopy_pt_sess.sess_acl_list); - INIT_LIST_HEAD(&xcopy_pt_sess.sess_cmd_list); - spin_lock_init(&xcopy_pt_sess.sess_cmd_lock); + transport_init_session(&xcopy_pt_sess); xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg; xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 010df9d5b977..84a681b6e5ca 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -115,6 +115,7 @@ struct se_session *target_alloc_session(struct se_portal_group *, int (*callback)(struct se_portal_group *, struct se_session *, void *)); +void transport_init_session(struct se_session *); struct se_session *transport_alloc_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); -- cgit v1.2.3 From 00d909a10710a3416272d4179adf3837b9a9f3c2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:53 -0700 Subject: scsi: target: Make the session shutdown code also wait for commands that are being aborted Target drivers must call target_sess_cmd_list_set_waiting() and target_wait_for_sess_cmds() before freeing a session. Since freeing a session is only safe after all commands that are associated with a session have finished, make target_wait_for_sess_cmds() also wait for commands that are being aborted. Instead of setting a flag in each pending command from target_sess_cmd_list_set_waiting() and waiting in target_wait_for_sess_cmds() on a per-command completion, only set a per-session flag in the former function and wait on a per-session completion in the latter function. This change is safe because once a SCSI initiator system has submitted a command a target system is always allowed to execute it to completion. See also commit 0f4a943168f3 ("target: Fix remote-port TMR ABORT + se_cmd fabric stop"). This patch is based on the following two patches: * Bart Van Assche, target: Simplify session shutdown code, February 19, 2015 (https://github.com/bvanassche/linux/commit/8df5463d7d7619f2f1b70cfe5172eaef0aa52815). * Christoph Hellwig, target: Rework session shutdown code, December 7, 2015 (http://thread.gmane.org/gmane.linux.scsi.target.devel/10695). Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Martin K. Petersen --- drivers/target/target_core_tmr.c | 5 +-- drivers/target/target_core_transport.c | 77 ++++++++++------------------------ include/target/target_core_base.h | 3 +- 3 files changed, 24 insertions(+), 61 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 9c7bc1ca341a..da8125dd3a4c 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -142,7 +142,7 @@ static bool __target_check_io_state(struct se_cmd *se_cmd, return false; } } - if (sess->sess_tearing_down || se_cmd->cmd_wait_set) { + if (sess->sess_tearing_down) { pr_debug("Attempted to abort io tag: %llu already shutdown," " skipping\n", se_cmd->tag); spin_unlock(&se_cmd->t_state_lock); @@ -187,7 +187,6 @@ void core_tmr_abort_task( if (!__target_check_io_state(se_cmd, se_sess, 0)) continue; - list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); cancel_work_sync(&se_cmd->work); @@ -259,7 +258,7 @@ static void core_tmr_drain_tmr_list( spin_unlock(&sess->sess_cmd_lock); continue; } - if (sess->sess_tearing_down || cmd->cmd_wait_set) { + if (sess->sess_tearing_down) { spin_unlock(&cmd->t_state_lock); spin_unlock(&sess->sess_cmd_lock); continue; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 595b2f12ca6a..087dddfc5c35 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -235,8 +235,8 @@ void transport_init_session(struct se_session *se_sess) INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_cmd_list); - INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); + init_waitqueue_head(&se_sess->cmd_list_wq); } EXPORT_SYMBOL(transport_init_session); @@ -2728,13 +2728,15 @@ static void target_release_cmd_kref(struct kref *kref) if (se_sess) { spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_del_init(&se_cmd->se_cmd_list); + if (list_empty(&se_sess->sess_cmd_list)) + wake_up(&se_sess->cmd_list_wq); spin_lock(&se_cmd->t_state_lock); fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) && (se_cmd->transport_state & CMD_T_ABORTED); spin_unlock(&se_cmd->t_state_lock); - if (se_cmd->cmd_wait_set || fabric_stop) { + if (fabric_stop) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); target_free_cmd_mem(se_cmd); complete(&se_cmd->cmd_wait_comp); @@ -2863,78 +2865,41 @@ void target_show_cmd(const char *pfx, struct se_cmd *cmd) 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. + * target_sess_cmd_list_set_waiting - Set sess_tearing_down so no new commands are queued. * @se_sess: session to flag */ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { - struct se_cmd *se_cmd, *tmp_cmd; unsigned long flags; - int rc; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - if (se_sess->sess_tearing_down) { - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - return; - } se_sess->sess_tearing_down = 1; - list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); - - list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_wait_list, se_cmd_list) { - rc = kref_get_unless_zero(&se_cmd->cmd_kref); - if (rc) { - se_cmd->cmd_wait_set = 1; - spin_lock(&se_cmd->t_state_lock); - se_cmd->transport_state |= CMD_T_FABRIC_STOP; - spin_unlock(&se_cmd->t_state_lock); - } else - list_del_init(&se_cmd->se_cmd_list); - } - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); /** - * target_wait_for_sess_cmds - Wait for outstanding descriptors + * target_wait_for_sess_cmds - Wait for outstanding commands * @se_sess: session to wait for active I/O */ void target_wait_for_sess_cmds(struct se_session *se_sess) { - struct se_cmd *se_cmd, *tmp_cmd; - unsigned long flags; - bool tas; - - list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_wait_list, se_cmd_list) { - pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" - " %d\n", se_cmd, se_cmd->t_state, - se_cmd->se_tfo->get_cmd_state(se_cmd)); - - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - tas = (se_cmd->transport_state & CMD_T_TAS); - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - - if (!target_put_sess_cmd(se_cmd)) { - if (tas) - target_put_sess_cmd(se_cmd); - } - - wait_for_completion(&se_cmd->cmd_wait_comp); - pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" - " fabric state: %d\n", se_cmd, se_cmd->t_state, - se_cmd->se_tfo->get_cmd_state(se_cmd)); - - se_cmd->se_tfo->release_cmd(se_cmd); - } - - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - WARN_ON(!list_empty(&se_sess->sess_cmd_list)); - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + struct se_cmd *cmd; + int ret; + WARN_ON_ONCE(!se_sess->sess_tearing_down); + + spin_lock_irq(&se_sess->sess_cmd_lock); + do { + ret = wait_event_interruptible_lock_irq_timeout( + se_sess->cmd_list_wq, + list_empty(&se_sess->sess_cmd_list), + se_sess->sess_cmd_lock, 180 * HZ); + list_for_each_entry(cmd, &se_sess->sess_cmd_list, se_cmd_list) + target_show_cmd("session shutdown: still waiting for ", + cmd); + } while (ret <= 0); + spin_unlock_irq(&se_sess->sess_cmd_lock); } EXPORT_SYMBOL(target_wait_for_sess_cmds); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 448f291125c2..906c1fc485e4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -443,7 +443,6 @@ struct se_cmd { u8 scsi_asc; u8 scsi_ascq; u16 scsi_sense_length; - unsigned cmd_wait_set:1; unsigned unknown_data_length:1; bool state_active:1; u64 tag; /* SAM command identifier aka task tag */ @@ -606,8 +605,8 @@ struct se_session { struct list_head sess_list; struct list_head sess_acl_list; struct list_head sess_cmd_list; - struct list_head sess_wait_list; spinlock_t sess_cmd_lock; + wait_queue_head_t cmd_list_wq; void *sess_cmd_map; struct sbitmap_queue sess_tag_pool; }; -- cgit v1.2.3 From 953bcf7ad16ac6ecee7d2f5593501aee5e5ae8b8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:54 -0700 Subject: scsi: target: Document when CMD_T_STOP and CMD_T_COMPLETE are set Document those aspects of transport_cmd_check_stop_to_fabric() and transport_generic_free_cmd() of which it is nontrivial to derive these from their implementation. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 087dddfc5c35..47318f64296d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -632,6 +632,13 @@ static void target_remove_from_state_list(struct se_cmd *cmd) spin_unlock_irqrestore(&dev->execute_task_lock, flags); } +/* + * This function is called by the target core after the target core has + * finished processing a SCSI command or SCSI TMF. Both the regular command + * processing code and the code for aborting commands can call this + * function. CMD_T_STOP is set if and only if another thread is waiting + * inside transport_wait_for_tasks() for t_transport_stop_comp. + */ static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd) { unsigned long flags; @@ -2624,6 +2631,27 @@ static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas) spin_unlock_irqrestore(&cmd->t_state_lock, flags); } +/* + * This function is called by frontend drivers after processing of a command + * has finished. + * + * The protocol for ensuring that either the regular flow or the TMF + * code drops one reference is as follows: + * - Calling .queue_data_in(), .queue_status() or queue_tm_rsp() will cause + * the frontend driver to drop one reference, synchronously or asynchronously. + * - During regular command processing the target core sets CMD_T_COMPLETE + * before invoking one of the .queue_*() functions. + * - The code that aborts commands skips commands and TMFs for which + * CMD_T_COMPLETE has been set. + * - CMD_T_ABORTED is set atomically after the CMD_T_COMPLETE check for + * commands that will be aborted. + * - If the CMD_T_ABORTED flag is set but CMD_T_TAS has not been set + * transport_generic_free_cmd() skips its call to target_put_sess_cmd(). + * - For aborted commands for which CMD_T_TAS has been set .queue_status() will + * be called and will drop a reference. + * - For aborted commands for which CMD_T_TAS has not been set .aborted_task() + * will be called. transport_cmd_finish_abort() will drop the final reference. + */ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { int ret = 0; @@ -2652,12 +2680,6 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (!aborted || tas) ret = target_put_sess_cmd(cmd); } - /* - * If the task has been internally aborted due to TMR ABORT_TASK - * or LUN_RESET, target_core_tmr.c is responsible for performing - * the remaining calls to target_put_sess_cmd(), and not the - * callers of this function. - */ if (aborted) { pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag); wait_for_completion(&cmd->cmd_wait_comp); -- cgit v1.2.3 From 709d56512fe8ed6d5092a1d43a4343d23df2b31c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:55 -0700 Subject: scsi: target: Simplify core_tmr_handle_tas_abort() The code that can set CMD_T_TAS is executed by the same thread as the thread that executes core_tmr_handle_tas_abort(). That means that no locking is needed to check CMD_T_TAS from inside core_tmr_handle_tas_abort(). This patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_tmr.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index da8125dd3a4c..08af053e7990 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -77,21 +77,12 @@ void core_tmr_release_req(struct se_tmr_req *tmr) static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) { - unsigned long flags; - bool remove = true, send_tas; - /* - * TASK ABORTED status (TAS) bit support - */ - spin_lock_irqsave(&cmd->t_state_lock, flags); - send_tas = (cmd->transport_state & CMD_T_TAS); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + bool send_tas = cmd->transport_state & CMD_T_TAS; - if (send_tas) { - remove = false; + if (send_tas) transport_send_task_abort(cmd); - } - return transport_cmd_finish_abort(cmd, remove); + return transport_cmd_finish_abort(cmd, !send_tas); } static int target_check_cdb_and_preempt(struct list_head *list, -- cgit v1.2.3 From 65422d705f1abf65897464b4e9c51ec3e1376ec4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:56 -0700 Subject: scsi: target: Fold core_tmr_handle_tas_abort() into transport_cmd_finish_abort() For the two calls to transport_cmd_finish_abort() outside core_tmr_handle_tas_abort() it is guaranteed that CMD_T_TAS is not set. Use this property to fold core_tmr_handle_tas_abort() into transport_cmd_finish_abort(). This patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_internal.h | 2 +- drivers/target/target_core_tmr.c | 16 +++------------- drivers/target/target_core_transport.c | 10 +++++++--- 3 files changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index dead30b1d32c..0c6635587930 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -138,7 +138,7 @@ int init_se_kmem_caches(void); void release_se_kmem_caches(void); u32 scsi_get_new_index(scsi_index_t); void transport_subsystem_check_init(void); -int transport_cmd_finish_abort(struct se_cmd *, int); +int transport_cmd_finish_abort(struct se_cmd *); unsigned char *transport_dump_cmd_direction(struct se_cmd *); void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_info(struct se_device *, struct se_lun *, diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 08af053e7990..6d1179a7f043 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -75,16 +75,6 @@ void core_tmr_release_req(struct se_tmr_req *tmr) kfree(tmr); } -static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) -{ - bool send_tas = cmd->transport_state & CMD_T_TAS; - - if (send_tas) - transport_send_task_abort(cmd); - - return transport_cmd_finish_abort(cmd, !send_tas); -} - static int target_check_cdb_and_preempt(struct list_head *list, struct se_cmd *cmd) { @@ -183,7 +173,7 @@ void core_tmr_abort_task( cancel_work_sync(&se_cmd->work); transport_wait_for_tasks(se_cmd); - if (!transport_cmd_finish_abort(se_cmd, true)) + if (!transport_cmd_finish_abort(se_cmd)) target_put_sess_cmd(se_cmd); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" @@ -281,7 +271,7 @@ static void core_tmr_drain_tmr_list( cancel_work_sync(&cmd->work); transport_wait_for_tasks(cmd); - if (!transport_cmd_finish_abort(cmd, 1)) + if (!transport_cmd_finish_abort(cmd)) target_put_sess_cmd(cmd); } } @@ -370,7 +360,7 @@ static void core_tmr_drain_state_list( cancel_work_sync(&cmd->work); transport_wait_for_tasks(cmd); - if (!core_tmr_handle_tas_abort(cmd, tas)) + if (!transport_cmd_finish_abort(cmd)) target_put_sess_cmd(cmd); } } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 47318f64296d..3f95ddea6b1c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -688,23 +688,27 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) percpu_ref_put(&lun->lun_ref); } -int transport_cmd_finish_abort(struct se_cmd *cmd, int remove) +int transport_cmd_finish_abort(struct se_cmd *cmd) { + bool send_tas = cmd->transport_state & CMD_T_TAS; bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF); int ret = 0; + if (send_tas) + transport_send_task_abort(cmd); + if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) transport_lun_remove_cmd(cmd); /* * Allow the fabric driver to unmap any resources before * releasing the descriptor via TFO->release_cmd() */ - if (remove) + if (!send_tas) cmd->se_tfo->aborted_task(cmd); if (transport_cmd_check_stop_to_fabric(cmd)) return 1; - if (remove && ack_kref) + if (!send_tas && ack_kref) ret = target_put_sess_cmd(cmd); return ret; -- cgit v1.2.3 From a8864d861d62feadc5f37c6651a7d7a2fc2477a8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:57 -0700 Subject: scsi: target: Simplify transport_generic_free_cmd() (1/2) Move identical code outside an if/else statement. This patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3f95ddea6b1c..65995532d02b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2664,9 +2664,6 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) target_wait_free_cmd(cmd, &aborted, &tas); - - if (!aborted || tas) - ret = target_put_sess_cmd(cmd); } else { if (wait_for_tasks) target_wait_free_cmd(cmd, &aborted, &tas); @@ -2680,10 +2677,9 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (cmd->se_lun) transport_lun_remove_cmd(cmd); - - if (!aborted || tas) - ret = target_put_sess_cmd(cmd); } + if (!aborted || tas) + ret = target_put_sess_cmd(cmd); if (aborted) { pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag); wait_for_completion(&cmd->cmd_wait_comp); -- cgit v1.2.3 From edf46eee59c5acd829c3b6a564c26b5386362ea3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:58 -0700 Subject: scsi: target: Simplify transport_generic_free_cmd() (2/2) Since target_wait_free_cmd() skips TMFs with no associated LUN, it is safe to call that function for such commands. Use this to simplify transport_generic_free_cmd(). The only functional change in this patch is that CMD_T_FABRIC_STOP gets set for TMFs with no associated LUN by transport_generic_free_cmd(). Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 65995532d02b..ebd54fc1f13a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2661,12 +2661,10 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) int ret = 0; bool aborted = false, tas = false; - if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { - if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) - target_wait_free_cmd(cmd, &aborted, &tas); - } else { - if (wait_for_tasks) - target_wait_free_cmd(cmd, &aborted, &tas); + if (wait_for_tasks) + target_wait_free_cmd(cmd, &aborted, &tas); + + if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) { /* * Handle WRITE failure case where transport_generic_new_cmd() * has already added se_cmd to state_list, but fabric has -- cgit v1.2.3 From 7b2cc7dc0dbf5da9cf16ffcf1ca8e904ab574ff5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:52:59 -0700 Subject: scsi: target: Simplify the code for waiting for command completion Instead of embedding the completion that is used for waiting for command completion in struct se_cmd, let the context that waits for command completion allocate it. This makes it possible to have a single code path for non-aborted and aborted commands in target_release_cmd_kref() and avoids that transport_generic_free_cmd() has to call cmd->se_tfo->release_cmd() directly. This patch does not change any functionality. Note: transport_generic_free_cmd() only waits until the se_cmd reference count has reached zero after it has set both CMD_T_FABRIC_STOP and CMD_T_ABORTED. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 24 ++++++++---------------- include/target/target_core_base.h | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ebd54fc1f13a..cb48dbc2c9ba 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1309,7 +1309,7 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->state_list); init_completion(&cmd->t_transport_stop_comp); - init_completion(&cmd->cmd_wait_comp); + cmd->compl = NULL; spin_lock_init(&cmd->t_state_lock); INIT_WORK(&cmd->work, NULL); kref_init(&cmd->cmd_kref); @@ -2658,6 +2658,7 @@ static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas) */ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { + DECLARE_COMPLETION_ONSTACK(compl); int ret = 0; bool aborted = false, tas = false; @@ -2676,12 +2677,13 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (cmd->se_lun) transport_lun_remove_cmd(cmd); } + if (aborted) + cmd->compl = &compl; if (!aborted || tas) ret = target_put_sess_cmd(cmd); if (aborted) { pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag); - wait_for_completion(&cmd->cmd_wait_comp); - cmd->se_tfo->release_cmd(cmd); + wait_for_completion(&compl); ret = 1; } return ret; @@ -2742,31 +2744,21 @@ static void target_release_cmd_kref(struct kref *kref) { struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); struct se_session *se_sess = se_cmd->se_sess; + struct completion *compl = se_cmd->compl; unsigned long flags; - bool fabric_stop; if (se_sess) { spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_del_init(&se_cmd->se_cmd_list); if (list_empty(&se_sess->sess_cmd_list)) wake_up(&se_sess->cmd_list_wq); - - spin_lock(&se_cmd->t_state_lock); - fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) && - (se_cmd->transport_state & CMD_T_ABORTED); - spin_unlock(&se_cmd->t_state_lock); - - if (fabric_stop) { - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - target_free_cmd_mem(se_cmd); - complete(&se_cmd->cmd_wait_comp); - return; - } spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } target_free_cmd_mem(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd); + if (compl) + complete(compl); } /** diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 906c1fc485e4..ca59e065c1fd 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -475,7 +475,7 @@ struct se_cmd { struct se_session *se_sess; struct se_tmr_req *se_tmr_req; struct list_head se_cmd_list; - struct completion cmd_wait_comp; + struct completion *compl; const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool, int *); -- cgit v1.2.3 From ed88f055788a89598c33d183652af8a84dfc5007 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:00 -0700 Subject: scsi: target/iscsi: Reduce number of __iscsit_free_cmd() callers Instead of calling __iscsit_free_cmd() from inside iscsit_aborted_task() if a command has been aborted and from inside iscsit_free_cmd() if a command has not been aborted, call __iscsit_free_cmd() from inside lio_release_cmd(). The latter function is namely called for all commands once the reference count has dropped to zero. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Varun Prakash Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 2 -- drivers/target/iscsi/iscsi_target_configfs.c | 1 + drivers/target/iscsi/iscsi_target_util.c | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 8e223799347a..d547dcd625d9 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -497,8 +497,6 @@ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) !(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, true); } EXPORT_SYMBOL(iscsit_aborted_task); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0ebc4818e132..0bc346b2c27c 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1546,6 +1546,7 @@ static void lio_release_cmd(struct se_cmd *se_cmd) struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd); + __iscsit_free_cmd(cmd, true); iscsit_release_cmd(cmd); } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 8cfcf9033507..5a645b5f1eb4 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -772,10 +772,8 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool 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); + if (!rc && shutdown && se_cmd->se_sess) target_put_sess_cmd(se_cmd); - } } else { iscsit_release_cmd(cmd); } -- cgit v1.2.3 From 35bea5c84fd13c643cce63f0b5cd4b148f8c901d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:01 -0700 Subject: scsi: target/iscsi: Make iscsit_ta_authentication() respect the output buffer size Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_tpg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 4b34f71547c6..101d62105c93 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -636,8 +636,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) none = strstr(buf1, NONE); if (none) goto out; - strncat(buf1, ",", strlen(",")); - strncat(buf1, NONE, strlen(NONE)); + strlcat(buf1, "," NONE, sizeof(buf1)); if (iscsi_update_param_value(param, buf1) < 0) return -EINVAL; } -- cgit v1.2.3 From aa090eabcb341b0c023e802884235c29598df1e5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:02 -0700 Subject: scsi: target: Remove second argument from fabric_make_tpg() Since most target drivers do not use the second fabric_make_tpg() argument ("group") and since it is trivial to derive the group pointer from the wwn pointer, do not pass the group pointer to fabric_make_tpg(). Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Felipe Balbi Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 -- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 12 ++++-------- drivers/target/iscsi/iscsi_target_configfs.c | 6 ++---- drivers/target/loopback/tcm_loop.c | 6 ++---- drivers/target/sbp/sbp_target.c | 6 ++---- drivers/target/target_core_fabric_configfs.c | 2 +- drivers/target/tcm_fc/tfc_conf.c | 5 +---- drivers/usb/gadget/function/f_tcm.c | 8 +++----- drivers/vhost/scsi.c | 4 +--- drivers/xen/xen-scsiback.c | 4 +--- include/target/target_core_fabric.h | 2 +- 12 files changed, 18 insertions(+), 40 deletions(-) (limited to 'drivers/target') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 3081c629a7f7..07b3e1c583bd 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3597,11 +3597,9 @@ static struct configfs_attribute *srpt_tpg_attrs[] = { /** * srpt_make_tpg - configfs callback invoked for mkdir /sys/kernel/config/target/$driver/$port/$tpg * @wwn: Corresponds to $driver/$port. - * @group: Not used. * @name: $tpg. */ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, - struct config_group *group, const char *name) { struct srpt_port *sport = wwn->priv; diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index c3a76af9f5fa..fdda04e5cf94 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -3928,7 +3928,6 @@ static void ibmvscsis_drop_tport(struct se_wwn *wwn) } static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, - struct config_group *group, const char *name) { struct ibmvscsis_tport *tport = diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 7732e9336d43..cfb5d6067f9f 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1049,10 +1049,8 @@ static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = { NULL, }; -static struct se_portal_group *tcm_qla2xxx_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *tcm_qla2xxx_make_tpg(struct se_wwn *wwn, + const char *name) { struct tcm_qla2xxx_lport *lport = container_of(wwn, struct tcm_qla2xxx_lport, lport_wwn); @@ -1171,10 +1169,8 @@ static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = { NULL, }; -static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(struct se_wwn *wwn, + const char *name) { struct tcm_qla2xxx_lport *lport = container_of(wwn, struct tcm_qla2xxx_lport, lport_wwn); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0bc346b2c27c..1fcd9bc7189d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1090,10 +1090,8 @@ static struct configfs_attribute *lio_target_tpg_attrs[] = { /* Start items for lio_target_tiqn_cit */ -static struct se_portal_group *lio_target_tiqn_addtpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *lio_target_tiqn_addtpg(struct se_wwn *wwn, + const char *name) { struct iscsi_portal_group *tpg; struct iscsi_tiqn *tiqn; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 60d5b918c4ac..4c8a97711291 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -983,10 +983,8 @@ static struct configfs_attribute *tcm_loop_tpg_attrs[] = { /* Start items for tcm_loop_naa_cit */ -static struct se_portal_group *tcm_loop_make_naa_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *tcm_loop_make_naa_tpg(struct se_wwn *wwn, + const char *name) { struct tcm_loop_hba *tl_hba = container_of(wwn, struct tcm_loop_hba, tl_hba_wwn); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 42b21f2ac8b0..b61b79ac98ff 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2006,10 +2006,8 @@ static void sbp_pre_unlink_lun( pr_err("unlink LUN: failed to update unit directory\n"); } -static struct se_portal_group *sbp_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *sbp_make_tpg(struct se_wwn *wwn, + const char *name) { struct sbp_tport *tport = container_of(wwn, struct sbp_tport, tport_wwn); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index e1416b007aa4..1fa436e865f9 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -841,7 +841,7 @@ static struct config_group *target_fabric_make_tpg( return ERR_PTR(-ENOSYS); } - se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name); + se_tpg = tf->tf_ops->fabric_make_tpg(wwn, name); if (!se_tpg || IS_ERR(se_tpg)) return ERR_PTR(-EINVAL); diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 42ee91123dca..e55c4d537592 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -223,10 +223,7 @@ static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name) /* * local_port port_group (tpg) ops. */ -static struct se_portal_group *ft_add_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *ft_add_tpg(struct se_wwn *wwn, const char *name) { struct ft_lport_wwn *ft_wwn; struct ft_tpg *tpg; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 5003e857dce7..4f183176b0b4 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1344,10 +1344,8 @@ static int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name) return 0; } -static struct se_portal_group *usbg_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) +static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn, + const char *name) { struct usbg_tport *tport = container_of(wwn, struct usbg_tport, tport_wwn); @@ -1380,7 +1378,7 @@ static struct se_portal_group *usbg_make_tpg( goto unlock_dep; } else { ret = configfs_depend_item_unlocked( - group->cg_subsys, + wwn->wwn_group.cg_subsys, &opts->func_inst.group.cg_item); if (ret) goto unlock_dep; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index ebaf831285ea..c84a6edd4c25 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1912,9 +1912,7 @@ static struct configfs_attribute *vhost_scsi_tpg_attrs[] = { }; static struct se_portal_group * -vhost_scsi_make_tpg(struct se_wwn *wwn, - struct config_group *group, - const char *name) +vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name) { struct vhost_scsi_tport *tport = container_of(wwn, struct vhost_scsi_tport, tport_wwn); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 764dd9aa0131..fd77ccfc7d6e 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1732,9 +1732,7 @@ static void scsiback_port_unlink(struct se_portal_group *se_tpg, } static struct se_portal_group * -scsiback_make_tpg(struct se_wwn *wwn, - struct config_group *group, - const char *name) +scsiback_make_tpg(struct se_wwn *wwn, const char *name) { struct scsiback_tport *tport = container_of(wwn, struct scsiback_tport, tport_wwn); diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 84a681b6e5ca..f61aa716cfe1 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -79,7 +79,7 @@ struct target_core_fabric_ops { void (*fabric_drop_wwn)(struct se_wwn *); void (*add_wwn_groups)(struct se_wwn *); struct se_portal_group *(*fabric_make_tpg)(struct se_wwn *, - struct config_group *, const char *); + const char *); void (*fabric_drop_tpg)(struct se_portal_group *); int (*fabric_post_link)(struct se_portal_group *, struct se_lun *); -- cgit v1.2.3 From 799d44d0fab60a96a0f13cdb13c9cc94ce06765e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:03 -0700 Subject: scsi: target/tcm_loop: Avoid that static checkers warn about dead code The code under the "release:" label can only be reached after se_cmd has been set to a non-NULL value. Hence remove the if (se_cmd) test. Keep the else-part since calling transport_generic_free_cmd() is not necessary for a command that has not been submitted to the core. Reported-by: Dan Carpenter Fixes: 4d3895d5ea43 ("target/tcm_loop: Merge struct tcm_loop_cmd and struct tcm_loop_tmr") Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Dan Carpenter Cc: Hannes Reinecke Cc: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/loopback/tcm_loop.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 4c8a97711291..b2e7ff50ff61 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -239,10 +239,7 @@ out: return ret; release: - if (se_cmd) - transport_generic_free_cmd(se_cmd, 0); - else - kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); + kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); goto out; } -- cgit v1.2.3 From 89a104ed4f6a6876c25fbe8de0253b89466869f0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:04 -0700 Subject: scsi: target: Do not duplicate the code that marks that a command has sense data This patch does not change any functionality. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index cb48dbc2c9ba..ebbc7e321cf3 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2121,9 +2121,6 @@ static void transport_complete_qf(struct se_cmd *cmd) if (cmd->scsi_status) goto queue_status; - cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - cmd->scsi_status = SAM_STAT_CHECK_CONDITION; - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; translate_sense_reason(cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE); goto queue_status; } @@ -3199,6 +3196,9 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) ascq = si->ascq; } + cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; + cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq); if (si->add_sector_info) return scsi_set_sense_information(buffer, @@ -3225,9 +3225,6 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, if (!from_transport) { int rc; - cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - cmd->scsi_status = SAM_STAT_CHECK_CONDITION; - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; rc = translate_sense_reason(cmd, reason); if (rc) return rc; -- cgit v1.2.3 From 17e391dd09f5b257365367ce812a4332dc2c9653 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:05 -0700 Subject: scsi: target: Send unit attention condition even if the sense buffer is too small Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ebbc7e321cf3..a71cfae46805 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -64,7 +64,7 @@ struct kmem_cache *t10_alua_lba_map_cache; struct kmem_cache *t10_alua_lba_map_mem_cache; static void transport_complete_task_attr(struct se_cmd *cmd); -static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason); +static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev, int err, bool write_pending); static void target_complete_ok_work(struct work_struct *work); @@ -3170,7 +3170,7 @@ static const struct sense_info sense_info_table[] = { }, }; -static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) +static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) { const struct sense_info *si; u8 *buffer = cmd->sense_buffer; @@ -3201,11 +3201,9 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq); if (si->add_sector_info) - return scsi_set_sense_information(buffer, - cmd->scsi_sense_length, - cmd->bad_sector); - - return 0; + WARN_ON_ONCE(scsi_set_sense_information(buffer, + cmd->scsi_sense_length, + cmd->bad_sector) < 0); } int @@ -3222,13 +3220,8 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (!from_transport) { - int rc; - - rc = translate_sense_reason(cmd, reason); - if (rc) - return rc; - } + if (!from_transport) + translate_sense_reason(cmd, reason); trace_target_cmd_complete(cmd); return cmd->se_tfo->queue_status(cmd); -- cgit v1.2.3 From 325c1e8b248ed12a685d0a904b774abef3821e8e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:06 -0700 Subject: scsi: target: Fix handling of removed LUNs Send a valid ASC / ASCQ combination back to the initiator if a SCSI command is received after a LUN has been removed. This patch fixes the following call trace: WARNING: CPU: 0 PID: 4 at drivers/target/target_core_transport.c:3131 translate_sense_reason+0x164/0x190 [target_core_mod] Workqueue: ib-comp-wq ib_cq_poll_work [ib_core] RIP: 0010:translate_sense_reason+0x164/0x190 [target_core_mod] Call Trace: transport_send_check_condition_and_sense+0x95/0x1c0 [target_core_mod] transport_generic_request_failure+0x102/0x270 [target_core_mod] transport_generic_new_cmd+0x138/0x340 [target_core_mod] transport_handle_cdb_direct+0x2f/0x80 [target_core_mod] target_submit_cmd_map_sgls+0x212/0x2a0 [target_core_mod] srpt_handle_new_iu+0x244/0x680 [ib_srpt] __ib_process_cq+0x6d/0xc0 [ib_core] ib_cq_poll_work+0x18/0x50 [ib_core] process_one_work+0x20b/0x6a0 worker_thread+0x35/0x380 kthread+0x117/0x130 ret_from_fork+0x24/0x30 Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 23 +++++++++++++++++++---- drivers/target/target_core_ua.c | 31 ++++++++++++++++++------------- drivers/target/target_core_ua.h | 3 ++- 3 files changed, 39 insertions(+), 18 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a71cfae46805..7261561e87cc 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3170,12 +3170,23 @@ static const struct sense_info sense_info_table[] = { }, }; +/** + * translate_sense_reason - translate a sense reason into T10 key, asc and ascq + * @cmd: SCSI command in which the resulting sense buffer or SCSI status will + * be stored. + * @reason: LIO sense reason code. If this argument has the value + * TCM_CHECK_CONDITION_UNIT_ATTENTION, try to dequeue a unit attention. If + * dequeuing a unit attention fails due to multiple commands being processed + * concurrently, set the command status to BUSY. + * + * Return: 0 upon success or -EINVAL if the sense buffer is too small. + */ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) { const struct sense_info *si; u8 *buffer = cmd->sense_buffer; int r = (__force int)reason; - u8 asc, ascq; + u8 key, asc, ascq; bool desc_format = target_sense_desc_format(cmd->se_dev); if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) @@ -3184,9 +3195,13 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) si = &sense_info_table[(__force int) TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; + key = si->key; if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { - core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); - WARN_ON_ONCE(asc == 0); + if (!core_scsi3_ua_for_check_condition(cmd, &key, &asc, + &ascq)) { + cmd->scsi_status = SAM_STAT_BUSY; + return; + } } else if (si->asc == 0) { WARN_ON_ONCE(cmd->scsi_asc == 0); asc = cmd->scsi_asc; @@ -3199,7 +3214,7 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; cmd->scsi_status = SAM_STAT_CHECK_CONDITION; cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; - scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq); + scsi_build_sense_buffer(desc_format, buffer, key, asc, ascq); if (si->add_sector_info) WARN_ON_ONCE(scsi_set_sense_information(buffer, cmd->scsi_sense_length, diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index be25eb807a5f..9399b38339f9 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -202,10 +202,13 @@ void core_scsi3_ua_release_all( spin_unlock(&deve->ua_lock); } -void core_scsi3_ua_for_check_condition( - struct se_cmd *cmd, - u8 *asc, - u8 *ascq) +/* + * Dequeue a unit attention from the unit attention list. This function + * returns true if the dequeuing succeeded and if *@key, *@asc and *@ascq have + * been set. + */ +bool core_scsi3_ua_for_check_condition(struct se_cmd *cmd, u8 *key, u8 *asc, + u8 *ascq) { struct se_device *dev = cmd->se_dev; struct se_dev_entry *deve; @@ -214,23 +217,23 @@ void core_scsi3_ua_for_check_condition( struct se_ua *ua = NULL, *ua_p; int head = 1; - if (!sess) - return; + if (WARN_ON_ONCE(!sess)) + return false; nacl = sess->se_node_acl; - if (!nacl) - return; + if (WARN_ON_ONCE(!nacl)) + return false; rcu_read_lock(); deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); if (!deve) { rcu_read_unlock(); - return; - } - if (!atomic_read(&deve->ua_count)) { - rcu_read_unlock(); - return; + *key = ILLEGAL_REQUEST; + *asc = 0x25; /* LOGICAL UNIT NOT SUPPORTED */ + *ascq = 0; + return true; } + *key = UNIT_ATTENTION; /* * The highest priority Unit Attentions are placed at the head of the * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION + @@ -273,6 +276,8 @@ void core_scsi3_ua_for_check_condition( (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : "Releasing", dev->dev_attrib.emulate_ua_intlck_ctrl, cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq); + + return head == 0; } int core_scsi3_ua_clear_for_request_sense( diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index b0f4205a96cd..76487c9be090 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -37,7 +37,8 @@ extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); extern int core_scsi3_ua_allocate(struct se_dev_entry *, u8, u8); extern void target_ua_allocate_lun(struct se_node_acl *, u32, u8, u8); extern void core_scsi3_ua_release_all(struct se_dev_entry *); -extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); +extern bool core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *, + u8 *); extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *, u8 *, u8 *); -- cgit v1.2.3 From e936a38ac92dd40867ac3b52cfd8f3f70fe717a5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 22 Jun 2018 14:53:07 -0700 Subject: scsi: target: Remove se_dev_entry.ua_count se_dev_entry.ua_count is only used to check whether or not se_dev_entry.ua_list is empty. Use list_empty_careful() instead. Checking whether or not ua_list is empty without holding the lock that protects that list is fine because the code that dequeues from that list will check again whether or not that list is empty. Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_device.c | 1 - drivers/target/target_core_ua.c | 12 ++---------- include/target/target_core_base.h | 1 - 3 files changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e5c90afb40e6..73675eec740d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -336,7 +336,6 @@ int core_enable_device_list_for_node( return -ENOMEM; } - atomic_set(&new->ua_count, 0); spin_lock_init(&new->ua_lock); INIT_LIST_HEAD(&new->ua_list); INIT_LIST_HEAD(&new->lun_link); diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 9399b38339f9..c8ac242ce888 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -55,7 +55,7 @@ target_scsi3_ua_check(struct se_cmd *cmd) rcu_read_unlock(); return 0; } - if (!atomic_read(&deve->ua_count)) { + if (list_empty_careful(&deve->ua_list)) { rcu_read_unlock(); return 0; } @@ -154,7 +154,6 @@ int core_scsi3_ua_allocate( &deve->ua_list); spin_unlock(&deve->ua_lock); - atomic_inc_mb(&deve->ua_count); return 0; } list_add_tail(&ua->ua_nacl_list, &deve->ua_list); @@ -164,7 +163,6 @@ int core_scsi3_ua_allocate( " 0x%02x, ASCQ: 0x%02x\n", deve->mapped_lun, asc, ascq); - atomic_inc_mb(&deve->ua_count); return 0; } @@ -196,8 +194,6 @@ void core_scsi3_ua_release_all( list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { list_del(&ua->ua_nacl_list); kmem_cache_free(se_ua_cache, ua); - - atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); } @@ -263,8 +259,6 @@ bool core_scsi3_ua_for_check_condition(struct se_cmd *cmd, u8 *key, u8 *asc, } list_del(&ua->ua_nacl_list); kmem_cache_free(se_ua_cache, ua); - - atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); rcu_read_unlock(); @@ -304,7 +298,7 @@ int core_scsi3_ua_clear_for_request_sense( rcu_read_unlock(); return -EINVAL; } - if (!atomic_read(&deve->ua_count)) { + if (list_empty_careful(&deve->ua_list)) { rcu_read_unlock(); return -EPERM; } @@ -327,8 +321,6 @@ int core_scsi3_ua_clear_for_request_sense( } list_del(&ua->ua_nacl_list); kmem_cache_free(se_ua_cache, ua); - - atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); rcu_read_unlock(); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index ca59e065c1fd..7a4ee7852ca4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -638,7 +638,6 @@ struct se_dev_entry { atomic_long_t total_cmds; atomic_long_t read_bytes; atomic_long_t write_bytes; - atomic_t ua_count; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ struct kref pr_kref; struct completion pr_comp; -- cgit v1.2.3 From f0e89aae609bebd430ce7a96d2f642917d89ca57 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:43 -0500 Subject: scsi: target_core_user: fix double unlock The caller of queue_cmd_ring grabs and releases the lock, so the tcmu_setup_cmd_timer failure handling inside queue_cmd_ring should not call mutex_unlock. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 847707a700cf..fafe65fd37f4 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1066,7 +1066,6 @@ static sense_reason_t queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, int *scsi_err) &udev->cmd_timer); if (ret) { tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt); - mutex_unlock(&udev->cmdr_lock); *scsi_err = TCM_OUT_OF_RESOURCES; return -1; -- cgit v1.2.3 From ff07e4a414d963d5b1ee1446f05a451e591256de Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:44 -0500 Subject: scsi: tcmu: initialize list head Use INIT_LIST_HEAD to initialize node list head. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index fafe65fd37f4..b010ed7e877b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1342,6 +1342,7 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) udev->max_blocks = DATA_BLOCK_BITS_DEF; mutex_init(&udev->cmdr_lock); + INIT_LIST_HEAD(&udev->node); INIT_LIST_HEAD(&udev->timedout_entry); INIT_LIST_HEAD(&udev->cmdr_queue); idr_init(&udev->commands); -- cgit v1.2.3 From cb0f32e12cded06e12ff19104eaf90c6f8310558 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:45 -0500 Subject: scsi: target: add helper to check if dev is configured This just adds a helper function to check if a device is configured and it converts the target users to use it. The next patch will add a backend module user so those types of modules do not have to know the lio core details. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 8 ++++---- drivers/target/target_core_device.c | 6 +++--- drivers/target/target_core_fabric_configfs.c | 3 ++- include/target/target_core_backend.h | 4 ++++ 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 93d3ff34b614..f6b1549f4142 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -810,7 +810,7 @@ static ssize_t pi_prot_type_store(struct config_item *item, dev->transport->name); return -ENOSYS; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("DIF protection requires device to be configured\n"); return -ENODEV; } @@ -859,7 +859,7 @@ static ssize_t pi_prot_format_store(struct config_item *item, dev->transport->name); return -ENOSYS; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("DIF protection format requires device to be configured\n"); return -ENODEV; } @@ -1948,7 +1948,7 @@ static ssize_t target_dev_enable_show(struct config_item *item, char *page) { struct se_device *dev = to_device(item); - return snprintf(page, PAGE_SIZE, "%d\n", !!(dev->dev_flags & DF_CONFIGURED)); + return snprintf(page, PAGE_SIZE, "%d\n", target_dev_configured(dev)); } static ssize_t target_dev_enable_store(struct config_item *item, @@ -2473,7 +2473,7 @@ static ssize_t target_tg_pt_gp_alua_access_state_store(struct config_item *item, " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id); return -EINVAL; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("Unable to set alua_access_state while device is" " not configured\n"); return -ENODEV; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 73675eec740d..47b5ef153135 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -900,7 +900,7 @@ static int target_devices_idr_iter(int id, void *p, void *data) * to allow other callers to access partially setup devices, * so we skip them here. */ - if (!(dev->dev_flags & DF_CONFIGURED)) + if (!target_dev_configured(dev)) return 0; iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item); @@ -940,7 +940,7 @@ int target_configure_device(struct se_device *dev) struct se_hba *hba = dev->se_hba; int ret, id; - if (dev->dev_flags & DF_CONFIGURED) { + if (target_dev_configured(dev)) { pr_err("se_dev->se_dev_ptr already set for storage" " object\n"); return -EEXIST; @@ -1045,7 +1045,7 @@ void target_free_device(struct se_device *dev) WARN_ON(!list_empty(&dev->dev_sep_list)); - if (dev->dev_flags & DF_CONFIGURED) { + if (target_dev_configured(dev)) { destroy_workqueue(dev->tmr_wq); dev->transport->destroy_device(dev); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 1fa436e865f9..aa2f4f632ebe 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -34,6 +34,7 @@ #include #include +#include #include #include "target_core_internal.h" @@ -642,7 +643,7 @@ static int target_fabric_port_link( } dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group); - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("se_device not configured yet, cannot port link\n"); return -ENODEV; } diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index c3ac47255218..51b6f50eabee 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -111,6 +111,10 @@ 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); +static inline bool target_dev_configured(struct se_device *se_dev) +{ + return !!(se_dev->dev_flags & DF_CONFIGURED); +} /* Only use get_unaligned_be24() if reading p - 1 is allowed. */ static inline uint32_t get_unaligned_be24(const uint8_t *const p) -- cgit v1.2.3 From 63d5be0f6a8053ba0c084dd6e2d5538e9376e7da Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:46 -0500 Subject: scsi: tcmu: use lio core se_device configuration helper Use the lio core helper to check if the device is configured. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index b010ed7e877b..bc8121f97d65 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1908,11 +1908,6 @@ err_bitmap_alloc: return ret; } -static bool tcmu_dev_configured(struct tcmu_dev *udev) -{ - return udev->uio_info.uio_dev ? true : false; -} - static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); @@ -2305,7 +2300,7 @@ static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, return -EINVAL; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(&udev->se_dev)) { ret = tcmu_send_dev_config_event(udev, page); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -2367,7 +2362,7 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, return ret; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(&udev->se_dev)) { ret = tcmu_send_dev_size_event(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -2449,7 +2444,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, return ret; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(&udev->se_dev)) { ret = tcmu_send_emulate_write_cache(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); -- cgit v1.2.3 From a30b0473b62652f9b8ccb1e4f4a3a3c31d2b72b3 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:47 -0500 Subject: scsi: tcmu: check if dev is configured before block/reset Do not allow userspace to block or reset the ring until the device has been configured. This will prevent the bug where userspace can write to those files and access mb_addr before it has been setup. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index bc8121f97d65..d6b402203b20 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2480,6 +2480,11 @@ static ssize_t tcmu_block_dev_store(struct config_item *item, const char *page, u8 val; int ret; + if (!target_dev_configured(&udev->se_dev)) { + pr_err("Device is not configured.\n"); + return -EINVAL; + } + ret = kstrtou8(page, 0, &val); if (ret < 0) return ret; @@ -2507,6 +2512,11 @@ static ssize_t tcmu_reset_ring_store(struct config_item *item, const char *page, u8 val; int ret; + if (!target_dev_configured(&udev->se_dev)) { + pr_err("Device is not configured.\n"); + return -EINVAL; + } + ret = kstrtou8(page, 0, &val); if (ret < 0) return ret; -- cgit v1.2.3 From dc335a995527fb1ee9ec5649162b22cd1ce728ee Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:48 -0500 Subject: scsi: tcmu: unmap if dev is configured The tcmu dev is added to the list of tcmu devices during configuration. At this time the tcmu setup has completed, but lio core has not completed its setup. The device is not yet usable so do not try to unmap blocks from it Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index d6b402203b20..31cfe8345ef3 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2581,6 +2581,11 @@ static void find_free_blocks(void) list_for_each_entry(udev, &root_udev, node) { mutex_lock(&udev->cmdr_lock); + if (!target_dev_configured(&udev->se_dev)) { + mutex_unlock(&udev->cmdr_lock); + continue; + } + /* Try to complete the finished commands first */ tcmu_handle_completions(udev); -- cgit v1.2.3 From c97840c84f5a4362a596a2751e9245a979377a16 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:49 -0500 Subject: scsi: tcmu: do not set max_blocks if data_bitmap has been setup This patch prevents a bug where data_bitmap is allocated in tcmu_configure_device, userspace changes the max_blocks setting, the device is mapped to a LUN, then we try to access the data_bitmap based on the new max_blocks limit which may now be out of range. To prevent this, we just check if data_bitmap has been setup. If it has then we fail the max_blocks update operation. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 73 +++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 31cfe8345ef3..969ccbaaccba 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1811,9 +1811,11 @@ static int tcmu_configure_device(struct se_device *dev) info = &udev->uio_info; + mutex_lock(&udev->cmdr_lock); udev->data_bitmap = kcalloc(BITS_TO_LONGS(udev->max_blocks), sizeof(unsigned long), GFP_KERNEL); + mutex_unlock(&udev->cmdr_lock); if (!udev->data_bitmap) { ret = -ENOMEM; goto err_bitmap_alloc; @@ -2018,7 +2020,7 @@ static match_table_t tokens = { {Opt_hw_block_size, "hw_block_size=%u"}, {Opt_hw_max_sectors, "hw_max_sectors=%u"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, - {Opt_max_data_area_mb, "max_data_area_mb=%u"}, + {Opt_max_data_area_mb, "max_data_area_mb=%d"}, {Opt_err, NULL} }; @@ -2046,13 +2048,48 @@ static int tcmu_set_dev_attrib(substring_t *arg, u32 *dev_attrib) return 0; } +static int tcmu_set_max_blocks_param(struct tcmu_dev *udev, substring_t *arg) +{ + int val, ret; + + ret = match_int(arg, &val); + if (ret < 0) { + pr_err("match_int() failed for max_data_area_mb=. Error %d.\n", + ret); + return ret; + } + + if (val <= 0) { + pr_err("Invalid max_data_area %d.\n", val); + return -EINVAL; + } + + mutex_lock(&udev->cmdr_lock); + if (udev->data_bitmap) { + pr_err("Cannot set max_data_area_mb after it has been enabled.\n"); + ret = -EINVAL; + goto unlock; + } + + udev->max_blocks = TCMU_MBS_TO_BLOCKS(val); + if (udev->max_blocks > tcmu_global_max_blocks) { + pr_err("%d is too large. Adjusting max_data_area_mb to global limit of %u\n", + val, TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); + udev->max_blocks = tcmu_global_max_blocks; + } + +unlock: + mutex_unlock(&udev->cmdr_lock); + return ret; +} + static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) { struct tcmu_dev *udev = TCMU_DEV(dev); char *orig, *ptr, *opts, *arg_p; substring_t args[MAX_OPT_ARGS]; - int ret = 0, token, tmpval; + int ret = 0, token; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -2105,37 +2142,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, pr_err("kstrtoint() failed for nl_reply_supported=\n"); break; case Opt_max_data_area_mb: - if (dev->export_count) { - pr_err("Unable to set max_data_area_mb while exports exist\n"); - ret = -EINVAL; - break; - } - - arg_p = match_strdup(&args[0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoint(arg_p, 0, &tmpval); - kfree(arg_p); - if (ret < 0) { - pr_err("kstrtoint() failed for max_data_area_mb=\n"); - break; - } - - if (tmpval <= 0) { - pr_err("Invalid max_data_area %d\n", tmpval); - ret = -EINVAL; - break; - } - - udev->max_blocks = TCMU_MBS_TO_BLOCKS(tmpval); - if (udev->max_blocks > tcmu_global_max_blocks) { - pr_err("%d is too large. Adjusting max_data_area_mb to global limit of %u\n", - tmpval, - TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); - udev->max_blocks = tcmu_global_max_blocks; - } + ret = tcmu_set_max_blocks_param(udev, &args[0]); break; default: break; -- cgit v1.2.3 From b60cb1f80157689d206b09affc43c2dc1cafcbc8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:50 -0500 Subject: scsi: tcmu: use match_int for dev params Instead of doing strdup and kstrto* just use match_int for dev params. It will be ok to use int instead of unsigned long in tcmu_set_dev_attrib because that is only being used for max sectors and block size and the supported values for them are well under the max possible integer value. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 969ccbaaccba..cfe4f4b8c45c 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2017,8 +2017,8 @@ enum { static match_table_t tokens = { {Opt_dev_config, "dev_config=%s"}, {Opt_dev_size, "dev_size=%u"}, - {Opt_hw_block_size, "hw_block_size=%u"}, - {Opt_hw_max_sectors, "hw_max_sectors=%u"}, + {Opt_hw_block_size, "hw_block_size=%d"}, + {Opt_hw_max_sectors, "hw_max_sectors=%d"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, {Opt_max_data_area_mb, "max_data_area_mb=%d"}, {Opt_err, NULL} @@ -2026,25 +2026,21 @@ static match_table_t tokens = { static int tcmu_set_dev_attrib(substring_t *arg, u32 *dev_attrib) { - unsigned long tmp_ul; - char *arg_p; - int ret; - - arg_p = match_strdup(arg); - if (!arg_p) - return -ENOMEM; + int val, ret; - ret = kstrtoul(arg_p, 0, &tmp_ul); - kfree(arg_p); + ret = match_int(arg, &val); if (ret < 0) { - pr_err("kstrtoul() failed for dev attrib\n"); + pr_err("match_int() failed for dev attrib. Error %d.\n", + ret); return ret; } - if (!tmp_ul) { - pr_err("dev attrib must be nonzero\n"); + + if (val <= 0) { + pr_err("Invalid dev attrib value %d. Must be greater than zero.\n", + val); return -EINVAL; } - *dev_attrib = tmp_ul; + *dev_attrib = val; return 0; } @@ -2131,15 +2127,10 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, &(dev->dev_attrib.hw_max_sectors)); break; case Opt_nl_reply_supported: - arg_p = match_strdup(&args[0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoint(arg_p, 0, &udev->nl_reply_supported); - kfree(arg_p); + ret = match_int(&args[0], &udev->nl_reply_supported); if (ret < 0) - pr_err("kstrtoint() failed for nl_reply_supported=\n"); + pr_err("match_int() failed for nl_reply_supported=. Error %d.\n", + ret); break; case Opt_max_data_area_mb: ret = tcmu_set_max_blocks_param(udev, &args[0]); -- cgit v1.2.3 From 0e0d75267107e6a557ea9314d55bcff05a6ede44 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 23 Jul 2018 14:07:51 -0500 Subject: scsi: tcmu: use u64 for dev_size We use unsigned long, size_t and u64 for dev_size. This has us standardize on u64. Signed-off-by: Mike Christie Reviewed-by: Xiubo Li Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index cfe4f4b8c45c..b34179ae71ae 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -137,7 +137,7 @@ struct tcmu_dev { struct inode *inode; struct tcmu_mailbox *mb_addr; - size_t dev_size; + uint64_t dev_size; u32 cmdr_size; u32 cmdr_last_cleaned; /* Offset of data area from start of mb */ @@ -2016,7 +2016,7 @@ enum { static match_table_t tokens = { {Opt_dev_config, "dev_config=%s"}, - {Opt_dev_size, "dev_size=%u"}, + {Opt_dev_size, "dev_size=%s"}, {Opt_hw_block_size, "hw_block_size=%d"}, {Opt_hw_max_sectors, "hw_max_sectors=%d"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, @@ -2083,7 +2083,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) { struct tcmu_dev *udev = TCMU_DEV(dev); - char *orig, *ptr, *opts, *arg_p; + char *orig, *ptr, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, token; @@ -2108,15 +2108,10 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, pr_debug("TCMU: Referencing Path: %s\n", udev->dev_config); break; case Opt_dev_size: - arg_p = match_strdup(&args[0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoul(arg_p, 0, (unsigned long *) &udev->dev_size); - kfree(arg_p); + ret = match_u64(&args[0], &udev->dev_size); if (ret < 0) - pr_err("kstrtoul() failed for dev_size=\n"); + pr_err("match_u64() failed for dev_size=. Error %d.\n", + ret); break; case Opt_hw_block_size: ret = tcmu_set_dev_attrib(&args[0], @@ -2154,7 +2149,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b) bl = sprintf(b + bl, "Config: %s ", udev->dev_config[0] ? udev->dev_config : "NULL"); - bl += sprintf(b + bl, "Size: %zu ", udev->dev_size); + bl += sprintf(b + bl, "Size: %llu ", udev->dev_size); bl += sprintf(b + bl, "MaxDataAreaMB: %u\n", TCMU_BLOCKS_TO_MBS(udev->max_blocks)); @@ -2323,7 +2318,7 @@ static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) 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); + return snprintf(page, PAGE_SIZE, "%llu\n", udev->dev_size); } static int tcmu_send_dev_size_event(struct tcmu_dev *udev, u64 size) -- cgit v1.2.3 From c8a75afbf72ee4c16dad5339f55f62095879f207 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 26 Jul 2018 10:20:37 -0700 Subject: Revert "scsi: target/iscsi: Reduce number of __iscsit_free_cmd() callers" The cxgbit driver expects that __iscsit_free_cmd() is called before the target core frees the command page list. Since this patch breaks the cxgbit driver, revert it. Reported-by: Varun Prakash Fixes: ed88f055788a ("scsi: target/iscsi: Reduce number of __iscsit_free_cmd() callers") Signed-off-by: Bart Van Assche Cc: Varun Prakash Cc: Mike Christie Cc: Hannes Reinecke Cc: Christoph Hellwig Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 2 ++ drivers/target/iscsi/iscsi_target_configfs.c | 1 - drivers/target/iscsi/iscsi_target_util.c | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d547dcd625d9..8e223799347a 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -497,6 +497,8 @@ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) !(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, true); } EXPORT_SYMBOL(iscsit_aborted_task); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 1fcd9bc7189d..95d0a22b2ad6 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1544,7 +1544,6 @@ static void lio_release_cmd(struct se_cmd *se_cmd) struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd); - __iscsit_free_cmd(cmd, true); iscsit_release_cmd(cmd); } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 5a645b5f1eb4..8cfcf9033507 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -772,8 +772,10 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) __iscsit_free_cmd(cmd, shutdown); if (se_cmd) { rc = transport_generic_free_cmd(se_cmd, shutdown); - if (!rc && shutdown && se_cmd->se_sess) + if (!rc && shutdown && se_cmd->se_sess) { + __iscsit_free_cmd(cmd, shutdown); target_put_sess_cmd(se_cmd); + } } else { iscsit_release_cmd(cmd); } -- cgit v1.2.3 From 6a64f6e1591322beb8ce16e952a53582caf2a15c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:20 -0500 Subject: scsi: target: fix __transport_register_session locking When __transport_register_session is called from transport_register_session irqs will already have been disabled, so we do not want the unlock irq call to enable them until the higher level has done the final spin_unlock_irqrestore/ spin_unlock_irq. This has __transport_register_session use the save/restore call. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7261561e87cc..b419d4f8cb96 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -347,6 +347,7 @@ void __transport_register_session( { const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; + unsigned long flags; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; @@ -383,7 +384,7 @@ void __transport_register_session( se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); } - spin_lock_irq(&se_nacl->nacl_sess_lock); + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); /* * The se_nacl->nacl_sess pointer will be set to the * last active I_T Nexus for each struct se_node_acl. @@ -392,7 +393,7 @@ void __transport_register_session( list_add_tail(&se_sess->sess_acl_list, &se_nacl->acl_sess_list); - spin_unlock_irq(&se_nacl->nacl_sess_lock); + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); } list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list); -- cgit v1.2.3 From aeb502794b75f201d1df05f2f351346e0eb2eb83 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:21 -0500 Subject: scsi: iscsi target: have iscsit_start_nopin_timer call __iscsit_start_nopin_timer Just have iscsit_start_nopin_timer grab the lock and call __iscsit_start_nopin_timer. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_util.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 8cfcf9033507..49be1e41290c 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1053,26 +1053,8 @@ void __iscsit_start_nopin_timer(struct iscsi_conn *conn) void iscsit_start_nopin_timer(struct iscsi_conn *conn) { - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - /* - * NOPIN timeout is disabled.. - */ - if (!na->nopin_timeout) - return; - spin_lock_bh(&conn->nopin_timer_lock); - if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - - conn->nopin_timer_flags &= ~ISCSI_TF_STOP; - conn->nopin_timer_flags |= ISCSI_TF_RUNNING; - mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ); - - pr_debug("Started NOPIN Timer on CID: %d at %u second" - " interval\n", conn->cid, na->nopin_timeout); + __iscsit_start_nopin_timer(conn); spin_unlock_bh(&conn->nopin_timer_lock); } -- cgit v1.2.3 From 3cd14285a1bb58eaa98c44aec0db4d914fdc8c13 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:22 -0500 Subject: scsi: target: make transport_init_session_tags static transport_init_session_tags is only called from target_core_transport.c so make it static. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 7 +++---- include/target/target_core_fabric.h | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b419d4f8cb96..8044b8115dbf 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -304,9 +304,9 @@ EXPORT_SYMBOL(transport_alloc_session_tags); * each command. * @sup_prot_ops: bitmask that defines which T10-PI modes are supported. */ -struct se_session *transport_init_session_tags(unsigned int tag_num, - unsigned int tag_size, - enum target_prot_op sup_prot_ops) +static struct se_session * +transport_init_session_tags(unsigned int tag_num, unsigned int tag_size, + enum target_prot_op sup_prot_ops) { struct se_session *se_sess; int rc; @@ -334,7 +334,6 @@ struct se_session *transport_init_session_tags(unsigned int tag_num, return se_sess; } -EXPORT_SYMBOL(transport_init_session_tags); /* * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called. diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index f61aa716cfe1..d0d064212bfc 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -119,8 +119,6 @@ void transport_init_session(struct se_session *); struct se_session *transport_alloc_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); -struct se_session *transport_init_session_tags(unsigned int, unsigned int, - enum target_prot_op); void __transport_register_session(struct se_portal_group *, struct se_node_acl *, struct se_session *, void *); void transport_register_session(struct se_portal_group *, -- cgit v1.2.3 From fa834287300ba6a89e0a590f520a3398527eb541 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:23 -0500 Subject: scsi: target: rename target_alloc_session Rename target_alloc_session to target_setup_session to avoid confusion with the other transport session allocation function that only allocates the session and because the target_alloc_session does so much more. It allocates the session, sets up the nacl and registers the session. The next patch will then add a remove function to match the setup in this one, so it should make sense for all drivers, except iscsi, to just call those 2 functions to setup and remove a session. iscsi will continue to be the odd driver. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Cc: Chris Boot Cc: Bryant G. Ly Cc: Michael Cyr Cc: Cc: Johannes Thumshirn Cc: Felipe Balbi Cc: Sebastian Andrzej Siewior Cc: Andrzej Pietrasiewicz Cc: Michael S. Tsirkin Cc: Juergen Gross Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srpt/ib_srpt.c | 6 +++--- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 2 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- drivers/target/loopback/tcm_loop.c | 2 +- drivers/target/sbp/sbp_target.c | 2 +- drivers/target/target_core_transport.c | 4 ++-- drivers/target/tcm_fc/tfc_sess.c | 2 +- drivers/usb/gadget/function/f_tcm.c | 2 +- drivers/vhost/scsi.c | 2 +- drivers/xen/xen-scsiback.c | 2 +- include/target/target_core_fabric.h | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/target') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 07b3e1c583bd..21435a73771a 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2221,16 +2221,16 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, pr_debug("registering session %s\n", ch->sess_name); if (sport->port_guid_tpg.se_tpg_wwn) - ch->sess = target_alloc_session(&sport->port_guid_tpg, 0, 0, + ch->sess = target_setup_session(&sport->port_guid_tpg, 0, 0, TARGET_PROT_NORMAL, ch->sess_name, ch, NULL); if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess)) - ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0, + ch->sess = target_setup_session(&sport->port_gid_tpg, 0, 0, TARGET_PROT_NORMAL, i_port_id, ch, NULL); /* Retry without leading "0x" */ if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess)) - ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0, + ch->sess = target_setup_session(&sport->port_gid_tpg, 0, 0, TARGET_PROT_NORMAL, i_port_id + 2, ch, NULL); if (IS_ERR_OR_NULL(ch->sess)) { diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index fdda04e5cf94..1bdf9379c4ce 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -2233,7 +2233,7 @@ static int ibmvscsis_make_nexus(struct ibmvscsis_tport *tport) return -ENOMEM; } - nexus->se_sess = target_alloc_session(&tport->se_tpg, 0, 0, + nexus->se_sess = target_setup_session(&tport->se_tpg, 0, 0, TARGET_PROT_NORMAL, name, nexus, NULL); if (IS_ERR(nexus->se_sess)) { diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cfb5d6067f9f..b9ce4e7e1c3e 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1539,7 +1539,7 @@ static int tcm_qla2xxx_check_initiator_node_acl( * Locate our struct se_node_acl either from an explict NodeACL created * via ConfigFS, or via running in TPG demo mode. */ - se_sess = target_alloc_session(&tpg->se_tpg, num_tags, + se_sess = target_setup_session(&tpg->se_tpg, num_tags, sizeof(struct qla_tgt_cmd), TARGET_PROT_ALL, port_name, qlat_sess, tcm_qla2xxx_session_cb); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b2e7ff50ff61..54b5b94dad37 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -765,7 +765,7 @@ static int tcm_loop_make_nexus( if (!tl_nexus) return -ENOMEM; - tl_nexus->se_sess = target_alloc_session(&tl_tpg->tl_se_tpg, 0, 0, + tl_nexus->se_sess = target_setup_session(&tl_tpg->tl_se_tpg, 0, 0, TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS, name, tl_nexus, tcm_loop_alloc_sess_cb); if (IS_ERR(tl_nexus->se_sess)) { diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index b61b79ac98ff..c4369b52a3fb 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -209,7 +209,7 @@ static struct sbp_session *sbp_session_create( INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work); sess->guid = guid; - sess->se_sess = target_alloc_session(&tpg->se_tpg, 128, + sess->se_sess = target_setup_session(&tpg->se_tpg, 128, sizeof(struct sbp_target_request), TARGET_PROT_NORMAL, guid_str, sess, NULL); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 8044b8115dbf..57fadec2d1ae 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -416,7 +416,7 @@ void transport_register_session( EXPORT_SYMBOL(transport_register_session); struct se_session * -target_alloc_session(struct se_portal_group *tpg, +target_setup_session(struct se_portal_group *tpg, unsigned int tag_num, unsigned int tag_size, enum target_prot_op prot_op, const char *initiatorname, void *private, @@ -458,7 +458,7 @@ target_alloc_session(struct se_portal_group *tpg, transport_register_session(tpg, sess->se_node_acl, sess, private); return sess; } -EXPORT_SYMBOL(target_alloc_session); +EXPORT_SYMBOL(target_setup_session); ssize_t target_show_dynamic_sessions(struct se_portal_group *se_tpg, char *page) { diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index c91979c1463d..efd7d5e5bfc4 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -239,7 +239,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, sess->tport = tport; sess->port_id = port_id; - sess->se_sess = target_alloc_session(se_tpg, TCM_FC_DEFAULT_TAGS, + sess->se_sess = target_setup_session(se_tpg, TCM_FC_DEFAULT_TAGS, sizeof(struct ft_cmd), TARGET_PROT_NORMAL, &initiatorname[0], sess, ft_sess_alloc_cb); diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 4f183176b0b4..ba7c5f68d38a 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1592,7 +1592,7 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) goto out_unlock; } - tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, + tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, USB_G_DEFAULT_SESSION_TAGS, sizeof(struct usbg_cmd), TARGET_PROT_NORMAL, name, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index c84a6edd4c25..e9368842c63f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1738,7 +1738,7 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, * struct se_node_acl for the vhost_scsi struct se_portal_group with * the SCSI Initiator port name of the passed configfs group 'name'. */ - tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, + tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, VHOST_SCSI_DEFAULT_TAGS, sizeof(struct vhost_scsi_cmd), TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index fd77ccfc7d6e..2ffc7ed944d8 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1521,7 +1521,7 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, goto out_unlock; } - tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, + tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, VSCSI_DEFAULT_SESSION_TAGS, sizeof(struct vscsibk_pend), TARGET_PROT_NORMAL, name, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index d0d064212bfc..fbcc9a4025b9 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -109,7 +109,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo); int target_depend_item(struct config_item *item); void target_undepend_item(struct config_item *item); -struct se_session *target_alloc_session(struct se_portal_group *, +struct se_session *target_setup_session(struct se_portal_group *, unsigned int, unsigned int, enum target_prot_op prot_op, const char *, void *, int (*callback)(struct se_portal_group *, -- cgit v1.2.3 From fb7c70f2d750a462c5a9757555bc23bf35360cec Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:24 -0500 Subject: scsi: target: add session removal function This adds a function to remove a session which should be used by drivers that use target_setup_session. The next patches will convert the target drivers to use this new function. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Cc: Chris Boot Cc: Bryant G. Ly Cc: Michael Cyr Cc: Cc: Johannes Thumshirn Cc: Felipe Balbi Cc: Sebastian Andrzej Siewior Cc: Andrzej Pietrasiewicz Cc: Michael S. Tsirkin Cc: Juergen Gross Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 7 +++++++ include/target/target_core_fabric.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 57fadec2d1ae..86c0156e6c88 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -616,6 +616,13 @@ void transport_deregister_session(struct se_session *se_sess) } EXPORT_SYMBOL(transport_deregister_session); +void target_remove_session(struct se_session *se_sess) +{ + transport_deregister_session_configfs(se_sess); + transport_deregister_session(se_sess); +} +EXPORT_SYMBOL(target_remove_session); + static void target_remove_from_state_list(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index fbcc9a4025b9..f4147b398431 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -114,6 +114,7 @@ struct se_session *target_setup_session(struct se_portal_group *, const char *, void *, int (*callback)(struct se_portal_group *, struct se_session *, void *)); +void target_remove_session(struct se_session *); void transport_init_session(struct se_session *); struct se_session *transport_alloc_session(enum target_prot_op); -- cgit v1.2.3 From b287e3517ed5c76ad48afdfc4f11fadb58a0707e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:25 -0500 Subject: scsi: target: srp, vscsi, sbp, qla: use target_remove_session This converts the drivers that called transport_deregister_session_configfs and then immediately called transport_deregister_session to use target_remove_session. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Cc: Chris Boot Cc: Bryant G. Ly Cc: Michael Cyr Cc: Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srpt/ib_srpt.c | 3 +-- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 3 +-- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 3 +-- drivers/target/sbp/sbp_target.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/target') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 21435a73771a..1ae638b58b63 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2029,8 +2029,7 @@ static void srpt_release_channel_work(struct work_struct *w) target_sess_cmd_list_set_waiting(se_sess); target_wait_for_sess_cmds(se_sess); - transport_deregister_session_configfs(se_sess); - transport_deregister_session(se_sess); + target_remove_session(se_sess); ch->sess = NULL; if (ch->using_rdma_cm) diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 1bdf9379c4ce..fac377320158 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -2267,8 +2267,7 @@ static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport) * Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port */ target_wait_for_sess_cmds(se_sess); - transport_deregister_session_configfs(se_sess); - transport_deregister_session(se_sess); + target_remove_session(se_sess); tport->ibmv_nexus = NULL; kfree(nexus); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index b9ce4e7e1c3e..f71ec94acc3b 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1461,8 +1461,7 @@ static void tcm_qla2xxx_free_session(struct fc_port *sess) } target_wait_for_sess_cmds(se_sess); - transport_deregister_session_configfs(sess->se_sess); - transport_deregister_session(sess->se_sess); + target_remove_session(se_sess); } static int tcm_qla2xxx_session_cb(struct se_portal_group *se_tpg, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index c4369b52a3fb..3d10189ecedc 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -235,8 +235,7 @@ static void sbp_session_release(struct sbp_session *sess, bool cancel_work) if (cancel_work) cancel_delayed_work_sync(&sess->maint_work); - transport_deregister_session_configfs(sess->se_sess); - transport_deregister_session(sess->se_sess); + target_remove_session(sess->se_sess); if (sess->card) fw_card_put(sess->card); -- cgit v1.2.3 From 60daca10065a13a133e88b738fdc5a40b3654575 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:26 -0500 Subject: scsi: tcm_fc: use target_remove_session This converts tcm_fc to use target_remove_session tcm_fc was calling transport_deregister_session_configfs then calling transport_deregister_session when commands have completed. It should be ok for it to call transport_deregister_session_configfs later via target_remove_session because transport_deregister_session_configfs only prevents access from configfs via tpg removal and its call to the close_session callback for that driver, and this is already protected by the ft_lport_lock and its port lookup handling. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Cc: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/target/tcm_fc/tfc_sess.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index efd7d5e5bfc4..6d4adf5ec26c 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -287,7 +287,6 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) static void ft_close_sess(struct ft_sess *sess) { - transport_deregister_session_configfs(sess->se_sess); target_sess_cmd_list_set_waiting(sess->se_sess); target_wait_for_sess_cmds(sess->se_sess); ft_sess_put(sess); @@ -448,7 +447,7 @@ static void ft_sess_free(struct kref *kref) { struct ft_sess *sess = container_of(kref, struct ft_sess, kref); - transport_deregister_session(sess->se_sess); + target_remove_session(sess->se_sess); kfree_rcu(sess, rcu); } -- cgit v1.2.3 From 25b88550b7d57c6ae91b0e5f4b1be2aaa73a60df Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 2 Aug 2018 12:12:27 -0500 Subject: scsi: target: loop, usb, vhost, xen: use target_remove_session This converts drivers that were only calling transport_deregister_session to use target_remove_session. The calling of transport_deregister_session_configfs via target_remove_session for these types of drivers is ok, because they were not exporting info from fields like sess_acl_list, sess->se_tpg and sess->fabric_sess_ptr from configfs accessible functions, so they will see no difference. Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Cc: Felipe Balbi Cc: Sebastian Andrzej Siewior Cc: Andrzej Pietrasiewicz Cc: Michael S. Tsirkin Cc: Juergen Gross Signed-off-by: Martin K. Petersen --- drivers/target/loopback/tcm_loop.c | 2 +- drivers/usb/gadget/function/f_tcm.c | 2 +- drivers/vhost/scsi.c | 2 +- drivers/xen/xen-scsiback.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 54b5b94dad37..bc8918f382e4 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -805,7 +805,7 @@ static int tcm_loop_drop_nexus( /* * Release the SCSI I_T Nexus to the emulated Target Port */ - transport_deregister_session(tl_nexus->se_sess); + target_remove_session(se_sess); tpg->tl_nexus = NULL; kfree(tl_nexus); return 0; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index ba7c5f68d38a..106988a6661a 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1638,7 +1638,7 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) /* * Release the SCSI I_T Nexus to the emulated vHost Target Port */ - transport_deregister_session(tv_nexus->tvn_se_sess); + target_remove_session(se_sess); tpg->tpg_nexus = NULL; kfree(tv_nexus); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e9368842c63f..76f8d649147b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1797,7 +1797,7 @@ static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg) /* * Release the SCSI I_T Nexus to the emulated vhost Target Port */ - transport_deregister_session(tv_nexus->tvn_se_sess); + target_remove_session(se_sess); tpg->tpg_nexus = NULL; mutex_unlock(&tpg->tv_tpg_mutex); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 2ffc7ed944d8..2aadabd053c2 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1576,7 +1576,7 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg) /* * Release the SCSI I_T Nexus to the emulated xen-pvscsi Target Port */ - transport_deregister_session(tv_nexus->tvn_se_sess); + target_remove_session(se_sess); tpg->tpg_nexus = NULL; mutex_unlock(&tpg->tv_tpg_mutex); -- cgit v1.2.3