EDAC: Rework workqueue handling
authorBorislav Petkov <bp@suse.de>
Mon, 30 Nov 2015 18:02:01 +0000 (19:02 +0100)
committerBorislav Petkov <bp@suse.de>
Fri, 11 Dec 2015 15:56:43 +0000 (16:56 +0100)
Hide the EDAC workqueue pointer in a separate compilation unit and add
accessors for the workqueue manipulations needed.

Remove edac_pci_reset_delay_period() which wasn't used by anything. It
seems it got added without a user with

  91b99041c1d5 ("drivers/edac: updated PCI monitoring")

Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/Makefile
drivers/edac/edac_device.c
drivers/edac/edac_mc.c
drivers/edac/edac_module.c
drivers/edac/edac_module.h
drivers/edac/edac_pci.c
drivers/edac/wq.c [new file with mode: 0644]

index dbf53e0..be163e2 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC)                    := edac_stub.o
 obj-$(CONFIG_EDAC_MM_EDAC)             += edac_core.o
 
 edac_core-y    := edac_mc.o edac_device.o edac_mc_sysfs.o
-edac_core-y    += edac_module.o edac_device_sysfs.o
+edac_core-y    += edac_module.o edac_device_sysfs.o wq.o
 
 edac_core-$(CONFIG_EDAC_DEBUG)         += debugfs.o
 
index 455a64b..a979003 100644 (file)
@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req)
         * between integral seconds
         */
        if (edac_dev->poll_msec == 1000)
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies_relative(edac_dev->delay));
+               edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               edac_dev->delay);
+               edac_queue_work(&edac_dev->work, edac_dev->delay);
 }
 
 /*
@@ -422,11 +420,9 @@ static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
         * to fire together on the 1 second exactly
         */
        if (edac_dev->poll_msec == 1000)
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               round_jiffies_relative(edac_dev->delay));
+               edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
-               queue_delayed_work(edac_workqueue, &edac_dev->work,
-                               edac_dev->delay);
+               edac_queue_work(&edac_dev->work, edac_dev->delay);
 }
 
 /*
@@ -440,8 +436,7 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
 
        edac_dev->op_state = OP_OFFLINE;
 
-       cancel_delayed_work_sync(&edac_dev->work);
-       flush_workqueue(edac_workqueue);
+       edac_stop_work(&edac_dev->work);
 }
 
 /*
@@ -454,16 +449,15 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
 void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
                                        unsigned long value)
 {
-       /* cancel the current workq request, without the mutex lock */
-       edac_device_workq_teardown(edac_dev);
+       unsigned long jiffs = msecs_to_jiffies(value);
 
-       /* acquire the mutex before doing the workq setup */
-       mutex_lock(&device_ctls_mutex);
+       if (value == 1000)
+               jiffs = round_jiffies_relative(value);
 
-       /* restart the workq request, with new delay value */
-       edac_device_workq_setup(edac_dev, value);
+       edac_dev->poll_msec = value;
+       edac_dev->delay     = jiffs;
 
-       mutex_unlock(&device_ctls_mutex);
+       edac_mod_work(&edac_dev->work, jiffs);
 }
 
 /*
index 1b2c218..8adfc16 100644 (file)
@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
        mutex_unlock(&mem_ctls_mutex);
 
        /* Reschedule */
-       queue_delayed_work(edac_workqueue, &mci->work,
-                       msecs_to_jiffies(edac_mc_get_poll_msec()));
+       edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
 }
 
 /*
@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
  *
  *             called with the mem_ctls_mutex held
  */
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
-                               bool init)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
 {
        edac_dbg(0, "\n");
 
@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
        if (mci->op_state != OP_RUNNING_POLL)
                return;
 
-       if (init)
-               INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+       INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
 
-       mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+       edac_queue_work(&mci->work, msecs_to_jiffies(msec));
 }
 
 /*
@@ -588,8 +585,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 {
        mci->op_state = OP_OFFLINE;
 
-       cancel_delayed_work_sync(&mci->work);
-       flush_workqueue(edac_workqueue);
+       edac_stop_work(&mci->work);
 }
 
 /*
@@ -608,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value)
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
-               edac_mc_workq_setup(mci, value, false);
+               edac_mod_work(&mci->work, value);
        }
-
        mutex_unlock(&mem_ctls_mutex);
 }
 
@@ -781,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
                /* This instance is NOW RUNNING */
                mci->op_state = OP_RUNNING_POLL;
 
-               edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
+               edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
        } else {
                mci->op_state = OP_RUNNING_INTERRUPT;
        }
index 2b53680..5f8543b 100644 (file)
@@ -43,9 +43,6 @@ module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
 MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
 #endif
 
-/* scope is to module level only */
-struct workqueue_struct *edac_workqueue;
-
 /*
  * edac_op_state_to_string()
  */
@@ -66,32 +63,6 @@ char *edac_op_state_to_string(int opstate)
 }
 
 /*
- * edac_workqueue_setup
- *     initialize the edac work queue for polling operations
- */
-static int edac_workqueue_setup(void)
-{
-       edac_workqueue = create_singlethread_workqueue("edac-poller");
-       if (edac_workqueue == NULL)
-               return -ENODEV;
-       else
-               return 0;
-}
-
-/*
- * edac_workqueue_teardown
- *     teardown the edac workqueue
- */
-static void edac_workqueue_teardown(void)
-{
-       if (edac_workqueue) {
-               flush_workqueue(edac_workqueue);
-               destroy_workqueue(edac_workqueue);
-               edac_workqueue = NULL;
-       }
-}
-
-/*
  * sysfs object: /sys/devices/system/edac
  *     need to export to other files
  */
index 7388abf..cfaacb9 100644 (file)
@@ -47,7 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
 
 /* edac core workqueue: single CPU mode */
-extern struct workqueue_struct *edac_workqueue;
+int edac_workqueue_setup(void);
+void edac_workqueue_teardown(void);
+bool edac_queue_work(struct delayed_work *work, unsigned long delay);
+bool edac_stop_work(struct delayed_work *work);
+bool edac_mod_work(struct delayed_work *work, unsigned long delay);
+
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
                                           *edac_dev, unsigned long value);
 extern void edac_mc_reset_delay_period(unsigned long value);
index d8b0831..9968538 100644 (file)
@@ -209,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
                        delay = msecs_to_jiffies(msec);
 
                /* Reschedule only if we are in POLL mode */
-               queue_delayed_work(edac_workqueue, &pci->work, delay);
+               edac_queue_work(&pci->work, delay);
        }
 
        mutex_unlock(&edac_pci_ctls_mutex);
@@ -229,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
        edac_dbg(0, "\n");
 
        INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
-       queue_delayed_work(edac_workqueue, &pci->work,
-                       msecs_to_jiffies(edac_pci_get_poll_msec()));
+
+       edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
 }
 
 /*
@@ -243,32 +243,8 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 
        pci->op_state = OP_OFFLINE;
 
-       cancel_delayed_work_sync(&pci->work);
-       flush_workqueue(edac_workqueue);
-}
-
-/*
- * edac_pci_reset_delay_period
- *
- *     called with a new period value for the workq period
- *     a) stop current workq timer
- *     b) restart workq timer with new value
- */
-void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
-                                unsigned long value)
-{
-       edac_dbg(0, "\n");
-
-       edac_pci_workq_teardown(pci);
-
-       /* need to lock for the setup */
-       mutex_lock(&edac_pci_ctls_mutex);
-
-       edac_pci_workq_setup(pci, value);
-
-       mutex_unlock(&edac_pci_ctls_mutex);
+       edac_stop_work(&pci->work);
 }
-EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
 
 /*
  * edac_pci_alloc_index: Allocate a unique PCI index number
diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c
new file mode 100644 (file)
index 0000000..1b8c07e
--- /dev/null
@@ -0,0 +1,42 @@
+#include "edac_module.h"
+
+static struct workqueue_struct *wq;
+
+bool edac_queue_work(struct delayed_work *work, unsigned long delay)
+{
+       return queue_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_queue_work);
+
+bool edac_mod_work(struct delayed_work *work, unsigned long delay)
+{
+       return mod_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_mod_work);
+
+bool edac_stop_work(struct delayed_work *work)
+{
+       bool ret;
+
+       ret = cancel_delayed_work_sync(work);
+       flush_workqueue(wq);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(edac_stop_work);
+
+int edac_workqueue_setup(void)
+{
+       wq = create_singlethread_workqueue("edac-poller");
+       if (!wq)
+               return -ENODEV;
+       else
+               return 0;
+}
+
+void edac_workqueue_teardown(void)
+{
+       flush_workqueue(wq);
+       destroy_workqueue(wq);
+       wq = NULL;
+}