[PATCH] target: simplify the target template registration API

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

 



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@xxxxxxxxxxx>.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>
---
 Documentation/target/tcm_mod_builder.py      |  79 ++----------
 drivers/infiniband/ulp/srpt/ib_srpt.c        |  49 ++------
 drivers/scsi/qla2xxx/qla_target.c            |   2 +-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c           | 118 ++++--------------
 drivers/target/iscsi/iscsi_target.c          |  23 ++--
 drivers/target/iscsi/iscsi_target.h          |   2 +-
 drivers/target/iscsi/iscsi_target_configfs.c | 177 +++++++++-----------------
 drivers/target/iscsi/iscsi_target_configfs.h |   7 --
 drivers/target/iscsi/iscsi_target_tpg.c      |   6 +-
 drivers/target/loopback/tcm_loop.c           | 174 +++++++-------------------
 drivers/target/sbp/sbp_target.c              |  68 ++--------
 drivers/target/target_core_configfs.c        | 178 ++++++++-------------------
 drivers/target/target_core_fabric_configfs.c |  39 ++++++
 drivers/target/target_core_pr.c              |  16 +--
 drivers/target/target_core_tpg.c             |   2 +-
 drivers/target/target_core_transport.c       |   4 +-
 drivers/target/target_core_xcopy.c           |   2 +-
 drivers/target/tcm_fc/tcm_fc.h               |   1 -
 drivers/target/tcm_fc/tfc_conf.c             |  89 ++++----------
 drivers/usb/gadget/legacy/tcm_usb_gadget.c   |  57 ++-------
 drivers/vhost/scsi.c                         |  75 ++---------
 drivers/xen/xen-scsiback.c                   |  74 ++---------
 include/target/target_core_base.h            |   4 +-
 include/target/target_core_configfs.h        |   7 --
 include/target/target_core_fabric.h          |  34 ++++-
 include/target/target_core_fabric_configfs.h |   5 +
 26 files changed, 381 insertions(+), 911 deletions(-)
 delete mode 100644 drivers/target/iscsi/iscsi_target_configfs.h

diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index 2b47704..27afc03 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -237,8 +237,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 	buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
 	buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
 
-	buf += "/* Local pointer to allocated TCM configfs fabric module */\n"
-	buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n"
+	buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n"
 
 	buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
 	buf += "	struct se_portal_group *se_tpg,\n"
@@ -309,8 +308,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 	buf += "	}\n"
 	buf += "	tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
 	buf += "	tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
-	buf += "	ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n"
-	buf += "				&tpg->se_tpg, (void *)tpg,\n"
+	buf += "	ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
+	buf += "				&tpg->se_tpg, tpg,\n"
 	buf += "				TRANSPORT_TPG_TYPE_NORMAL);\n"
 	buf += "	if (ret < 0) {\n"
 	buf += "		kfree(tpg);\n"
@@ -370,7 +369,10 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 	buf += "	NULL,\n"
 	buf += "};\n\n"
 
-	buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
+	buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
+	buf += "	.module				= THIS_MODULE\n",
+	buf += "	.name				= " + fabric_mod_name + ",\n"
+	buf += "	.get_fabric_proto_ident		= " + fabric_mod_name + "_get_fabric_proto_ident,\n"
 	buf += "	.get_fabric_name		= " + fabric_mod_name + "_get_fabric_name,\n"
 	buf += "	.get_fabric_proto_ident		= " + fabric_mod_name + "_get_fabric_proto_ident,\n"
 	buf += "	.tpg_get_wwn			= " + fabric_mod_name + "_get_fabric_wwn,\n"
@@ -413,75 +415,18 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 	buf += "	.fabric_drop_np			= NULL,\n"
 	buf += "	.fabric_make_nodeacl		= " + fabric_mod_name + "_make_nodeacl,\n"
 	buf += "	.fabric_drop_nodeacl		= " + fabric_mod_name + "_drop_nodeacl,\n"
-	buf += "};\n\n"
-
-	buf += "static int " + fabric_mod_name + "_register_configfs(void)\n"
-	buf += "{\n"
-	buf += "	struct target_fabric_configfs *fabric;\n"
-	buf += "	int ret;\n\n"
-	buf += "	printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
-	buf += "		\" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
-	buf += "		utsname()->machine);\n"
-	buf += "	/*\n"
-	buf += "	 * Register the top level struct config_item_type with TCM core\n"
-	buf += "	 */\n"
-	buf += "	fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n"
-	buf += "	if (IS_ERR(fabric)) {\n"
-	buf += "		printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
-	buf += "		return PTR_ERR(fabric);\n"
-	buf += "	}\n"
-	buf += "	/*\n"
-	buf += "	 * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n"
-	buf += "	 */\n"
-	buf += "	fabric->tf_ops = " + fabric_mod_name + "_ops;\n"
-	buf += "	/*\n"
-	buf += "	 * Setup default attribute lists for various fabric->tf_cit_tmpl\n"
-	buf += "	 */\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n"
-	buf += "	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n"
-	buf += "	/*\n"
-	buf += "	 * Register the fabric for use within TCM\n"
-	buf += "	 */\n"
-	buf += "	ret = target_fabric_configfs_register(fabric);\n"
-	buf += "	if (ret < 0) {\n"
-	buf += "		printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n"
-	buf += "				\" for " + fabric_mod_name.upper() + "\\n\");\n"
-	buf += "		return ret;\n"
-	buf += "	}\n"
-	buf += "	/*\n"
-	buf += "	 * Setup our local pointer to *fabric\n"
-	buf += "	 */\n"
-	buf += "	" + fabric_mod_name + "_fabric_configfs = fabric;\n"
-	buf += "	printk(KERN_INFO \"" +  fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n"
-	buf += "	return 0;\n"
-	buf += "};\n\n"
-	buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n"
-	buf += "{\n"
-	buf += "	if (!" + fabric_mod_name + "_fabric_configfs)\n"
-	buf += "		return;\n\n"
-	buf += "	target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n"
-	buf += "	" + fabric_mod_name + "_fabric_configfs = NULL;\n"
-	buf += "	printk(KERN_INFO \"" +  fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n"
+	buf += "\n"
+	buf += "	.tfc_wwn_attrs			= " + fabric_mod_name + "_wwn_attrs;\n"
 	buf += "};\n\n"
 
 	buf += "static int __init " + fabric_mod_name + "_init(void)\n"
 	buf += "{\n"
-	buf += "	int ret;\n\n"
-	buf += "	ret = " + fabric_mod_name + "_register_configfs();\n"
-	buf += "	if (ret < 0)\n"
-	buf += "		return ret;\n\n"
-	buf += "	return 0;\n"
+	buf += "	return target_register_template(" + fabric_mod_name + "_ops);\n"
 	buf += "};\n\n"
+
 	buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
 	buf += "{\n"
-	buf += "	" + fabric_mod_name + "_deregister_configfs();\n"
+	buf += "	target_unregister_template(" + fabric_mod_name + "_ops);\n"
 	buf += "};\n\n"
 
 	buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 6e0a477..0701538 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -93,7 +93,7 @@ MODULE_PARM_DESC(srpt_service_guid,
 		 " instead of using the node_guid of the first HCA.");
 
 static struct ib_client srpt_client;
-static struct target_fabric_configfs *srpt_target;
+static const struct target_core_fabric_ops srpt_template;
 static void srpt_release_channel(struct srpt_rdma_ch *ch);
 static int srpt_queue_status(struct se_cmd *cmd);
 
@@ -3851,7 +3851,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
 	int res;
 
 	/* Initialize sport->port_wwn and sport->port_tpg_1 */
-	res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn,
+	res = core_tpg_register(&srpt_template, &sport->port_wwn,
 			&sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL);
 	if (res)
 		return ERR_PTR(res);
@@ -3919,7 +3919,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = {
 	NULL,
 };
 
