target: simplify the target template registration API

Instead of calling target_fabric_configfs_init() +
target_fabric_configfs_register() / target_fabric_configfs_deregister()
target_fabric_configfs_free() from every target driver, rewrite the API
so that we have simple register/unregister functions that operate on
a const operations vector.

This patch also fixes a memory leak in several target drivers. Several
target drivers namely called target_fabric_configfs_deregister()
without calling target_fabric_configfs_free().

A large part of this patch is based on earlier changes from
Bart Van Assche <bart.vanassche@sandisk.com>.

(v2: Add a new TF_CIT_SETUP_DRV macro so that the core configfs code
can declare attributes as either core only or for drivers)

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 2114c1d..5b143d2c 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -41,8 +41,7 @@
 
 #define to_tcm_loop_hba(hba)	container_of(hba, struct tcm_loop_hba, dev)
 
-/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *tcm_loop_fabric_configfs;
+static const struct target_core_fabric_ops loop_ops;
 
 static struct workqueue_struct *tcm_loop_workqueue;
 static struct kmem_cache *tcm_loop_cmd_cache;
@@ -1238,8 +1237,7 @@
 	/*
 	 * Register the tl_tpg as a emulated SAS TCM Target Endpoint
 	 */
-	ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops,
-			wwn, &tl_tpg->tl_se_tpg, tl_tpg,
+	ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg,
 			TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0)
 		return ERR_PTR(-ENOMEM);
@@ -1387,129 +1385,51 @@
 
 /* End items for tcm_loop_cit */
 
-static int tcm_loop_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-	/*
-	 * Set the TCM Loop HBA counter to zero
-	 */
-	tcm_loop_hba_no_cnt = 0;
-	/*
-	 * Register the top level struct config_item_type with TCM core
-	 */
-	fabric = target_fabric_configfs_init(THIS_MODULE, "loopback");
-	if (IS_ERR(fabric)) {
-		pr_err("tcm_loop_register_configfs() failed!\n");
-		return PTR_ERR(fabric);
-	}
-	/*
-	 * Setup the fabric API of function pointers used by target_core_mod
-	 */
-	fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name;
-	fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident;
-	fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn;
-	fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag;
-	fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth;
-	fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id;
-	fabric->tf_ops.tpg_get_pr_transport_id_len =
-					&tcm_loop_get_pr_transport_id_len;
-	fabric->tf_ops.tpg_parse_pr_out_transport_id =
-					&tcm_loop_parse_pr_out_transport_id;
-	fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode;
-	fabric->tf_ops.tpg_check_demo_mode_cache =
-					&tcm_loop_check_demo_mode_cache;
-	fabric->tf_ops.tpg_check_demo_mode_write_protect =
-					&tcm_loop_check_demo_mode_write_protect;
-	fabric->tf_ops.tpg_check_prod_mode_write_protect =
-					&tcm_loop_check_prod_mode_write_protect;
-	fabric->tf_ops.tpg_check_prot_fabric_only =
-					&tcm_loop_check_prot_fabric_only;
-	/*
-	 * The TCM loopback fabric module runs in demo-mode to a local
-	 * virtual SCSI device, so fabric dependent initator ACLs are
-	 * not required.
-	 */
-	fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl;
-	fabric->tf_ops.tpg_release_fabric_acl =
-					&tcm_loop_tpg_release_fabric_acl;
-	fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index;
-	/*
-	 * Used for setting up remaining TCM resources in process context
-	 */
-	fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free;
-	fabric->tf_ops.release_cmd = &tcm_loop_release_cmd;
-	fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session;
-	fabric->tf_ops.close_session = &tcm_loop_close_session;
-	fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index;
-	fabric->tf_ops.sess_get_initiator_sid = NULL;
-	fabric->tf_ops.write_pending = &tcm_loop_write_pending;
-	fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status;
-	/*
-	 * Not used for TCM loopback
-	 */
-	fabric->tf_ops.set_default_node_attributes =
-					&tcm_loop_set_default_node_attributes;
-	fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag;
-	fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state;
-	fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in;
-	fabric->tf_ops.queue_status = &tcm_loop_queue_status;
-	fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp;
-	fabric->tf_ops.aborted_task = &tcm_loop_aborted_task;
-
-	/*
-	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
-	 */
-	fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba;
-	fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba;
-	fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg;
-	fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg;
-	/*
-	 * fabric_post_link() and fabric_pre_unlink() are used for
-	 * registration and release of TCM Loop Virtual SCSI LUNs.
-	 */
-	fabric->tf_ops.fabric_post_link = &tcm_loop_port_link;
-	fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink;
-	fabric->tf_ops.fabric_make_np = NULL;
-	fabric->tf_ops.fabric_drop_np = NULL;
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = tcm_loop_tpg_attrib_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	/*
-	 * Once fabric->tf_ops has been setup, now register the fabric for
-	 * use within TCM
-	 */
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() for"
-				" TCM_Loop failed!\n");
-		target_fabric_configfs_free(fabric);
-		return -1;
-	}
-	/*
-	 * Setup our local pointer to *fabric.
-	 */
-	tcm_loop_fabric_configfs = fabric;
-	pr_debug("TCM_LOOP[0] - Set fabric ->"
-			" tcm_loop_fabric_configfs\n");
-	return 0;
-}
-
-static void tcm_loop_deregister_configfs(void)
-{
-	if (!tcm_loop_fabric_configfs)
-		return;
-
-	target_fabric_configfs_deregister(tcm_loop_fabric_configfs);
-	tcm_loop_fabric_configfs = NULL;
-	pr_debug("TCM_LOOP[0] - Cleared"
-				" tcm_loop_fabric_configfs\n");
-}
+static const struct target_core_fabric_ops loop_ops = {
+	.module				= THIS_MODULE,
+	.name				= "loopback",
+	.get_fabric_name		= tcm_loop_get_fabric_name,
+	.get_fabric_proto_ident		= tcm_loop_get_fabric_proto_ident,
+	.tpg_get_wwn			= tcm_loop_get_endpoint_wwn,
+	.tpg_get_tag			= tcm_loop_get_tag,
+	.tpg_get_default_depth		= tcm_loop_get_default_depth,
+	.tpg_get_pr_transport_id	= tcm_loop_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= tcm_loop_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= tcm_loop_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= tcm_loop_check_demo_mode,
+	.tpg_check_demo_mode_cache	= tcm_loop_check_demo_mode_cache,
+	.tpg_check_demo_mode_write_protect =
+				tcm_loop_check_demo_mode_write_protect,
+	.tpg_check_prod_mode_write_protect =
+				tcm_loop_check_prod_mode_write_protect,
+	.tpg_check_prot_fabric_only	= tcm_loop_check_prot_fabric_only,
+	.tpg_alloc_fabric_acl		= tcm_loop_tpg_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= tcm_loop_tpg_release_fabric_acl,
+	.tpg_get_inst_index		= tcm_loop_get_inst_index,
+	.check_stop_free		= tcm_loop_check_stop_free,
+	.release_cmd			= tcm_loop_release_cmd,
+	.shutdown_session		= tcm_loop_shutdown_session,
+	.close_session			= tcm_loop_close_session,
+	.sess_get_index			= tcm_loop_sess_get_index,
+	.write_pending			= tcm_loop_write_pending,
+	.write_pending_status		= tcm_loop_write_pending_status,
+	.set_default_node_attributes	= tcm_loop_set_default_node_attributes,
+	.get_task_tag			= tcm_loop_get_task_tag,
+	.get_cmd_state			= tcm_loop_get_cmd_state,
+	.queue_data_in			= tcm_loop_queue_data_in,
+	.queue_status			= tcm_loop_queue_status,
+	.queue_tm_rsp			= tcm_loop_queue_tm_rsp,
+	.aborted_task			= tcm_loop_aborted_task,
+	.fabric_make_wwn		= tcm_loop_make_scsi_hba,
+	.fabric_drop_wwn		= tcm_loop_drop_scsi_hba,
+	.fabric_make_tpg		= tcm_loop_make_naa_tpg,
+	.fabric_drop_tpg		= tcm_loop_drop_naa_tpg,
+	.fabric_post_link		= tcm_loop_port_link,
+	.fabric_pre_unlink		= tcm_loop_port_unlink,
+	.tfc_wwn_attrs			= tcm_loop_wwn_attrs,
+	.tfc_tpg_base_attrs		= tcm_loop_tpg_attrs,
+	.tfc_tpg_attrib_attrs		= tcm_loop_tpg_attrib_attrs,
+};
 
 static int __init tcm_loop_fabric_init(void)
 {
@@ -1533,7 +1453,7 @@
 	if (ret)
 		goto out_destroy_cache;
 
-	ret = tcm_loop_register_configfs();
+	ret = target_register_template(&loop_ops);
 	if (ret)
 		goto out_release_core_bus;
 
@@ -1551,7 +1471,7 @@
 
 static void __exit tcm_loop_fabric_exit(void)
 {
-	tcm_loop_deregister_configfs();
+	target_unregister_template(&loop_ops);
 	tcm_loop_release_core_bus();
 	kmem_cache_destroy(tcm_loop_cmd_cache);
 	destroy_workqueue(tcm_loop_workqueue);