[PATCH 20/21] target drivers: Add transport_register_session() error handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux