diff mbox

configfs: switch ->default groups to a linked list

Message ID 1456490031-7132-1-git-send-email-hch@lst.de (mailing list archive)
State New, archived
Headers show

Commit Message

Christoph Hellwig Feb. 26, 2016, 12:33 p.m. UTC
Replace the current NULL-terminated array of default groups with a linked
list.  This gets rid of lots of nasty code to size and/or dynamically
allocate the array.

While we're at it also provide a conveniant helper to remove the default
groups.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 Documentation/filesystems/configfs/configfs.txt |  11 +-
 drivers/infiniband/core/cma_configfs.c          |  31 ++--
 drivers/target/iscsi/iscsi_target_configfs.c    |  75 +++------
 drivers/target/target_core_configfs.c           | 203 +++++-------------------
 drivers/target/target_core_fabric_configfs.c    | 194 ++++++----------------
 drivers/target/target_core_internal.h           |   1 -
 drivers/target/target_core_stat.c               |  41 ++---
 drivers/usb/gadget/configfs.c                   |  36 ++---
 drivers/usb/gadget/function/f_mass_storage.c    |   6 +-
 drivers/usb/gadget/function/f_rndis.c           |   1 -
 drivers/usb/gadget/function/uvc_configfs.c      | 198 +++++++++--------------
 fs/configfs/dir.c                               |  44 +++--
 fs/configfs/item.c                              |   1 +
 fs/dlm/config.c                                 |  38 +----
 fs/ocfs2/cluster/nodemanager.c                  |  22 +--
 include/linux/configfs.h                        |  11 +-
 include/target/target_core_base.h               |   3 -
 17 files changed, 284 insertions(+), 632 deletions(-)

Comments

Felipe Balbi Feb. 26, 2016, 12:43 p.m. UTC | #1
Christoph Hellwig <hch@lst.de> writes:

> Replace the current NULL-terminated array of default groups with a linked
> list.  This gets rid of lots of nasty code to size and/or dynamically
> allocate the array.
>
> While we're at it also provide a conveniant helper to remove the default
> groups.
>

looks ok to my eyes. For drivers/usb/gadget:

Acked-by: Felipe Balbi <balbi@kernel.org>
Nicholas A. Bellinger Feb. 27, 2016, 11:22 p.m. UTC | #2
On Fri, 2016-02-26 at 13:33 +0100, Christoph Hellwig wrote:
> Replace the current NULL-terminated array of default groups with a linked
> list.  This gets rid of lots of nasty code to size and/or dynamically
> allocate the array.
> 
> While we're at it also provide a conveniant helper to remove the default
> groups.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  Documentation/filesystems/configfs/configfs.txt |  11 +-
>  drivers/infiniband/core/cma_configfs.c          |  31 ++--
>  drivers/target/iscsi/iscsi_target_configfs.c    |  75 +++------
>  drivers/target/target_core_configfs.c           | 203 +++++-------------------
>  drivers/target/target_core_fabric_configfs.c    | 194 ++++++----------------
>  drivers/target/target_core_internal.h           |   1 -
>  drivers/target/target_core_stat.c               |  41 ++---
>  drivers/usb/gadget/configfs.c                   |  36 ++---
>  drivers/usb/gadget/function/f_mass_storage.c    |   6 +-
>  drivers/usb/gadget/function/f_rndis.c           |   1 -
>  drivers/usb/gadget/function/uvc_configfs.c      | 198 +++++++++--------------
>  fs/configfs/dir.c                               |  44 +++--
>  fs/configfs/item.c                              |   1 +
>  fs/dlm/config.c                                 |  38 +----
>  fs/ocfs2/cluster/nodemanager.c                  |  22 +--
>  include/linux/configfs.h                        |  11 +-
>  include/target/target_core_base.h               |   3 -
>  17 files changed, 284 insertions(+), 632 deletions(-)
> 

This is a very nice simplification to drop the long-standing fixed size
->default_groups[] usage tree-wide for configfs consumers.

For the target parts:

Acked-by: Nicholas Bellinger <nab@linux-iscsi.org>

Also, this applies cleanly to target-pending/for-next, so I don't see a
problem merging it up via your new configfs tree.

Otherwise let me know, and I'll be happy to merge via target-pending.

Thanks HCH.
Sagi Grimberg Feb. 28, 2016, 10:58 a.m. UTC | #3
On 26/02/2016 14:33, Christoph Hellwig wrote:
> Replace the current NULL-terminated array of default groups with a linked
> list.  This gets rid of lots of nasty code to size and/or dynamically
> allocate the array.
>
> While we're at it also provide a conveniant helper to remove the default
> groups.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---

Nice!

> -As a consequence of this, default_groups cannot be removed directly via
> +As a consequence of this, default groups cannot be removed directly via
>   rmdir(2).  They also are not considered when rmdir(2) on the parent
>   group is checking for children.
>

What's changed here?

Other than that, looks good

Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Christoph Hellwig Feb. 28, 2016, 1:09 p.m. UTC | #4
On Sun, Feb 28, 2016 at 12:58:42PM +0200, Sagi Grimberg wrote:
>> -As a consequence of this, default_groups cannot be removed directly via
>> +As a consequence of this, default groups cannot be removed directly via
>>   rmdir(2).  They also are not considered when rmdir(2) on the parent
>>   group is checking for children.
>>
>
> What's changed here?

I removed the underscore in default_groups - while we still have
a member of that name it's not exposed directly anymore, so I'd rather
not have the documentation refer to it.
Joel Becker March 5, 2016, 9:40 p.m. UTC | #5
Acked-by: Joel Becker <jlbec@evilplan.org>

On Fri, Feb 26, 2016 at 01:33:51PM +0100, Christoph Hellwig wrote:
> Replace the current NULL-terminated array of default groups with a linked
> list.  This gets rid of lots of nasty code to size and/or dynamically
> allocate the array.
> 
> While we're at it also provide a conveniant helper to remove the default
> groups.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  Documentation/filesystems/configfs/configfs.txt |  11 +-
>  drivers/infiniband/core/cma_configfs.c          |  31 ++--
>  drivers/target/iscsi/iscsi_target_configfs.c    |  75 +++------
>  drivers/target/target_core_configfs.c           | 203 +++++-------------------
>  drivers/target/target_core_fabric_configfs.c    | 194 ++++++----------------
>  drivers/target/target_core_internal.h           |   1 -
>  drivers/target/target_core_stat.c               |  41 ++---
>  drivers/usb/gadget/configfs.c                   |  36 ++---
>  drivers/usb/gadget/function/f_mass_storage.c    |   6 +-
>  drivers/usb/gadget/function/f_rndis.c           |   1 -
>  drivers/usb/gadget/function/uvc_configfs.c      | 198 +++++++++--------------
>  fs/configfs/dir.c                               |  44 +++--
>  fs/configfs/item.c                              |   1 +
>  fs/dlm/config.c                                 |  38 +----
>  fs/ocfs2/cluster/nodemanager.c                  |  22 +--
>  include/linux/configfs.h                        |  11 +-
>  include/target/target_core_base.h               |   3 -
>  17 files changed, 284 insertions(+), 632 deletions(-)
> 
> diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
> index e5fe521..8ec9136 100644
> --- a/Documentation/filesystems/configfs/configfs.txt
> +++ b/Documentation/filesystems/configfs/configfs.txt
> @@ -250,7 +250,8 @@ child item.
>  		struct config_item		cg_item;
>  		struct list_head		cg_children;
>  		struct configfs_subsystem 	*cg_subsys;
> -		struct config_group		**default_groups;
> +		struct list_head		default_groups;
> +		struct list_head		group_entry;
>  	};
>  
>  	void config_group_init(struct config_group *group);
> @@ -420,15 +421,15 @@ These automatic subgroups, or default groups, do not preclude other
>  children of the parent group.  If ct_group_ops->make_group() exists,
>  other child groups can be created on the parent group directly.
>  
> -A configfs subsystem specifies default groups by filling in the
> -NULL-terminated array default_groups on the config_group structure.
> -Each group in that array is populated in the configfs tree at the same
> +A configfs subsystem specifies default groups by adding them using the
> +configfs_add_default_group() function to the parent config_group
> +structure.  Each added group is populated in the configfs tree at the same
>  time as the parent group.  Similarly, they are removed at the same time
>  as the parent.  No extra notification is provided.  When a ->drop_item()
>  method call notifies the subsystem the parent group is going away, it
>  also means every default group child associated with that parent group.
>  
> -As a consequence of this, default_groups cannot be removed directly via
> +As a consequence of this, default groups cannot be removed directly via
>  rmdir(2).  They also are not considered when rmdir(2) on the parent
>  group is checking for children.
>  
> diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c
> index 18b112a..41573df 100644
> --- a/drivers/infiniband/core/cma_configfs.c
> +++ b/drivers/infiniband/core/cma_configfs.c
> @@ -49,8 +49,6 @@ struct cma_dev_group {
>  	char				name[IB_DEVICE_NAME_MAX];
>  	struct config_group		device_group;
>  	struct config_group		ports_group;
> -	struct config_group		*default_dev_group[2];
> -	struct config_group		**default_ports_group;
>  	struct cma_dev_port_group	*ports;
>  };
>  
> @@ -158,7 +156,6 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
>  	unsigned int i;
>  	unsigned int ports_num;
>  	struct cma_dev_port_group *ports;
> -	struct config_group **ports_group;
>  	int err;
>  
>  	ibdev = cma_get_ib_dev(cma_dev);
> @@ -169,9 +166,8 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
>  	ports_num = ibdev->phys_port_cnt;
>  	ports = kcalloc(ports_num, sizeof(*cma_dev_group->ports),
>  			GFP_KERNEL);
> -	ports_group = kcalloc(ports_num + 1, sizeof(*ports_group), GFP_KERNEL);
>  
> -	if (!ports || !ports_group) {
> +	if (!ports) {
>  		err = -ENOMEM;
>  		goto free;
>  	}
> @@ -185,18 +181,16 @@ static int make_cma_ports(struct cma_dev_group *cma_dev_group,
>  		config_group_init_type_name(&ports[i].group,
>  					    port_str,
>  					    &cma_port_group_type);
> -		ports_group[i] = &ports[i].group;
> +		configfs_add_default_group(&ports[i].group,
> +				&cma_dev_group->ports_group);
> +
>  	}
> -	ports_group[i] = NULL;
> -	cma_dev_group->default_ports_group = ports_group;
>  	cma_dev_group->ports = ports;
>  
>  	return 0;
>  free:
>  	kfree(ports);
> -	kfree(ports_group);
>  	cma_dev_group->ports = NULL;
> -	cma_dev_group->default_ports_group = NULL;
>  	return err;
>  }
>  
> @@ -220,9 +214,7 @@ static void release_cma_ports_group(struct config_item  *item)
>  							   ports_group);
>  
>  	kfree(cma_dev_group->ports);
> -	kfree(cma_dev_group->default_ports_group);
>  	cma_dev_group->ports = NULL;
> -	cma_dev_group->default_ports_group = NULL;
>  };
>  
>  static struct configfs_item_operations cma_ports_item_ops = {
> @@ -263,22 +255,17 @@ static struct config_group *make_cma_dev(struct config_group *group,
>  
>  	strncpy(cma_dev_group->name, name, sizeof(cma_dev_group->name));
>  
> -	err = make_cma_ports(cma_dev_group, cma_dev);
> -	if (err)
> -		goto fail;
> -
> -	cma_dev_group->ports_group.default_groups =
> -		cma_dev_group->default_ports_group;
>  	config_group_init_type_name(&cma_dev_group->ports_group, "ports",
>  				    &cma_ports_group_type);
>  
> -	cma_dev_group->device_group.default_groups
> -		= cma_dev_group->default_dev_group;
> -	cma_dev_group->default_dev_group[0] = &cma_dev_group->ports_group;
> -	cma_dev_group->default_dev_group[1] = NULL;
> +	err = make_cma_ports(cma_dev_group, cma_dev);
> +	if (err)
> +		goto fail;
>  
>  	config_group_init_type_name(&cma_dev_group->device_group, name,
>  				    &cma_device_group_type);
> +	configfs_add_default_group(&cma_dev_group->ports_group,
> +			&cma_dev_group->device_group);
>  
>  	cma_deref_dev(cma_dev);
>  	return &cma_dev_group->device_group;
> diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
> index 2f821de..a24443b 100644
> --- a/drivers/target/iscsi/iscsi_target_configfs.c
> +++ b/drivers/target/iscsi/iscsi_target_configfs.c
> @@ -771,21 +771,11 @@ static int lio_target_init_nodeacl(struct se_node_acl *se_nacl,
>  {
>  	struct iscsi_node_acl *acl =
>  		container_of(se_nacl, struct iscsi_node_acl, se_node_acl);
> -	struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group;
> -
> -	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!stats_cg->default_groups) {
> -		pr_err("Unable to allocate memory for"
> -				" stats_cg->default_groups\n");
> -		return -ENOMEM;
> -	}
>  
> -	stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group;
> -	stats_cg->default_groups[1] = NULL;
>  	config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group,
>  			"iscsi_sess_stats", &iscsi_stat_sess_cit);
> -
> +	configfs_add_default_group(&acl->node_stat_grps.iscsi_sess_stats_group,
> +			&se_nacl->acl_fabric_stat_group);
>  	return 0;
>  }
>  
> @@ -793,17 +783,8 @@ static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl)
>  {
>  	struct iscsi_node_acl *acl = container_of(se_nacl,
>  			struct iscsi_node_acl, se_node_acl);
> -	struct config_item *df_item;
> -	struct config_group *stats_cg;
> -	int i;
> -
> -	stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
> -	for (i = 0; stats_cg->default_groups[i]; i++) {
> -		df_item = &stats_cg->default_groups[i]->cg_item;
> -		stats_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(stats_cg->default_groups);
> +
> +	configfs_remove_default_groups(&acl->se_node_acl.acl_fabric_stat_group);
>  }
>  
>  /* End items for lio_target_acl_cit */
> @@ -1260,42 +1241,37 @@ static struct se_wwn *lio_target_call_coreaddtiqn(
>  	struct config_group *group,
>  	const char *name)
>  {
> -	struct config_group *stats_cg;
>  	struct iscsi_tiqn *tiqn;
>  
>  	tiqn = iscsit_add_tiqn((unsigned char *)name);
>  	if (IS_ERR(tiqn))
>  		return ERR_CAST(tiqn);
> -	/*
> -	 * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
> -	 */
> -	stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
> -
> -	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
> -				GFP_KERNEL);
> -	if (!stats_cg->default_groups) {
> -		pr_err("Unable to allocate memory for"
> -				" stats_cg->default_groups\n");
> -		iscsit_del_tiqn(tiqn);
> -		return ERR_PTR(-ENOMEM);
> -	}
>  
> -	stats_cg->default_groups[0] = &tiqn->tiqn_stat_grps.iscsi_instance_group;
> -	stats_cg->default_groups[1] = &tiqn->tiqn_stat_grps.iscsi_sess_err_group;
> -	stats_cg->default_groups[2] = &tiqn->tiqn_stat_grps.iscsi_tgt_attr_group;
> -	stats_cg->default_groups[3] = &tiqn->tiqn_stat_grps.iscsi_login_stats_group;
> -	stats_cg->default_groups[4] = &tiqn->tiqn_stat_grps.iscsi_logout_stats_group;
> -	stats_cg->default_groups[5] = NULL;
>  	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_instance_group,
>  			"iscsi_instance", &iscsi_stat_instance_cit);
> +	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_instance_group,
> +			&tiqn->tiqn_wwn.fabric_stat_group);
> +
>  	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
>  			"iscsi_sess_err", &iscsi_stat_sess_err_cit);
> +	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
> +			&tiqn->tiqn_wwn.fabric_stat_group);
> +
>  	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
>  			"iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit);
> +	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
> +			&tiqn->tiqn_wwn.fabric_stat_group);
> +
>  	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
>  			"iscsi_login_stats", &iscsi_stat_login_cit);
> +	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
> +			&tiqn->tiqn_wwn.fabric_stat_group);
> +
>  	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
>  			"iscsi_logout_stats", &iscsi_stat_logout_cit);
> +	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
> +			&tiqn->tiqn_wwn.fabric_stat_group);
> +
>  
>  	pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
>  	pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:"
> @@ -1307,17 +1283,8 @@ static void lio_target_call_coredeltiqn(
>  	struct se_wwn *wwn)
>  {
>  	struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
> -	struct config_item *df_item;
> -	struct config_group *stats_cg;
> -	int i;
> -
> -	stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
> -	for (i = 0; stats_cg->default_groups[i]; i++) {
> -		df_item = &stats_cg->default_groups[i]->cg_item;
> -		stats_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(stats_cg->default_groups);
> +
> +	configfs_remove_default_groups(&tiqn->tiqn_wwn.fabric_stat_group);
>  
>  	pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n",
>  			tiqn->tiqn);
> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
> index 713c63d9..d498533 100644
> --- a/drivers/target/target_core_configfs.c
> +++ b/drivers/target/target_core_configfs.c
> @@ -194,13 +194,11 @@ static struct config_group *target_core_register_fabric(
>  	pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n",
>  			&tf->tf_wwn_cit);
>  
> -	tf->tf_group.default_groups = tf->tf_default_groups;
> -	tf->tf_group.default_groups[0] = &tf->tf_disc_group;
> -	tf->tf_group.default_groups[1] = NULL;
> -
>  	config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit);
> +
>  	config_group_init_type_name(&tf->tf_disc_group, "discovery_auth",
>  			&tf->tf_discovery_cit);
> +	configfs_add_default_group(&tf->tf_disc_group, &tf->tf_group);
>  
>  	pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
>  			" %s\n", tf->tf_group.cg_item.ci_name);
> @@ -216,9 +214,6 @@ static void target_core_deregister_fabric(
>  {
>  	struct target_fabric_configfs *tf = container_of(
>  		to_config_group(item), struct target_fabric_configfs, tf_group);
> -	struct config_group *tf_group;
> -	struct config_item *df_item;
> -	int i;
>  
>  	pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in"
>  		" tf list\n", config_item_name(item));
> @@ -230,12 +225,7 @@ static void target_core_deregister_fabric(
>  	pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci"
>  			" %s\n", config_item_name(item));
>  
> -	tf_group = &tf->tf_group;
> -	for (i = 0; tf_group->default_groups[i]; i++) {
> -		df_item = &tf_group->default_groups[i]->cg_item;
> -		tf_group->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> +	configfs_remove_default_groups(&tf->tf_group);
>  	config_item_put(item);
>  }
>  
> @@ -2151,7 +2141,6 @@ static void target_core_dev_release(struct config_item *item)
>  	struct se_device *dev =
>  		container_of(dev_cg, struct se_device, dev_group);
>  
> -	kfree(dev_cg->default_groups);
>  	target_free_device(dev);
>  }
>  
> @@ -2819,8 +2808,6 @@ static struct config_group *target_core_make_subdev(
>  	struct se_hba *hba = item_to_hba(hba_ci);
>  	struct target_backend *tb = hba->backend;
>  	struct se_device *dev;
> -	struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;
> -	struct config_group *dev_stat_grp = NULL;
>  	int errno = -ENOMEM, ret;
>  
>  	ret = mutex_lock_interruptible(&hba->hba_access_mutex);
> @@ -2831,73 +2818,52 @@ static struct config_group *target_core_make_subdev(
>  	if (!dev)
>  		goto out_unlock;
>  
> -	dev_cg = &dev->dev_group;
> -
> -	dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
> -			GFP_KERNEL);
> -	if (!dev_cg->default_groups)
> -		goto out_free_device;
> +	config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit);
>  
> -	config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit);
>  	config_group_init_type_name(&dev->dev_attrib.da_group, "attrib",
>  			&tb->tb_dev_attrib_cit);
> +	configfs_add_default_group(&dev->dev_attrib.da_group, &dev->dev_group);
> +
>  	config_group_init_type_name(&dev->dev_pr_group, "pr",
>  			&tb->tb_dev_pr_cit);
> +	configfs_add_default_group(&dev->dev_pr_group, &dev->dev_group);
> +
>  	config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn",
>  			&tb->tb_dev_wwn_cit);
> +	configfs_add_default_group(&dev->t10_wwn.t10_wwn_group,
> +			&dev->dev_group);
> +
>  	config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group,
>  			"alua", &tb->tb_dev_alua_tg_pt_gps_cit);
> +	configfs_add_default_group(&dev->t10_alua.alua_tg_pt_gps_group,
> +			&dev->dev_group);
> +
>  	config_group_init_type_name(&dev->dev_stat_grps.stat_group,
>  			"statistics", &tb->tb_dev_stat_cit);
> +	configfs_add_default_group(&dev->dev_stat_grps.stat_group,
> +			&dev->dev_group);
>  
> -	dev_cg->default_groups[0] = &dev->dev_attrib.da_group;
> -	dev_cg->default_groups[1] = &dev->dev_pr_group;
> -	dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group;
> -	dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group;
> -	dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group;
> -	dev_cg->default_groups[5] = NULL;
>  	/*
>  	 * Add core/$HBA/$DEV/alua/default_tg_pt_gp
>  	 */
>  	tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1);
>  	if (!tg_pt_gp)
> -		goto out_free_dev_cg_default_groups;
> +		goto out_free_device;
>  	dev->t10_alua.default_tg_pt_gp = tg_pt_gp;
>  
> -	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
> -	tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!tg_pt_gp_cg->default_groups) {
> -		pr_err("Unable to allocate tg_pt_gp_cg->"
> -				"default_groups\n");
> -		goto out_free_tg_pt_gp;
> -	}
> -
>  	config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,
>  			"default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);
> -	tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;
> -	tg_pt_gp_cg->default_groups[1] = NULL;
> +	configfs_add_default_group(&tg_pt_gp->tg_pt_gp_group,
> +			&dev->t10_alua.alua_tg_pt_gps_group);
> +
>  	/*
>  	 * Add core/$HBA/$DEV/statistics/ default groups
>  	 */
> -	dev_stat_grp = &dev->dev_stat_grps.stat_group;
> -	dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4,
> -				GFP_KERNEL);
> -	if (!dev_stat_grp->default_groups) {
> -		pr_err("Unable to allocate dev_stat_grp->default_groups\n");
> -		goto out_free_tg_pt_gp_cg_default_groups;
> -	}
>  	target_stat_setup_dev_default_groups(dev);
>  
>  	mutex_unlock(&hba->hba_access_mutex);
> -	return dev_cg;
> +	return &dev->dev_group;
>  
> -out_free_tg_pt_gp_cg_default_groups:
> -	kfree(tg_pt_gp_cg->default_groups);
> -out_free_tg_pt_gp:
> -	core_alua_free_tg_pt_gp(tg_pt_gp);
> -out_free_dev_cg_default_groups:
> -	kfree(dev_cg->default_groups);
>  out_free_device:
>  	target_free_device(dev);
>  out_unlock:
> @@ -2913,40 +2879,22 @@ static void target_core_drop_subdev(
>  	struct se_device *dev =
>  		container_of(dev_cg, struct se_device, dev_group);
>  	struct se_hba *hba;
> -	struct config_item *df_item;
> -	struct config_group *tg_pt_gp_cg, *dev_stat_grp;
> -	int i;
>  
>  	hba = item_to_hba(&dev->se_hba->hba_group.cg_item);
>  
>  	mutex_lock(&hba->hba_access_mutex);
>  
> -	dev_stat_grp = &dev->dev_stat_grps.stat_group;
> -	for (i = 0; dev_stat_grp->default_groups[i]; i++) {
> -		df_item = &dev_stat_grp->default_groups[i]->cg_item;
> -		dev_stat_grp->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(dev_stat_grp->default_groups);
> +	configfs_remove_default_groups(&dev->dev_stat_grps.stat_group);
> +	configfs_remove_default_groups(&dev->t10_alua.alua_tg_pt_gps_group);
>  
> -	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
> -	for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {
> -		df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;
> -		tg_pt_gp_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(tg_pt_gp_cg->default_groups);
>  	/*
>  	 * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp
>  	 * directly from target_core_alua_tg_pt_gp_release().
>  	 */
>  	dev->t10_alua.default_tg_pt_gp = NULL;
>  
> -	for (i = 0; dev_cg->default_groups[i]; i++) {
> -		df_item = &dev_cg->default_groups[i]->cg_item;
> -		dev_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> +	configfs_remove_default_groups(dev_cg);
> +
>  	/*
>  	 * se_dev is released from target_core_dev_item_ops->release()
>  	 */
> @@ -3141,8 +3089,6 @@ void target_setup_backend_cits(struct target_backend *tb)
>  
>  static int __init target_core_init_configfs(void)
>  {
> -	struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
> -	struct config_group *lu_gp_cg = NULL;
>  	struct configfs_subsystem *subsys = &target_core_fabrics;
>  	struct t10_alua_lu_gp *lu_gp;
>  	int ret;
> @@ -3161,51 +3107,24 @@ static int __init target_core_init_configfs(void)
>  	 * Create $CONFIGFS/target/core default group for HBA <-> Storage Object
>  	 * and ALUA Logical Unit Group and Target Port Group infrastructure.
>  	 */
> -	target_cg = &subsys->su_group;
> -	target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!target_cg->default_groups) {
> -		pr_err("Unable to allocate target_cg->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out_global;
> -	}
> +	config_group_init_type_name(&target_core_hbagroup, "core",
> +			&target_core_cit);
> +	configfs_add_default_group(&target_core_hbagroup, &subsys->su_group);
>  
> -	config_group_init_type_name(&target_core_hbagroup,
> -			"core", &target_core_cit);
> -	target_cg->default_groups[0] = &target_core_hbagroup;
> -	target_cg->default_groups[1] = NULL;
>  	/*
>  	 * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/
>  	 */
> -	hba_cg = &target_core_hbagroup;
> -	hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!hba_cg->default_groups) {
> -		pr_err("Unable to allocate hba_cg->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out_global;
> -	}
> -	config_group_init_type_name(&alua_group,
> -			"alua", &target_core_alua_cit);
> -	hba_cg->default_groups[0] = &alua_group;
> -	hba_cg->default_groups[1] = NULL;
> +	config_group_init_type_name(&alua_group, "alua", &target_core_alua_cit);
> +	configfs_add_default_group(&alua_group, &target_core_hbagroup);
> +
>  	/*
>  	 * Add ALUA Logical Unit Group and Target Port Group ConfigFS
>  	 * groups under /sys/kernel/config/target/core/alua/
>  	 */
> -	alua_cg = &alua_group;
> -	alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -			GFP_KERNEL);
> -	if (!alua_cg->default_groups) {
> -		pr_err("Unable to allocate alua_cg->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out_global;
> -	}
> +	config_group_init_type_name(&alua_lu_gps_group, "lu_gps",
> +			&target_core_alua_lu_gps_cit);
> +	configfs_add_default_group(&alua_lu_gps_group, &alua_group);
>  
> -	config_group_init_type_name(&alua_lu_gps_group,
> -			"lu_gps", &target_core_alua_lu_gps_cit);
> -	alua_cg->default_groups[0] = &alua_lu_gps_group;
> -	alua_cg->default_groups[1] = NULL;
>  	/*
>  	 * Add core/alua/lu_gps/default_lu_gp
>  	 */
> @@ -3215,20 +3134,12 @@ static int __init target_core_init_configfs(void)
>  		goto out_global;
>  	}
>  
> -	lu_gp_cg = &alua_lu_gps_group;
> -	lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -			GFP_KERNEL);
> -	if (!lu_gp_cg->default_groups) {
> -		pr_err("Unable to allocate lu_gp_cg->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out_global;
> -	}
> -
>  	config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp",
>  				&target_core_alua_lu_gp_cit);
> -	lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group;
> -	lu_gp_cg->default_groups[1] = NULL;
> +	configfs_add_default_group(&lu_gp->lu_gp_group, &alua_lu_gps_group);
> +
>  	default_lu_gp = lu_gp;
> +
>  	/*
>  	 * Register the target_core_mod subsystem with configfs.
>  	 */
> @@ -3267,55 +3178,21 @@ out_global:
>  		core_alua_free_lu_gp(default_lu_gp);
>  		default_lu_gp = NULL;
>  	}
> -	if (lu_gp_cg)
> -		kfree(lu_gp_cg->default_groups);
> -	if (alua_cg)
> -		kfree(alua_cg->default_groups);
> -	if (hba_cg)
> -		kfree(hba_cg->default_groups);
> -	kfree(target_cg->default_groups);
>  	release_se_kmem_caches();
>  	return ret;
>  }
>  
>  static void __exit target_core_exit_configfs(void)
>  {
> -	struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
> -	struct config_item *item;
> -	int i;
> +	configfs_remove_default_groups(&alua_lu_gps_group);
> +	configfs_remove_default_groups(&alua_group);
> +	configfs_remove_default_groups(&target_core_hbagroup);
>  
> -	lu_gp_cg = &alua_lu_gps_group;
> -	for (i = 0; lu_gp_cg->default_groups[i]; i++) {
> -		item = &lu_gp_cg->default_groups[i]->cg_item;
> -		lu_gp_cg->default_groups[i] = NULL;
> -		config_item_put(item);
> -	}
> -	kfree(lu_gp_cg->default_groups);
> -	lu_gp_cg->default_groups = NULL;
> -
> -	alua_cg = &alua_group;
> -	for (i = 0; alua_cg->default_groups[i]; i++) {
> -		item = &alua_cg->default_groups[i]->cg_item;
> -		alua_cg->default_groups[i] = NULL;
> -		config_item_put(item);
> -	}
> -	kfree(alua_cg->default_groups);
> -	alua_cg->default_groups = NULL;
> -
> -	hba_cg = &target_core_hbagroup;
> -	for (i = 0; hba_cg->default_groups[i]; i++) {
> -		item = &hba_cg->default_groups[i]->cg_item;
> -		hba_cg->default_groups[i] = NULL;
> -		config_item_put(item);
> -	}
> -	kfree(hba_cg->default_groups);
> -	hba_cg->default_groups = NULL;
>  	/*
>  	 * We expect subsys->su_group.default_groups to be released
>  	 * by configfs subsystem provider logic..
>  	 */
>  	configfs_unregister_subsystem(&target_core_fabrics);
> -	kfree(target_core_fabrics.su_group.default_groups);
>  
>  	core_alua_free_lu_gp(default_lu_gp);
>  	default_lu_gp = NULL;
> diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
> index f916d18..8caef31 100644
> --- a/drivers/target/target_core_fabric_configfs.c
> +++ b/drivers/target/target_core_fabric_configfs.c
> @@ -273,18 +273,10 @@ static struct config_group *target_fabric_make_mappedlun(
>  	struct se_portal_group *se_tpg = se_nacl->se_tpg;
>  	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
>  	struct se_lun_acl *lacl = NULL;
> -	struct config_item *acl_ci;
> -	struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
>  	char *buf;
>  	unsigned long long mapped_lun;
>  	int ret = 0;
>  
> -	acl_ci = &group->cg_item;
> -	if (!acl_ci) {
> -		pr_err("Unable to locatel acl_ci\n");
> -		return NULL;
> -	}
> -
>  	buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
>  	if (!buf) {
>  		pr_err("Unable to allocate memory for name buf\n");
> @@ -315,37 +307,19 @@ static struct config_group *target_fabric_make_mappedlun(
>  		goto out;
>  	}
>  
> -	lacl_cg = &lacl->se_lun_group;
> -	lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!lacl_cg->default_groups) {
> -		pr_err("Unable to allocate lacl_cg->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out;
> -	}
> -
>  	config_group_init_type_name(&lacl->se_lun_group, name,
>  			&tf->tf_tpg_mappedlun_cit);
> +
>  	config_group_init_type_name(&lacl->ml_stat_grps.stat_group,
>  			"statistics", &tf->tf_tpg_mappedlun_stat_cit);
> -	lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group;
> -	lacl_cg->default_groups[1] = NULL;
> -
> -	ml_stat_grp = &lacl->ml_stat_grps.stat_group;
> -	ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3,
> -				GFP_KERNEL);
> -	if (!ml_stat_grp->default_groups) {
> -		pr_err("Unable to allocate ml_stat_grp->default_groups\n");
> -		ret = -ENOMEM;
> -		goto out;
> -	}
> +	configfs_add_default_group(&lacl->ml_stat_grps.stat_group,
> +			&lacl->se_lun_group);
> +
>  	target_stat_setup_mappedlun_default_groups(lacl);
>  
>  	kfree(buf);
>  	return &lacl->se_lun_group;
>  out:
> -	if (lacl_cg)
> -		kfree(lacl_cg->default_groups);
>  	kfree(lacl);
>  	kfree(buf);
>  	return ERR_PTR(ret);
> @@ -357,25 +331,9 @@ static void target_fabric_drop_mappedlun(
>  {
>  	struct se_lun_acl *lacl = container_of(to_config_group(item),
>  			struct se_lun_acl, se_lun_group);
> -	struct config_item *df_item;
> -	struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
> -	int i;
> -
> -	ml_stat_grp = &lacl->ml_stat_grps.stat_group;
> -	for (i = 0; ml_stat_grp->default_groups[i]; i++) {
> -		df_item = &ml_stat_grp->default_groups[i]->cg_item;
> -		ml_stat_grp->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(ml_stat_grp->default_groups);
>  
> -	lacl_cg = &lacl->se_lun_group;
> -	for (i = 0; lacl_cg->default_groups[i]; i++) {
> -		df_item = &lacl_cg->default_groups[i]->cg_item;
> -		lacl_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(lacl_cg->default_groups);
> +	configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group);
> +	configfs_remove_default_groups(&lacl->se_lun_group);
>  
>  	config_item_put(item);
>  }
> @@ -424,7 +382,6 @@ static struct config_group *target_fabric_make_nodeacl(
>  			struct se_portal_group, tpg_acl_group);
>  	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
>  	struct se_node_acl *se_nacl;
> -	struct config_group *nacl_cg;
>  
>  	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name);
>  	if (IS_ERR(se_nacl))
> @@ -438,24 +395,28 @@ static struct config_group *target_fabric_make_nodeacl(
>  		}
>  	}
>  
> -	nacl_cg = &se_nacl->acl_group;
> -	nacl_cg->default_groups = se_nacl->acl_default_groups;
> -	nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
> -	nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
> -	nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
> -	nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group;
> -	nacl_cg->default_groups[4] = NULL;
> -
>  	config_group_init_type_name(&se_nacl->acl_group, name,
>  			&tf->tf_tpg_nacl_base_cit);
> +
>  	config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
>  			&tf->tf_tpg_nacl_attrib_cit);
> +	configfs_add_default_group(&se_nacl->acl_attrib_group,
> +			&se_nacl->acl_group);
> +
>  	config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
>  			&tf->tf_tpg_nacl_auth_cit);
> +	configfs_add_default_group(&se_nacl->acl_auth_group,
> +			&se_nacl->acl_group);
> +
>  	config_group_init_type_name(&se_nacl->acl_param_group, "param",
>  			&tf->tf_tpg_nacl_param_cit);
> +	configfs_add_default_group(&se_nacl->acl_param_group,
> +			&se_nacl->acl_group);
> +
>  	config_group_init_type_name(&se_nacl->acl_fabric_stat_group,
>  			"fabric_statistics", &tf->tf_tpg_nacl_stat_cit);
> +	configfs_add_default_group(&se_nacl->acl_fabric_stat_group,
> +			&se_nacl->acl_group);
>  
>  	return &se_nacl->acl_group;
>  }
> @@ -466,16 +427,9 @@ static void target_fabric_drop_nodeacl(
>  {
>  	struct se_node_acl *se_nacl = container_of(to_config_group(item),
>  			struct se_node_acl, acl_group);
> -	struct config_item *df_item;
> -	struct config_group *nacl_cg;
> -	int i;
> -
> -	nacl_cg = &se_nacl->acl_group;
> -	for (i = 0; nacl_cg->default_groups[i]; i++) {
> -		df_item = &nacl_cg->default_groups[i]->cg_item;
> -		nacl_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> +
> +	configfs_remove_default_groups(&se_nacl->acl_group);
> +
>  	/*
>  	 * struct se_node_acl free is done in target_fabric_nacl_base_release()
>  	 */
> @@ -795,7 +749,6 @@ static struct config_group *target_fabric_make_lun(
>  	struct se_portal_group *se_tpg = container_of(group,
>  			struct se_portal_group, tpg_lun_group);
>  	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
> -	struct config_group *lun_cg = NULL, *port_stat_grp = NULL;
>  	unsigned long long unpacked_lun;
>  	int errno;
>  
> @@ -812,31 +765,14 @@ static struct config_group *target_fabric_make_lun(
>  	if (IS_ERR(lun))
>  		return ERR_CAST(lun);
>  
> -	lun_cg = &lun->lun_group;
> -	lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
> -				GFP_KERNEL);
> -	if (!lun_cg->default_groups) {
> -		pr_err("Unable to allocate lun_cg->default_groups\n");
> -		kfree(lun);
> -		return ERR_PTR(-ENOMEM);
> -	}
> -
>  	config_group_init_type_name(&lun->lun_group, name,
>  			&tf->tf_tpg_port_cit);
> +
>  	config_group_init_type_name(&lun->port_stat_grps.stat_group,
>  			"statistics", &tf->tf_tpg_port_stat_cit);
> -	lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group;
> -	lun_cg->default_groups[1] = NULL;
> -
> -	port_stat_grp = &lun->port_stat_grps.stat_group;
> -	port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group *) * 4,
> -				GFP_KERNEL);
> -	if (!port_stat_grp->default_groups) {
> -		pr_err("Unable to allocate port_stat_grp->default_groups\n");
> -		kfree(lun_cg->default_groups);
> -		kfree(lun);
> -		return ERR_PTR(-ENOMEM);
> -	}
> +	configfs_add_default_group(&lun->port_stat_grps.stat_group,
> +			&lun->lun_group);
> +
>  	target_stat_setup_port_default_groups(lun);
>  
>  	return &lun->lun_group;
> @@ -848,25 +784,9 @@ static void target_fabric_drop_lun(
>  {
>  	struct se_lun *lun = container_of(to_config_group(item),
>  				struct se_lun, lun_group);
> -	struct config_item *df_item;
> -	struct config_group *lun_cg, *port_stat_grp;
> -	int i;
> -
> -	port_stat_grp = &lun->port_stat_grps.stat_group;
> -	for (i = 0; port_stat_grp->default_groups[i]; i++) {
> -		df_item = &port_stat_grp->default_groups[i]->cg_item;
> -		port_stat_grp->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(port_stat_grp->default_groups);
>  
> -	lun_cg = &lun->lun_group;
> -	for (i = 0; lun_cg->default_groups[i]; i++) {
> -		df_item = &lun_cg->default_groups[i]->cg_item;
> -		lun_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
> -	kfree(lun_cg->default_groups);
> +	configfs_remove_default_groups(&lun->port_stat_grps.stat_group);
> +	configfs_remove_default_groups(&lun->lun_group);
>  
>  	config_item_put(item);
>  }
> @@ -922,32 +842,39 @@ static struct config_group *target_fabric_make_tpg(
>  	se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name);
>  	if (!se_tpg || IS_ERR(se_tpg))
>  		return ERR_PTR(-EINVAL);
> -	/*
> -	 * Setup default groups from pre-allocated se_tpg->tpg_default_groups
> -	 */
> -	se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
> -	se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
> -	se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
> -	se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
> -	se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
> -	se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
> -	se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
> -	se_tpg->tpg_group.default_groups[6] = NULL;
>  
>  	config_group_init_type_name(&se_tpg->tpg_group, name,
>  			&tf->tf_tpg_base_cit);
> +
>  	config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
>  			&tf->tf_tpg_lun_cit);
> +	configfs_add_default_group(&se_tpg->tpg_lun_group,
> +			&se_tpg->tpg_group);
> +
>  	config_group_init_type_name(&se_tpg->tpg_np_group, "np",
>  			&tf->tf_tpg_np_cit);
> +	configfs_add_default_group(&se_tpg->tpg_np_group,
> +			&se_tpg->tpg_group);
> +
>  	config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
>  			&tf->tf_tpg_nacl_cit);
> +	configfs_add_default_group(&se_tpg->tpg_acl_group,
> +			&se_tpg->tpg_group);
> +
>  	config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
>  			&tf->tf_tpg_attrib_cit);
> +	configfs_add_default_group(&se_tpg->tpg_attrib_group,
> +			&se_tpg->tpg_group);
> +
>  	config_group_init_type_name(&se_tpg->tpg_auth_group, "auth",
>  			&tf->tf_tpg_auth_cit);
> +	configfs_add_default_group(&se_tpg->tpg_auth_group,
> +			&se_tpg->tpg_group);
> +
>  	config_group_init_type_name(&se_tpg->tpg_param_group, "param",
>  			&tf->tf_tpg_param_cit);
> +	configfs_add_default_group(&se_tpg->tpg_param_group,
> +			&se_tpg->tpg_group);
>  
>  	return &se_tpg->tpg_group;
>  }
> @@ -958,19 +885,8 @@ static void target_fabric_drop_tpg(
>  {
>  	struct se_portal_group *se_tpg = container_of(to_config_group(item),
>  				struct se_portal_group, tpg_group);
> -	struct config_group *tpg_cg = &se_tpg->tpg_group;
> -	struct config_item *df_item;
> -	int i;
> -	/*
> -	 * Release default groups, but do not release tpg_cg->default_groups
> -	 * memory as it is statically allocated at se_tpg->tpg_default_groups.
> -	 */
> -	for (i = 0; tpg_cg->default_groups[i]; i++) {
> -		df_item = &tpg_cg->default_groups[i]->cg_item;
> -		tpg_cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
>  
> +	configfs_remove_default_groups(&se_tpg->tpg_group);
>  	config_item_put(item);
>  }
>  
> @@ -1026,16 +942,12 @@ static struct config_group *target_fabric_make_wwn(
>  		return ERR_PTR(-EINVAL);
>  
>  	wwn->wwn_tf = tf;
> -	/*
> -	 * Setup default groups from pre-allocated wwn->wwn_default_groups
> -	 */
> -	wwn->wwn_group.default_groups = wwn->wwn_default_groups;
> -	wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group;
> -	wwn->wwn_group.default_groups[1] = NULL;
>  
>  	config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit);
> +
>  	config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics",
>  			&tf->tf_wwn_fabric_stats_cit);
> +	configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group);
>  
>  	return &wwn->wwn_group;
>  }
> @@ -1046,16 +958,8 @@ static void target_fabric_drop_wwn(
>  {
>  	struct se_wwn *wwn = container_of(to_config_group(item),
>  				struct se_wwn, wwn_group);
> -	struct config_item *df_item;
> -	struct config_group *cg = &wwn->wwn_group;
> -	int i;
> -
> -	for (i = 0; cg->default_groups[i]; i++) {
> -		df_item = &cg->default_groups[i]->cg_item;
> -		cg->default_groups[i] = NULL;
> -		config_item_put(df_item);
> -	}
>  
> +	configfs_remove_default_groups(&wwn->wwn_group);
>  	config_item_put(item);
>  }
>  
> diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
> index db4412f..4a7cf49 100644
> --- a/drivers/target/target_core_internal.h
> +++ b/drivers/target/target_core_internal.h
> @@ -22,7 +22,6 @@ struct target_fabric_configfs {
>  	struct list_head	tf_list;
>  	struct config_group	tf_group;
>  	struct config_group	tf_disc_group;
> -	struct config_group	*tf_default_groups[2];
>  	const struct target_core_fabric_ops *tf_ops;
>  
>  	struct config_item_type tf_discovery_cit;
> diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
> index 81a6b3e..1a39033 100644
> --- a/drivers/target/target_core_stat.c
> +++ b/drivers/target/target_core_stat.c
> @@ -407,19 +407,20 @@ static struct config_item_type target_stat_scsi_lu_cit = {
>   */
>  void target_stat_setup_dev_default_groups(struct se_device *dev)
>  {
> -	struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group;
> -
>  	config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group,
>  			"scsi_dev", &target_stat_scsi_dev_cit);
> +	configfs_add_default_group(&dev->dev_stat_grps.scsi_dev_group,
> +			&dev->dev_stat_grps.stat_group);
> +
>  	config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group,
>  			"scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit);
> +	configfs_add_default_group(&dev->dev_stat_grps.scsi_tgt_dev_group,
> +			&dev->dev_stat_grps.stat_group);
> +
>  	config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group,
>  			"scsi_lu", &target_stat_scsi_lu_cit);
> -
> -	dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group;
> -	dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group;
> -	dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group;
> -	dev_stat_grp->default_groups[3] = NULL;
> +	configfs_add_default_group(&dev->dev_stat_grps.scsi_lu_group,
> +			&dev->dev_stat_grps.stat_group);
>  }
>  
>  /*
> @@ -818,19 +819,20 @@ static struct config_item_type target_stat_scsi_transport_cit = {
>   */
>  void target_stat_setup_port_default_groups(struct se_lun *lun)
>  {
> -	struct config_group *port_stat_grp = &lun->port_stat_grps.stat_group;
> -
>  	config_group_init_type_name(&lun->port_stat_grps.scsi_port_group,
>  			"scsi_port", &target_stat_scsi_port_cit);
> +	configfs_add_default_group(&lun->port_stat_grps.scsi_port_group,
> +			&lun->port_stat_grps.stat_group);
> +
>  	config_group_init_type_name(&lun->port_stat_grps.scsi_tgt_port_group,
>  			"scsi_tgt_port", &target_stat_scsi_tgt_port_cit);
> +	configfs_add_default_group(&lun->port_stat_grps.scsi_tgt_port_group,
> +			&lun->port_stat_grps.stat_group);
> +
>  	config_group_init_type_name(&lun->port_stat_grps.scsi_transport_group,
>  			"scsi_transport", &target_stat_scsi_transport_cit);
> -
> -	port_stat_grp->default_groups[0] = &lun->port_stat_grps.scsi_port_group;
> -	port_stat_grp->default_groups[1] = &lun->port_stat_grps.scsi_tgt_port_group;
> -	port_stat_grp->default_groups[2] = &lun->port_stat_grps.scsi_transport_group;
> -	port_stat_grp->default_groups[3] = NULL;
> +	configfs_add_default_group(&lun->port_stat_grps.scsi_transport_group,
> +			&lun->port_stat_grps.stat_group);
>  }
>  
>  /*
> @@ -1351,14 +1353,13 @@ static struct config_item_type target_stat_scsi_att_intr_port_cit = {
>   */
>  void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl)
>  {
> -	struct config_group *ml_stat_grp = &lacl->ml_stat_grps.stat_group;
> -
>  	config_group_init_type_name(&lacl->ml_stat_grps.scsi_auth_intr_group,
>  			"scsi_auth_intr", &target_stat_scsi_auth_intr_cit);
> +	configfs_add_default_group(&lacl->ml_stat_grps.scsi_auth_intr_group,
> +			&lacl->ml_stat_grps.stat_group);
> +
>  	config_group_init_type_name(&lacl->ml_stat_grps.scsi_att_intr_port_group,
>  			"scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit);
> -
> -	ml_stat_grp->default_groups[0] = &lacl->ml_stat_grps.scsi_auth_intr_group;
> -	ml_stat_grp->default_groups[1] = &lacl->ml_stat_grps.scsi_att_intr_port_group;
> -	ml_stat_grp->default_groups[2] = NULL;
> +	configfs_add_default_group(&lacl->ml_stat_grps.scsi_att_intr_port_group,
> +			&lacl->ml_stat_grps.stat_group);
>  }
> diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
> index 590c449..2f8081f 100644
> --- a/drivers/usb/gadget/configfs.c
> +++ b/drivers/usb/gadget/configfs.c
> @@ -49,7 +49,6 @@ struct gadget_info {
>  	struct config_group configs_group;
>  	struct config_group strings_group;
>  	struct config_group os_desc_group;
> -	struct config_group *default_groups[5];
>  
>  	struct mutex lock;
>  	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
> @@ -71,7 +70,6 @@ static inline struct gadget_info *to_gadget_info(struct config_item *item)
>  struct config_usb_cfg {
>  	struct config_group group;
>  	struct config_group strings_group;
> -	struct config_group *default_groups[2];
>  	struct list_head string_list;
>  	struct usb_configuration c;
>  	struct list_head func_list;
> @@ -666,13 +664,12 @@ static struct config_group *config_desc_make(
>  	INIT_LIST_HEAD(&cfg->string_list);
>  	INIT_LIST_HEAD(&cfg->func_list);
>  
> -	cfg->group.default_groups = cfg->default_groups;
> -	cfg->default_groups[0] = &cfg->strings_group;
> -
>  	config_group_init_type_name(&cfg->group, name,
>  				&gadget_config_type);
> +
>  	config_group_init_type_name(&cfg->strings_group, "strings",
>  			&gadget_config_name_strings_type);
> +	configfs_add_default_group(&cfg->strings_group, &cfg->group);
>  
>  	ret = usb_add_config_only(&gi->cdev, &cfg->c);
>  	if (ret)
> @@ -1149,15 +1146,11 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
>  				   char **names,
>  				   struct module *owner)
>  {
> -	struct config_group **f_default_groups, *os_desc_group,
> -				**interface_groups;
> +	struct config_group *os_desc_group;
>  	struct config_item_type *os_desc_type, *interface_type;
>  
>  	vla_group(data_chunk);
> -	vla_item(data_chunk, struct config_group *, f_default_groups, 2);
>  	vla_item(data_chunk, struct config_group, os_desc_group, 1);
> -	vla_item(data_chunk, struct config_group *, interface_groups,
> -		 n_interf + 1);
>  	vla_item(data_chunk, struct config_item_type, os_desc_type, 1);
>  	vla_item(data_chunk, struct config_item_type, interface_type, 1);
>  
> @@ -1165,18 +1158,14 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
>  	if (!vlabuf)
>  		return -ENOMEM;
>  
> -	f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups);
>  	os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
>  	os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
> -	interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups);
>  	interface_type = vla_ptr(vlabuf, data_chunk, interface_type);
>  
> -	parent->default_groups = f_default_groups;
>  	os_desc_type->ct_owner = owner;
>  	config_group_init_type_name(os_desc_group, "os_desc", os_desc_type);
> -	f_default_groups[0] = os_desc_group;
> +	configfs_add_default_group(os_desc_group, parent);
>  
> -	os_desc_group->default_groups = interface_groups;
>  	interface_type->ct_group_ops = &interf_grp_ops;
>  	interface_type->ct_attrs = interf_grp_attrs;
>  	interface_type->ct_owner = owner;
> @@ -1189,7 +1178,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
>  		config_group_init_type_name(&d->group, "", interface_type);
>  		config_item_set_name(&d->group.cg_item, "interface.%s",
>  				     names[n_interf]);
> -		interface_groups[n_interf] = &d->group;
> +		configfs_add_default_group(&d->group, os_desc_group);
>  	}
>  
>  	return 0;
> @@ -1423,20 +1412,23 @@ static struct config_group *gadgets_make(
>  	if (!gi)
>  		return ERR_PTR(-ENOMEM);
>  
> -	gi->group.default_groups = gi->default_groups;
> -	gi->group.default_groups[0] = &gi->functions_group;
> -	gi->group.default_groups[1] = &gi->configs_group;
> -	gi->group.default_groups[2] = &gi->strings_group;
> -	gi->group.default_groups[3] = &gi->os_desc_group;
> +	config_group_init_type_name(&gi->group, name, &gadget_root_type);
>  
>  	config_group_init_type_name(&gi->functions_group, "functions",
>  			&functions_type);
> +	configfs_add_default_group(&gi->functions_group, &gi->group);
> +
>  	config_group_init_type_name(&gi->configs_group, "configs",
>  			&config_desc_type);
> +	configfs_add_default_group(&gi->configs_group, &gi->group);
> +
>  	config_group_init_type_name(&gi->strings_group, "strings",
>  			&gadget_strings_strings_type);
> +	configfs_add_default_group(&gi->strings_group, &gi->group);
> +
>  	config_group_init_type_name(&gi->os_desc_group, "os_desc",
>  			&os_desc_type);
> +	configfs_add_default_group(&gi->os_desc_group, &gi->group);
>  
>  	gi->composite.bind = configfs_do_nothing;
>  	gi->composite.unbind = configfs_do_nothing;
> @@ -1461,8 +1453,6 @@ static struct config_group *gadgets_make(
>  	if (!gi->composite.gadget_driver.function)
>  		goto err;
>  
> -	config_group_init_type_name(&gi->group, name,
> -				&gadget_root_type);
>  	return &gi->group;
>  err:
>  	kfree(gi);
> diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
> index 223ccf8..142bb77 100644
> --- a/drivers/usb/gadget/function/f_mass_storage.c
> +++ b/drivers/usb/gadget/function/f_mass_storage.c
> @@ -3484,12 +3484,12 @@ static struct usb_function_instance *fsg_alloc_inst(void)
>  
>  	opts->lun0.lun = opts->common->luns[0];
>  	opts->lun0.lun_id = 0;
> -	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
> -	opts->default_groups[0] = &opts->lun0.group;
> -	opts->func_inst.group.default_groups = opts->default_groups;
>  
>  	config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type);
>  
> +	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
> +	configfs_add_default_group(&opts->lun0.group, &opts->func_inst.group);
> +
>  	return &opts->func_inst;
>  
>  release_buffers:
> diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
> index e587767..931953e 100644
> --- a/drivers/usb/gadget/function/f_rndis.c
> +++ b/drivers/usb/gadget/function/f_rndis.c
> @@ -889,7 +889,6 @@ static void rndis_free_inst(struct usb_function_instance *f)
>  			free_netdev(opts->net);
>  	}
>  
> -	kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */
>  	kfree(opts);
>  }
>  
> diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
> index ad8c9b0..66753ba 100644
> --- a/drivers/usb/gadget/function/uvc_configfs.c
> +++ b/drivers/usb/gadget/function/uvc_configfs.c
> @@ -272,11 +272,6 @@ static struct config_item_type uvcg_default_processing_type = {
>  
>  /* struct uvcg_processing {}; */
>  
> -static struct config_group *uvcg_processing_default_groups[] = {
> -	&uvcg_default_processing.group,
> -	NULL,
> -};
> -
>  /* control/processing */
>  static struct uvcg_processing_grp {
>  	struct config_group	group;
> @@ -394,11 +389,6 @@ static struct config_item_type uvcg_default_camera_type = {
>  
>  /* struct uvcg_camera {}; */
>  
> -static struct config_group *uvcg_camera_default_groups[] = {
> -	&uvcg_default_camera.group,
> -	NULL,
> -};
> -
>  /* control/terminal/camera */
>  static struct uvcg_camera_grp {
>  	struct config_group	group;
> @@ -477,11 +467,6 @@ static struct config_item_type uvcg_default_output_type = {
>  
>  /* struct uvcg_output {}; */
>  
> -static struct config_group *uvcg_output_default_groups[] = {
> -	&uvcg_default_output.group,
> -	NULL,
> -};
> -
>  /* control/terminal/output */
>  static struct uvcg_output_grp {
>  	struct config_group	group;
> @@ -491,12 +476,6 @@ static struct config_item_type uvcg_output_grp_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_terminal_default_groups[] = {
> -	&uvcg_camera_grp.group,
> -	&uvcg_output_grp.group,
> -	NULL,
> -};
> -
>  /* control/terminal */
>  static struct uvcg_terminal_grp {
>  	struct config_group	group;
> @@ -619,12 +598,6 @@ static struct config_item_type uvcg_control_class_type = {
>  	.ct_owner	= THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_control_class_default_groups[] = {
> -	&uvcg_control_class_fs.group,
> -	&uvcg_control_class_ss.group,
> -	NULL,
> -};
> -
>  /* control/class */
>  static struct uvcg_control_class_grp {
>  	struct config_group	group;
> @@ -634,14 +607,6 @@ static struct config_item_type uvcg_control_class_grp_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_control_default_groups[] = {
> -	&uvcg_control_header_grp.group,
> -	&uvcg_processing_grp.group,
> -	&uvcg_terminal_grp.group,
> -	&uvcg_control_class_grp.group,
> -	NULL,
> -};
> -
>  /* control */
>  static struct uvcg_control_grp {
>  	struct config_group	group;
> @@ -1780,11 +1745,6 @@ static struct config_item_type uvcg_default_color_matching_type = {
>  
>  /* struct uvcg_color_matching {}; */
>  
> -static struct config_group *uvcg_color_matching_default_groups[] = {
> -	&uvcg_default_color_matching.group,
> -	NULL,
> -};
> -
>  /* streaming/color_matching */
>  static struct uvcg_color_matching_grp {
>  	struct config_group	group;
> @@ -2145,13 +2105,6 @@ static struct config_item_type uvcg_streaming_class_type = {
>  	.ct_owner	= THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_streaming_class_default_groups[] = {
> -	&uvcg_streaming_class_fs.group,
> -	&uvcg_streaming_class_hs.group,
> -	&uvcg_streaming_class_ss.group,
> -	NULL,
> -};
> -
>  /* streaming/class */
>  static struct uvcg_streaming_class_grp {
>  	struct config_group	group;
> @@ -2161,15 +2114,6 @@ static struct config_item_type uvcg_streaming_class_grp_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_streaming_default_groups[] = {
> -	&uvcg_streaming_header_grp.group,
> -	&uvcg_uncompressed_grp.group,
> -	&uvcg_mjpeg_grp.group,
> -	&uvcg_color_matching_grp.group,
> -	&uvcg_streaming_class_grp.group,
> -	NULL,
> -};
> -
>  /* streaming */
>  static struct uvcg_streaming_grp {
>  	struct config_group	group;
> @@ -2179,12 +2123,6 @@ static struct config_item_type uvcg_streaming_grp_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> -static struct config_group *uvcg_default_groups[] = {
> -	&uvcg_control_grp.group,
> -	&uvcg_streaming_grp.group,
> -	NULL,
> -};
> -
>  static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
>  {
>  	return container_of(to_config_group(item), struct f_uvc_opts,
> @@ -2273,59 +2211,64 @@ static struct config_item_type uvc_func_type = {
>  	.ct_owner	= THIS_MODULE,
>  };
>  
> -static inline void uvcg_init_group(struct config_group *g,
> -				   struct config_group **default_groups,
> -				   const char *name,
> -				   struct config_item_type *type)
> -{
> -	g->default_groups = default_groups;
> -	config_group_init_type_name(g, name, type);
> -}
> -
>  int uvcg_attach_configfs(struct f_uvc_opts *opts)
>  {
>  	config_group_init_type_name(&uvcg_control_header_grp.group,
>  				    "header",
>  				    &uvcg_control_header_grp_type);
> +
>  	config_group_init_type_name(&uvcg_default_processing.group,
> -				    "default",
> -				    &uvcg_default_processing_type);
> -	uvcg_init_group(&uvcg_processing_grp.group,
> -			uvcg_processing_default_groups,
> -			"processing",
> -			&uvcg_processing_grp_type);
> +			"default", &uvcg_default_processing_type);
> +	config_group_init_type_name(&uvcg_processing_grp.group,
> +			"processing", &uvcg_processing_grp_type);
> +	configfs_add_default_group(&uvcg_default_processing.group,
> +			&uvcg_processing_grp.group);
> +
>  	config_group_init_type_name(&uvcg_default_camera.group,
> -				    "default",
> -				    &uvcg_default_camera_type);
> -	uvcg_init_group(&uvcg_camera_grp.group,
> -			uvcg_camera_default_groups,
> -			"camera",
> -			&uvcg_camera_grp_type);
> +			"default", &uvcg_default_camera_type);
> +	config_group_init_type_name(&uvcg_camera_grp.group,
> +			"camera", &uvcg_camera_grp_type);
> +	configfs_add_default_group(&uvcg_default_camera.group,
> +			&uvcg_camera_grp.group);
> +
>  	config_group_init_type_name(&uvcg_default_output.group,
> -				    "default",
> -				    &uvcg_default_output_type);
> -	uvcg_init_group(&uvcg_output_grp.group,
> -			uvcg_output_default_groups,
> -			"output",
> -			&uvcg_output_grp_type);
> -	uvcg_init_group(&uvcg_terminal_grp.group,
> -			uvcg_terminal_default_groups,
> -			"terminal",
> -			&uvcg_terminal_grp_type);
> +			"default", &uvcg_default_output_type);
> +	config_group_init_type_name(&uvcg_output_grp.group,
> +			"output", &uvcg_output_grp_type);
> +	configfs_add_default_group(&uvcg_default_output.group,
> +			&uvcg_output_grp.group);
> +
> +	config_group_init_type_name(&uvcg_terminal_grp.group,
> +			"terminal", &uvcg_terminal_grp_type);
> +	configfs_add_default_group(&uvcg_camera_grp.group,
> +			&uvcg_terminal_grp.group);
> +	configfs_add_default_group(&uvcg_output_grp.group,
> +			&uvcg_terminal_grp.group);
> +
>  	config_group_init_type_name(&uvcg_control_class_fs.group,
> -				    "fs",
> -				    &uvcg_control_class_type);
> +			"fs", &uvcg_control_class_type);
>  	config_group_init_type_name(&uvcg_control_class_ss.group,
> -				    "ss",
> -				    &uvcg_control_class_type);
> -	uvcg_init_group(&uvcg_control_class_grp.group,
> -			uvcg_control_class_default_groups,
> +			"ss", &uvcg_control_class_type);
> +	config_group_init_type_name(&uvcg_control_class_grp.group,
>  			"class",
>  			&uvcg_control_class_grp_type);
> -	uvcg_init_group(&uvcg_control_grp.group,
> -			uvcg_control_default_groups,
> +	configfs_add_default_group(&uvcg_control_class_fs.group,
> +			&uvcg_control_class_grp.group);
> +	configfs_add_default_group(&uvcg_control_class_ss.group,
> +			&uvcg_control_class_grp.group);
> +
> +	config_group_init_type_name(&uvcg_control_grp.group,
>  			"control",
>  			&uvcg_control_grp_type);
> +	configfs_add_default_group(&uvcg_control_header_grp.group,
> +			&uvcg_control_grp.group);
> +	configfs_add_default_group(&uvcg_processing_grp.group,
> +			&uvcg_control_grp.group);
> +	configfs_add_default_group(&uvcg_terminal_grp.group,
> +			&uvcg_control_grp.group);
> +	configfs_add_default_group(&uvcg_control_class_grp.group,
> +			&uvcg_control_grp.group);
> +
>  	config_group_init_type_name(&uvcg_streaming_header_grp.group,
>  				    "header",
>  				    &uvcg_streaming_header_grp_type);
> @@ -2338,30 +2281,47 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
>  	config_group_init_type_name(&uvcg_default_color_matching.group,
>  				    "default",
>  				    &uvcg_default_color_matching_type);
> -	uvcg_init_group(&uvcg_color_matching_grp.group,
> -			uvcg_color_matching_default_groups,
> +	config_group_init_type_name(&uvcg_color_matching_grp.group,
>  			"color_matching",
>  			&uvcg_color_matching_grp_type);
> +	configfs_add_default_group(&uvcg_default_color_matching.group,
> +			&uvcg_color_matching_grp.group);
> +
>  	config_group_init_type_name(&uvcg_streaming_class_fs.group,
> -				    "fs",
> -				    &uvcg_streaming_class_type);
> +			"fs", &uvcg_streaming_class_type);
>  	config_group_init_type_name(&uvcg_streaming_class_hs.group,
> -				    "hs",
> -				    &uvcg_streaming_class_type);
> +			"hs", &uvcg_streaming_class_type);
>  	config_group_init_type_name(&uvcg_streaming_class_ss.group,
> -				    "ss",
> -				    &uvcg_streaming_class_type);
> -	uvcg_init_group(&uvcg_streaming_class_grp.group,
> -			uvcg_streaming_class_default_groups,
> -			"class",
> -			&uvcg_streaming_class_grp_type);
> -	uvcg_init_group(&uvcg_streaming_grp.group,
> -			uvcg_streaming_default_groups,
> -			"streaming",
> -			&uvcg_streaming_grp_type);
> -	uvcg_init_group(&opts->func_inst.group,
> -			uvcg_default_groups,
> +			"ss", &uvcg_streaming_class_type);
> +	config_group_init_type_name(&uvcg_streaming_class_grp.group,
> +			"class", &uvcg_streaming_class_grp_type);
> +	configfs_add_default_group(&uvcg_streaming_class_fs.group,
> +			&uvcg_streaming_class_grp.group);
> +	configfs_add_default_group(&uvcg_streaming_class_hs.group,
> +			&uvcg_streaming_class_grp.group);
> +	configfs_add_default_group(&uvcg_streaming_class_ss.group,
> +			&uvcg_streaming_class_grp.group);
> +
> +	config_group_init_type_name(&uvcg_streaming_grp.group,
> +			"streaming", &uvcg_streaming_grp_type);
> +	configfs_add_default_group(&uvcg_streaming_header_grp.group,
> +			&uvcg_streaming_grp.group);
> +	configfs_add_default_group(&uvcg_uncompressed_grp.group,
> +			&uvcg_streaming_grp.group);
> +	configfs_add_default_group(&uvcg_mjpeg_grp.group,
> +			&uvcg_streaming_grp.group);
> +	configfs_add_default_group(&uvcg_color_matching_grp.group,
> +			&uvcg_streaming_grp.group);
> +	configfs_add_default_group(&uvcg_streaming_class_grp.group,
> +			&uvcg_streaming_grp.group);
> +
> +	config_group_init_type_name(&opts->func_inst.group,
>  			"",
>  			&uvc_func_type);
> +	configfs_add_default_group(&uvcg_control_grp.group,
> +			&opts->func_inst.group);
> +	configfs_add_default_group(&uvcg_streaming_grp.group,
> +			&opts->func_inst.group);
> +
>  	return 0;
>  }
> diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
> index f419519..b51ce67 100644
> --- a/fs/configfs/dir.c
> +++ b/fs/configfs/dir.c
> @@ -701,23 +701,29 @@ static int populate_groups(struct config_group *group)
>  {
>  	struct config_group *new_group;
>  	int ret = 0;
> -	int i;
> -
> -	if (group->default_groups) {
> -		for (i = 0; group->default_groups[i]; i++) {
> -			new_group = group->default_groups[i];
>  
> -			ret = create_default_group(group, new_group);
> -			if (ret) {
> -				detach_groups(group);
> -				break;
> -			}
> +	list_for_each_entry(new_group, &group->default_groups, group_entry) {
> +		ret = create_default_group(group, new_group);
> +		if (ret) {
> +			detach_groups(group);
> +			break;
>  		}
>  	}
>  
>  	return ret;
>  }
>  
> +void configfs_remove_default_groups(struct config_group *group)
> +{
> +	struct config_group *g, *n;
> +
> +	list_for_each_entry_safe(g, n, &group->default_groups, group_entry) {
> +		list_del(&g->group_entry);
> +		config_item_put(&g->cg_item);
> +	}
> +}
> +EXPORT_SYMBOL(configfs_remove_default_groups);
> +
>  /*
>   * All of link_obj/unlink_obj/link_group/unlink_group require that
>   * subsys->su_mutex is held.
> @@ -766,15 +772,10 @@ static void link_obj(struct config_item *parent_item, struct config_item *item)
>  
>  static void unlink_group(struct config_group *group)
>  {
> -	int i;
>  	struct config_group *new_group;
>  
> -	if (group->default_groups) {
> -		for (i = 0; group->default_groups[i]; i++) {
> -			new_group = group->default_groups[i];
> -			unlink_group(new_group);
> -		}
> -	}
> +	list_for_each_entry(new_group, &group->default_groups, group_entry)
> +		unlink_group(new_group);
>  
>  	group->cg_subsys = NULL;
>  	unlink_obj(&group->cg_item);
> @@ -782,7 +783,6 @@ static void unlink_group(struct config_group *group)
>  
>  static void link_group(struct config_group *parent_group, struct config_group *group)
>  {
> -	int i;
>  	struct config_group *new_group;
>  	struct configfs_subsystem *subsys = NULL; /* gcc is a turd */
>  
> @@ -796,12 +796,8 @@ static void link_group(struct config_group *parent_group, struct config_group *g
>  		BUG();
>  	group->cg_subsys = subsys;
>  
> -	if (group->default_groups) {
> -		for (i = 0; group->default_groups[i]; i++) {
> -			new_group = group->default_groups[i];
> -			link_group(group, new_group);
> -		}
> -	}
> +	list_for_each_entry(new_group, &group->default_groups, group_entry)
> +		link_group(group, new_group);
>  }
>  
>  /*
> diff --git a/fs/configfs/item.c b/fs/configfs/item.c
> index b863a09..8b2a994 100644
> --- a/fs/configfs/item.c
> +++ b/fs/configfs/item.c
> @@ -182,6 +182,7 @@ void config_group_init(struct config_group *group)
>  {
>  	config_item_init(&group->cg_item);
>  	INIT_LIST_HEAD(&group->cg_children);
> +	INIT_LIST_HEAD(&group->default_groups);
>  }
>  EXPORT_SYMBOL(config_group_init);
>  
> diff --git a/fs/dlm/config.c b/fs/dlm/config.c
> index 8e294fb..5191121 100644
> --- a/fs/dlm/config.c
> +++ b/fs/dlm/config.c
> @@ -346,7 +346,6 @@ static struct config_group *make_cluster(struct config_group *g,
>  	void *gps = NULL;
>  
>  	cl = kzalloc(sizeof(struct dlm_cluster), GFP_NOFS);
> -	gps = kcalloc(3, sizeof(struct config_group *), GFP_NOFS);
>  	sps = kzalloc(sizeof(struct dlm_spaces), GFP_NOFS);
>  	cms = kzalloc(sizeof(struct dlm_comms), GFP_NOFS);
>  
> @@ -357,10 +356,8 @@ static struct config_group *make_cluster(struct config_group *g,
>  	config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
>  	config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
>  
> -	cl->group.default_groups = gps;
> -	cl->group.default_groups[0] = &sps->ss_group;
> -	cl->group.default_groups[1] = &cms->cs_group;
> -	cl->group.default_groups[2] = NULL;
> +	configfs_add_default_group(&sps->ss_group, &cl->group);
> +	configfs_add_default_group(&cms->cs_group, &cl->group);
>  
>  	cl->cl_tcp_port = dlm_config.ci_tcp_port;
>  	cl->cl_buffer_size = dlm_config.ci_buffer_size;
> @@ -383,7 +380,6 @@ static struct config_group *make_cluster(struct config_group *g,
>  
>   fail:
>  	kfree(cl);
> -	kfree(gps);
>  	kfree(sps);
>  	kfree(cms);
>  	return ERR_PTR(-ENOMEM);
> @@ -392,14 +388,8 @@ static struct config_group *make_cluster(struct config_group *g,
>  static void drop_cluster(struct config_group *g, struct config_item *i)
>  {
>  	struct dlm_cluster *cl = config_item_to_cluster(i);
> -	struct config_item *tmp;
> -	int j;
>  
> -	for (j = 0; cl->group.default_groups[j]; j++) {
> -		tmp = &cl->group.default_groups[j]->cg_item;
> -		cl->group.default_groups[j] = NULL;
> -		config_item_put(tmp);
> -	}
> +	configfs_remove_default_groups(&cl->group);
>  
>  	space_list = NULL;
>  	comm_list = NULL;
> @@ -410,7 +400,6 @@ static void drop_cluster(struct config_group *g, struct config_item *i)
>  static void release_cluster(struct config_item *i)
>  {
>  	struct dlm_cluster *cl = config_item_to_cluster(i);
> -	kfree(cl->group.default_groups);
>  	kfree(cl);
>  }
>  
> @@ -418,21 +407,17 @@ static struct config_group *make_space(struct config_group *g, const char *name)
>  {
>  	struct dlm_space *sp = NULL;
>  	struct dlm_nodes *nds = NULL;
> -	void *gps = NULL;
>  
>  	sp = kzalloc(sizeof(struct dlm_space), GFP_NOFS);
> -	gps = kcalloc(2, sizeof(struct config_group *), GFP_NOFS);
>  	nds = kzalloc(sizeof(struct dlm_nodes), GFP_NOFS);
>  
> -	if (!sp || !gps || !nds)
> +	if (!sp || !nds)
>  		goto fail;
>  
>  	config_group_init_type_name(&sp->group, name, &space_type);
> -	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
>  
> -	sp->group.default_groups = gps;
> -	sp->group.default_groups[0] = &nds->ns_group;
> -	sp->group.default_groups[1] = NULL;
> +	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
> +	configfs_add_default_group(&nds->ns_group, &sp->group);
>  
>  	INIT_LIST_HEAD(&sp->members);
>  	mutex_init(&sp->members_lock);
> @@ -441,7 +426,6 @@ static struct config_group *make_space(struct config_group *g, const char *name)
>  
>   fail:
>  	kfree(sp);
> -	kfree(gps);
>  	kfree(nds);
>  	return ERR_PTR(-ENOMEM);
>  }
> @@ -449,24 +433,16 @@ static struct config_group *make_space(struct config_group *g, const char *name)
>  static void drop_space(struct config_group *g, struct config_item *i)
>  {
>  	struct dlm_space *sp = config_item_to_space(i);
> -	struct config_item *tmp;
> -	int j;
>  
>  	/* assert list_empty(&sp->members) */
>  
> -	for (j = 0; sp->group.default_groups[j]; j++) {
> -		tmp = &sp->group.default_groups[j]->cg_item;
> -		sp->group.default_groups[j] = NULL;
> -		config_item_put(tmp);
> -	}
> -
> +	configfs_remove_default_groups(&sp->group);
>  	config_item_put(i);
>  }
>  
>  static void release_space(struct config_item *i)
>  {
>  	struct dlm_space *sp = config_item_to_space(i);
> -	kfree(sp->group.default_groups);
>  	kfree(sp);
>  }
>  
> diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
> index ebe5438..b17d180 100644
> --- a/fs/ocfs2/cluster/nodemanager.c
> +++ b/fs/ocfs2/cluster/nodemanager.c
> @@ -630,7 +630,6 @@ static void o2nm_cluster_release(struct config_item *item)
>  {
>  	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
>  
> -	kfree(cluster->cl_group.default_groups);
>  	kfree(cluster);
>  }
>  
> @@ -666,7 +665,6 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
>  	struct o2nm_cluster *cluster = NULL;
>  	struct o2nm_node_group *ns = NULL;
>  	struct config_group *o2hb_group = NULL, *ret = NULL;
> -	void *defs = NULL;
>  
>  	/* this runs under the parent dir's i_mutex; there can be only
>  	 * one caller in here at a time */
> @@ -675,20 +673,18 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
>  
>  	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
>  	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
> -	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
>  	o2hb_group = o2hb_alloc_hb_set();
> -	if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL)
> +	if (cluster == NULL || ns == NULL || o2hb_group == NULL)
>  		goto out;
>  
>  	config_group_init_type_name(&cluster->cl_group, name,
>  				    &o2nm_cluster_type);
> +	configfs_add_default_group(&ns->ns_group, &cluster->cl_group);
> +
>  	config_group_init_type_name(&ns->ns_group, "node",
>  				    &o2nm_node_group_type);
> +	configfs_add_default_group(o2hb_group, &cluster->cl_group);
>  
> -	cluster->cl_group.default_groups = defs;
> -	cluster->cl_group.default_groups[0] = &ns->ns_group;
> -	cluster->cl_group.default_groups[1] = o2hb_group;
> -	cluster->cl_group.default_groups[2] = NULL;
>  	rwlock_init(&cluster->cl_nodes_lock);
>  	cluster->cl_node_ip_tree = RB_ROOT;
>  	cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
> @@ -704,7 +700,6 @@ out:
>  		kfree(cluster);
>  		kfree(ns);
>  		o2hb_free_hb_set(o2hb_group);
> -		kfree(defs);
>  		ret = ERR_PTR(-ENOMEM);
>  	}
>  
> @@ -714,18 +709,11 @@ out:
>  static void o2nm_cluster_group_drop_item(struct config_group *group, struct config_item *item)
>  {
>  	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
> -	int i;
> -	struct config_item *killme;
>  
>  	BUG_ON(o2nm_single_cluster != cluster);
>  	o2nm_single_cluster = NULL;
>  
> -	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
> -		killme = &cluster->cl_group.default_groups[i]->cg_item;
> -		cluster->cl_group.default_groups[i] = NULL;
> -		config_item_put(killme);
> -	}
> -
> +	configfs_remove_default_groups(&cluster->cl_group);
>  	config_item_put(item);
>  }
>  
> diff --git a/include/linux/configfs.h b/include/linux/configfs.h
> index f8165c1..485fe55 100644
> --- a/include/linux/configfs.h
> +++ b/include/linux/configfs.h
> @@ -96,7 +96,8 @@ struct config_group {
>  	struct config_item		cg_item;
>  	struct list_head		cg_children;
>  	struct configfs_subsystem 	*cg_subsys;
> -	struct config_group		**default_groups;
> +	struct list_head		default_groups;
> +	struct list_head		group_entry;
>  };
>  
>  extern void config_group_init(struct config_group *group);
> @@ -123,6 +124,12 @@ extern struct config_item *config_group_find_item(struct config_group *,
>  						  const char *);
>  
>  
> +static inline void configfs_add_default_group(struct config_group *new_group,
> +		struct config_group *group)
> +{
> +	list_add_tail(&new_group->group_entry, &group->default_groups);
> +}
> +
>  struct configfs_attribute {
>  	const char		*ca_name;
>  	struct module 		*ca_owner;
> @@ -251,6 +258,8 @@ int configfs_register_group(struct config_group *parent_group,
>  			    struct config_group *group);
>  void configfs_unregister_group(struct config_group *group);
>  
> +void configfs_remove_default_groups(struct config_group *group);
> +
>  struct config_group *
>  configfs_register_default_group(struct config_group *parent_group,
>  				const char *name,
> diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
> index e8c8c08..1b09cac 100644
> --- a/include/target/target_core_base.h
> +++ b/include/target/target_core_base.h
> @@ -560,7 +560,6 @@ struct se_node_acl {
>  	struct config_group	acl_auth_group;
>  	struct config_group	acl_param_group;
>  	struct config_group	acl_fabric_stat_group;
> -	struct config_group	*acl_default_groups[5];
>  	struct list_head	acl_list;
>  	struct list_head	acl_sess_list;
>  	struct completion	acl_free_comp;
> @@ -887,7 +886,6 @@ struct se_portal_group {
>  	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];
>  	struct config_group	tpg_lun_group;
>  	struct config_group	tpg_np_group;
>  	struct config_group	tpg_acl_group;
> @@ -923,7 +921,6 @@ static inline struct se_portal_group *param_to_tpg(struct config_item *item)
>  struct se_wwn {
>  	struct target_fabric_configfs *wwn_tf;
>  	struct config_group	wwn_group;
> -	struct config_group	*wwn_default_groups[2];
>  	struct config_group	fabric_stat_group;
>  };
>  
> -- 
> 2.1.4
>
Doug Ledford March 11, 2016, 2:19 a.m. UTC | #6
On 02/27/2016 06:22 PM, Nicholas A. Bellinger wrote:
> On Fri, 2016-02-26 at 13:33 +0100, Christoph Hellwig wrote:
>> Replace the current NULL-terminated array of default groups with a linked
>> list.  This gets rid of lots of nasty code to size and/or dynamically
>> allocate the array.
>>
>> While we're at it also provide a conveniant helper to remove the default
>> groups.
>>
>> Signed-off-by: Christoph Hellwig <hch@lst.de>
>> ---
>>  Documentation/filesystems/configfs/configfs.txt |  11 +-
>>  drivers/infiniband/core/cma_configfs.c          |  31 ++--
>>  drivers/target/iscsi/iscsi_target_configfs.c    |  75 +++------
>>  drivers/target/target_core_configfs.c           | 203 +++++-------------------
>>  drivers/target/target_core_fabric_configfs.c    | 194 ++++++----------------
>>  drivers/target/target_core_internal.h           |   1 -
>>  drivers/target/target_core_stat.c               |  41 ++---
>>  drivers/usb/gadget/configfs.c                   |  36 ++---
>>  drivers/usb/gadget/function/f_mass_storage.c    |   6 +-
>>  drivers/usb/gadget/function/f_rndis.c           |   1 -
>>  drivers/usb/gadget/function/uvc_configfs.c      | 198 +++++++++--------------
>>  fs/configfs/dir.c                               |  44 +++--
>>  fs/configfs/item.c                              |   1 +
>>  fs/dlm/config.c                                 |  38 +----
>>  fs/ocfs2/cluster/nodemanager.c                  |  22 +--
>>  include/linux/configfs.h                        |  11 +-
>>  include/target/target_core_base.h               |   3 -
>>  17 files changed, 284 insertions(+), 632 deletions(-)
>>
> 
> This is a very nice simplification to drop the long-standing fixed size
> ->default_groups[] usage tree-wide for configfs consumers.
> 
> For the target parts:
> 
> Acked-by: Nicholas Bellinger <nab@linux-iscsi.org>

For the (minor) RDMA parts:

Acked-by: Doug Ledford <dledford@redhat.com>

> Also, this applies cleanly to target-pending/for-next, so I don't see a
> problem merging it up via your new configfs tree.
> 
> Otherwise let me know, and I'll be happy to merge via target-pending.

Given that it touches target more than anything else, I'm happy to see
it merged through your tree.
diff mbox

Patch

diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index e5fe521..8ec9136 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -250,7 +250,8 @@  child item.
 		struct config_item		cg_item;
 		struct list_head		cg_children;
 		struct configfs_subsystem 	*cg_subsys;
-		struct config_group		**default_groups;
+		struct list_head		default_groups;
+		struct list_head		group_entry;
 	};
 
 	void config_group_init(struct config_group *group);
@@ -420,15 +421,15 @@  These automatic subgroups, or default groups, do not preclude other
 children of the parent group.  If ct_group_ops->make_group() exists,
 other child groups can be created on the parent group directly.
 
-A configfs subsystem specifies default groups by filling in the
-NULL-terminated array default_groups on the config_group structure.
-Each group in that array is populated in the configfs tree at the same
+A configfs subsystem specifies default groups by adding them using the
+configfs_add_default_group() function to the parent config_group
+structure.  Each added group is populated in the configfs tree at the same
 time as the parent group.  Similarly, they are removed at the same time
 as the parent.  No extra notification is provided.  When a ->drop_item()
 method call notifies the subsystem the parent group is going away, it
 also means every default group child associated with that parent group.
 
-As a consequence of this, default_groups cannot be removed directly via
+As a consequence of this, default groups cannot be removed directly via
 rmdir(2).  They also are not considered when rmdir(2) on the parent
 group is checking for children.
 
diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c
index 18b112a..41573df 100644
--- a/drivers/infiniband/core/cma_configfs.c
+++ b/drivers/infiniband/core/cma_configfs.c
@@ -49,8 +49,6 @@  struct cma_dev_group {
 	char				name[IB_DEVICE_NAME_MAX];
 	struct config_group		device_group;
 	struct config_group		ports_group;
-	struct config_group		*default_dev_group[2];
-	struct config_group		**default_ports_group;
 	struct cma_dev_port_group	*ports;
 };
 
@@ -158,7 +156,6 @@  static int make_cma_ports(struct cma_dev_group *cma_dev_group,
 	unsigned int i;
 	unsigned int ports_num;
 	struct cma_dev_port_group *ports;
-	struct config_group **ports_group;
 	int err;
 
 	ibdev = cma_get_ib_dev(cma_dev);
@@ -169,9 +166,8 @@  static int make_cma_ports(struct cma_dev_group *cma_dev_group,
 	ports_num = ibdev->phys_port_cnt;
 	ports = kcalloc(ports_num, sizeof(*cma_dev_group->ports),
 			GFP_KERNEL);
-	ports_group = kcalloc(ports_num + 1, sizeof(*ports_group), GFP_KERNEL);
 
-	if (!ports || !ports_group) {
+	if (!ports) {
 		err = -ENOMEM;
 		goto free;
 	}
@@ -185,18 +181,16 @@  static int make_cma_ports(struct cma_dev_group *cma_dev_group,
 		config_group_init_type_name(&ports[i].group,
 					    port_str,
 					    &cma_port_group_type);
-		ports_group[i] = &ports[i].group;
+		configfs_add_default_group(&ports[i].group,
+				&cma_dev_group->ports_group);
+
 	}
-	ports_group[i] = NULL;
-	cma_dev_group->default_ports_group = ports_group;
 	cma_dev_group->ports = ports;
 
 	return 0;
 free:
 	kfree(ports);
-	kfree(ports_group);
 	cma_dev_group->ports = NULL;
-	cma_dev_group->default_ports_group = NULL;
 	return err;
 }
 
@@ -220,9 +214,7 @@  static void release_cma_ports_group(struct config_item  *item)
 							   ports_group);
 
 	kfree(cma_dev_group->ports);
-	kfree(cma_dev_group->default_ports_group);
 	cma_dev_group->ports = NULL;
-	cma_dev_group->default_ports_group = NULL;
 };
 
 static struct configfs_item_operations cma_ports_item_ops = {
@@ -263,22 +255,17 @@  static struct config_group *make_cma_dev(struct config_group *group,
 
 	strncpy(cma_dev_group->name, name, sizeof(cma_dev_group->name));
 
-	err = make_cma_ports(cma_dev_group, cma_dev);
-	if (err)
-		goto fail;
-
-	cma_dev_group->ports_group.default_groups =
-		cma_dev_group->default_ports_group;
 	config_group_init_type_name(&cma_dev_group->ports_group, "ports",
 				    &cma_ports_group_type);
 
-	cma_dev_group->device_group.default_groups
-		= cma_dev_group->default_dev_group;
-	cma_dev_group->default_dev_group[0] = &cma_dev_group->ports_group;
-	cma_dev_group->default_dev_group[1] = NULL;
+	err = make_cma_ports(cma_dev_group, cma_dev);
+	if (err)
+		goto fail;
 
 	config_group_init_type_name(&cma_dev_group->device_group, name,
 				    &cma_device_group_type);
+	configfs_add_default_group(&cma_dev_group->ports_group,
+			&cma_dev_group->device_group);
 
 	cma_deref_dev(cma_dev);
 	return &cma_dev_group->device_group;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 2f821de..a24443b 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -771,21 +771,11 @@  static int lio_target_init_nodeacl(struct se_node_acl *se_nacl,
 {
 	struct iscsi_node_acl *acl =
 		container_of(se_nacl, struct iscsi_node_acl, se_node_acl);
-	struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group;
-
-	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!stats_cg->default_groups) {
-		pr_err("Unable to allocate memory for"
-				" stats_cg->default_groups\n");
-		return -ENOMEM;
-	}
 
-	stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group;
-	stats_cg->default_groups[1] = NULL;
 	config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group,
 			"iscsi_sess_stats", &iscsi_stat_sess_cit);
-
+	configfs_add_default_group(&acl->node_stat_grps.iscsi_sess_stats_group,
+			&se_nacl->acl_fabric_stat_group);
 	return 0;
 }
 
@@ -793,17 +783,8 @@  static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl)
 {
 	struct iscsi_node_acl *acl = container_of(se_nacl,
 			struct iscsi_node_acl, se_node_acl);
-	struct config_item *df_item;
-	struct config_group *stats_cg;
-	int i;
-
-	stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
-	for (i = 0; stats_cg->default_groups[i]; i++) {
-		df_item = &stats_cg->default_groups[i]->cg_item;
-		stats_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(stats_cg->default_groups);
+
+	configfs_remove_default_groups(&acl->se_node_acl.acl_fabric_stat_group);
 }
 
 /* End items for lio_target_acl_cit */
@@ -1260,42 +1241,37 @@  static struct se_wwn *lio_target_call_coreaddtiqn(
 	struct config_group *group,
 	const char *name)
 {
-	struct config_group *stats_cg;
 	struct iscsi_tiqn *tiqn;
 
 	tiqn = iscsit_add_tiqn((unsigned char *)name);
 	if (IS_ERR(tiqn))
 		return ERR_CAST(tiqn);
-	/*
-	 * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
-	 */
-	stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
-
-	stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
-				GFP_KERNEL);
-	if (!stats_cg->default_groups) {
-		pr_err("Unable to allocate memory for"
-				" stats_cg->default_groups\n");
-		iscsit_del_tiqn(tiqn);
-		return ERR_PTR(-ENOMEM);
-	}
 
-	stats_cg->default_groups[0] = &tiqn->tiqn_stat_grps.iscsi_instance_group;
-	stats_cg->default_groups[1] = &tiqn->tiqn_stat_grps.iscsi_sess_err_group;
-	stats_cg->default_groups[2] = &tiqn->tiqn_stat_grps.iscsi_tgt_attr_group;
-	stats_cg->default_groups[3] = &tiqn->tiqn_stat_grps.iscsi_login_stats_group;
-	stats_cg->default_groups[4] = &tiqn->tiqn_stat_grps.iscsi_logout_stats_group;
-	stats_cg->default_groups[5] = NULL;
 	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_instance_group,
 			"iscsi_instance", &iscsi_stat_instance_cit);
+	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_instance_group,
+			&tiqn->tiqn_wwn.fabric_stat_group);
+
 	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
 			"iscsi_sess_err", &iscsi_stat_sess_err_cit);
+	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
+			&tiqn->tiqn_wwn.fabric_stat_group);
+
 	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
 			"iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit);
+	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
+			&tiqn->tiqn_wwn.fabric_stat_group);
+
 	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
 			"iscsi_login_stats", &iscsi_stat_login_cit);
+	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
+			&tiqn->tiqn_wwn.fabric_stat_group);
+
 	config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
 			"iscsi_logout_stats", &iscsi_stat_logout_cit);
+	configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
+			&tiqn->tiqn_wwn.fabric_stat_group);
+
 
 	pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
 	pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:"
@@ -1307,17 +1283,8 @@  static void lio_target_call_coredeltiqn(
 	struct se_wwn *wwn)
 {
 	struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
-	struct config_item *df_item;
-	struct config_group *stats_cg;
-	int i;
-
-	stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
-	for (i = 0; stats_cg->default_groups[i]; i++) {
-		df_item = &stats_cg->default_groups[i]->cg_item;
-		stats_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(stats_cg->default_groups);
+
+	configfs_remove_default_groups(&tiqn->tiqn_wwn.fabric_stat_group);
 
 	pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n",
 			tiqn->tiqn);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 713c63d9..d498533 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -194,13 +194,11 @@  static struct config_group *target_core_register_fabric(
 	pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n",
 			&tf->tf_wwn_cit);
 
-	tf->tf_group.default_groups = tf->tf_default_groups;
-	tf->tf_group.default_groups[0] = &tf->tf_disc_group;
-	tf->tf_group.default_groups[1] = NULL;
-
 	config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit);
+
 	config_group_init_type_name(&tf->tf_disc_group, "discovery_auth",
 			&tf->tf_discovery_cit);
+	configfs_add_default_group(&tf->tf_disc_group, &tf->tf_group);
 
 	pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
 			" %s\n", tf->tf_group.cg_item.ci_name);
@@ -216,9 +214,6 @@  static void target_core_deregister_fabric(
 {
 	struct target_fabric_configfs *tf = container_of(
 		to_config_group(item), struct target_fabric_configfs, tf_group);
-	struct config_group *tf_group;
-	struct config_item *df_item;
-	int i;
 
 	pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in"
 		" tf list\n", config_item_name(item));
@@ -230,12 +225,7 @@  static void target_core_deregister_fabric(
 	pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci"
 			" %s\n", config_item_name(item));
 
-	tf_group = &tf->tf_group;
-	for (i = 0; tf_group->default_groups[i]; i++) {
-		df_item = &tf_group->default_groups[i]->cg_item;
-		tf_group->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
+	configfs_remove_default_groups(&tf->tf_group);
 	config_item_put(item);
 }
 
@@ -2151,7 +2141,6 @@  static void target_core_dev_release(struct config_item *item)
 	struct se_device *dev =
 		container_of(dev_cg, struct se_device, dev_group);
 
-	kfree(dev_cg->default_groups);
 	target_free_device(dev);
 }
 
@@ -2819,8 +2808,6 @@  static struct config_group *target_core_make_subdev(
 	struct se_hba *hba = item_to_hba(hba_ci);
 	struct target_backend *tb = hba->backend;
 	struct se_device *dev;
-	struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;
-	struct config_group *dev_stat_grp = NULL;
 	int errno = -ENOMEM, ret;
 
 	ret = mutex_lock_interruptible(&hba->hba_access_mutex);
@@ -2831,73 +2818,52 @@  static struct config_group *target_core_make_subdev(
 	if (!dev)
 		goto out_unlock;
 
-	dev_cg = &dev->dev_group;
-
-	dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
-			GFP_KERNEL);
-	if (!dev_cg->default_groups)
-		goto out_free_device;
+	config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit);
 
-	config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit);
 	config_group_init_type_name(&dev->dev_attrib.da_group, "attrib",
 			&tb->tb_dev_attrib_cit);
+	configfs_add_default_group(&dev->dev_attrib.da_group, &dev->dev_group);
+
 	config_group_init_type_name(&dev->dev_pr_group, "pr",
 			&tb->tb_dev_pr_cit);
+	configfs_add_default_group(&dev->dev_pr_group, &dev->dev_group);
+
 	config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn",
 			&tb->tb_dev_wwn_cit);
+	configfs_add_default_group(&dev->t10_wwn.t10_wwn_group,
+			&dev->dev_group);
+
 	config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group,
 			"alua", &tb->tb_dev_alua_tg_pt_gps_cit);
+	configfs_add_default_group(&dev->t10_alua.alua_tg_pt_gps_group,
+			&dev->dev_group);
+
 	config_group_init_type_name(&dev->dev_stat_grps.stat_group,
 			"statistics", &tb->tb_dev_stat_cit);
+	configfs_add_default_group(&dev->dev_stat_grps.stat_group,
+			&dev->dev_group);
 
-	dev_cg->default_groups[0] = &dev->dev_attrib.da_group;
-	dev_cg->default_groups[1] = &dev->dev_pr_group;
-	dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group;
-	dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group;
-	dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group;
-	dev_cg->default_groups[5] = NULL;
 	/*
 	 * Add core/$HBA/$DEV/alua/default_tg_pt_gp
 	 */
 	tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1);
 	if (!tg_pt_gp)
