Skip to content

Commit

Permalink
drivers/edac: fix edac_mc sysfs completion code
Browse files Browse the repository at this point in the history
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: 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
Doug Thompson authored and Linus Torvalds committed Jul 19, 2007
1 parent d45e782 commit 8096cfa
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 249 deletions.
4 changes: 1 addition & 3 deletions drivers/edac/edac_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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.
Expand Down
36 changes: 21 additions & 15 deletions drivers/edac/edac_mc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -391,7 +407,6 @@ struct mem_ctl_info *edac_mc_find(int idx)

return NULL;
}

EXPORT_SYMBOL(edac_mc_find);

/**
Expand Down Expand Up @@ -465,7 +480,6 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
mutex_unlock(&mem_ctls_mutex);
return 1;
}

EXPORT_SYMBOL_GPL(edac_mc_add_mc);

/**
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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);

/*************************************************************
Expand Down Expand Up @@ -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);

/*************************************************************
Expand Down Expand Up @@ -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);

/*
Expand Down
Loading

0 comments on commit 8096cfa

Please sign in to comment.