Commit 09667606 authored by Borislav Petkov's avatar Borislav Petkov

EDAC: Balance workqueue setup and teardown

We use the ->edac_check function pointers to determine whether we need
to setup a polling workqueue. However, the destroy path is not balanced
and we might try to teardown an unitialized workqueue.

Balance init and destroy paths by looking at ->edac_check in both cases.
Set op_state to OP_OFFLINE *before* destroying anything.
Reported-by: default avatarZhiqiang Hou <Zhiqiang.Hou@freescale.com>
Cc: Varun Sethi <Varun.Sethi@freescale.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
parent f5793c97
...@@ -583,8 +583,6 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) ...@@ -583,8 +583,6 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
*/ */
static void edac_mc_workq_teardown(struct mem_ctl_info *mci) static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{ {
mci->op_state = OP_OFFLINE;
edac_stop_work(&mci->work); edac_stop_work(&mci->work);
} }
...@@ -772,7 +770,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, ...@@ -772,7 +770,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
} }
/* If there IS a check routine, then we are running POLLED */ /* If there IS a check routine, then we are running POLLED */
if (mci->edac_check != NULL) { if (mci->edac_check) {
/* This instance is NOW RUNNING */ /* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL; mci->op_state = OP_RUNNING_POLL;
...@@ -823,15 +821,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) ...@@ -823,15 +821,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
return NULL; return NULL;
} }
/* mark MCI offline: */
mci->op_state = OP_OFFLINE;
if (!del_mc_from_global_list(mci)) if (!del_mc_from_global_list(mci))
edac_mc_owner = NULL; edac_mc_owner = NULL;
mutex_unlock(&mem_ctls_mutex);
/* flush workq processes */ mutex_unlock(&mem_ctls_mutex);
edac_mc_workq_teardown(mci);
/* marking MCI offline */ if (mci->edac_check)
mci->op_state = OP_OFFLINE; edac_mc_workq_teardown(mci);
/* remove from sysfs */ /* remove from sysfs */
edac_remove_sysfs_mci_device(mci); edac_remove_sysfs_mci_device(mci);
......
...@@ -241,8 +241,6 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) ...@@ -241,8 +241,6 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
{ {
edac_dbg(0, "\n"); edac_dbg(0, "\n");
pci->op_state = OP_OFFLINE;
edac_stop_work(&pci->work); edac_stop_work(&pci->work);
} }
...@@ -289,7 +287,7 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx) ...@@ -289,7 +287,7 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
goto fail1; goto fail1;
} }
if (pci->edac_check != NULL) { if (pci->edac_check) {
pci->op_state = OP_RUNNING_POLL; pci->op_state = OP_RUNNING_POLL;
edac_pci_workq_setup(pci, 1000); edac_pci_workq_setup(pci, 1000);
...@@ -350,8 +348,8 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev) ...@@ -350,8 +348,8 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
mutex_unlock(&edac_pci_ctls_mutex); mutex_unlock(&edac_pci_ctls_mutex);
/* stop the workq timer */ if (pci->edac_check)
edac_pci_workq_teardown(pci); edac_pci_workq_teardown(pci);
edac_printk(KERN_INFO, EDAC_PCI, edac_printk(KERN_INFO, EDAC_PCI,
"Removed device %d for %s %s: DEV %s\n", "Removed device %d for %s %s: DEV %s\n",
......
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