]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
EDAC: Balance workqueue setup and teardown
authorBorislav Petkov <bp@suse.de>
Tue, 2 Feb 2016 09:59:53 +0000 (10:59 +0100)
committerBorislav Petkov <bp@suse.de>
Tue, 2 Feb 2016 10:04:29 +0000 (11:04 +0100)
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: Zhiqiang Hou <Zhiqiang.Hou@freescale.com>
Cc: Varun Sethi <Varun.Sethi@freescale.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/edac_mc.c
drivers/edac/edac_pci.c

index 8adfc167c2e38e7de64c0a08224a803ad737ae7a..50802c154915951309474d921eee83e7d74261f9 100644 (file)
@@ -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)
 {
-       mci->op_state = OP_OFFLINE;
-
        edac_stop_work(&mci->work);
 }
 
@@ -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 (mci->edac_check != NULL) {
+       if (mci->edac_check) {
                /* This instance is NOW RUNNING */
                mci->op_state = OP_RUNNING_POLL;
 
@@ -823,15 +821,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
                return NULL;
        }
 
+       /* mark MCI offline: */
+       mci->op_state = OP_OFFLINE;
+
        if (!del_mc_from_global_list(mci))
                edac_mc_owner = NULL;
-       mutex_unlock(&mem_ctls_mutex);
 
-       /* flush workq processes */
-       edac_mc_workq_teardown(mci);
+       mutex_unlock(&mem_ctls_mutex);
 
-       /* marking MCI offline */
-       mci->op_state = OP_OFFLINE;
+       if (mci->edac_check)
+               edac_mc_workq_teardown(mci);
 
        /* remove from sysfs */
        edac_remove_sysfs_mci_device(mci);
index 99685388d3fb5a1a8c6f52f5fbb675a61fa4a065..f0e8c3d01ed51435725b218a34a27d5e8502ca18 100644 (file)
@@ -241,8 +241,6 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 {
        edac_dbg(0, "\n");
 
-       pci->op_state = OP_OFFLINE;
-
        edac_stop_work(&pci->work);
 }
 
@@ -289,7 +287,7 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
                goto fail1;
        }
 
-       if (pci->edac_check != NULL) {
+       if (pci->edac_check) {
                pci->op_state = OP_RUNNING_POLL;
 
                edac_pci_workq_setup(pci, 1000);
@@ -350,8 +348,8 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
 
        mutex_unlock(&edac_pci_ctls_mutex);
 
-       /* stop the workq timer */
-       edac_pci_workq_teardown(pci);
+       if (pci->edac_check)
+               edac_pci_workq_teardown(pci);
 
        edac_printk(KERN_INFO, EDAC_PCI,
                "Removed device %d for %s %s: DEV %s\n",