Commit 8096cfaf authored by Doug Thompson's avatar Doug Thompson Committed by Linus Torvalds

drivers/edac: fix edac_mc sysfs completion code

This patch refactors the 'releasing' of kobjects for the edac_mc type of
device.  The correct pattern of kobject release is followed.

As internal kobjs are allocated they bump a ref count on the top level kobj.
It in turn has a module ref count on the edac_core module.  When internal
kobjects are released, they dec the ref count on the top level kobj.  When the
top level kobj reaches zero, it decrements the ref count on the edac_core
object, allow it to be unloaded, as all resources have all now been released.

Cc: Alan Cox alan@lxorguk.ukuu.org.uk
Signed-off-by: default avatarDoug Thompson <dougthompson@xmission.com>
Acked-by: default avatarGreg KH <greg@kroah.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d45e7823
......@@ -317,9 +317,8 @@ struct csrow_info {
struct mem_ctl_info *mci; /* the parent */
struct kobject kobj; /* sysfs kobject for this csrow */
struct completion kobj_complete;
/* FIXME the number of CHANNELs might need to become dynamic */
/* channel information for this csrow */
u32 nr_channels;
struct channel_info *channels;
};
......@@ -403,7 +402,6 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
struct completion kobj_complete;
/* Additional top controller level attributes, but specified
* by the low level driver.
......
......@@ -137,6 +137,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
void *pvt;
unsigned size;
int row, chn;
int err;
/* Figure out the offsets of the various items from the start of an mc
* structure. We want the alignment of each item to be at least as
......@@ -149,7 +150,8 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
size = ((unsigned long)pvt) + sz_pvt;
if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
mci = kzalloc(size, GFP_KERNEL);
if (mci == NULL)
return NULL;
/* Adjust pointers so they point within the memory we just allocated
......@@ -182,20 +184,34 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
mci->op_state = OP_ALLOC;
/*
* Initialize the 'root' kobj for the edac_mc controller
*/
err = edac_mc_register_sysfs_main_kobj(mci);
if (err) {
kfree(mci);
return NULL;
}
/* at this point, the root kobj is valid, and in order to
* 'free' the object, then the function:
* edac_mc_unregister_sysfs_main_kobj() must be called
* which will perform kobj unregistration and the actual free
* will occur during the kobject callback operation
*/
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_alloc);
/**
* edac_mc_free: Free a previously allocated 'mci' structure
* edac_mc_free
* 'Free' a previously allocated 'mci' structure
* @mci: pointer to a struct mem_ctl_info structure
*/
void edac_mc_free(struct mem_ctl_info *mci)
{
kfree(mci);
edac_mc_unregister_sysfs_main_kobj(mci);
}
EXPORT_SYMBOL_GPL(edac_mc_free);
static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
......@@ -391,7 +407,6 @@ struct mem_ctl_info *edac_mc_find(int idx)
return NULL;
}
EXPORT_SYMBOL(edac_mc_find);
/**
......@@ -465,7 +480,6 @@ fail0:
mutex_unlock(&mem_ctls_mutex);
return 1;
}
EXPORT_SYMBOL_GPL(edac_mc_add_mc);
/**
......@@ -501,7 +515,6 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
mci->mod_name, mci->ctl_name, dev_name(mci));
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_del_mc);
static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
......@@ -571,7 +584,6 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
return row;
}
EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
/* FIXME - setable log (warning/emerg) levels */
......@@ -636,7 +648,6 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
mci->csrows[row].grain);
}
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
......@@ -648,7 +659,6 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
mci->ce_noinfo_count++;
mci->ce_count++;
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
void edac_mc_handle_ue(struct mem_ctl_info *mci,
......@@ -702,7 +712,6 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci,
mci->ue_count++;
mci->csrows[row].ue_count++;
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
......@@ -716,7 +725,6 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
mci->ue_noinfo_count++;
mci->ue_count++;
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
/*************************************************************
......@@ -784,7 +792,6 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
"labels \"%s\": %s\n", csrow, channela,
channelb, labels, msg);
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
/*************************************************************
......@@ -824,7 +831,6 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
mci->csrows[csrow].ce_count++;
mci->csrows[csrow].channels[channel].ce_count++;
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
/*
......
This diff is collapsed.
......@@ -14,11 +14,11 @@
#include "edac_core.h"
#include "edac_module.h"
#define EDAC_MC_VERSION "Ver: 2.0.4 " __DATE__
#define EDAC_MC_VERSION "Ver: 2.0.5 " __DATE__
#ifdef CONFIG_EDAC_DEBUG
/* Values of 0 to 4 will generate output */
int edac_debug_level = 1;
int edac_debug_level = 2;
EXPORT_SYMBOL_GPL(edac_debug_level);
#endif
......@@ -153,7 +153,7 @@ static int __init edac_init(void)
edac_pci_clear_parity_errors();
/*
* perform the registration of the /sys/devices/system/edac object
* perform the registration of the /sys/devices/system/edac class object
*/
if (edac_register_sysfs_edac_name()) {
edac_printk(KERN_ERR, EDAC_MC,
......@@ -162,29 +162,29 @@ static int __init edac_init(void)
goto error;
}
/* Create the MC sysfs entries, must be first
/*
* now set up the mc_kset under the edac class object
*/
if (edac_sysfs_memctrl_setup()) {
edac_printk(KERN_ERR, EDAC_MC,
"Error initializing sysfs code\n");
err = -ENODEV;
goto error_sysfs;
}
err = edac_sysfs_setup_mc_kset();
if (err)
goto sysfs_setup_fail;
/* Setup/Initialize the edac_device system */
/* Setup/Initialize the workq for this core */
err = edac_workqueue_setup();
if (err) {
edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
goto error_mem;
goto workq_fail;
}
return 0;
/* Error teardown stack */
error_mem:
edac_sysfs_memctrl_teardown();
error_sysfs:
workq_fail:
edac_sysfs_teardown_mc_kset();
sysfs_setup_fail:
edac_unregister_sysfs_edac_name();
error:
return err;
}
......@@ -199,7 +199,7 @@ static void __exit edac_exit(void)
/* tear down the various subsystems */
edac_workqueue_teardown();
edac_sysfs_memctrl_teardown();
edac_sysfs_teardown_mc_kset();
edac_unregister_sysfs_edac_name();
}
......
......@@ -18,11 +18,15 @@
* INTERNAL EDAC MODULE:
* EDAC memory controller sysfs create/remove functions
* and setup/teardown functions
*
* edac_mc objects
*/
extern int edac_sysfs_setup_mc_kset(void);
extern void edac_sysfs_teardown_mc_kset(void);
extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
extern int edac_sysfs_memctrl_setup(void);
extern void edac_sysfs_memctrl_teardown(void);
extern void edac_check_mc_devices(void);
extern int edac_get_log_ue(void);
extern int edac_get_log_ce(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment