Skip to content

Commit

Permalink
drivers/edac: fix edac_device sysfs completion code
Browse files Browse the repository at this point in the history
With feedback, this patch corrects operation of the kobject release operation
on kobjects, attributes and controls for the edac_device.

Cc: Alan Cox alan@lxorguk.ukuu.org.uk
Signed-off-by: Doug Thompson <dougthompson@xmission.com>
Acked-by: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Douglas Thompson authored and Linus Torvalds committed Jul 19, 2007
1 parent 8096cfa commit 1c3631f
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 115 deletions.
10 changes: 6 additions & 4 deletions drivers/edac/edac_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ struct mcidev_sysfs_attribute {
*/
struct mem_ctl_info {
struct list_head link; /* for global list of mem_ctl_info structs */

struct module *owner; /* Module owner of this control struct */

unsigned long mtype_cap; /* memory types supported by mc */
unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */
unsigned long edac_cap; /* configuration capabilities - this is
Expand Down Expand Up @@ -510,7 +513,6 @@ struct edac_device_block {

/* edac sysfs device control */
struct kobject kobj;
struct completion kobj_complete;
};

/* device instance control structure */
Expand All @@ -525,7 +527,6 @@ struct edac_device_instance {

/* edac sysfs device control */
struct kobject kobj;
struct completion kobj_complete;
};


Expand All @@ -537,6 +538,8 @@ struct edac_device_ctl_info {
/* for global list of edac_device_ctl_info structs */
struct list_head link;

struct module *owner; /* Module owner of this control struct */

int dev_idx;

/* Per instance controls for this edac_device */
Expand Down Expand Up @@ -587,7 +590,7 @@ struct edac_device_ctl_info {
* NMI handlers may be traversing list
*/
struct rcu_head rcu;
struct completion complete;
struct completion removal_complete;

/* sysfs top name under 'edac' directory
* and instance name:
Expand All @@ -611,7 +614,6 @@ struct edac_device_ctl_info {
* device this structure controls
*/
struct kobject kobj;
struct completion kobj_complete;
};

/* To get from the instance's wq to the beginning of the ctl structure */
Expand Down
37 changes: 28 additions & 9 deletions drivers/edac/edac_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
}
#endif /* CONFIG_EDAC_DEBUG */


/*
* edac_device_alloc_ctl_info()
* Allocate a new edac device control info structure
Expand Down Expand Up @@ -78,6 +79,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
unsigned count;
unsigned instance, block, attr;
void *pvt;
int err;

debugf1("%s() instances=%d blocks=%d\n",
__func__, nr_instances, nr_blocks);
Expand Down Expand Up @@ -208,6 +210,22 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
/* Mark this instance as merely ALLOCATED */
dev_ctl->op_state = OP_ALLOC;

/*
* Initialize the 'root' kobj for the edac_device controller
*/
err = edac_device_register_sysfs_main_kobj(dev_ctl);
if (err) {
kfree(dev_ctl);
return NULL;
}

/* at this point, the root kobj is valid, and in order to
* 'free' the object, then the function:
* edac_device_unregister_sysfs_main_kobj() must be called
* which will perform kobj unregistration and the actual free
* will occur during the kobject callback operation
*/

return dev_ctl;
}
EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
Expand All @@ -219,7 +237,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
*/
void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
{
kfree(ctl_info);
edac_device_unregister_sysfs_main_kobj(ctl_info);
}
EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);

Expand Down Expand Up @@ -315,22 +333,23 @@ static void complete_edac_device_list_del(struct rcu_head *head)

edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
INIT_LIST_HEAD(&edac_dev->link);
complete(&edac_dev->complete);
complete(&edac_dev->removal_complete);
}

/*
* del_edac_device_from_global_list
*
* remove the RCU, setup for a callback call, then wait for the
* callback to occur
* remove the RCU, setup for a callback call,
* then wait for the callback to occur
*/
static void del_edac_device_from_global_list(struct edac_device_ctl_info
*edac_device)
{
list_del_rcu(&edac_device->link);
init_completion(&edac_device->complete);

init_completion(&edac_device->removal_complete);
call_rcu(&edac_device->rcu, complete_edac_device_list_del);
wait_for_completion(&edac_device->complete);
wait_for_completion(&edac_device->removal_complete);
}

/**
Expand Down Expand Up @@ -542,14 +561,14 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
/* clear workq processing on this instance */
edac_device_workq_teardown(edac_dev);

/* Tear down the sysfs entries for this instance */
edac_device_remove_sysfs(edac_dev);

/* deregister from global list */
del_edac_device_from_global_list(edac_dev);

mutex_unlock(&device_ctls_mutex);

/* Tear down the sysfs entries for this instance */
edac_device_remove_sysfs(edac_dev);

edac_printk(KERN_INFO, EDAC_MC,
"Removed device %d for %s %s: DEV %s\n",
edac_dev->dev_idx,
Expand Down
Loading

0 comments on commit 1c3631f

Please sign in to comment.