From 096676061987c613bdacddbae838cb63a815db94 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 2 Feb 2016 10:59:53 +0100 Subject: [PATCH] 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: Zhiqiang Hou Cc: Varun Sethi Signed-off-by: Borislav Petkov --- drivers/edac/edac_mc.c | 15 +++++++-------- drivers/edac/edac_pci.c | 8 +++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 8adfc167c2e3..50802c154915 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -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); - - /* 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); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 99685388d3fb..f0e8c3d01ed5 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -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",