-		goto out_free_dev_cg_default_groups;
+		goto out_free_device;
 	dev->t10_alua.default_tg_pt_gp = tg_pt_gp;
 
-	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
-	tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!tg_pt_gp_cg->default_groups) {
-		pr_err("Unable to allocate tg_pt_gp_cg->"
-				"default_groups\n");
-		goto out_free_tg_pt_gp;
-	}
-
 	config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,
 			"default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);
-	tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;
-	tg_pt_gp_cg->default_groups[1] = NULL;
+	configfs_add_default_group(&tg_pt_gp->tg_pt_gp_group,
+			&dev->t10_alua.alua_tg_pt_gps_group);
+
 	/*
 	 * Add core/$HBA/$DEV/statistics/ default groups
 	 */
-	dev_stat_grp = &dev->dev_stat_grps.stat_group;
-	dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4,
-				GFP_KERNEL);
-	if (!dev_stat_grp->default_groups) {
-		pr_err("Unable to allocate dev_stat_grp->default_groups\n");
-		goto out_free_tg_pt_gp_cg_default_groups;
-	}
 	target_stat_setup_dev_default_groups(dev);
 
 	mutex_unlock(&hba->hba_access_mutex);
-	return dev_cg;
+	return &dev->dev_group;
 
-out_free_tg_pt_gp_cg_default_groups:
-	kfree(tg_pt_gp_cg->default_groups);
-out_free_tg_pt_gp:
-	core_alua_free_tg_pt_gp(tg_pt_gp);
-out_free_dev_cg_default_groups:
-	kfree(dev_cg->default_groups);
 out_free_device:
 	target_free_device(dev);
 out_unlock:
@@ -2913,40 +2879,22 @@  static void target_core_drop_subdev(
 	struct se_device *dev =
 		container_of(dev_cg, struct se_device, dev_group);
 	struct se_hba *hba;
-	struct config_item *df_item;
-	struct config_group *tg_pt_gp_cg, *dev_stat_grp;
-	int i;
 
 	hba = item_to_hba(&dev->se_hba->hba_group.cg_item);
 
 	mutex_lock(&hba->hba_access_mutex);
 
-	dev_stat_grp = &dev->dev_stat_grps.stat_group;
-	for (i = 0; dev_stat_grp->default_groups[i]; i++) {
-		df_item = &dev_stat_grp->default_groups[i]->cg_item;
-		dev_stat_grp->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(dev_stat_grp->default_groups);
+	configfs_remove_default_groups(&dev->dev_stat_grps.stat_group);
+	configfs_remove_default_groups(&dev->t10_alua.alua_tg_pt_gps_group);
 
-	tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group;
-	for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {
-		df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;
-		tg_pt_gp_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(tg_pt_gp_cg->default_groups);
 	/*
 	 * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp
 	 * directly from target_core_alua_tg_pt_gp_release().
 	 */
 	dev->t10_alua.default_tg_pt_gp = NULL;
 
-	for (i = 0; dev_cg->default_groups[i]; i++) {
-		df_item = &dev_cg->default_groups[i]->cg_item;
-		dev_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
+	configfs_remove_default_groups(dev_cg);
+
 	/*
 	 * se_dev is released from target_core_dev_item_ops->release()
 	 */
@@ -3141,8 +3089,6 @@  void target_setup_backend_cits(struct target_backend *tb)
 
 static int __init target_core_init_configfs(void)
 {
-	struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
-	struct config_group *lu_gp_cg = NULL;
 	struct configfs_subsystem *subsys = &target_core_fabrics;
 	struct t10_alua_lu_gp *lu_gp;
 	int ret;
@@ -3161,51 +3107,24 @@  static int __init target_core_init_configfs(void)
 	 * Create $CONFIGFS/target/core default group for HBA <-> Storage Object
 	 * and ALUA Logical Unit Group and Target Port Group infrastructure.
 	 */
-	target_cg = &subsys->su_group;
-	target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!target_cg->default_groups) {
-		pr_err("Unable to allocate target_cg->default_groups\n");
-		ret = -ENOMEM;
-		goto out_global;
-	}
+	config_group_init_type_name(&target_core_hbagroup, "core",
+			&target_core_cit);
+	configfs_add_default_group(&target_core_hbagroup, &subsys->su_group);
 
-	config_group_init_type_name(&target_core_hbagroup,
-			"core", &target_core_cit);
-	target_cg->default_groups[0] = &target_core_hbagroup;
-	target_cg->default_groups[1] = NULL;
 	/*
 	 * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/
 	 */
-	hba_cg = &target_core_hbagroup;
-	hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!hba_cg->default_groups) {
-		pr_err("Unable to allocate hba_cg->default_groups\n");
-		ret = -ENOMEM;
-		goto out_global;
-	}
-	config_group_init_type_name(&alua_group,
-			"alua", &target_core_alua_cit);
-	hba_cg->default_groups[0] = &alua_group;
-	hba_cg->default_groups[1] = NULL;
+	config_group_init_type_name(&alua_group, "alua", &target_core_alua_cit);
+	configfs_add_default_group(&alua_group, &target_core_hbagroup);
+
 	/*
 	 * Add ALUA Logical Unit Group and Target Port Group ConfigFS
 	 * groups under /sys/kernel/config/target/core/alua/
 	 */
-	alua_cg = &alua_group;
-	alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-			GFP_KERNEL);
-	if (!alua_cg->default_groups) {
-		pr_err("Unable to allocate alua_cg->default_groups\n");
-		ret = -ENOMEM;
-		goto out_global;
-	}
+	config_group_init_type_name(&alua_lu_gps_group, "lu_gps",
+			&target_core_alua_lu_gps_cit);
+	configfs_add_default_group(&alua_lu_gps_group, &alua_group);
 
-	config_group_init_type_name(&alua_lu_gps_group,
-			"lu_gps", &target_core_alua_lu_gps_cit);
-	alua_cg->default_groups[0] = &alua_lu_gps_group;
-	alua_cg->default_groups[1] = NULL;
 	/*
 	 * Add core/alua/lu_gps/default_lu_gp
 	 */
@@ -3215,20 +3134,12 @@  static int __init target_core_init_configfs(void)
 		goto out_global;
 	}
 
-	lu_gp_cg = &alua_lu_gps_group;
-	lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-			GFP_KERNEL);
-	if (!lu_gp_cg->default_groups) {
-		pr_err("Unable to allocate lu_gp_cg->default_groups\n");
-		ret = -ENOMEM;
-		goto out_global;
-	}
-
 	config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp",
 				&target_core_alua_lu_gp_cit);