-static struct target_core_fabric_ops srpt_template = {
+static const struct target_core_fabric_ops srpt_template = {
+	.module				= THIS_MODULE,
+	.name				= "srpt",
 	.get_fabric_name		= srpt_get_fabric_name,
 	.get_fabric_proto_ident		= srpt_get_fabric_proto_ident,
 	.tpg_get_wwn			= srpt_get_fabric_wwn,
@@ -3964,6 +3966,10 @@ static struct target_core_fabric_ops srpt_template = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= srpt_make_nodeacl,
 	.fabric_drop_nodeacl		= srpt_drop_nodeacl,
+
+	.tfc_wwn_attrs			= srpt_wwn_attrs,
+	.tfc_tpg_base_attrs		= srpt_tpg_attrs,
+	.tfc_tpg_attrib_attrs		= srpt_tpg_attrib_attrs,
 };
 
 /**
@@ -3994,33 +4000,9 @@ static int __init srpt_init_module(void)
 		goto out;
 	}
 
-	srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt");
-	if (IS_ERR(srpt_target)) {
-		printk(KERN_ERR "couldn't register\n");
-		ret = PTR_ERR(srpt_target);
+	ret = target_register_template(&srpt_template);
+	if (ret)
 		goto out;
-	}
-
-	srpt_target->tf_ops = srpt_template;
-
-	/*
-	 * Set up default attribute lists.
-	 */
-	srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs;
-	srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs;
-	srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs;
-	srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-
-	ret = target_fabric_configfs_register(srpt_target);
-	if (ret < 0) {
-		printk(KERN_ERR "couldn't register\n");
-		goto out_free_target;
-	}
 
 	ret = ib_register_client(&srpt_client);
 	if (ret) {
@@ -4031,11 +4013,7 @@ static int __init srpt_init_module(void)
 	return 0;
 
 out_unregister_target:
-	target_fabric_configfs_deregister(srpt_target);
-	srpt_target = NULL;
-out_free_target:
-	if (srpt_target)
-		target_fabric_configfs_free(srpt_target);
+	target_unregister_template(&srpt_template);
 out:
 	return ret;
 }
@@ -4043,8 +4021,7 @@ out:
 static void __exit srpt_cleanup_module(void)
 {
 	ib_unregister_client(&srpt_client);
-	target_fabric_configfs_deregister(srpt_target);
-	srpt_target = NULL;
+	target_unregister_template(&srpt_template);
 }
 
 module_init(srpt_init_module);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 5741825..fe8a8d1 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3065,7 +3065,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 {
 	struct qla_hw_data *ha = vha->hw;
 	struct se_cmd *se_cmd;
-	struct target_core_fabric_ops *tfo;
+	const struct target_core_fabric_ops *tfo;
 	struct qla_tgt_cmd *cmd;
 
 	if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) {
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index c4f66f5..ec00237 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -53,9 +53,8 @@
 static struct workqueue_struct *tcm_qla2xxx_free_wq;
 static struct workqueue_struct *tcm_qla2xxx_cmd_wq;
 
-/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
-static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
+static const struct target_core_fabric_ops tcm_qla2xxx_ops;
+static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops;
 
 /*
  * Parse WWN.
@@ -1134,7 +1133,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
 	tpg->tpg_attrib.cache_dynamic_acls = 1;
 	tpg->tpg_attrib.demo_mode_login_only = 1;
 
-	ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn,
+	ret = core_tpg_register(&tcm_qla2xxx_ops, wwn,
 				&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		kfree(tpg);
@@ -1254,7 +1253,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
 	tpg->tpg_attrib.cache_dynamic_acls = 1;
 	tpg->tpg_attrib.demo_mode_login_only = 1;
 
-	ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
+	ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn,
 				&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		kfree(tpg);
@@ -1944,7 +1943,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
 	NULL,
 };
 
-static struct target_core_fabric_ops tcm_qla2xxx_ops = {
+static const struct target_core_fabric_ops tcm_qla2xxx_ops = {
+	.module				= THIS_MODULE,
+	.name				= "qla2xxx",
 	.get_fabric_name		= tcm_qla2xxx_get_fabric_name,
 	.get_fabric_proto_ident		= tcm_qla2xxx_get_fabric_proto_ident,
 	.tpg_get_wwn			= tcm_qla2xxx_get_fabric_wwn,
@@ -1993,9 +1994,15 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= tcm_qla2xxx_make_nodeacl,
 	.fabric_drop_nodeacl		= tcm_qla2xxx_drop_nodeacl,
+
+	.tfc_wwn_attrs			= tcm_qla2xxx_wwn_attrs,
+	.tfc_tpg_base_attrs		= tcm_qla2xxx_tpg_attrs,
+	.tfc_tpg_attrib_attrs		= tcm_qla2xxx_tpg_attrib_attrs,
 };
 
-static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
+static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
+	.module				= THIS_MODULE,
+	.name				= "qla2xxx",
 	.get_fabric_name		= tcm_qla2xxx_npiv_get_fabric_name,
 	.get_fabric_proto_ident		= tcm_qla2xxx_get_fabric_proto_ident,
 	.tpg_get_wwn			= tcm_qla2xxx_get_fabric_wwn,
@@ -2043,94 +2050,26 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= tcm_qla2xxx_make_nodeacl,
 	.fabric_drop_nodeacl		= tcm_qla2xxx_drop_nodeacl,
+
+	.tfc_wwn_attrs			= tcm_qla2xxx_wwn_attrs,
+	.tfc_tpg_base_attrs		= tcm_qla2xxx_npiv_tpg_attrs,
 };
 
 static int tcm_qla2xxx_register_configfs(void)
 {
-	struct target_fabric_configfs *fabric, *npiv_fabric;
 	int ret;
 
 	pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
 	    UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
 	    utsname()->machine);
-	/*
-	 * Register the top level struct config_item_type with TCM core
-	 */
-	fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx");
-	if (IS_ERR(fabric)) {
-		pr_err("target_fabric_configfs_init() failed\n");
-		return PTR_ERR(fabric);
-	}
-	/*
-	 * Setup fabric->tf_ops from our local tcm_qla2xxx_ops
-	 */
-	fabric->tf_ops = tcm_qla2xxx_ops;
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs =
-						tcm_qla2xxx_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;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	/*
-	 * Register the fabric for use within TCM
-	 */
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
+
+	ret = target_register_template(&tcm_qla2xxx_ops);
+	if (ret)
 		return ret;
-	}
-	/*
-	 * Setup our local pointer to *fabric
-	 */
-	tcm_qla2xxx_fabric_configfs = fabric;
-	pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n");
 
-	/*
-	 * Register the top level struct config_item_type for NPIV with TCM core
-	 */
-	npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv");
-	if (IS_ERR(npiv_fabric)) {
-		pr_err("target_fabric_configfs_init() failed\n");
-		ret = PTR_ERR(npiv_fabric);
+	ret = target_register_template(&tcm_qla2xxx_npiv_ops);
+	if (ret)
 		goto out_fabric;
-	}
-	/*
-	 * Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops
-	 */
-	npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops;
-	/*
-	 * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
-	 */
-	npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
-	    tcm_qla2xxx_npiv_tpg_attrs;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	/*
-	 * Register the npiv_fabric for use within TCM
-	 */
-	ret = target_fabric_configfs_register(npiv_fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n");
-		goto out_fabric;
-	}
-	/*
-	 * Setup our local pointer to *npiv_fabric
-	 */
-	tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric;
-	pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n");
 
 	tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free",
 						WQ_MEM_RECLAIM, 0);
@@ -2150,9 +2089,9 @@ static int tcm_qla2xxx_register_configfs(void)
 out_free_wq:
 	destroy_workqueue(tcm_qla2xxx_free_wq);
 out_fabric_npiv:
-	target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
+	target_unregister_template(&tcm_qla2xxx_npiv_ops);
 out_fabric:
-	target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
+	target_unregister_template(&tcm_qla2xxx_ops);
 	return ret;
 }
 
@@ -2161,13 +2100,8 @@ static void tcm_qla2xxx_deregister_configfs(void)
 	destroy_workqueue(tcm_qla2xxx_cmd_wq);
 	destroy_workqueue(tcm_qla2xxx_free_wq);
 
-	target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
-	tcm_qla2xxx_fabric_configfs = NULL;
-	pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n");
-
-	target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
-	tcm_qla2xxx_npiv_fabric_configfs = NULL;
-	pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n");
+	target_unregister_template(&tcm_qla2xxx_ops);
+	target_unregister_template(&tcm_qla2xxx_npiv_ops);
 }
 
 static int __init tcm_qla2xxx_init(void)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index a802551..c57c54e 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -33,7 +33,6 @@
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_parameters.h"
 #include "iscsi_target_seq_pdu_list.h"
-#include "iscsi_target_configfs.h"
 #include "iscsi_target_datain_values.h"
 #include "iscsi_target_erl0.h"
 #include "iscsi_target_erl1.h"
@@ -551,8 +550,8 @@ static int __init iscsi_target_init_module(void)
 	idr_init(&tiqn_idr);
 	idr_init(&sess_idr);
 
-	ret = iscsi_target_register_configfs();
-	if (ret < 0)
+	ret = target_register_template(&iscsi_ops);
+	if (ret)
 		goto out;
 
 	size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
@@ -616,7 +615,10 @@ qr_out:
 bitmap_out:
 	vfree(iscsit_global->ts_bitmap);
 configfs_out:
-	iscsi_target_deregister_configfs();
+	/* XXX: this probably wants it to be it's own unwind step.. */
+	if (iscsit_global->discovery_tpg)
+		iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
+	target_unregister_template(&iscsi_ops);
 out:
 	kfree(iscsit_global);
 	return -ENOMEM;
@@ -631,7 +633,13 @@ static void __exit iscsi_target_cleanup_module(void)
 	kmem_cache_destroy(lio_ooo_cache);
 	kmem_cache_destroy(lio_r2t_cache);
 
-	iscsi_target_deregister_configfs();
+	/*
+	 * Shutdown discovery sessions and disable discovery TPG
+	 */
+	if (iscsit_global->discovery_tpg)
+		iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
+
+	target_unregister_template(&iscsi_ops);
 
 	vfree(iscsit_global->ts_bitmap);
 	kfree(iscsit_global);
@@ -983,7 +991,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 	/*
 	 * Initialize struct se_cmd descriptor from target_core_mod infrastructure
 	 */
-	transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops,
+	transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
 			conn->sess->se_sess, be32_to_cpu(hdr->data_length),
 			cmd->data_direction, sam_task_attr,
 			cmd->sense_buffer + 2);
@@ -1798,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 		u8 tcm_function;
 		int ret;
 
-		transport_init_se_cmd(&cmd->se_cmd,
-				      &lio_target_fabric_configfs->tf_ops,
+		transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
 				      conn->sess->se_sess, 0, DMA_NONE,
 				      TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
 
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index e936d56..7d0f9c0 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -35,7 +35,7 @@ extern void iscsit_stop_session(struct iscsi_session *, int, int);
 extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
 
 extern struct iscsit_global *iscsit_global;
-extern struct target_fabric_configfs *lio_target_fabric_configfs;
+extern const struct target_core_fabric_ops iscsi_ops;
 
 extern struct kmem_cache *lio_dr_cache;
 extern struct kmem_cache *lio_ooo_cache;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 95a67f6..bd9baea 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -37,9 +37,6 @@
 #include "iscsi_target_util.h"
 #include "iscsi_target.h"
 #include <target/iscsi/iscsi_target_stat.h>
-#include "iscsi_target_configfs.h"
-
-struct target_fabric_configfs *lio_target_fabric_configfs;
 
 struct lio_target_configfs_attribute {
 	struct configfs_attribute attr;
@@ -1460,10 +1457,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
 	if (!tpg)
 		return NULL;
 
-	ret = core_tpg_register(
-			&lio_target_fabric_configfs->tf_ops,
-			wwn, &tpg->tpg_se_tpg, tpg,
-			TRANSPORT_TPG_TYPE_NORMAL);
+	ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg,
+				tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0)
 		return NULL;
 
@@ -1963,115 +1958,59 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
 	iscsit_release_cmd(cmd);
 }
 
-/* End functions for target_core_fabric_ops */
-
-int iscsi_target_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-
-	lio_target_fabric_configfs = NULL;
-	fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi");
-	if (IS_ERR(fabric)) {
-		pr_err("target_fabric_configfs_init() for"
-				" LIO-Target failed!\n");
-		return PTR_ERR(fabric);
-	}
-	/*
-	 * Setup the fabric API of function pointers used by target_core_mod..
-	 */
-	fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name;
-	fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident;
-	fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn;
-	fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag;
-	fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth;
-	fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id;
-	fabric->tf_ops.tpg_get_pr_transport_id_len =
-				&iscsi_get_pr_transport_id_len;
-	fabric->tf_ops.tpg_parse_pr_out_transport_id =
-				&iscsi_parse_pr_out_transport_id;
-	fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode;
-	fabric->tf_ops.tpg_check_demo_mode_cache =
-				&lio_tpg_check_demo_mode_cache;
-	fabric->tf_ops.tpg_check_demo_mode_write_protect =
-				&lio_tpg_check_demo_mode_write_protect;
-	fabric->tf_ops.tpg_check_prod_mode_write_protect =
-				&lio_tpg_check_prod_mode_write_protect;
-	fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl;
-	fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl;
-	fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index;
-	fabric->tf_ops.check_stop_free = &lio_check_stop_free,
-	fabric->tf_ops.release_cmd = &lio_release_cmd;
-	fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
-	fabric->tf_ops.close_session = &lio_tpg_close_session;
-	fabric->tf_ops.sess_get_index = &lio_sess_get_index;
-	fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid;
-	fabric->tf_ops.write_pending = &lio_write_pending;
-	fabric->tf_ops.write_pending_status = &lio_write_pending_status;
-	fabric->tf_ops.set_default_node_attributes =
-				&lio_set_default_node_attributes;
-	fabric->tf_ops.get_task_tag = &iscsi_get_task_tag;
-	fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state;
-	fabric->tf_ops.queue_data_in = &lio_queue_data_in;
-	fabric->tf_ops.queue_status = &lio_queue_status;
-	fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
-	fabric->tf_ops.aborted_task = &lio_aborted_task;
-	/*
-	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
-	 */
-	fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn;
-	fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn;
-	fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg;
-	fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg;
-	fabric->tf_ops.fabric_post_link	= NULL;
-	fabric->tf_ops.fabric_pre_unlink = NULL;
-	fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg;
-	fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg;
-	fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl;
-	fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl;
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 * sturct config_item_type's
-	 */
-	fabric->tf_cit_tmpl.tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs;
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs;
-
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() for"
-				" LIO-Target failed!\n");
-		target_fabric_configfs_free(fabric);
-		return ret;
-	}
-
-	lio_target_fabric_configfs = fabric;
-	pr_debug("LIO_TARGET[0] - Set fabric ->"
-			" lio_target_fabric_configfs\n");
-	return 0;
-}
-
-
-void iscsi_target_deregister_configfs(void)
-{
-	if (!lio_target_fabric_configfs)
-		return;
-	/*
-	 * Shutdown discovery sessions and disable discovery TPG
-	 */
-	if (iscsit_global->discovery_tpg)
-		iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
-
-	target_fabric_configfs_deregister(lio_target_fabric_configfs);
-	lio_target_fabric_configfs = NULL;
-	pr_debug("LIO_TARGET[0] - Cleared"
-				" lio_target_fabric_configfs\n");
-}
+const struct target_core_fabric_ops iscsi_ops = {
+	.module				= THIS_MODULE,
+	.name				= "iscsi",
+	.get_fabric_name		= iscsi_get_fabric_name,
+	.get_fabric_proto_ident		= iscsi_get_fabric_proto_ident,
+	.tpg_get_wwn			= lio_tpg_get_endpoint_wwn,
+	.tpg_get_tag			= lio_tpg_get_tag,
+	.tpg_get_default_depth		= lio_tpg_get_default_depth,
+	.tpg_get_pr_transport_id	= iscsi_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= iscsi_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= iscsi_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= lio_tpg_check_demo_mode,
+	.tpg_check_demo_mode_cache	= lio_tpg_check_demo_mode_cache,
+	.tpg_check_demo_mode_write_protect =
+			lio_tpg_check_demo_mode_write_protect,
+	.tpg_check_prod_mode_write_protect =
+			lio_tpg_check_prod_mode_write_protect,
+	.tpg_alloc_fabric_acl		= lio_tpg_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= lio_tpg_release_fabric_acl,
+	.tpg_get_inst_index		= lio_tpg_get_inst_index,
+	.check_stop_free		= lio_check_stop_free,
+	.release_cmd			= lio_release_cmd,
+	.shutdown_session		= lio_tpg_shutdown_session,
+	.close_session			= lio_tpg_close_session,
+	.sess_get_index			= lio_sess_get_index,
+	.sess_get_initiator_sid		= lio_sess_get_initiator_sid,
+	.write_pending			= lio_write_pending,
+	.write_pending_status		= lio_write_pending_status,
+	.set_default_node_attributes	= lio_set_default_node_attributes,
+	.get_task_tag			= iscsi_get_task_tag,
+	.get_cmd_state			= iscsi_get_cmd_state,
+	.queue_data_in			= lio_queue_data_in,
+	.queue_status			= lio_queue_status,
+	.queue_tm_rsp			= lio_queue_tm_rsp,
+	.aborted_task			= lio_aborted_task,
+	.fabric_make_wwn		= lio_target_call_coreaddtiqn,
+	.fabric_drop_wwn		= lio_target_call_coredeltiqn,
+	.fabric_make_tpg		= lio_target_tiqn_addtpg,
+	.fabric_drop_tpg		= lio_target_tiqn_deltpg,
+	.fabric_make_np			= lio_target_call_addnptotpg,
+	.fabric_drop_np			= lio_target_call_delnpfromtpg,
+	.fabric_make_nodeacl		= lio_target_make_nodeacl,
+	.fabric_drop_nodeacl		= lio_target_drop_nodeacl,
+
+	.tfc_discovery_attrs		= lio_target_discovery_auth_attrs,
+	.tfc_wwn_attrs			= lio_target_wwn_attrs,
+	.tfc_tpg_base_attrs		= lio_target_tpg_attrs,
+	.tfc_tpg_attrib_attrs		= lio_target_tpg_attrib_attrs,
+	.tfc_tpg_auth_attrs		= lio_target_tpg_auth_attrs,
+	.tfc_tpg_param_attrs		= lio_target_tpg_param_attrs,
+	.tfc_tpg_np_base_attrs		= lio_target_portal_attrs,
+	.tfc_tpg_nacl_base_attrs	= lio_target_initiator_attrs,
+	.tfc_tpg_nacl_attrib_attrs	= lio_target_nacl_attrib_attrs,
+	.tfc_tpg_nacl_auth_attrs	= lio_target_nacl_auth_attrs,
+	.tfc_tpg_nacl_param_attrs	= lio_target_nacl_param_attrs,
+};
diff --git a/drivers/target/iscsi/iscsi_target_configfs.h b/drivers/target/iscsi/iscsi_target_configfs.h
deleted file mode 100644
index 8cd5a63..0000000
--- a/drivers/target/iscsi/iscsi_target_configfs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef ISCSI_TARGET_CONFIGFS_H
-#define ISCSI_TARGET_CONFIGFS_H
-
-extern int iscsi_target_register_configfs(void);
-extern void iscsi_target_deregister_configfs(void);
-
-#endif /* ISCSI_TARGET_CONFIGFS_H */
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index bdd127c..2d763ad 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void)
 		return -1;
 	}
 
-	ret = core_tpg_register(
-			&lio_target_fabric_configfs->tf_ops,
-			NULL, &tpg->tpg_se_tpg, tpg,
-			TRANSPORT_TPG_TYPE_DISCOVERY);
+	ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg,
+				tpg, TRANSPORT_TPG_TYPE_DISCOVERY);
 	if (ret < 0) {
 		kfree(tpg);
 		return -1;
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index f4618e7..1f9f01c 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;
@@ -1192,8 +1191,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
 	/*
 	 * 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);
@@ -1341,127 +1339,49 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
 
 /* 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;
-	/*
-	 * 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 = NULL;
-	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_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,
+};
 
 static int __init tcm_loop_fabric_init(void)
 {
@@ -1485,7 +1405,7 @@ static int __init tcm_loop_fabric_init(void)
 	if (ret)
 		goto out_destroy_cache;
 
-	ret = tcm_loop_register_configfs();
+	ret = target_register_template(&loop_ops);
 	if (ret)
 		goto out_release_core_bus;
 
@@ -1503,7 +1423,7 @@ out:
 
 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);
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 9512af6..18b0f97 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -42,8 +42,7 @@
 
 #include "sbp_target.h"
 
-/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *sbp_fabric_configfs;
+static const struct target_core_fabric_ops sbp_ops;
 
 /* FireWire address region for management and command block address handlers */
 static const struct fw_address_region sbp_register_region = {
@@ -2215,8 +2214,7 @@ static struct se_portal_group *sbp_make_tpg(
 		goto out_free_tpg;
 	}
 
-	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
-			&tpg->se_tpg, (void *)tpg,
+	ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg,
 			TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0)
 		goto out_unreg_mgt_agt;
@@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
 	NULL,
 };
 
-static struct target_core_fabric_ops sbp_ops = {
+static const struct target_core_fabric_ops sbp_ops = {
+	.module				= THIS_MODULE,
+	.name				= "sbp",
 	.get_fabric_name		= sbp_get_fabric_name,
 	.get_fabric_proto_ident		= sbp_get_fabric_proto_ident,
 	.tpg_get_wwn			= sbp_get_fabric_wwn,
@@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= sbp_make_nodeacl,
 	.fabric_drop_nodeacl		= sbp_drop_nodeacl,
-};
-
-static int sbp_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-
-	fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
-	if (IS_ERR(fabric)) {
-		pr_err("target_fabric_configfs_init() failed\n");
-		return PTR_ERR(fabric);
-	}
-
-	fabric->tf_ops = sbp_ops;
-
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = sbp_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;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() failed for SBP\n");
-		return ret;
-	}
 
-	sbp_fabric_configfs = fabric;
-
-	return 0;
-};
-
-static void sbp_deregister_configfs(void)
-{
-	if (!sbp_fabric_configfs)
-		return;
-
-	target_fabric_configfs_deregister(sbp_fabric_configfs);
-	sbp_fabric_configfs = NULL;
+	.tfc_wwn_attrs			= sbp_wwn_attrs,
+	.tfc_tpg_base_attrs		= sbp_tpg_base_attrs,
+	.tfc_tpg_attrib_attrs		= sbp_tpg_attrib_attrs,
 };
 
 static int __init sbp_init(void)
 {
-	int ret;
-
-	ret = sbp_register_configfs();
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	return target_register_template(&sbp_ops);
 };
 
 static void __exit sbp_exit(void)
 {
-	sbp_deregister_configfs();
+	target_unregister_template(&sbp_ops);
 };
 
 MODULE_DESCRIPTION("FireWire SBP fabric driver");
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 69baf1c..a653694 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -300,81 +300,17 @@ struct configfs_subsystem *target_core_subsystem[] = {
 // Start functions called by external Target Fabrics Modules
 //############################################################################*/
 
-/*
- * First function called by fabric modules to:
- *
- * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer.
- * 2) Add struct target_fabric_configfs to g_tf_list
- * 3) Return struct target_fabric_configfs to fabric module to be passed
- *    into target_fabric_configfs_register().
- */
-struct target_fabric_configfs *target_fabric_configfs_init(
-	struct module *fabric_mod,
-	const char *name)
+static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo)
 {
-	struct target_fabric_configfs *tf;
-
-	if (!(name)) {
-		pr_err("Unable to locate passed fabric name\n");
-		return ERR_PTR(-EINVAL);
+	if (!tfo->name) {
+		pr_err("Missing tfo->name\n");
+		return -EINVAL;
 	}
-	if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) {
+	if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) {
 		pr_err("Passed name: %s exceeds TARGET_FABRIC"
-			"_NAME_SIZE\n", name);
-		return ERR_PTR(-EINVAL);
+			"_NAME_SIZE\n", tfo->name);
+		return -EINVAL;
 	}
-
-	tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
-	if (!tf)
-		return ERR_PTR(-ENOMEM);
-
-	INIT_LIST_HEAD(&tf->tf_list);
-	atomic_set(&tf->tf_access_cnt, 0);
-	/*
-	 * Setup the default generic struct config_item_type's (cits) in
-	 * struct target_fabric_configfs->tf_cit_tmpl
-	 */
-	tf->tf_module = fabric_mod;
-	target_fabric_setup_cits(tf);
-
-	tf->tf_subsys = target_core_subsystem[0];
-	snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name);
-
-	mutex_lock(&g_tf_lock);
-	list_add_tail(&tf->tf_list, &g_tf_list);
-	mutex_unlock(&g_tf_lock);
-
-	pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>"
-			">>>>>>>>>>>>>>\n");
-	pr_debug("Initialized struct target_fabric_configfs: %p for"
-			" %s\n", tf, tf->tf_name);
-	return tf;
-}
-EXPORT_SYMBOL(target_fabric_configfs_init);
-
-/*
- * Called by fabric plugins after FAILED target_fabric_configfs_register() call.
- */
-void target_fabric_configfs_free(
-	struct target_fabric_configfs *tf)
-{
-	mutex_lock(&g_tf_lock);
-	list_del(&tf->tf_list);
-	mutex_unlock(&g_tf_lock);
-
-	kfree(tf);
-}
-EXPORT_SYMBOL(target_fabric_configfs_free);
-
-/*
- * Perform a sanity check of the passed tf->tf_ops before completing
- * TCM fabric module registration.
- */
-static int target_fabric_tf_ops_check(
-	struct target_fabric_configfs *tf)
-{
-	struct target_core_fabric_ops *tfo = &tf->tf_ops;
-
 	if (!tfo->get_fabric_name) {
 		pr_err("Missing tfo->get_fabric_name()\n");
 		return -EINVAL;
@@ -508,77 +444,61 @@ static int target_fabric_tf_ops_check(
 	return 0;
 }
 
-/*
- * Called 2nd from fabric module with returned parameter of
- * struct target_fabric_configfs * from target_fabric_configfs_init().
- *
- * Upon a successful registration, the new fabric's struct config_item is
- * return.  Also, a pointer to this struct is set in the passed
- * struct target_fabric_configfs.
- */
-int target_fabric_configfs_register(
-	struct target_fabric_configfs *tf)
+int target_register_template(const struct target_core_fabric_ops *fo)
 {
+	struct target_fabric_configfs *tf;
 	int ret;
 
+	ret = target_fabric_tf_ops_check(fo);
+	if (ret)
+		return ret;
+
+	tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
 	if (!tf) {
-		pr_err("Unable to locate target_fabric_configfs"
-			" pointer\n");
-		return -EINVAL;
-	}
-	if (!tf->tf_subsys) {
-		pr_err("Unable to target struct config_subsystem"
-			" pointer\n");
-		return -EINVAL;
+		pr_err("%s: could not allocate memory!\n", __func__);
+		return -ENOMEM;
 	}
-	ret = target_fabric_tf_ops_check(tf);
-	if (ret < 0)
-		return ret;
 
-	pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
-		">>>>>>>>>>\n");
+	INIT_LIST_HEAD(&tf->tf_list);
+	atomic_set(&tf->tf_access_cnt, 0);
+
+	/*
+	 * Setup the default generic struct config_item_type's (cits) in
+	 * struct target_fabric_configfs->tf_cit_tmpl
+	 */
+	tf->tf_module = fo->module;
+	target_fabric_setup_cits(tf);
+
+	tf->tf_subsys = target_core_subsystem[0];
+	snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name);
+
+	tf->tf_ops = *fo;
+	target_fabric_copy_attrs(&tf->tf_cit_tmpl, &tf->tf_ops);
+
+	mutex_lock(&g_tf_lock);
+	list_add_tail(&tf->tf_list, &g_tf_list);
+	mutex_unlock(&g_tf_lock);
+
 	return 0;
 }
-EXPORT_SYMBOL(target_fabric_configfs_register);
+EXPORT_SYMBOL(target_register_template);
 
-void target_fabric_configfs_deregister(
-	struct target_fabric_configfs *tf)
+void target_unregister_template(const struct target_core_fabric_ops *fo)
 {
-	struct configfs_subsystem *su;
+	struct target_fabric_configfs *t;
 
-	if (!tf) {
-		pr_err("Unable to locate passed target_fabric_"
-			"configfs\n");
-		return;
-	}
-	su = tf->tf_subsys;
-	if (!su) {
-		pr_err("Unable to locate passed tf->tf_subsys"
-			" pointer\n");
-		return;
-	}
-	pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
-			">>>>>>>>>>>>\n");
 	mutex_lock(&g_tf_lock);
-	if (atomic_read(&tf->tf_access_cnt)) {
-		mutex_unlock(&g_tf_lock);
-		pr_err("Non zero tf->tf_access_cnt for fabric %s\n",
-			tf->tf_name);
-		BUG();
+	list_for_each_entry(t, &g_tf_list, tf_list) {
+		if (strcmp(t->tf_name, fo->name)) {
+			BUG_ON(atomic_read(&t->tf_access_cnt));
+			list_del(&t->tf_list);
+			kfree(t);
+			break;
+		}
 	}
-	list_del(&tf->tf_list);
 	mutex_unlock(&g_tf_lock);
-
-	pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
-			" %s\n", tf->tf_name);
-	tf->tf_module = NULL;
-	tf->tf_subsys = NULL;
-	kfree(tf);
-
-	pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
-			">>>>>\n");
 }
-EXPORT_SYMBOL(target_fabric_configfs_deregister);
+EXPORT_SYMBOL(target_unregister_template);
 
 /*##############################################################################
 // Stop functions called by external Target Fabrics Modules
@@ -945,7 +865,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
 	struct se_lun *lun;
 	struct se_portal_group *se_tpg;
 	struct t10_pr_registration *pr_reg;
-	struct target_core_fabric_ops *tfo;
+	const struct target_core_fabric_ops *tfo;
 	ssize_t len = 0;
 
 	spin_lock(&dev->dev_reservation_lock);
@@ -979,7 +899,7 @@ SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
 static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
 		struct se_device *dev, char *page)
 {
-	struct target_core_fabric_ops *tfo;
+	const struct target_core_fabric_ops *tfo;
 	struct t10_pr_registration *pr_reg;
 	unsigned char buf[384];
 	char i_buf[PR_REG_ISID_ID_LEN];
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 0c3f901..4bd7d38 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -1236,3 +1236,42 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 
 	return 0;
 }
+
+#define copy_attr(dst, orig, m)						\
+do {									\
+	struct configfs_attribute **oa = orig->tfc_##m##_attrs;	\
+	struct configfs_attribute ***da = &dst->tfc_##m##_cit.ct_attrs;	\
+									\
+	if (oa) {							\
+		if (!*da)						\
+			*da = oa;					\
+		else							\
+			pr_err("Both the target core and the target driver define tfc_" #m "attributes"); \
+	}								\
+} while (0)
+
+void target_fabric_copy_attrs(struct target_fabric_configfs_template *ct,
+			      const struct target_core_fabric_ops *fo)
+{
+	copy_attr(ct, fo, discovery);
+	copy_attr(ct, fo, wwn);
+	copy_attr(ct, fo, wwn_fabric_stats);
+	copy_attr(ct, fo, tpg);
+	copy_attr(ct, fo, tpg_base);
+	copy_attr(ct, fo, tpg_port);
+	copy_attr(ct, fo, tpg_port_stat);
+	copy_attr(ct, fo, tpg_lun);
+	copy_attr(ct, fo, tpg_np);
+	copy_attr(ct, fo, tpg_np_base);
+	copy_attr(ct, fo, tpg_attrib);
+	copy_attr(ct, fo, tpg_auth);
+	copy_attr(ct, fo, tpg_param);
+	copy_attr(ct, fo, tpg_nacl);
+	copy_attr(ct, fo, tpg_nacl_base);
+	copy_attr(ct, fo, tpg_nacl_attrib);
+	copy_attr(ct, fo, tpg_nacl_auth);
+	copy_attr(ct, fo, tpg_nacl_param);
+	copy_attr(ct, fo, tpg_nacl_stat);
+	copy_attr(ct, fo, tpg_mappedlun);
+	copy_attr(ct, fo, tpg_mappedlun_stat);
+}
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 2de6fb8..6dc8915 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -664,7 +664,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
 	struct se_dev_entry *deve_tmp;
 	struct se_node_acl *nacl_tmp;
 	struct se_port *port, *port_tmp;
-	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+	const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
 	struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
 	int ret;
 	/*
@@ -963,7 +963,7 @@ int core_scsi3_check_aptpl_registration(
 }
 
 static void __core_scsi3_dump_registration(
-	struct target_core_fabric_ops *tfo,
+	const struct target_core_fabric_ops *tfo,
 	struct se_device *dev,
 	struct se_node_acl *nacl,
 	struct t10_pr_registration *pr_reg,
@@ -1004,7 +1004,7 @@ static void __core_scsi3_add_registration(
 	enum register_type register_type,
 	int register_move)
 {
-	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+	const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
 	struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
 	struct t10_reservation *pr_tmpl = &dev->t10_pr;
 
@@ -1221,7 +1221,7 @@ static void __core_scsi3_free_registration(
 	struct list_head *preempt_and_abort_list,
 	int dec_holders)
 {
-	struct target_core_fabric_ops *tfo =
+	const struct target_core_fabric_ops *tfo =
 			pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
 	struct t10_reservation *pr_tmpl = &dev->t10_pr;
 	char i_buf[PR_REG_ISID_ID_LEN];
@@ -1445,7 +1445,7 @@ core_scsi3_decode_spec_i_port(
 	struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
 	LIST_HEAD(tid_dest_list);
 	struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
-	struct target_core_fabric_ops *tmp_tf_ops;
+	const struct target_core_fabric_ops *tmp_tf_ops;
 	unsigned char *buf;
 	unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
 	char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
@@ -2409,7 +2409,7 @@ static void __core_scsi3_complete_pro_release(
 	int explicit,
 	int unreg)
 {
-	struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
+	const struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
 	char i_buf[PR_REG_ISID_ID_LEN];
 	int pr_res_type = 0, pr_res_scope = 0;
 
@@ -2726,7 +2726,7 @@ static void __core_scsi3_complete_pro_preempt(
 	enum preempt_type preempt_type)
 {
 	struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
-	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+	const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
 	char i_buf[PR_REG_ISID_ID_LEN];
 
 	memset(i_buf, 0, PR_REG_ISID_ID_LEN);
@@ -3111,7 +3111,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
 	struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
 	struct se_port *se_port;
 	struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
-	struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
+	const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
 	struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
 	struct t10_reservation *pr_tmpl = &dev->t10_pr;
 	unsigned char *buf;
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 0696de9..47f0644 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -672,7 +672,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
 }
 
 int core_tpg_register(
-	struct target_core_fabric_ops *tfo,
+	const struct target_core_fabric_ops *tfo,
 	struct se_wwn *se_wwn,
 	struct se_portal_group *se_tpg,
 	void *tpg_fabric_ptr,
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4a00ed5..32c5e3d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -486,7 +486,7 @@ EXPORT_SYMBOL(transport_free_session);
 void transport_deregister_session(struct se_session *se_sess)
 {
 	struct se_portal_group *se_tpg = se_sess->se_tpg;
-	struct target_core_fabric_ops *se_tfo;
+	const struct target_core_fabric_ops *se_tfo;
 	struct se_node_acl *se_nacl;
 	unsigned long flags;
 	bool comp_nacl = true;
@@ -1142,7 +1142,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
  */
 void transport_init_se_cmd(
 	struct se_cmd *cmd,
-	struct target_core_fabric_ops *tfo,
+	const struct target_core_fabric_ops *tfo,
 	struct se_session *se_sess,
 	u32 data_length,
 	int data_direction,
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 04cad3b..8091ea1 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -425,7 +425,7 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
 	return 0;
 }
 
-static struct target_core_fabric_ops xcopy_pt_tfo = {
+static const struct target_core_fabric_ops xcopy_pt_tfo = {
 	.get_fabric_name	= xcopy_pt_get_fabric_name,
 	.get_task_tag		= xcopy_pt_get_tag,
 	.get_cmd_state		= xcopy_pt_get_cmd_state,
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index a0bcfd3..881deb3 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -129,7 +129,6 @@ struct ft_cmd {
 
 extern struct mutex ft_lport_lock;
 extern struct fc4_prov ft_prov;
-extern struct target_fabric_configfs *ft_configfs;
 extern unsigned int ft_debug_logging;
 
 /*
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index efdcb96..65dce13 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -48,7 +48,7 @@
 
 #include "tcm_fc.h"
 
-struct target_fabric_configfs *ft_configfs;
+static const struct target_core_fabric_ops ft_fabric_ops;
 
 static LIST_HEAD(ft_wwn_list);
 DEFINE_MUTEX(ft_lport_lock);
@@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg(
 		return NULL;
 	}
 
-	ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
+	ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg,
 				tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		destroy_workqueue(wq);
@@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
 	return tpg->index;
 }
 
-static struct target_core_fabric_ops ft_fabric_ops = {
+static const struct target_core_fabric_ops ft_fabric_ops = {
+	.module =			THIS_MODULE,
+	.name =				"fc",
 	.get_fabric_name =		ft_get_fabric_name,
 	.get_fabric_proto_ident =	fc_get_fabric_proto_ident,
 	.tpg_get_wwn =			ft_get_fabric_wwn,
@@ -552,62 +554,10 @@ static struct target_core_fabric_ops ft_fabric_ops = {
 	.fabric_drop_np =		NULL,
 	.fabric_make_nodeacl =		&ft_add_acl,
 	.fabric_drop_nodeacl =		&ft_del_acl,
-};
-
-static int ft_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-
-	/*
-	 * Register the top level struct config_item_type with TCM core
-	 */
-	fabric = target_fabric_configfs_init(THIS_MODULE, "fc");
-	if (IS_ERR(fabric)) {
-		pr_err("%s: target_fabric_configfs_init() failed!\n",
-		       __func__);
-		return PTR_ERR(fabric);
-	}
-	fabric->tf_ops = ft_fabric_ops;
-
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs =
-						    ft_nacl_base_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	/*
-	 * register the fabric for use within TCM
-	 */
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_debug("target_fabric_configfs_register() for"
-			    " FC Target failed!\n");
-		target_fabric_configfs_free(fabric);
-		return -1;
-	}
-
-	/*
-	 * Setup our local pointer to *fabric.
-	 */
-	ft_configfs = fabric;
-	return 0;
-}
 
-static void ft_deregister_configfs(void)
-{
-	if (!ft_configfs)
-		return;
-	target_fabric_configfs_deregister(ft_configfs);
-	ft_configfs = NULL;
-}
+	.tfc_wwn_attrs			= ft_wwn_attrs,
+	.tfc_tpg_nacl_base_attrs	= ft_nacl_base_attrs,
+};
 
 static struct notifier_block ft_notifier = {
 	.notifier_call = ft_lport_notify
@@ -615,15 +565,24 @@ static struct notifier_block ft_notifier = {
 
 static int __init ft_init(void)
 {
-	if (ft_register_configfs())
-		return -1;
-	if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) {
-		ft_deregister_configfs();
-		return -1;
-	}
+	int ret;
+
+	ret = target_register_template(&ft_fabric_ops);
+	if (ret)
+		goto out;
+
+	ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov);
+	if (ret)
+		goto out_unregister_template;
+
 	blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
 	fc_lport_iterate(ft_lport_add, NULL);
 	return 0;
+
+out_unregister_template:
+	target_unregister_template(&ft_fabric_ops);
+out:
+	return ret;
 }
 
 static void __exit ft_exit(void)
@@ -632,7 +591,7 @@ static void __exit ft_exit(void)
 					   &ft_notifier);
 	fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
 	fc_lport_iterate(ft_lport_del, NULL);
-	ft_deregister_configfs();
+	target_unregister_template(&ft_fabric_ops);
 	synchronize_rcu();
 }
 
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
index 3a49416..7ea2a44c 100644
--- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
@@ -29,7 +29,7 @@
 
 USB_GADGET_COMPOSITE_OPTIONS();
 
-static struct target_fabric_configfs *usbg_fabric_configfs;
+static const struct target_core_fabric_ops usbg_ops;
 
 static inline struct f_uas *to_f_uas(struct usb_function *f)
 {
@@ -1572,8 +1572,7 @@ static struct se_portal_group *usbg_make_tpg(
 	tpg->tport = tport;
 	tpg->tport_tpgt = tpgt;
 
-	ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
-				&tpg->se_tpg, tpg,
+	ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg,
 				TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		destroy_workqueue(tpg->workqueue);
@@ -1865,7 +1864,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd)
 	return 1;
 }
 
-static struct target_core_fabric_ops usbg_ops = {
+static const struct target_core_fabric_ops usbg_ops = {
+	.module				= THIS_MODULE,
+	.name				= "usb_gadget",
 	.get_fabric_name		= usbg_get_fabric_name,
 	.get_fabric_proto_ident		= usbg_get_fabric_proto_ident,
 	.tpg_get_wwn			= usbg_get_fabric_wwn,
@@ -1907,46 +1908,9 @@ static struct target_core_fabric_ops usbg_ops = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= usbg_make_nodeacl,
 	.fabric_drop_nodeacl		= usbg_drop_nodeacl,
-};
-
-static int usbg_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
-
-	fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
-	if (IS_ERR(fabric)) {
-		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
-		return PTR_ERR(fabric);
-	}
-
-	fabric->tf_ops = usbg_ops;
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		printk(KERN_ERR "target_fabric_configfs_register() failed"
-				" for usb-gadget\n");
-		return ret;
-	}
-	usbg_fabric_configfs = fabric;
-	return 0;
-};
 
-static void usbg_deregister_configfs(void)
-{
-	if (!(usbg_fabric_configfs))
-		return;
-
-	target_fabric_configfs_deregister(usbg_fabric_configfs);
-	usbg_fabric_configfs = NULL;
+	.tfc_wwn_attrs			= usbg_wwn_attrs,
+	.tfc_tpg_base_attrs		= usbg_base_attrs,
 };
 
 /* Start gadget.c code */
@@ -2455,16 +2419,13 @@ static void usbg_detach(struct usbg_tpg *tpg)
 
 static int __init usb_target_gadget_init(void)
 {
-	int ret;
-
-	ret = usbg_register_configfs();
-	return ret;
+	return target_register_template(&usbg_ops);
 }
 module_init(usb_target_gadget_init);
 
 static void __exit usb_target_gadget_exit(void)
 {
-	usbg_deregister_configfs();
+	target_unregister_template(&usbg_ops);
 }
 module_exit(usb_target_gadget_exit);
 
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 8d4f3f1..492ec2e 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -214,9 +214,7 @@ struct vhost_scsi {
 	int vs_events_nr; /* num of pending events, protected by vq->mutex */
 };
 
-/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
-
+static struct target_core_fabric_ops vhost_scsi_ops;
 static struct workqueue_struct *vhost_scsi_workqueue;
 
 /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
@@ -2156,7 +2154,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn,
 	tpg->tport = tport;
 	tpg->tport_tpgt = tpgt;
 
-	ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn,
+	ret = core_tpg_register(&vhost_scsi_ops, wwn,
 				&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		kfree(tpg);
@@ -2278,6 +2276,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
 };
 
 static struct target_core_fabric_ops vhost_scsi_ops = {
+	.module				= THIS_MODULE,
+	.name				= "vhost",
 	.get_fabric_name		= vhost_scsi_get_fabric_name,
 	.get_fabric_proto_ident		= vhost_scsi_get_fabric_proto_ident,
 	.tpg_get_wwn			= vhost_scsi_get_fabric_wwn,
@@ -2321,70 +2321,19 @@ static struct target_core_fabric_ops vhost_scsi_ops = {
 	.fabric_drop_np			= NULL,
 	.fabric_make_nodeacl		= vhost_scsi_make_nodeacl,
 	.fabric_drop_nodeacl		= vhost_scsi_drop_nodeacl,
+
+	.tfc_wwn_attrs			= vhost_scsi_wwn_attrs,
+	.tfc_tpg_base_attrs		= vhost_scsi_tpg_attrs,
 };
 
-static int vhost_scsi_register_configfs(void)
+static int __init vhost_scsi_init(void)
 {
-	struct target_fabric_configfs *fabric;
-	int ret;
+	int ret = -ENOMEM;
 
-	pr_debug("vhost-scsi fabric module %s on %s/%s"
+	pr_debug("TCM_VHOST fabric module %s on %s/%s"
 		" on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
 		utsname()->machine);
-	/*
-	 * Register the top level struct config_item_type with TCM core
-	 */
-	fabric = target_fabric_configfs_init(THIS_MODULE, "vhost");
-	if (IS_ERR(fabric)) {
-		pr_err("target_fabric_configfs_init() failed\n");
-		return PTR_ERR(fabric);
-	}
-	/*
-	 * Setup fabric->tf_ops from our local vhost_scsi_ops
-	 */
-	fabric->tf_ops = vhost_scsi_ops;
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	/*
-	 * Register the fabric for use within TCM
-	 */
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		pr_err("target_fabric_configfs_register() failed"
-				" for TCM_VHOST\n");
-		return ret;
-	}
-	/*
-	 * Setup our local pointer to *fabric
-	 */
-	vhost_scsi_fabric_configfs = fabric;
-	pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n");
-	return 0;
-};
-
-static void vhost_scsi_deregister_configfs(void)
-{
-	if (!vhost_scsi_fabric_configfs)
-		return;
-
-	target_fabric_configfs_deregister(vhost_scsi_fabric_configfs);
-	vhost_scsi_fabric_configfs = NULL;
-	pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n");
-};
 
-static int __init vhost_scsi_init(void)
-{
-	int ret = -ENOMEM;
 	/*
 	 * Use our own dedicated workqueue for submitting I/O into
 	 * target core to avoid contention within system_wq.
@@ -2397,7 +2346,7 @@ static int __init vhost_scsi_init(void)
 	if (ret < 0)
 		goto out_destroy_workqueue;
 
-	ret = vhost_scsi_register_configfs();
+	ret = target_register_template(&vhost_scsi_ops);
 	if (ret < 0)
 		goto out_vhost_scsi_deregister;
 
@@ -2413,7 +2362,7 @@ out:
 
 static void vhost_scsi_exit(void)
 {
-	vhost_scsi_deregister_configfs();
+	target_unregister_template(&vhost_scsi_ops);
 	vhost_scsi_deregister();
 	destroy_workqueue(vhost_scsi_workqueue);
 };
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index 61653a0..f8a1bd7 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -205,8 +205,7 @@ static LIST_HEAD(scsiback_free_pages);
 static DEFINE_MUTEX(scsiback_mutex);
 static LIST_HEAD(scsiback_list);
 
-/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *scsiback_fabric_configfs;
+static const struct target_core_fabric_ops scsiback_ops;
 
 static void scsiback_get(struct vscsibk_info *info)
 {
@@ -1901,7 +1900,7 @@ scsiback_make_tpg(struct se_wwn *wwn,
 	tpg->tport = tport;
 	tpg->tport_tpgt = tpgt;
 
-	ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn,
+	ret = core_tpg_register(&scsiback_ops, wwn,
 				&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
 	if (ret < 0) {
 		kfree(tpg);
@@ -1943,7 +1942,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg)
 	return 0;
 }
 
-static struct target_core_fabric_ops scsiback_ops = {
+static const struct target_core_fabric_ops scsiback_ops = {
+	.module				= THIS_MODULE,
+	.name				= "xen-pvscsi",
 	.get_fabric_name		= scsiback_get_fabric_name,
 	.get_fabric_proto_ident		= scsiback_get_fabric_proto_ident,
 	.tpg_get_wwn			= scsiback_get_fabric_wwn,
@@ -1990,62 +1991,10 @@ static struct target_core_fabric_ops scsiback_ops = {
 	.fabric_make_nodeacl		= scsiback_make_nodeacl,
 	.fabric_drop_nodeacl		= scsiback_drop_nodeacl,
 #endif
-};
-
-static int scsiback_register_configfs(void)
-{
-	struct target_fabric_configfs *fabric;
-	int ret;
 
-	pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n",
-		 VSCSI_VERSION, utsname()->sysname, utsname()->machine);
-	/*
-	 * Register the top level struct config_item_type with TCM core
-	 */
-	fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi");
-	if (IS_ERR(fabric))
-		return PTR_ERR(fabric);
-
-	/*
-	 * Setup fabric->tf_ops from our local scsiback_ops
-	 */
-	fabric->tf_ops = scsiback_ops;
-	/*
-	 * Setup default attribute lists for various fabric->tf_cit_tmpl
-	 */
-	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs;
-	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-	/*
-	 * Register the fabric for use within TCM
-	 */
-	ret = target_fabric_configfs_register(fabric);
-	if (ret < 0) {
-		target_fabric_configfs_free(fabric);
-		return ret;
-	}
-	/*
-	 * Setup our local pointer to *fabric
-	 */
-	scsiback_fabric_configfs = fabric;
-	pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n");
-	return 0;
-};
-
-static void scsiback_deregister_configfs(void)
-{
-	if (!scsiback_fabric_configfs)
-		return;
-
-	target_fabric_configfs_deregister(scsiback_fabric_configfs);
-	scsiback_fabric_configfs = NULL;
-	pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n");
+	.tfc_wwn_attrs			= scsiback_wwn_attrs,
+	.tfc_tpg_base_attrs		= scsiback_tpg_attrs,
+	.tfc_tpg_param_attrs		= scsiback_param_attrs,
 };
 
 static const struct xenbus_device_id scsiback_ids[] = {
@@ -2077,6 +2026,9 @@ static int __init scsiback_init(void)
 	if (!xen_domain())
 		return -ENODEV;
 
+	pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n",
+		 VSCSI_VERSION, utsname()->sysname, utsname()->machine);
+
 	scsiback_cachep = kmem_cache_create("vscsiif_cache",
 		sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend);
 	if (!scsiback_cachep)
@@ -2086,7 +2038,7 @@ static int __init scsiback_init(void)
 	if (ret)
 		goto out_cache_destroy;
 
-	ret = scsiback_register_configfs();
+	ret = target_register_template(&scsiback_ops);
 	if (ret)
 		goto out_unregister_xenbus;
 
@@ -2109,7 +2061,7 @@ static void __exit scsiback_exit(void)
 			BUG();
 		gnttab_free_pages(1, &page);
 	}
