};
struct mcidev_sysfs_group {
- const char *name;
- struct mcidev_sysfs_attribute *mcidev_attr;
- struct kobject kobj;
+ const char *name; /* group name */
+ struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
+};
+
+struct mcidev_sysfs_group_kobj {
+ struct list_head list; /* list for all instances within a mc */
+
+ struct kobject kobj; /* kobj for the group */
+ struct mcidev_sysfs_group *grp; /* group description table */
struct mem_ctl_info *mci; /* the parent */
};
-
/* mcidev_sysfs_attribute structure
* used for driver sysfs attributes and in mem_ctl_info
* sysfs top level entries
*/
struct mcidev_sysfs_attribute {
+ /* It should use either attr or grp */
struct attribute attr;
+ struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
- struct mcidev_sysfs_group *grp;
-
+ /* Ops for show/store values at the attribute - not used on group */
ssize_t (*show)(struct mem_ctl_info *,char *);
ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
};
/* edac sysfs device control */
struct kobject edac_mci_kobj;
+ /* list for all grp instances within a mc */
+ struct list_head grp_kobj_list;
+
/* Additional top controller level attributes, but specified
* by the low level driver.
*
#define EDAC_DEVICE_SYMLINK "device"
-#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group, kobj)->mci)
+#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
/* MCI show/store functions for top most object */
static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
/* No memory to release for this kobj */
static void edac_inst_grp_release(struct kobject *kobj)
{
- struct mcidev_sysfs_group *grp;
+ struct mcidev_sysfs_group_kobj *grp;
struct mem_ctl_info *mci;
debugf1("%s()\n", __func__);
- grp = container_of(kobj, struct mcidev_sysfs_group, kobj);
+ grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
mci = grp->mci;
kobject_put(&mci->edac_mci_kobj);
while (sysfs_attrib) {
if (sysfs_attrib->grp) {
- struct kobject *newkobj = &sysfs_attrib->grp->kobj;
+ struct mcidev_sysfs_group_kobj *grp_kobj;
+
+ grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
+ if (!grp_kobj)
+ return -ENOMEM;
+
+ list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
+
+ grp_kobj->grp = sysfs_attrib->grp;
+ grp_kobj->mci = mci;
debugf0("%s() grp %s, mci %p\n", __func__,
sysfs_attrib->grp->name, mci);
- sysfs_attrib->grp->mci = mci;
-
- err = kobject_init_and_add(newkobj, &ktype_inst_grp,
+ err = kobject_init_and_add(&grp_kobj->kobj,
+ &ktype_inst_grp,
&mci->edac_mci_kobj,
sysfs_attrib->grp->name);
if (err)
return err;
err = edac_create_mci_instance_attributes(mci,
- sysfs_attrib->grp->mcidev_attr,
- newkobj);
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj);
if (err)
return err;
* remove MC driver specific attributes at the topmost level
* directory of this mci instance.
*/
-static void edac_remove_mci_instance_attributes(
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
struct mcidev_sysfs_attribute *sysfs_attrib,
- struct kobject *kobj)
+ struct kobject *kobj, int count)
{
+ struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
+
debugf1("%s()\n", __func__);
- /* loop if there are attributes and until we hit a NULL entry */
+ /*
+ * loop if there are attributes and until we hit a NULL entry
+ * Remove first all the atributes
+ */
while (sysfs_attrib) {
if (sysfs_attrib->grp) {
- struct kobject *newkobj = &sysfs_attrib->grp->kobj;
-
- debugf0("%s() grp %s\n", __func__,
- sysfs_attrib->grp->name);
-
- edac_remove_mci_instance_attributes(
- sysfs_attrib->grp->mcidev_attr, newkobj);
-
- kobject_put(newkobj);
- } else if (sysfs_attrib->attr.name) {
+ list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
+ list)
+ if (grp_kobj->grp == sysfs_attrib->grp)
+ edac_remove_mci_instance_attributes(mci,
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj, count + 1);
+ } else if (sysfs_attrib->attr.name) {
debugf0("%s() file %s\n", __func__,
sysfs_attrib->attr.name);
sysfs_remove_file(kobj, &sysfs_attrib->attr);
break;
sysfs_attrib++;
}
+
+ /*
+ * Now that all attributes got removed, it is save to remove all groups
+ */
+ if (!count)
+ list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
+ list) {
+ debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
+ kobject_put(&grp_kobj->kobj);
+ }
}
debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+ INIT_LIST_HEAD(&mci->grp_kobj_list);
+
/* create a symlink for the device */
err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
EDAC_DEVICE_SYMLINK);
}
/* remove the mci instance's attributes, if any */
- edac_remove_mci_instance_attributes(
- mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj);
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
/* remove the symlink */
sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
debugf0("%s() remove_mci_instance\n", __func__);
/* remove this mci instance's attribtes */
- edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes,
- &mci->edac_mci_kobj);
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes,
+ &mci->edac_mci_kobj, 0);
debugf0("%s() unregister this mci kobj\n", __func__);
/* unregister this instance's kobject */