-	lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group;
-	lu_gp_cg->default_groups[1] = NULL;
+	configfs_add_default_group(&lu_gp->lu_gp_group, &alua_lu_gps_group);
+
 	default_lu_gp = lu_gp;
+
 	/*
 	 * Register the target_core_mod subsystem with configfs.
 	 */
@@ -3267,55 +3178,21 @@  out_global:
 		core_alua_free_lu_gp(default_lu_gp);
 		default_lu_gp = NULL;
 	}
-	if (lu_gp_cg)
-		kfree(lu_gp_cg->default_groups);
-	if (alua_cg)
-		kfree(alua_cg->default_groups);
-	if (hba_cg)
-		kfree(hba_cg->default_groups);
-	kfree(target_cg->default_groups);
 	release_se_kmem_caches();
 	return ret;
 }
 
 static void __exit target_core_exit_configfs(void)
 {
-	struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
-	struct config_item *item;
-	int i;
+	configfs_remove_default_groups(&alua_lu_gps_group);
+	configfs_remove_default_groups(&alua_group);
+	configfs_remove_default_groups(&target_core_hbagroup);
 
-	lu_gp_cg = &alua_lu_gps_group;
-	for (i = 0; lu_gp_cg->default_groups[i]; i++) {
-		item = &lu_gp_cg->default_groups[i]->cg_item;
-		lu_gp_cg->default_groups[i] = NULL;
-		config_item_put(item);
-	}
-	kfree(lu_gp_cg->default_groups);
-	lu_gp_cg->default_groups = NULL;
-
-	alua_cg = &alua_group;
-	for (i = 0; alua_cg->default_groups[i]; i++) {
-		item = &alua_cg->default_groups[i]->cg_item;
-		alua_cg->default_groups[i] = NULL;
-		config_item_put(item);
-	}
-	kfree(alua_cg->default_groups);
-	alua_cg->default_groups = NULL;
-
-	hba_cg = &target_core_hbagroup;
-	for (i = 0; hba_cg->default_groups[i]; i++) {
-		item = &hba_cg->default_groups[i]->cg_item;
-		hba_cg->default_groups[i] = NULL;
-		config_item_put(item);
-	}
-	kfree(hba_cg->default_groups);
-	hba_cg->default_groups = NULL;
 	/*
 	 * We expect subsys->su_group.default_groups to be released
 	 * by configfs subsystem provider logic..
 	 */
 	configfs_unregister_subsystem(&target_core_fabrics);
-	kfree(target_core_fabrics.su_group.default_groups);
 
 	core_alua_free_lu_gp(default_lu_gp);
 	default_lu_gp = NULL;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index f916d18..8caef31 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -273,18 +273,10 @@  static struct config_group *target_fabric_make_mappedlun(
 	struct se_portal_group *se_tpg = se_nacl->se_tpg;
 	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
 	struct se_lun_acl *lacl = NULL;
-	struct config_item *acl_ci;
-	struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
 	char *buf;
 	unsigned long long mapped_lun;
 	int ret = 0;
 
-	acl_ci = &group->cg_item;
-	if (!acl_ci) {
-		pr_err("Unable to locatel acl_ci\n");
-		return NULL;
-	}
-
 	buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
 	if (!buf) {
 		pr_err("Unable to allocate memory for name buf\n");
@@ -315,37 +307,19 @@  static struct config_group *target_fabric_make_mappedlun(
 		goto out;
 	}
 
-	lacl_cg = &lacl->se_lun_group;
-	lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!lacl_cg->default_groups) {
-		pr_err("Unable to allocate lacl_cg->default_groups\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	config_group_init_type_name(&lacl->se_lun_group, name,
 			&tf->tf_tpg_mappedlun_cit);
+
 	config_group_init_type_name(&lacl->ml_stat_grps.stat_group,
 			"statistics", &tf->tf_tpg_mappedlun_stat_cit);
-	lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group;
-	lacl_cg->default_groups[1] = NULL;
-
-	ml_stat_grp = &lacl->ml_stat_grps.stat_group;
-	ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3,
-				GFP_KERNEL);
-	if (!ml_stat_grp->default_groups) {
-		pr_err("Unable to allocate ml_stat_grp->default_groups\n");
-		ret = -ENOMEM;
-		goto out;
-	}
+	configfs_add_default_group(&lacl->ml_stat_grps.stat_group,
+			&lacl->se_lun_group);
+
 	target_stat_setup_mappedlun_default_groups(lacl);
 
 	kfree(buf);
 	return &lacl->se_lun_group;
 out:
-	if (lacl_cg)
-		kfree(lacl_cg->default_groups);
 	kfree(lacl);
 	kfree(buf);
 	return ERR_PTR(ret);
@@ -357,25 +331,9 @@  static void target_fabric_drop_mappedlun(
 {
 	struct se_lun_acl *lacl = container_of(to_config_group(item),
 			struct se_lun_acl, se_lun_group);
-	struct config_item *df_item;
-	struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
-	int i;
-
-	ml_stat_grp = &lacl->ml_stat_grps.stat_group;
-	for (i = 0; ml_stat_grp->default_groups[i]; i++) {
-		df_item = &ml_stat_grp->default_groups[i]->cg_item;
-		ml_stat_grp->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(ml_stat_grp->default_groups);
 
-	lacl_cg = &lacl->se_lun_group;
-	for (i = 0; lacl_cg->default_groups[i]; i++) {
-		df_item = &lacl_cg->default_groups[i]->cg_item;
-		lacl_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(lacl_cg->default_groups);
+	configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group);
+	configfs_remove_default_groups(&lacl->se_lun_group);
 
 	config_item_put(item);
 }
@@ -424,7 +382,6 @@  static struct config_group *target_fabric_make_nodeacl(
 			struct se_portal_group, tpg_acl_group);
 	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
 	struct se_node_acl *se_nacl;
-	struct config_group *nacl_cg;
 
 	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name);
 	if (IS_ERR(se_nacl))
@@ -438,24 +395,28 @@  static struct config_group *target_fabric_make_nodeacl(
 		}
 	}
 
-	nacl_cg = &se_nacl->acl_group;
-	nacl_cg->default_groups = se_nacl->acl_default_groups;
-	nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
-	nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
-	nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
-	nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group;
-	nacl_cg->default_groups[4] = NULL;
-
 	config_group_init_type_name(&se_nacl->acl_group, name,
 			&tf->tf_tpg_nacl_base_cit);
+
 	config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
 			&tf->tf_tpg_nacl_attrib_cit);
+	configfs_add_default_group(&se_nacl->acl_attrib_group,
+			&se_nacl->acl_group);
+
 	config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
 			&tf->tf_tpg_nacl_auth_cit);
+	configfs_add_default_group(&se_nacl->acl_auth_group,
+			&se_nacl->acl_group);
+
 	config_group_init_type_name(&se_nacl->acl_param_group, "param",
 			&tf->tf_tpg_nacl_param_cit);
+	configfs_add_default_group(&se_nacl->acl_param_group,
+			&se_nacl->acl_group);
+
 	config_group_init_type_name(&se_nacl->acl_fabric_stat_group,
 			"fabric_statistics", &tf->tf_tpg_nacl_stat_cit);
+	configfs_add_default_group(&se_nacl->acl_fabric_stat_group,
+			&se_nacl->acl_group);
 
 	return &se_nacl->acl_group;
 }
@@ -466,16 +427,9 @@  static void target_fabric_drop_nodeacl(
 {
 	struct se_node_acl *se_nacl = container_of(to_config_group(item),
 			struct se_node_acl, acl_group);
-	struct config_item *df_item;
-	struct config_group *nacl_cg;
-	int i;
-
-	nacl_cg = &se_nacl->acl_group;
-	for (i = 0; nacl_cg->default_groups[i]; i++) {
-		df_item = &nacl_cg->default_groups[i]->cg_item;
-		nacl_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
+
+	configfs_remove_default_groups(&se_nacl->acl_group);
+
 	/*
 	 * struct se_node_acl free is done in target_fabric_nacl_base_release()
 	 */
@@ -795,7 +749,6 @@  static struct config_group *target_fabric_make_lun(
 	struct se_portal_group *se_tpg = container_of(group,
 			struct se_portal_group, tpg_lun_group);
 	struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
-	struct config_group *lun_cg = NULL, *port_stat_grp = NULL;
 	unsigned long long unpacked_lun;
 	int errno;
 
@@ -812,31 +765,14 @@  static struct config_group *target_fabric_make_lun(
 	if (IS_ERR(lun))
 		return ERR_CAST(lun);
 
-	lun_cg = &lun->lun_group;
-	lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
-				GFP_KERNEL);
-	if (!lun_cg->default_groups) {
-		pr_err("Unable to allocate lun_cg->default_groups\n");
-		kfree(lun);
-		return ERR_PTR(-ENOMEM);
-	}
-
 	config_group_init_type_name(&lun->lun_group, name,
 			&tf->tf_tpg_port_cit);
+
 	config_group_init_type_name(&lun->port_stat_grps.stat_group,
 			"statistics", &tf->tf_tpg_port_stat_cit);
-	lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group;
-	lun_cg->default_groups[1] = NULL;
-
-	port_stat_grp = &lun->port_stat_grps.stat_group;
-	port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group *) * 4,
-				GFP_KERNEL);
-	if (!port_stat_grp->default_groups) {
-		pr_err("Unable to allocate port_stat_grp->default_groups\n");
-		kfree(lun_cg->default_groups);
-		kfree(lun);
-		return ERR_PTR(-ENOMEM);
-	}
+	configfs_add_default_group(&lun->port_stat_grps.stat_group,
+			&lun->lun_group);
+
 	target_stat_setup_port_default_groups(lun);
 
 	return &lun->lun_group;
@@ -848,25 +784,9 @@  static void target_fabric_drop_lun(
 {
 	struct se_lun *lun = container_of(to_config_group(item),
 				struct se_lun, lun_group);
-	struct config_item *df_item;
-	struct config_group *lun_cg, *port_stat_grp;
-	int i;
-
-	port_stat_grp = &lun->port_stat_grps.stat_group;
-	for (i = 0; port_stat_grp->default_groups[i]; i++) {
-		df_item = &port_stat_grp->default_groups[i]->cg_item;
-		port_stat_grp->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(port_stat_grp->default_groups);
 
-	lun_cg = &lun->lun_group;
-	for (i = 0; lun_cg->default_groups[i]; i++) {
-		df_item = &lun_cg->default_groups[i]->cg_item;
-		lun_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
-	kfree(lun_cg->default_groups);
+	configfs_remove_default_groups(&lun->port_stat_grps.stat_group);
+	configfs_remove_default_groups(&lun->lun_group);
 
 	config_item_put(item);
 }
@@ -922,32 +842,39 @@  static struct config_group *target_fabric_make_tpg(
 	se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name);
 	if (!se_tpg || IS_ERR(se_tpg))
 		return ERR_PTR(-EINVAL);
-	/*
-	 * Setup default groups from pre-allocated se_tpg->tpg_default_groups
-	 */
-	se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
-	se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
-	se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
-	se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
-	se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
-	se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group;
-	se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group;
-	se_tpg->tpg_group.default_groups[6] = NULL;
 
 	config_group_init_type_name(&se_tpg->tpg_group, name,
 			&tf->tf_tpg_base_cit);
+
 	config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
 			&tf->tf_tpg_lun_cit);
+	configfs_add_default_group(&se_tpg->tpg_lun_group,
+			&se_tpg->tpg_group);
+
 	config_group_init_type_name(&se_tpg->tpg_np_group, "np",
 			&tf->tf_tpg_np_cit);
+	configfs_add_default_group(&se_tpg->tpg_np_group,
+			&se_tpg->tpg_group);
+
 	config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
 			&tf->tf_tpg_nacl_cit);
+	configfs_add_default_group(&se_tpg->tpg_acl_group,
+			&se_tpg->tpg_group);
+
 	config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
 			&tf->tf_tpg_attrib_cit);
+	configfs_add_default_group(&se_tpg->tpg_attrib_group,
+			&se_tpg->tpg_group);
+
 	config_group_init_type_name(&se_tpg->tpg_auth_group, "auth",
 			&tf->tf_tpg_auth_cit);
+	configfs_add_default_group(&se_tpg->tpg_auth_group,
+			&se_tpg->tpg_group);
+
 	config_group_init_type_name(&se_tpg->tpg_param_group, "param",
 			&tf->tf_tpg_param_cit);
+	configfs_add_default_group(&se_tpg->tpg_param_group,
+			&se_tpg->tpg_group);
 
 	return &se_tpg->tpg_group;
 }
@@ -958,19 +885,8 @@  static void target_fabric_drop_tpg(
 {
 	struct se_portal_group *se_tpg = container_of(to_config_group(item),
 				struct se_portal_group, tpg_group);
-	struct config_group *tpg_cg = &se_tpg->tpg_group;
-	struct config_item *df_item;
-	int i;
-	/*
-	 * Release default groups, but do not release tpg_cg->default_groups
-	 * memory as it is statically allocated at se_tpg->tpg_default_groups.
-	 */
-	for (i = 0; tpg_cg->default_groups[i]; i++) {
-		df_item = &tpg_cg->default_groups[i]->cg_item;
-		tpg_cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
 
+	configfs_remove_default_groups(&se_tpg->tpg_group);
 	config_item_put(item);
 }
 
@@ -1026,16 +942,12 @@  static struct config_group *target_fabric_make_wwn(
 		return ERR_PTR(-EINVAL);
 
 	wwn->wwn_tf = tf;
-	/*
-	 * Setup default groups from pre-allocated wwn->wwn_default_groups
-	 */
-	wwn->wwn_group.default_groups = wwn->wwn_default_groups;
-	wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group;
-	wwn->wwn_group.default_groups[1] = NULL;
 
 	config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit);
+
 	config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics",
 			&tf->tf_wwn_fabric_stats_cit);
+	configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group);
 
 	return &wwn->wwn_group;
 }
