edac: Create an unique instance for each kobj
authorMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 25 Sep 2009 16:42:25 +0000 (13:42 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 10 May 2010 14:49:30 +0000 (11:49 -0300)
Current code only works when there's just one memory
controller, since we need one kobj for each instance.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/edac/edac_core.h
drivers/edac/edac_mc_sysfs.c

index 02bbbc9..efca934 100644 (file)
@@ -342,23 +342,29 @@ struct csrow_info {
 };
 
 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);
 };
@@ -436,6 +442,9 @@ struct mem_ctl_info {
        /* 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.
         *
index f689d7d..c200c2f 100644 (file)
@@ -730,7 +730,7 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 
 #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,
@@ -764,12 +764,12 @@ static ssize_t inst_grp_store(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);
@@ -804,22 +804,30 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
 
        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;
@@ -845,25 +853,27 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
  *     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);
@@ -871,6 +881,16 @@ static void edac_remove_mci_instance_attributes(
                        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);
+               }
 }
 
 
@@ -891,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 
        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);
@@ -940,8 +962,8 @@ fail1:
        }
 
        /* 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);
@@ -975,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
        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 */