The next patch changes the behavior of transport_register_session() such that this function returns an error value if invoked after nacl removal has started. This patch introduces error handling for transport_register_session() in target drivers. To do: handle session registration failure properly in the iSCSI target driver. Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx> Cc: qla2xxx-upstream@xxxxxxxxxx Cc: Chris Boot <bootc@xxxxxxxxx> Cc: Felipe Balbi <balbi@xxxxxx> Cc: "Michael S. Tsirkin" <mst@xxxxxxxxxx> Cc: Juergen Gross <jgross@xxxxxxxx> --- drivers/infiniband/ulp/srpt/ib_srpt.c | 5 +++- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 5 ++-- drivers/target/iscsi/iscsi_target_login.c | 5 ++-- drivers/target/loopback/tcm_loop.c | 28 ++++++++++++--------- drivers/target/sbp/sbp_target.c | 29 +++++++++++++--------- drivers/target/tcm_fc/tfc_sess.c | 25 +++++++++++++------ drivers/usb/gadget/function/f_tcm.c | 7 ++++-- drivers/vhost/scsi.c | 41 +++++++++++++++++-------------- drivers/xen/xen-scsiback.c | 35 +++++++++++++++----------- 9 files changed, 109 insertions(+), 71 deletions(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index fa77443..0c3ed7c 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2438,7 +2438,10 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto deregister_session; } ch->sess->se_node_acl = &nacl->nacl; - transport_register_session(&sport->port_tpg_1, &nacl->nacl, ch->sess, ch); + ret = transport_register_session(&sport->port_tpg_1, &nacl->nacl, + ch->sess, ch); + if (ret < 0) + goto deregister_session; pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess, ch->sess_name, ch->cm_id); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index e65ba34..3b0e2bc 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1388,9 +1388,8 @@ static int tcm_qla2xxx_check_initiator_node_acl( /* * Finally register the new FC Nexus with TCM */ - transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); - - return 0; + return transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, + sess); } static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id, diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 96e78c8..b466182 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -771,8 +771,9 @@ void iscsi_post_login_handler( iscsit_determine_maxcmdsn(sess); spin_lock_bh(&se_tpg->session_lock); - __transport_register_session(&sess->tpg->tpg_se_tpg, - se_sess->se_node_acl, se_sess, sess); + WARN_ON_ONCE(__transport_register_session(&sess->tpg->tpg_se_tpg, + se_sess->se_node_acl, se_sess, + sess) < 0); pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); sess->session_state = TARG_SESS_STATE_LOGGED_IN; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 29a05f1..a3bf04a 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -804,18 +804,19 @@ static int tcm_loop_make_nexus( struct se_portal_group *se_tpg; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; struct tcm_loop_nexus *tl_nexus; - int ret = -ENOMEM; + int ret = -EEXIST; if (tl_tpg->tl_nexus) { pr_debug("tl_tpg->tl_nexus already exists\n"); - return -EEXIST; + goto out; } se_tpg = &tl_tpg->tl_se_tpg; + ret = -ENOMEM; tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); if (!tl_nexus) { pr_err("Unable to allocate struct tcm_loop_nexus\n"); - return -ENOMEM; + goto out; } /* * Initialize the struct se_session pointer @@ -824,7 +825,7 @@ static int tcm_loop_make_nexus( TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS); if (IS_ERR(tl_nexus->se_sess)) { ret = PTR_ERR(tl_nexus->se_sess); - goto out; + goto free_nexus; } /* * Since we are running in 'demo mode' this call with generate a @@ -833,21 +834,26 @@ static int tcm_loop_make_nexus( */ tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( se_tpg, (unsigned char *)name); - if (!tl_nexus->se_sess->se_node_acl) { - transport_free_session(tl_nexus->se_sess); - goto out; - } + if (!tl_nexus->se_sess->se_node_acl) + goto free_session; /* Now, register the I_T Nexus as active. */ - transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, - tl_nexus->se_sess, tl_nexus); + ret = transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, + tl_nexus->se_sess, tl_nexus); + if (ret < 0) + goto free_session; tl_tpg->tl_nexus = tl_nexus; pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), name); return 0; -out: +free_session: + transport_free_session(tl_nexus->se_sess); + +free_nexus: kfree(tl_nexus); + +out: return ret; } diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index d1daee0f..7561d69 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -194,35 +194,30 @@ static struct sbp_session *sbp_session_create( u64 guid) { struct sbp_session *sess; - int ret; + int ret = -ENOMEM; char guid_str[17]; struct se_node_acl *se_nacl; sess = kmalloc(sizeof(*sess), GFP_KERNEL); if (!sess) { pr_err("failed to allocate session descriptor\n"); - return ERR_PTR(-ENOMEM); + goto err; } sess->se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(sess->se_sess)) { pr_err("failed to init se_session\n"); - ret = PTR_ERR(sess->se_sess); - kfree(sess); - return ERR_PTR(ret); + goto free_sbp_sess; } snprintf(guid_str, sizeof(guid_str), "%016llx", guid); + ret = -EPERM; se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str); if (!se_nacl) { pr_warn("Node ACL not found for %s\n", guid_str); - - transport_free_session(sess->se_sess); - kfree(sess); - - return ERR_PTR(-EPERM); + goto free_tgt_sess; } sess->se_sess->se_node_acl = se_nacl; @@ -233,9 +228,21 @@ static struct sbp_session *sbp_session_create( sess->guid = guid; - transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess); + ret = transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, + sess); + if (ret < 0) + goto free_tgt_sess; return sess; + +free_tgt_sess: + transport_free_session(sess->se_sess); + +free_sbp_sess: + kfree(sess); + +err: + return ERR_PTR(ret); } static void sbp_session_release(struct sbp_session *sess, bool cancel_work) diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 45947e2..66ec92c 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -203,15 +203,13 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, sess = kzalloc(sizeof(*sess), GFP_KERNEL); if (!sess) - return NULL; + goto err; sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS, sizeof(struct ft_cmd), TARGET_PROT_NORMAL); - if (IS_ERR(sess->se_sess)) { - kfree(sess); - return NULL; - } + if (IS_ERR(sess->se_sess)) + goto free_ft_sess; sess->se_sess->se_node_acl = &acl->se_node_acl; sess->tport = tport; sess->port_id = port_id; @@ -221,9 +219,22 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, pr_debug("port_id %x sess %p\n", port_id, sess); - transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl, - sess->se_sess, sess); + if (transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl, + sess->se_sess, sess) < 0) + goto del_sess; + return sess; + +del_sess: + tport->sess_count--; + hlist_del_rcu(&sess->hash); + transport_free_session(sess->se_sess); + +free_ft_sess: + kfree(sess); + +err: + return NULL; } /* diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index ec9f5200..2effd49 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1609,8 +1609,11 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) /* * Now register the TCM vHost virtual I_T Nexus as active. */ - transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, - tv_nexus->tvn_se_sess, tv_nexus); + ret = transport_register_session(se_tpg, + tv_nexus->tvn_se_sess->se_node_acl, + tv_nexus->tvn_se_sess, tv_nexus); + if (ret < 0) + goto err_session; tpg->tpg_nexus = tv_nexus; mutex_unlock(&tpg->tpg_mutex); return 0; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index b81ba1a..6c57e0e 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1724,20 +1724,20 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, struct vhost_scsi_nexus *tv_nexus; struct vhost_scsi_cmd *tv_cmd; unsigned int i; + int ret = -EEXIST; mutex_lock(&tpg->tv_tpg_mutex); if (tpg->tpg_nexus) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_debug("tpg->tpg_nexus already exists\n"); - return -EEXIST; + goto err; } se_tpg = &tpg->se_tpg; + ret = -ENOMEM; tv_nexus = kzalloc(sizeof(struct vhost_scsi_nexus), GFP_KERNEL); if (!tv_nexus) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_err("Unable to allocate struct vhost_scsi_nexus\n"); - return -ENOMEM; + goto err; } /* * Initialize the struct se_session pointer and setup tagpool @@ -1748,9 +1748,8 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, sizeof(struct vhost_scsi_cmd), TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS); if (IS_ERR(tv_nexus->tvn_se_sess)) { - mutex_unlock(&tpg->tv_tpg_mutex); - kfree(tv_nexus); - return -ENOMEM; + ret = PTR_ERR(tv_nexus->tvn_se_sess); + goto free_nexus; } se_sess = tv_nexus->tvn_se_sess; for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) { @@ -1759,25 +1758,22 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) * VHOST_SCSI_PREALLOC_SGLS, GFP_KERNEL); if (!tv_cmd->tvc_sgl) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_err("Unable to allocate tv_cmd->tvc_sgl\n"); - goto out; + goto free_sess; } tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * VHOST_SCSI_PREALLOC_UPAGES, GFP_KERNEL); if (!tv_cmd->tvc_upages) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_err("Unable to allocate tv_cmd->tvc_upages\n"); - goto out; + goto free_sess; } tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) * VHOST_SCSI_PREALLOC_PROT_SGLS, GFP_KERNEL); if (!tv_cmd->tvc_prot_sgl) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n"); - goto out; + goto free_sess; } } /* @@ -1788,26 +1784,33 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( se_tpg, (unsigned char *)name); if (!tv_nexus->tvn_se_sess->se_node_acl) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_debug("core_tpg_check_initiator_node_acl() failed" " for %s\n", name); - goto out; + goto free_sess; } /* * Now register the TCM vhost virtual I_T Nexus as active. */ - transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, - tv_nexus->tvn_se_sess, tv_nexus); + ret = transport_register_session(se_tpg, + tv_nexus->tvn_se_sess->se_node_acl, + tv_nexus->tvn_se_sess, tv_nexus); + if (ret < 0) + goto free_sess; tpg->tpg_nexus = tv_nexus; mutex_unlock(&tpg->tv_tpg_mutex); return 0; -out: +free_sess: vhost_scsi_free_cmd_map_res(tv_nexus, se_sess); transport_free_session(se_sess); + +free_nexus: kfree(tv_nexus); - return -ENOMEM; + +err: + mutex_unlock(&tpg->tv_tpg_mutex); + return ret; } static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg) diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index ed4c47c..bb1f2fb 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1483,28 +1483,26 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, struct se_portal_group *se_tpg; struct se_session *se_sess; struct scsiback_nexus *tv_nexus; + int ret = -EEXIST; mutex_lock(&tpg->tv_tpg_mutex); if (tpg->tpg_nexus) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_debug("tpg->tpg_nexus already exists\n"); - return -EEXIST; + goto err; } se_tpg = &tpg->se_tpg; + ret = -ENOMEM; tv_nexus = kzalloc(sizeof(struct scsiback_nexus), GFP_KERNEL); - if (!tv_nexus) { - mutex_unlock(&tpg->tv_tpg_mutex); - return -ENOMEM; - } + if (!tv_nexus) + goto err; /* * Initialize the struct se_session pointer */ tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(tv_nexus->tvn_se_sess)) { - mutex_unlock(&tpg->tv_tpg_mutex); - kfree(tv_nexus); - return -ENOMEM; + ret = PTR_ERR(tv_nexus->tvn_se_sess); + goto free_nexus; } se_sess = tv_nexus->tvn_se_sess; /* @@ -1515,23 +1513,30 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( se_tpg, (unsigned char *)name); if (!tv_nexus->tvn_se_sess->se_node_acl) { - mutex_unlock(&tpg->tv_tpg_mutex); pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n", name); - goto out; + goto free_sess; } /* Now register the TCM pvscsi virtual I_T Nexus as active. */ - transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, - tv_nexus->tvn_se_sess, tv_nexus); + ret = transport_register_session(se_tpg, + tv_nexus->tvn_se_sess->se_node_acl, + tv_nexus->tvn_se_sess, tv_nexus); + if (ret < 0) + goto free_sess; tpg->tpg_nexus = tv_nexus; mutex_unlock(&tpg->tv_tpg_mutex); return 0; -out: +free_sess: transport_free_session(se_sess); + +free_nexus: kfree(tv_nexus); - return -ENOMEM; + +err: + mutex_unlock(&tpg->tv_tpg_mutex); + return ret; } static int scsiback_drop_nexus(struct scsiback_tpg *tpg) -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html