@@ -1046,16 +958,8 @@  static void target_fabric_drop_wwn(
 {
 	struct se_wwn *wwn = container_of(to_config_group(item),
 				struct se_wwn, wwn_group);
-	struct config_item *df_item;
-	struct config_group *cg = &wwn->wwn_group;
-	int i;
-
-	for (i = 0; cg->default_groups[i]; i++) {
-		df_item = &cg->default_groups[i]->cg_item;
-		cg->default_groups[i] = NULL;
-		config_item_put(df_item);
-	}
 
+	configfs_remove_default_groups(&wwn->wwn_group);
 	config_item_put(item);
 }
 
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index db4412f..4a7cf49 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -22,7 +22,6 @@  struct target_fabric_configfs {
 	struct list_head	tf_list;
 	struct config_group	tf_group;
 	struct config_group	tf_disc_group;
-	struct config_group	*tf_default_groups[2];
 	const struct target_core_fabric_ops *tf_ops;
 
 	struct config_item_type tf_discovery_cit;
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 81a6b3e..1a39033 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -407,19 +407,20 @@  static struct config_item_type target_stat_scsi_lu_cit = {
  */
 void target_stat_setup_dev_default_groups(struct se_device *dev)
 {
-	struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group;
-
 	config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group,
 			"scsi_dev", &target_stat_scsi_dev_cit);
+	configfs_add_default_group(&dev->dev_stat_grps.scsi_dev_group,
+			&dev->dev_stat_grps.stat_group);
+
 	config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group,
 			"scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit);
+	configfs_add_default_group(&dev->dev_stat_grps.scsi_tgt_dev_group,
+			&dev->dev_stat_grps.stat_group);
+
 	config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group,
 			"scsi_lu", &target_stat_scsi_lu_cit);
-
-	dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group;
-	dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group;
-	dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group;
-	dev_stat_grp->default_groups[3] = NULL;
+	configfs_add_default_group(&dev->dev_stat_grps.scsi_lu_group,
+			&dev->dev_stat_grps.stat_group);
 }
 
 /*
@@ -818,19 +819,20 @@  static struct config_item_type target_stat_scsi_transport_cit = {
  */
 void target_stat_setup_port_default_groups(struct se_lun *lun)
 {
-	struct config_group *port_stat_grp = &lun->port_stat_grps.stat_group;
-
 	config_group_init_type_name(&lun->port_stat_grps.scsi_port_group,
 			"scsi_port", &target_stat_scsi_port_cit);
+	configfs_add_default_group(&lun->port_stat_grps.scsi_port_group,
+			&lun->port_stat_grps.stat_group);
+
 	config_group_init_type_name(&lun->port_stat_grps.scsi_tgt_port_group,
 			"scsi_tgt_port", &target_stat_scsi_tgt_port_cit);
+	configfs_add_default_group(&lun->port_stat_grps.scsi_tgt_port_group,
+			&lun->port_stat_grps.stat_group);
+
 	config_group_init_type_name(&lun->port_stat_grps.scsi_transport_group,
 			"scsi_transport", &target_stat_scsi_transport_cit);
-
-	port_stat_grp->default_groups[0] = &lun->port_stat_grps.scsi_port_group;
-	port_stat_grp->default_groups[1] = &lun->port_stat_grps.scsi_tgt_port_group;
-	port_stat_grp->default_groups[2] = &lun->port_stat_grps.scsi_transport_group;
-	port_stat_grp->default_groups[3] = NULL;
+	configfs_add_default_group(&lun->port_stat_grps.scsi_transport_group,
+			&lun->port_stat_grps.stat_group);
 }
 
 /*
@@ -1351,14 +1353,13 @@  static struct config_item_type target_stat_scsi_att_intr_port_cit = {
  */
 void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl)
 {
-	struct config_group *ml_stat_grp = &lacl->ml_stat_grps.stat_group;
-
 	config_group_init_type_name(&lacl->ml_stat_grps.scsi_auth_intr_group,
 			"scsi_auth_intr", &target_stat_scsi_auth_intr_cit);
+	configfs_add_default_group(&lacl->ml_stat_grps.scsi_auth_intr_group,
+			&lacl->ml_stat_grps.stat_group);
+
 	config_group_init_type_name(&lacl->ml_stat_grps.scsi_att_intr_port_group,
 			"scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit);
-
-	ml_stat_grp->default_groups[0] = &lacl->ml_stat_grps.scsi_auth_intr_group;
-	ml_stat_grp->default_groups[1] = &lacl->ml_stat_grps.scsi_att_intr_port_group;
-	ml_stat_grp->default_groups[2] = NULL;
+	configfs_add_default_group(&lacl->ml_stat_grps.scsi_att_intr_port_group,
+			&lacl->ml_stat_grps.stat_group);
 }
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 590c449..2f8081f 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -49,7 +49,6 @@  struct gadget_info {
 	struct config_group configs_group;
 	struct config_group strings_group;
 	struct config_group os_desc_group;
-	struct config_group *default_groups[5];
 
 	struct mutex lock;
 	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
@@ -71,7 +70,6 @@  static inline struct gadget_info *to_gadget_info(struct config_item *item)
 struct config_usb_cfg {
 	struct config_group group;
 	struct config_group strings_group;
-	struct config_group *default_groups[2];
 	struct list_head string_list;
 	struct usb_configuration c;
 	struct list_head func_list;
@@ -666,13 +664,12 @@  static struct config_group *config_desc_make(
 	INIT_LIST_HEAD(&cfg->string_list);
 	INIT_LIST_HEAD(&cfg->func_list);
 
-	cfg->group.default_groups = cfg->default_groups;
-	cfg->default_groups[0] = &cfg->strings_group;
-
 	config_group_init_type_name(&cfg->group, name,
 				&gadget_config_type);
+
 	config_group_init_type_name(&cfg->strings_group, "strings",
 			&gadget_config_name_strings_type);
+	configfs_add_default_group(&cfg->strings_group, &cfg->group);
 
 	ret = usb_add_config_only(&gi->cdev, &cfg->c);
 	if (ret)
@@ -1149,15 +1146,11 @@  int usb_os_desc_prepare_interf_dir(struct config_group *parent,
 				   char **names,
 				   struct module *owner)
 {
-	struct config_group **f_default_groups, *os_desc_group,
-				**interface_groups;
+	struct config_group *os_desc_group;
 	struct config_item_type *os_desc_type, *interface_type;
 
 	vla_group(data_chunk);
-	vla_item(data_chunk, struct config_group *, f_default_groups, 2);
 	vla_item(data_chunk, struct config_group, os_desc_group, 1);
-	vla_item(data_chunk, struct config_group *, interface_groups,
-		 n_interf + 1);
 	vla_item(data_chunk, struct config_item_type, os_desc_type, 1);
 	vla_item(data_chunk, struct config_item_type, interface_type, 1);
 
@@ -1165,18 +1158,14 @@  int usb_os_desc_prepare_interf_dir(struct config_group *parent,
 	if (!vlabuf)
 		return -ENOMEM;
 
-	f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups);
 	os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
 	os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
-	interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups);
 	interface_type = vla_ptr(vlabuf, data_chunk, interface_type);
 
-	parent->default_groups = f_default_groups;
 	os_desc_type->ct_owner = owner;
 	config_group_init_type_name(os_desc_group, "os_desc", os_desc_type);
-	f_default_groups[0] = os_desc_group;
+	configfs_add_default_group(os_desc_group, parent);
 
-	os_desc_group->default_groups = interface_groups;
 	interface_type->ct_group_ops = &interf_grp_ops;
 	interface_type->ct_attrs = interf_grp_attrs;
 	interface_type->ct_owner = owner;
@@ -1189,7 +1178,7 @@  int usb_os_desc_prepare_interf_dir(struct config_group *parent,
 		config_group_init_type_name(&d->group, "", interface_type);
 		config_item_set_name(&d->group.cg_item, "interface.%s",
 				     names[n_interf]);
-		interface_groups[n_interf] = &d->group;
+		configfs_add_default_group(&d->group, os_desc_group);
 	}
 
 	return 0;
@@ -1423,20 +1412,23 @@  static struct config_group *gadgets_make(
 	if (!gi)
 		return ERR_PTR(-ENOMEM);
 
-	gi->group.default_groups = gi->default_groups;
-	gi->group.default_groups[0] = &gi->functions_group;
-	gi->group.default_groups[1] = &gi->configs_group;
-	gi->group.default_groups[2] = &gi->strings_group;
-	gi->group.default_groups[3] = &gi->os_desc_group;
+	config_group_init_type_name(&gi->group, name, &gadget_root_type);
 
 	config_group_init_type_name(&gi->functions_group, "functions",
 			&functions_type);
+	configfs_add_default_group(&gi->functions_group, &gi->group);
+
 	config_group_init_type_name(&gi->configs_group, "configs",
 			&config_desc_type);
+	configfs_add_default_group(&gi->configs_group, &gi->group);
+
 	config_group_init_type_name(&gi->strings_group, "strings",
 			&gadget_strings_strings_type);
+	configfs_add_default_group(&gi->strings_group, &gi->group);
+
 	config_group_init_type_name(&gi->os_desc_group, "os_desc",
 			&os_desc_type);
+	configfs_add_default_group(&gi->os_desc_group, &gi->group);
 
 	gi->composite.bind = configfs_do_nothing;
 	gi->composite.unbind = configfs_do_nothing;
@@ -1461,8 +1453,6 @@  static struct config_group *gadgets_make(
 	if (!gi->composite.gadget_driver.function)
 		goto err;
 
-	config_group_init_type_name(&gi->group, name,
-				&gadget_root_type);
 	return &gi->group;
 err:
 	kfree(gi);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 223ccf8..142bb77 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -3484,12 +3484,12 @@  static struct usb_function_instance *fsg_alloc_inst(void)
 
 	opts->lun0.lun = opts->common->luns[0];
 	opts->lun0.lun_id = 0;
-	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
-	opts->default_groups[0] = &opts->lun0.group;
-	opts->func_inst.group.default_groups = opts->default_groups;
 
 	config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type);
 
+	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
+	configfs_add_default_group(&opts->lun0.group, &opts->func_inst.group);
+
 	return &opts->func_inst;
 
 release_buffers:
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index e587767..931953e 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -889,7 +889,6 @@  static void rndis_free_inst(struct usb_function_instance *f)
 			free_netdev(opts->net);
 	}
 
-	kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */
 	kfree(opts);
 }
 
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index ad8c9b0..66753ba 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -272,11 +272,6 @@  static struct config_item_type uvcg_default_processing_type = {
 
 /* struct uvcg_processing {}; */
 
-static struct config_group *uvcg_processing_default_groups[] = {
-	&uvcg_default_processing.group,
-	NULL,
-};
-
 /* control/processing */
 static struct uvcg_processing_grp {
 	struct config_group	group;
@@ -394,11 +389,6 @@  static struct config_item_type uvcg_default_camera_type = {
 
 /* struct uvcg_camera {}; */
 
-static struct config_group *uvcg_camera_default_groups[] = {
-	&uvcg_default_camera.group,
-	NULL,
-};
-
 /* control/terminal/camera */
 static struct uvcg_camera_grp {
 	struct config_group	group;
@@ -477,11 +467,6 @@  static struct config_item_type uvcg_default_output_type = {
 
 /* struct uvcg_output {}; */
 
-static struct config_group *uvcg_output_default_groups[] = {
-	&uvcg_default_output.group,
-	NULL,
-};
-
 /* control/terminal/output */
 static struct uvcg_output_grp {
 	struct config_group	group;
@@ -491,12 +476,6 @@  static struct config_item_type uvcg_output_grp_type = {
 	.ct_owner = THIS_MODULE,
 };
 
-static struct config_group *uvcg_terminal_default_groups[] = {
-	&uvcg_camera_grp.group,
-	&uvcg_output_grp.group,
-	NULL,
-};
-
 /* control/terminal */
 static struct uvcg_terminal_grp {
 	struct config_group	group;
@@ -619,12 +598,6 @@  static struct config_item_type uvcg_control_class_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
-static struct config_group *uvcg_control_class_default_groups[] = {
-	&uvcg_control_class_fs.group,
-	&uvcg_control_class_ss.group,
-	NULL,
-};
-
 /* control/class */
 static struct uvcg_control_class_grp {
 	struct config_group	group;
@@ -634,14 +607,6 @@  static struct config_item_type uvcg_control_class_grp_type = {
 	.ct_owner = THIS_MODULE,
 };
 
-static struct config_group *uvcg_control_default_groups[] = {
-	&uvcg_control_header_grp.group,
-	&uvcg_processing_grp.group,
-	&uvcg_terminal_grp.group,
-	&uvcg_control_class_grp.group,
-	NULL,
-};
-
 /* control */
 static struct uvcg_control_grp {
 	struct config_group	group;
@@ -1780,11 +1745,6 @@  static struct config_item_type uvcg_default_color_matching_type = {
 
 /* struct uvcg_color_matching {}; */
 
-static struct config_group *uvcg_color_matching_default_groups[] = {
-	&uvcg_default_color_matching.group,
-	NULL,
-};
-
 /* streaming/color_matching */
 static struct uvcg_color_matching_grp {
 	struct config_group	group;
@@ -2145,13 +2105,6 @@  static struct config_item_type uvcg_streaming_class_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
-static struct config_group *uvcg_streaming_class_default_groups[] = {
-	&uvcg_streaming_class_fs.group,
-	&uvcg_streaming_class_hs.group,
-	&uvcg_streaming_class_ss.group,
-	NULL,
-};
-
 /* streaming/class */
 static struct uvcg_streaming_class_grp {
 	struct config_group	group;
@@ -2161,15 +2114,6 @@  static struct config_item_type uvcg_streaming_class_grp_type = {
 	.ct_owner = THIS_MODULE,
 };
 
-static struct config_group *uvcg_streaming_default_groups[] = {
-	&uvcg_streaming_header_grp.group,
-	&uvcg_uncompressed_grp.group,
-	&uvcg_mjpeg_grp.group,
-	&uvcg_color_matching_grp.group,
-	&uvcg_streaming_class_grp.group,
-	NULL,
-};
-
 /* streaming */
 static struct uvcg_streaming_grp {
 	struct config_group	group;
@@ -2179,12 +2123,6 @@  static struct config_item_type uvcg_streaming_grp_type = {
 	.ct_owner = THIS_MODULE,
 };
 
-static struct config_group *uvcg_default_groups[] = {
-	&uvcg_control_grp.group,
-	&uvcg_streaming_grp.group,
-	NULL,
-};
-
 static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
 {
 	return container_of(to_config_group(item), struct f_uvc_opts,
@@ -2273,59 +2211,64 @@  static struct config_item_type uvc_func_type = {
 	.ct_owner	= THIS_MODULE,
 };
 
-static inline void uvcg_init_group(struct config_group *g,
-				   struct config_group **default_groups,
-				   const char *name,
-				   struct config_item_type *type)
-{
-	g->default_groups = default_groups;
-	config_group_init_type_name(g, name, type);
-}
-
 int uvcg_attach_configfs(struct f_uvc_opts *opts)
 {
 	config_group_init_type_name(&uvcg_control_header_grp.group,
 				    "header",
 				    &uvcg_control_header_grp_type);
+
 	config_group_init_type_name(&uvcg_default_processing.group,
-				    "default",
-				    &uvcg_default_processing_type);
-	uvcg_init_group(&uvcg_processing_grp.group,
-			uvcg_processing_default_groups,
-			"processing",
-			&uvcg_processing_grp_type);
+			"default", &uvcg_default_processing_type);
+	config_group_init_type_name(&uvcg_processing_grp.group,
+			"processing", &uvcg_processing_grp_type);
+	configfs_add_default_group(&uvcg_default_processing.group,
+			&uvcg_processing_grp.group);
+
 	config_group_init_type_name(&uvcg_default_camera.group,
-				    "default",
-				    &uvcg_default_camera_type);
-	uvcg_init_group(&uvcg_camera_grp.group,
-			uvcg_camera_default_groups,
-			"camera",
-			&uvcg_camera_grp_type);
+			"default", &uvcg_default_camera_type);
+	config_group_init_type_name(&uvcg_camera_grp.group,
+			"camera", &uvcg_camera_grp_type);
+	configfs_add_default_group(&uvcg_default_camera.group,
+			&uvcg_camera_grp.group);
+
 	config_group_init_type_name(&uvcg_default_output.group,
-				    "default",
-				    &uvcg_default_output_type);
-	uvcg_init_group(&uvcg_output_grp.group,
-			uvcg_output_default_groups,
-			"output",
-			&uvcg_output_grp_type);
-	uvcg_init_group(&uvcg_terminal_grp.group,
-			uvcg_terminal_default_groups,
-			"terminal",
-			&uvcg_terminal_grp_type);
+			"default", &uvcg_default_output_type);
+	config_group_init_type_name(&uvcg_output_grp.group,
+			"output", &uvcg_output_grp_type);
+	configfs_add_default_group(&uvcg_default_output.group,
+			&uvcg_output_grp.group);
+
+	config_group_init_type_name(&uvcg_terminal_grp.group,
+			"terminal", &uvcg_terminal_grp_type);
+	configfs_add_default_group(&uvcg_camera_grp.group,
+			&uvcg_terminal_grp.group);
+	configfs_add_default_group(&uvcg_output_grp.group,
+			&uvcg_terminal_grp.group);
+
 	config_group_init_type_name(&uvcg_control_class_fs.group,
-				    "fs",
-				    &uvcg_control_class_type);
+			"fs", &uvcg_control_class_type);
 	config_group_init_type_name(&uvcg_control_class_ss.group,
-				    "ss",
-				    &uvcg_control_class_type);
-	uvcg_init_group(&uvcg_control_class_grp.group,
-			uvcg_control_class_default_groups,
+			"ss", &uvcg_control_class_type);
+	config_group_init_type_name(&uvcg_control_class_grp.group,
 			"class",
 			&uvcg_control_class_grp_type);
-	uvcg_init_group(&uvcg_control_grp.group,
-			uvcg_control_default_groups,
+	configfs_add_default_group(&uvcg_control_class_fs.group,
+			&uvcg_control_class_grp.group);
+	configfs_add_default_group(&uvcg_control_class_ss.group,
+			&uvcg_control_class_grp.group);
+
+	config_group_init_type_name(&uvcg_control_grp.group,
 			"control",
 			&uvcg_control_grp_type);
+	configfs_add_default_group(&uvcg_control_header_grp.group,
+			&uvcg_control_grp.group);
+	configfs_add_default_group(&uvcg_processing_grp.group,
+			&uvcg_control_grp.group);
+	configfs_add_default_group(&uvcg_terminal_grp.group,
+			&uvcg_control_grp.group);
+	configfs_add_default_group(&uvcg_control_class_grp.group,
+			&uvcg_control_grp.group);
+
 	config_group_init_type_name(&uvcg_streaming_header_grp.group,
 				    "header",
 				    &uvcg_streaming_header_grp_type);
@@ -2338,30 +2281,47 @@  int uvcg_attach_configfs(struct f_uvc_opts *opts)
 	config_group_init_type_name(&uvcg_default_color_matching.group,
 				    "default",
 				    &uvcg_default_color_matching_type);
-	uvcg_init_group(&uvcg_color_matching_grp.group,
-			uvcg_color_matching_default_groups,
+	config_group_init_type_name(&uvcg_color_matching_grp.group,
 			"color_matching",
 			&uvcg_color_matching_grp_type);
+	configfs_add_default_group(&uvcg_default_color_matching.group,
+			&uvcg_color_matching_grp.group);
+
 	config_group_init_type_name(&uvcg_streaming_class_fs.group,
-				    "fs",
-				    &uvcg_streaming_class_type);
+			"fs", &uvcg_streaming_class_type);
 	config_group_init_type_name(&uvcg_streaming_class_hs.group,
-				    "hs",
-				    &uvcg_streaming_class_type);
+			"hs", &uvcg_streaming_class_type);
 	config_group_init_type_name(&uvcg_streaming_class_ss.group,
-				    "ss",
-				    &uvcg_streaming_class_type);
-	uvcg_init_group(&uvcg_streaming_class_grp.group,
-			uvcg_streaming_class_default_groups,
-			"class",
-			&uvcg_streaming_class_grp_type);
-	uvcg_init_group(&uvcg_streaming_grp.group,
-			uvcg_streaming_default_groups,
-			"streaming",
-			&uvcg_streaming_grp_type);
-	uvcg_init_group(&opts->func_inst.group,
-			uvcg_default_groups,
+			"ss", &uvcg_streaming_class_type);
+	config_group_init_type_name(&uvcg_streaming_class_grp.group,
+			"class", &uvcg_streaming_class_grp_type);
+	configfs_add_default_group(&uvcg_streaming_class_fs.group,
+			&uvcg_streaming_class_grp.group);
+	configfs_add_default_group(&uvcg_streaming_class_hs.group,
+			&uvcg_streaming_class_grp.group);
+	configfs_add_default_group(&uvcg_streaming_class_ss.group,
+			&uvcg_streaming_class_grp.group);
+
+	config_group_init_type_name(&uvcg_streaming_grp.group,
+			"streaming", &uvcg_streaming_grp_type);
+	configfs_add_default_group(&uvcg_streaming_header_grp.group,
+			&uvcg_streaming_grp.group);
+	configfs_add_default_group(&uvcg_uncompressed_grp.group,
+			&uvcg_streaming_grp.group);
+	configfs_add_default_group(&uvcg_mjpeg_grp.group,
+			&uvcg_streaming_grp.group);
+	configfs_add_default_group(&uvcg_color_matching_grp.group,
+			&uvcg_streaming_grp.group);
+	configfs_add_default_group(&uvcg_streaming_class_grp.group,
+			&uvcg_streaming_grp.group);
+
+	config_group_init_type_name(&opts->func_inst.group,
 			"",
 			&uvc_func_type);
+	configfs_add_default_group(&uvcg_control_grp.group,
+			&opts->func_inst.group);
+	configfs_add_default_group(&uvcg_streaming_grp.group,
+			&opts->func_inst.group);
+
 	return 0;
 }
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index f419519..b51ce67 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -701,23 +701,29 @@  static int populate_groups(struct config_group *group)
 {
 	struct config_group *new_group;
 	int ret = 0;
-	int i;
-
-	if (group->default_groups) {
-		for (i = 0; group->default_groups[i]; i++) {
-			new_group = group->default_groups[i];
 
-			ret = create_default_group(group, new_group);
-			if (ret) {
-				detach_groups(group);
-				break;
-			}
+	list_for_each_entry(new_group, &group->default_groups, group_entry) {
+		ret = create_default_group(group, new_group);
+		if (ret) {
+			detach_groups(group);
+			break;
 		}
 	}
 
 	return ret;
 }
 
+void configfs_remove_default_groups(struct config_group *group)
+{
+	struct config_group *g, *n;
+
+	list_for_each_entry_safe(g, n, &group->default_groups, group_entry) {
+		list_del(&g->group_entry);
+		config_item_put(&g->cg_item);
+	}
+}
+EXPORT_SYMBOL(configfs_remove_default_groups);
+
 /*
  * All of link_obj/unlink_obj/link_group/unlink_group require that
  * subsys->su_mutex is held.
@@ -766,15 +772,10 @@  static void link_obj(struct config_item *parent_item, struct config_item *item)
 
 static void unlink_group(struct config_group *group)
 {
-	int i;
 	struct config_group *new_group;
 
-	if (group->default_groups) {
-		for (i = 0; group->default_groups[i]; i++) {
-			new_group = group->default_groups[i];
-			unlink_group(new_group);
-		}
-	}
+	list_for_each_entry(new_group, &group->default_groups, group_entry)
+		unlink_group(new_group);
 
 	group->cg_subsys = NULL;
 	unlink_obj(&group->cg_item);
@@ -782,7 +783,6 @@  static void unlink_group(struct config_group *group)
 
 static void link_group(struct config_group *parent_group, struct config_group *group)
 {
-	int i;
 	struct config_group *new_group;
 	struct configfs_subsystem *subsys = NULL; /* gcc is a turd */
 
@@ -796,12 +796,8 @@  static void link_group(struct config_group *parent_group, struct config_group *g
 		BUG();
 	group->cg_subsys = subsys;
 
-	if (group->default_groups) {
-		for (i = 0; group->default_groups[i]; i++) {
-			new_group = group->default_groups[i];
-			link_group(group, new_group);
-		}
-	}
+	list_for_each_entry(new_group, &group->default_groups, group_entry)
+		link_group(group, new_group);
 }
 
 /*
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
index b863a09..8b2a994 100644
--- a/fs/configfs/item.c
+++ b/fs/configfs/item.c
@@ -182,6 +182,7 @@  void config_group_init(struct config_group *group)
 {
 	config_item_init(&group->cg_item);
 	INIT_LIST_HEAD(&group->cg_children);
+	INIT_LIST_HEAD(&group->default_groups);
 }
 EXPORT_SYMBOL(config_group_init);
 
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 8e294fb..5191121 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -346,7 +346,6 @@  static struct config_group *make_cluster(struct config_group *g,
 	void *gps = NULL;
 
 	cl = kzalloc(sizeof(struct dlm_cluster), GFP_NOFS);
-	gps = kcalloc(3, sizeof(struct config_group *), GFP_NOFS);
 	sps = kzalloc(sizeof(struct dlm_spaces), GFP_NOFS);
 	cms = kzalloc(sizeof(struct dlm_comms), GFP_NOFS);
 
@@ -357,10 +356,8 @@  static struct config_group *make_cluster(struct config_group *g,
 	config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
 	config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
 
-	cl->group.default_groups = gps;
-	cl->group.default_groups[0] = &sps->ss_group;
-	cl->group.default_groups[1] = &cms->cs_group;
-	cl->group.default_groups[2] = NULL;
+	configfs_add_default_group(&sps->ss_group, &cl->group);
+	configfs_add_default_group(&cms->cs_group, &cl->group);
 
 	cl->cl_tcp_port = dlm_config.ci_tcp_port;
 	cl->cl_buffer_size = dlm_config.ci_buffer_size;
@@ -383,7 +380,6 @@  static struct config_group *make_cluster(struct config_group *g,
 
  fail:
 	kfree(cl);
-	kfree(gps);
 	kfree(sps);
 	kfree(cms);
 	return ERR_PTR(-ENOMEM);
@@ -392,14 +388,8 @@  static struct config_group *make_cluster(struct config_group *g,
 static void drop_cluster(struct config_group *g, struct config_item *i)
 {
 	struct dlm_cluster *cl = config_item_to_cluster(i);
-	struct config_item *tmp;
-	int j;
 
-	for (j = 0; cl->group.default_groups[j]; j++) {
-		tmp = &cl->group.default_groups[j]->cg_item;
-		cl->group.default_groups[j] = NULL;
-		config_item_put(tmp);
-	}
+	configfs_remove_default_groups(&cl->group);
 
 	space_list = NULL;
 	comm_list = NULL;
@@ -410,7 +400,6 @@  static void drop_cluster(struct config_group *g, struct config_item *i)
 static void release_cluster(struct config_item *i)
 {
 	struct dlm_cluster *cl = config_item_to_cluster(i);
-	kfree(cl->group.default_groups);
 	kfree(cl);
 }
 
@@ -418,21 +407,17 @@  static struct config_group *make_space(struct config_group *g, const char *name)
 {
 	struct dlm_space *sp = NULL;
 	struct dlm_nodes *nds = NULL;
-	void *gps = NULL;
 
 	sp = kzalloc(sizeof(struct dlm_space), GFP_NOFS);
-	gps = kcalloc(2, sizeof(struct config_group *), GFP_NOFS);
 	nds = kzalloc(sizeof(struct dlm_nodes), GFP_NOFS);
 
-	if (!sp || !gps || !nds)
+	if (!sp || !nds)
 		goto fail;
 
 	config_group_init_type_name(&sp->group, name, &space_type);
-	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
 
-	sp->group.default_groups = gps;
-	sp->group.default_groups[0] = &nds->ns_group;
-	sp->group.default_groups[1] = NULL;
+	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
+	configfs_add_default_group(&nds->ns_group, &sp->group);
 
 	INIT_LIST_HEAD(&sp->members);
 	mutex_init(&sp->members_lock);
@@ -441,7 +426,6 @@  static struct config_group *make_space(struct config_group *g, const char *name)
 
  fail:
 	kfree(sp);
-	kfree(gps);
 	kfree(nds);
 	return ERR_PTR(-ENOMEM);
 }
@@ -449,24 +433,16 @@  static struct config_group *make_space(struct config_group *g, const char *name)
 static void drop_space(struct config_group *g, struct config_item *i)
 {
 	struct dlm_space *sp = config_item_to_space(i);
-	struct config_item *tmp;
-	int j;
 
 	/* assert list_empty(&sp->members) */
 
-	for (j = 0; sp->group.default_groups[j]; j++) {
-		tmp = &sp->group.default_groups[j]->cg_item;
-		sp->group.default_groups[j] = NULL;
-		config_item_put(tmp);
-	}
-
+	configfs_remove_default_groups(&sp->group);
 	config_item_put(i);
 }
 
 static void release_space(struct config_item *i)
 {
 	struct dlm_space *sp = config_item_to_space(i);
-	kfree(sp->group.default_groups);
 	kfree(sp);
 }
 
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index ebe5438..b17d180 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -630,7 +630,6 @@  static void o2nm_cluster_release(struct config_item *item)
 {
 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
 
-	kfree(cluster->cl_group.default_groups);
 	kfree(cluster);
 }
 
@@ -666,7 +665,6 @@  static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
 	struct o2nm_cluster *cluster = NULL;
 	struct o2nm_node_group *ns = NULL;
 	struct config_group *o2hb_group = NULL, *ret = NULL;
-	void *defs = NULL;
 
 	/* this runs under the parent dir's i_mutex; there can be only
 	 * one caller in here at a time */
@@ -675,20 +673,18 @@  static struct config_group *o2nm_cluster_group_make_group(struct config_group *g
 
 	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
 	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
-	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
 	o2hb_group = o2hb_alloc_hb_set();
-	if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL)
+	if (cluster == NULL || ns == NULL || o2hb_group == NULL)
 		goto out;
 
 	config_group_init_type_name(&cluster->cl_group, name,
 				    &o2nm_cluster_type);
+	configfs_add_default_group(&ns->ns_group, &cluster->cl_group);
+
 	config_group_init_type_name(&ns->ns_group, "node",
 				    &o2nm_node_group_type);
+	configfs_add_default_group(o2hb_group, &cluster->cl_group);
 
-	cluster->cl_group.default_groups = defs;
-	cluster->cl_group.default_groups[0] = &ns->ns_group;
-	cluster->cl_group.default_groups[1] = o2hb_group;
-	cluster->cl_group.default_groups[2] = NULL;
 	rwlock_init(&cluster->cl_nodes_lock);
 	cluster->cl_node_ip_tree = RB_ROOT;
 	cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
@@ -704,7 +700,6 @@  out:
 		kfree(cluster);
 		kfree(ns);
 		o2hb_free_hb_set(o2hb_group);
-		kfree(defs);
 		ret = ERR_PTR(-ENOMEM);
 	}
 
@@ -714,18 +709,11 @@  out:
 static void o2nm_cluster_group_drop_item(struct config_group *group, struct config_item *item)
 {
 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
-	int i;
-	struct config_item *killme;
 
 	BUG_ON(o2nm_single_cluster != cluster);
 	o2nm_single_cluster = NULL;
 
-	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
-		killme = &cluster->cl_group.default_groups[i]->cg_item;
-		cluster->cl_group.default_groups[i] = NULL;
-		config_item_put(killme);
-	}
-
+	configfs_remove_default_groups(&cluster->cl_group);
 	config_item_put(item);
 }
 
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index f8165c1..485fe55 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -96,7 +96,8 @@  struct config_group {
 	struct config_item		cg_item;
 	struct list_head		cg_children;
 	struct configfs_subsystem 	*cg_subsys;
-	struct config_group		**default_groups;
+	struct list_head		default_groups;
+	struct list_head		group_entry;
 };
 
 extern void config_group_init(struct config_group *group);
@@ -123,6 +124,12 @@  extern struct config_item *config_group_find_item(struct config_group *,
 						  const char *);
 
 
+static inline void configfs_add_default_group(struct config_group *new_group,
+		struct config_group *group)
+{
+	list_add_tail(&new_group->group_entry, &group->default_groups);
+}
+
 struct configfs_attribute {
 	const char		*ca_name;
 	struct module 		*ca_owner;
@@ -251,6 +258,8 @@  int configfs_register_group(struct config_group *parent_group,
 			    struct config_group *group);
 void configfs_unregister_group(struct config_group *group);
 
+void configfs_remove_default_groups(struct config_group *group);
+
 struct config_group *
 configfs_register_default_group(struct config_group *parent_group,
 				const char *name,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index e8c8c08..1b09cac 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -560,7 +560,6 @@  struct se_node_acl {
 	struct config_group	acl_auth_group;
 	struct config_group	acl_param_group;
 	struct config_group	acl_fabric_stat_group;
-	struct config_group	*acl_default_groups[5];
 	struct list_head	acl_list;
 	struct list_head	acl_sess_list;
 	struct completion	acl_free_comp;
@@ -887,7 +886,6 @@  struct se_portal_group {
 	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];
 	struct config_group	tpg_lun_group;
 	struct config_group	tpg_np_group;
 	struct config_group	tpg_acl_group;
@@ -923,7 +921,6 @@  static inline struct se_portal_group *param_to_tpg(struct config_item *item)
 struct se_wwn {
 	struct target_fabric_configfs *wwn_tf;
 	struct config_group	wwn_group;
-	struct config_group	*wwn_default_groups[2];
 	struct config_group	fabric_stat_group;
 };