-	scsiback_deregister_configfs();
+	target_unregister_template(&scsiback_ops);
 	xenbus_unregister_driver(&scsiback_driver);
 	kmem_cache_destroy(scsiback_cachep);
 }
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 672150b..905a7f4 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -520,7 +520,7 @@ struct se_cmd {
 	struct list_head	se_cmd_list;
 	struct completion	cmd_wait_comp;
 	struct kref		cmd_kref;
-	struct target_core_fabric_ops *se_tfo;
+	const struct target_core_fabric_ops *se_tfo;
 	sense_reason_t		(*execute_cmd)(struct se_cmd *);
 	sense_reason_t		(*execute_rw)(struct se_cmd *, struct scatterlist *,
 					      u32, enum dma_data_direction);
@@ -890,7 +890,7 @@ struct se_portal_group {
 	/* List of TCM sessions associated wth this TPG */
 	struct list_head	tpg_sess_list;
 	/* Pointer to $FABRIC_MOD dependent code */
-	struct target_core_fabric_ops *se_tpg_tfo;
+	const struct target_core_fabric_ops *se_tpg_tfo;
 	struct se_wwn		*se_tpg_wwn;
 	struct config_group	tpg_group;
 	struct config_group	*tpg_default_groups[7];
diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h
index e080138..1f9600e 100644
--- a/include/target/target_core_configfs.h
+++ b/include/target/target_core_configfs.h
@@ -5,12 +5,6 @@
 #define TARGET_CORE_NAME_MAX_LEN	64
 #define TARGET_FABRIC_NAME_SIZE		32
 
-extern struct target_fabric_configfs *target_fabric_configfs_init(
-				struct module *, const char *);
-extern void target_fabric_configfs_free(struct target_fabric_configfs *);
-extern int target_fabric_configfs_register(struct target_fabric_configfs *);
-extern void target_fabric_configfs_deregister(struct target_fabric_configfs *);
-
 struct target_fabric_configfs_template {
 	struct config_item_type tfc_discovery_cit;
 	struct config_item_type	tfc_wwn_cit;
@@ -53,4 +47,3 @@ struct target_fabric_configfs {
 	struct target_core_fabric_ops tf_ops;
 	struct target_fabric_configfs_template tf_cit_tmpl;
 };
-
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 2f4a250..b155290 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -2,6 +2,8 @@
 #define TARGET_CORE_FABRIC_H
 
 struct target_core_fabric_ops {
+	struct module *module;
+	const char *name;
 	struct configfs_subsystem *tf_subsys;
 	char *(*get_fabric_name)(void);
 	u8 (*get_fabric_proto_ident)(struct se_portal_group *);
@@ -82,8 +84,33 @@ struct target_core_fabric_ops {
 	struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *,
 				struct config_group *, const char *);
 	void (*fabric_drop_nodeacl)(struct se_node_acl *);
+
+	struct configfs_attribute **tfc_discovery_attrs;
+	struct configfs_attribute **tfc_wwn_attrs;
+	struct configfs_attribute **tfc_wwn_fabric_stats_attrs;
+	struct configfs_attribute **tfc_tpg_attrs;
+	struct configfs_attribute **tfc_tpg_base_attrs;
+	struct configfs_attribute **tfc_tpg_lun_attrs;
+	struct configfs_attribute **tfc_tpg_port_attrs;
+	struct configfs_attribute **tfc_tpg_port_stat_attrs;
+	struct configfs_attribute **tfc_tpg_np_attrs;
+	struct configfs_attribute **tfc_tpg_np_base_attrs;
+	struct configfs_attribute **tfc_tpg_attrib_attrs;
+	struct configfs_attribute **tfc_tpg_auth_attrs;
+	struct configfs_attribute **tfc_tpg_param_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_base_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_attrib_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_auth_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_param_attrs;
+	struct configfs_attribute **tfc_tpg_nacl_stat_attrs;
+	struct configfs_attribute **tfc_tpg_mappedlun_attrs;
+	struct configfs_attribute **tfc_tpg_mappedlun_stat_attrs;
 };
 
+int target_register_template(const struct target_core_fabric_ops *fo);
+void target_unregister_template(const struct target_core_fabric_ops *fo);
+
 struct se_session *transport_init_session(enum target_prot_op);
 int transport_alloc_session_tags(struct se_session *, unsigned int,
 		unsigned int);
@@ -102,7 +129,8 @@ void	transport_deregister_session_configfs(struct se_session *);
 void	transport_deregister_session(struct se_session *);
 
 
-void	transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
+void	transport_init_se_cmd(struct se_cmd *,
+		const struct target_core_fabric_ops *,
 		struct se_session *, u32, int, int, unsigned char *);
 sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
 sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
@@ -154,8 +182,8 @@ int	core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
 		unsigned char *, u32, int);
 int	core_tpg_set_initiator_node_tag(struct se_portal_group *,
 		struct se_node_acl *, const char *);
-int	core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *,
-		struct se_portal_group *, void *, int);
+int	core_tpg_register(const struct target_core_fabric_ops *,
+		struct se_wwn *, struct se_portal_group *, void *, int);
 int	core_tpg_deregister(struct se_portal_group *);
 
 /* SAS helpers */
diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h
index 7a0649c..f7d2d09 100644
--- a/include/target/target_core_fabric_configfs.h
+++ b/include/target/target_core_fabric_configfs.h
@@ -119,4 +119,9 @@ static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \
 	__CONFIGFS_EATTR_RO(_name,					\
 	_fabric##_disc_show_##_name);
 
+struct target_fabric_configfs_template;
+struct target_core_fabric_ops;
+
 extern int target_fabric_setup_cits(struct target_fabric_configfs *);
+void target_fabric_copy_attrs(struct target_fabric_configfs_template *ct,
+			      const struct target_core_fabric_ops *fo);
-- 
1.9.1

--
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