From 21c3bad89f96dd7a695058f32c4b6fdc1ec9f2ef Mon Sep 17 00:00:00 2001 From: Robert Nelson <robertcnelson@gmail.com> Date: Mon, 28 Mar 2016 09:40:39 -0500 Subject: [PATCH] fix: configfs build error Signed-off-by: Robert Nelson <robertcnelson@gmail.com> --- patch.sh | 1 + ...switch-default-groups-to-a-linked-li.patch | 1886 +++++++++++++++++ version.sh | 2 +- 3 files changed, 1888 insertions(+), 1 deletion(-) create mode 100644 patches/bbb_overlays/configfs/0001-Revert-configfs-switch-default-groups-to-a-linked-li.patch diff --git a/patch.sh b/patch.sh index 69e715fe4..10c1ac9a6 100644 --- a/patch.sh +++ b/patch.sh @@ -403,6 +403,7 @@ bbb_overlays () { #merged in 4.5.0-rc0 ${git} "${DIR}/patches/bbb_overlays/configfs/0001-configfs-implement-binary-attributes.patch" fi + ${git} "${DIR}/patches/bbb_overlays/configfs/0001-Revert-configfs-switch-default-groups-to-a-linked-li.patch" echo "dir: bbb_overlays/of" #regenerate="enable" diff --git a/patches/bbb_overlays/configfs/0001-Revert-configfs-switch-default-groups-to-a-linked-li.patch b/patches/bbb_overlays/configfs/0001-Revert-configfs-switch-default-groups-to-a-linked-li.patch new file mode 100644 index 000000000..ce635f862 --- /dev/null +++ b/patches/bbb_overlays/configfs/0001-Revert-configfs-switch-default-groups-to-a-linked-li.patch @@ -0,0 +1,1886 @@ +From 3964e9a38d77837c635c5316cdae246b2cf6dc7f Mon Sep 17 00:00:00 2001 +From: Robert Nelson <robertcnelson@gmail.com> +Date: Mon, 28 Mar 2016 09:31:22 -0500 +Subject: [PATCH] Revert "configfs: switch ->default groups to a linked list" + +This reverts commit 1ae1602de028acaa42a0f6ff18d19756f8e825c6. + +Signed-off-by: Robert Nelson <robertcnelson@gmail.com> +--- + 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 | 5 +- + 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, 634 insertions(+), 286 deletions(-) + +diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt +index 8ec9136..e5fe521 100644 +--- a/Documentation/filesystems/configfs/configfs.txt ++++ b/Documentation/filesystems/configfs/configfs.txt +@@ -250,8 +250,7 @@ child item. + struct config_item cg_item; + struct list_head cg_children; + struct configfs_subsystem *cg_subsys; +- struct list_head default_groups; +- struct list_head group_entry; ++ struct config_group **default_groups; + }; + + void config_group_init(struct config_group *group); +@@ -421,15 +420,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 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 ++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 + 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 41573df..18b112a 100644 +--- a/drivers/infiniband/core/cma_configfs.c ++++ b/drivers/infiniband/core/cma_configfs.c +@@ -49,6 +49,8 @@ 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; + }; + +@@ -156,6 +158,7 @@ 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); +@@ -166,8 +169,9 @@ 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) { ++ if (!ports || !ports_group) { + err = -ENOMEM; + goto free; + } +@@ -181,16 +185,18 @@ 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); +- configfs_add_default_group(&ports[i].group, +- &cma_dev_group->ports_group); +- ++ ports_group[i] = &ports[i].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; + } + +@@ -214,7 +220,9 @@ 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 = { +@@ -255,17 +263,22 @@ static struct config_group *make_cma_dev(struct config_group *group, + + strncpy(cma_dev_group->name, name, sizeof(cma_dev_group->name)); + +- config_group_init_type_name(&cma_dev_group->ports_group, "ports", +- &cma_ports_group_type); +- + 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; ++ + 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 a24443b..2f821de 100644 +--- a/drivers/target/iscsi/iscsi_target_configfs.c ++++ b/drivers/target/iscsi/iscsi_target_configfs.c +@@ -771,11 +771,21 @@ 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; + } + +@@ -783,8 +793,17 @@ 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); +- +- configfs_remove_default_groups(&acl->se_node_acl.acl_fabric_stat_group); ++ 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); + } + + /* End items for lio_target_acl_cit */ +@@ -1241,37 +1260,42 @@ 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:" +@@ -1283,8 +1307,17 @@ static void lio_target_call_coredeltiqn( + struct se_wwn *wwn) + { + struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); +- +- configfs_remove_default_groups(&tiqn->tiqn_wwn.fabric_stat_group); ++ 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); + + 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 d498533..713c63d9 100644 +--- a/drivers/target/target_core_configfs.c ++++ b/drivers/target/target_core_configfs.c +@@ -194,11 +194,13 @@ static struct config_group *target_core_register_fabric( + pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", + &tf->tf_wwn_cit); + +- config_group_init_type_name(&tf->tf_group, name, &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); +@@ -214,6 +216,9 @@ 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)); +@@ -225,7 +230,12 @@ static void target_core_deregister_fabric( + pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" + " %s\n", config_item_name(item)); + +- configfs_remove_default_groups(&tf->tf_group); ++ 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); ++ } + config_item_put(item); + } + +@@ -2141,6 +2151,7 @@ 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); + } + +@@ -2808,6 +2819,8 @@ 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); +@@ -2818,52 +2831,73 @@ static struct config_group *target_core_make_subdev( + if (!dev) + goto out_unlock; + +- config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit); ++ 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_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_device; ++ goto out_free_dev_cg_default_groups; + 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); +- configfs_add_default_group(&tg_pt_gp->tg_pt_gp_group, +- &dev->t10_alua.alua_tg_pt_gps_group); +- ++ tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; ++ tg_pt_gp_cg->default_groups[1] = NULL; + /* + * 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->dev_group; ++ return dev_cg; + ++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: +@@ -2879,22 +2913,40 @@ 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); + +- configfs_remove_default_groups(&dev->dev_stat_grps.stat_group); +- configfs_remove_default_groups(&dev->t10_alua.alua_tg_pt_gps_group); ++ 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); + ++ 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; + +- configfs_remove_default_groups(dev_cg); +- ++ 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); ++ } + /* + * se_dev is released from target_core_dev_item_ops->release() + */ +@@ -3089,6 +3141,8 @@ 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; +@@ -3107,24 +3161,51 @@ 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. + */ +- config_group_init_type_name(&target_core_hbagroup, "core", +- &target_core_cit); +- configfs_add_default_group(&target_core_hbagroup, &subsys->su_group); ++ 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); ++ target_cg->default_groups[0] = &target_core_hbagroup; ++ target_cg->default_groups[1] = NULL; + /* + * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ + */ +- config_group_init_type_name(&alua_group, "alua", &target_core_alua_cit); +- configfs_add_default_group(&alua_group, &target_core_hbagroup); +- ++ 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; + /* + * Add ALUA Logical Unit Group and Target Port Group ConfigFS + * groups under /sys/kernel/config/target/core/alua/ + */ +- 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); ++ 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); ++ alua_cg->default_groups[0] = &alua_lu_gps_group; ++ alua_cg->default_groups[1] = NULL; + /* + * Add core/alua/lu_gps/default_lu_gp + */ +@@ -3134,12 +3215,20 @@ 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); +- configfs_add_default_group(&lu_gp->lu_gp_group, &alua_lu_gps_group); +- ++ lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group; ++ lu_gp_cg->default_groups[1] = NULL; + default_lu_gp = lu_gp; +- + /* + * Register the target_core_mod subsystem with configfs. + */ +@@ -3178,21 +3267,55 @@ 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) + { +- configfs_remove_default_groups(&alua_lu_gps_group); +- configfs_remove_default_groups(&alua_group); +- configfs_remove_default_groups(&target_core_hbagroup); ++ struct config_group *hba_cg, *alua_cg, *lu_gp_cg; ++ struct config_item *item; ++ int i; + ++ 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 1bd5c72..8cc68be 100644 +--- a/drivers/target/target_core_fabric_configfs.c ++++ b/drivers/target/target_core_fabric_configfs.c +@@ -269,10 +269,18 @@ 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"); +@@ -303,19 +311,37 @@ 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); +- configfs_add_default_group(&lacl->ml_stat_grps.stat_group, +- &lacl->se_lun_group); +- ++ 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; ++ } + 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); +@@ -327,9 +353,25 @@ 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); + +- configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group); +- configfs_remove_default_groups(&lacl->se_lun_group); ++ 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); + + config_item_put(item); + } +@@ -378,6 +420,7 @@ 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)) +@@ -391,28 +434,24 @@ 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; + } +@@ -423,9 +462,16 @@ static void target_fabric_drop_nodeacl( + { + struct se_node_acl *se_nacl = container_of(to_config_group(item), + struct se_node_acl, acl_group); +- +- configfs_remove_default_groups(&se_nacl->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); ++ } + /* + * struct se_node_acl free is done in target_fabric_nacl_base_release() + */ +@@ -745,6 +791,7 @@ 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; + +@@ -761,14 +808,31 @@ 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); +- configfs_add_default_group(&lun->port_stat_grps.stat_group, +- &lun->lun_group); +- ++ 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); ++ } + target_stat_setup_port_default_groups(lun); + + return &lun->lun_group; +@@ -780,9 +844,25 @@ 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); + +- configfs_remove_default_groups(&lun->port_stat_grps.stat_group); +- configfs_remove_default_groups(&lun->lun_group); ++ 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); + + config_item_put(item); + } +@@ -838,39 +918,32 @@ 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; + } +@@ -881,8 +954,19 @@ 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); + } + +@@ -938,12 +1022,16 @@ 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; + } +@@ -954,8 +1042,16 @@ 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 86b4a83..040cf52 100644 +--- a/drivers/target/target_core_internal.h ++++ b/drivers/target/target_core_internal.h +@@ -22,6 +22,7 @@ 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 1a39033..81a6b3e 100644 +--- a/drivers/target/target_core_stat.c ++++ b/drivers/target/target_core_stat.c +@@ -407,20 +407,19 @@ 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); +- configfs_add_default_group(&dev->dev_stat_grps.scsi_lu_group, +- &dev->dev_stat_grps.stat_group); ++ ++ 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; + } + + /* +@@ -819,20 +818,19 @@ 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); +- configfs_add_default_group(&lun->port_stat_grps.scsi_transport_group, +- &lun->port_stat_grps.stat_group); ++ ++ 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; + } + + /* +@@ -1353,13 +1351,14 @@ 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); +- configfs_add_default_group(&lacl->ml_stat_grps.scsi_att_intr_port_group, +- &lacl->ml_stat_grps.stat_group); ++ ++ 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; + } +diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c +index b6f60ca..c6cc15e 100644 +--- a/drivers/usb/gadget/configfs.c ++++ b/drivers/usb/gadget/configfs.c +@@ -49,6 +49,7 @@ 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]; +@@ -70,6 +71,7 @@ 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; +@@ -664,12 +666,13 @@ 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) +@@ -1146,11 +1149,15 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent, + char **names, + struct module *owner) + { +- struct config_group *os_desc_group; ++ struct config_group **f_default_groups, *os_desc_group, ++ **interface_groups; + 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); + +@@ -1158,14 +1165,18 @@ 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); +- configfs_add_default_group(os_desc_group, parent); ++ f_default_groups[0] = os_desc_group; + ++ 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; +@@ -1178,7 +1189,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]); +- configfs_add_default_group(&d->group, os_desc_group); ++ interface_groups[n_interf] = &d->group; + } + + return 0; +@@ -1413,23 +1424,20 @@ static struct config_group *gadgets_make( + if (!gi) + return ERR_PTR(-ENOMEM); + +- config_group_init_type_name(&gi->group, name, &gadget_root_type); ++ 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->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; +@@ -1454,6 +1462,8 @@ 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 acf210f..ee9390b 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 c800582..d99dd95 100644 +--- a/drivers/usb/gadget/function/f_rndis.c ++++ b/drivers/usb/gadget/function/f_rndis.c +@@ -889,6 +889,7 @@ 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); + } + +@@ -915,10 +916,10 @@ static struct usb_function_instance *rndis_alloc_inst(void) + + descs[0] = &opts->rndis_os_desc; + names[0] = "rndis"; +- config_group_init_type_name(&opts->func_inst.group, "", +- &rndis_func_type); + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, + names, THIS_MODULE); ++ config_group_init_type_name(&opts->func_inst.group, "", ++ &rndis_func_type); + + return &opts->func_inst; + } +diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c +index 66753ba..ad8c9b0 100644 +--- a/drivers/usb/gadget/function/uvc_configfs.c ++++ b/drivers/usb/gadget/function/uvc_configfs.c +@@ -272,6 +272,11 @@ 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; +@@ -389,6 +394,11 @@ 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; +@@ -467,6 +477,11 @@ 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; +@@ -476,6 +491,12 @@ 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; +@@ -598,6 +619,12 @@ 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; +@@ -607,6 +634,14 @@ 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; +@@ -1745,6 +1780,11 @@ 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; +@@ -2105,6 +2145,13 @@ 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; +@@ -2114,6 +2161,15 @@ 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; +@@ -2123,6 +2179,12 @@ 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, +@@ -2211,64 +2273,59 @@ 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); +- 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); +- ++ "default", ++ &uvcg_default_processing_type); ++ uvcg_init_group(&uvcg_processing_grp.group, ++ uvcg_processing_default_groups, ++ "processing", ++ &uvcg_processing_grp_type); + config_group_init_type_name(&uvcg_default_camera.group, +- "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); +- ++ "default", ++ &uvcg_default_camera_type); ++ uvcg_init_group(&uvcg_camera_grp.group, ++ uvcg_camera_default_groups, ++ "camera", ++ &uvcg_camera_grp_type); + config_group_init_type_name(&uvcg_default_output.group, +- "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); +- ++ "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); + 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); +- config_group_init_type_name(&uvcg_control_class_grp.group, ++ "ss", ++ &uvcg_control_class_type); ++ uvcg_init_group(&uvcg_control_class_grp.group, ++ uvcg_control_class_default_groups, + "class", + &uvcg_control_class_grp_type); +- 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, ++ uvcg_init_group(&uvcg_control_grp.group, ++ uvcg_control_default_groups, + "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); +@@ -2281,47 +2338,30 @@ 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); +- config_group_init_type_name(&uvcg_color_matching_grp.group, ++ uvcg_init_group(&uvcg_color_matching_grp.group, ++ uvcg_color_matching_default_groups, + "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); +- 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, ++ "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, + "", + &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 ea59c89..214ec14 100644 +--- a/fs/configfs/dir.c ++++ b/fs/configfs/dir.c +@@ -696,29 +696,23 @@ static int populate_groups(struct config_group *group) + { + struct config_group *new_group; + int ret = 0; ++ int i; + +- list_for_each_entry(new_group, &group->default_groups, group_entry) { +- ret = create_default_group(group, new_group); +- if (ret) { +- detach_groups(group); +- break; ++ 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; ++ } + } + } + + 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. +@@ -767,10 +761,15 @@ 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; + +- list_for_each_entry(new_group, &group->default_groups, group_entry) +- unlink_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); ++ } ++ } + + group->cg_subsys = NULL; + unlink_obj(&group->cg_item); +@@ -778,6 +777,7 @@ 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 */ + +@@ -791,8 +791,12 @@ static void link_group(struct config_group *parent_group, struct config_group *g + BUG(); + group->cg_subsys = subsys; + +- list_for_each_entry(new_group, &group->default_groups, group_entry) +- link_group(group, new_group); ++ if (group->default_groups) { ++ for (i = 0; group->default_groups[i]; i++) { ++ new_group = group->default_groups[i]; ++ link_group(group, new_group); ++ } ++ } + } + + /* +diff --git a/fs/configfs/item.c b/fs/configfs/item.c +index 8b2a994..b863a09 100644 +--- a/fs/configfs/item.c ++++ b/fs/configfs/item.c +@@ -182,7 +182,6 @@ 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 5191121..8e294fb 100644 +--- a/fs/dlm/config.c ++++ b/fs/dlm/config.c +@@ -346,6 +346,7 @@ 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); + +@@ -356,8 +357,10 @@ 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); + +- configfs_add_default_group(&sps->ss_group, &cl->group); +- configfs_add_default_group(&cms->cs_group, &cl->group); ++ 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; + + cl->cl_tcp_port = dlm_config.ci_tcp_port; + cl->cl_buffer_size = dlm_config.ci_buffer_size; +@@ -380,6 +383,7 @@ static struct config_group *make_cluster(struct config_group *g, + + fail: + kfree(cl); ++ kfree(gps); + kfree(sps); + kfree(cms); + return ERR_PTR(-ENOMEM); +@@ -388,8 +392,14 @@ 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; + +- configfs_remove_default_groups(&cl->group); ++ 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); ++ } + + space_list = NULL; + comm_list = NULL; +@@ -400,6 +410,7 @@ 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); + } + +@@ -407,17 +418,21 @@ 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 || !nds) ++ if (!sp || !gps || !nds) + goto fail; + + config_group_init_type_name(&sp->group, name, &space_type); +- + config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type); +- configfs_add_default_group(&nds->ns_group, &sp->group); ++ ++ sp->group.default_groups = gps; ++ sp->group.default_groups[0] = &nds->ns_group; ++ sp->group.default_groups[1] = NULL; + + INIT_LIST_HEAD(&sp->members); + mutex_init(&sp->members_lock); +@@ -426,6 +441,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) + + fail: + kfree(sp); ++ kfree(gps); + kfree(nds); + return ERR_PTR(-ENOMEM); + } +@@ -433,16 +449,24 @@ 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) */ + +- configfs_remove_default_groups(&sp->group); ++ 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); ++ } ++ + 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 b17d180..ebe5438 100644 +--- a/fs/ocfs2/cluster/nodemanager.c ++++ b/fs/ocfs2/cluster/nodemanager.c +@@ -630,6 +630,7 @@ 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); + } + +@@ -665,6 +666,7 @@ 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 */ +@@ -673,18 +675,20 @@ 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) ++ if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == 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; +@@ -700,6 +704,7 @@ out: + kfree(cluster); + kfree(ns); + o2hb_free_hb_set(o2hb_group); ++ kfree(defs); + ret = ERR_PTR(-ENOMEM); + } + +@@ -709,11 +714,18 @@ 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; + +- configfs_remove_default_groups(&cluster->cl_group); ++ 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); ++ } ++ + config_item_put(item); + } + +diff --git a/include/linux/configfs.h b/include/linux/configfs.h +index 485fe55..f8165c1 100644 +--- a/include/linux/configfs.h ++++ b/include/linux/configfs.h +@@ -96,8 +96,7 @@ struct config_group { + struct config_item cg_item; + struct list_head cg_children; + struct configfs_subsystem *cg_subsys; +- struct list_head default_groups; +- struct list_head group_entry; ++ struct config_group **default_groups; + }; + + extern void config_group_init(struct config_group *group); +@@ -124,12 +123,6 @@ 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; +@@ -258,8 +251,6 @@ 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 3e0dd86..fca03b9 100644 +--- a/include/target/target_core_base.h ++++ b/include/target/target_core_base.h +@@ -554,6 +554,7 @@ 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; +@@ -879,6 +880,7 @@ 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; +@@ -914,6 +916,7 @@ 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.8.0.rc3 + diff --git a/version.sh b/version.sh index 0d5f5a7d4..54d8c2369 100644 --- a/version.sh +++ b/version.sh @@ -25,7 +25,7 @@ toolchain="gcc_linaro_gnueabihf_5" #Kernel/Build KERNEL_REL=4.6 KERNEL_TAG=${KERNEL_REL}-rc1 -BUILD=${build_prefix}0.1 +BUILD=${build_prefix}0.2 kernel_rt=".X-rtY" #v4.X-rcX + upto SHA -- GitLab