Commit 3bd354ab authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

Pull EDAC fixes from Borislav Petkov:
 "Fix polling timeout setting through sysfs.

  You're surely wondering why the patches are not based on an rc.  Well,
  Andrew sent you 79040cad ("drivers/edac/edac_mc_sysfs.c: poll
  timeout cannot be zero sent you") already (it got in in -rc2) but it
  is not enough as a fix because for one, setting too low polling
  intervals (< 1sec) don't make any sense and cause unnecessary polling
  load on the system.

  Then, even if we set some interval, we explode with

    [ 4143.094342] WARNING: CPU: 1 PID: 0 at kernel/workqueue.c:1393 __queue_work+0x1d7/0x340()

  because the workqueue setup path is used also for the timeout period
  resetting and we're doing INIT_DELAYED_WORK() on an already active
  workqueue.  Which is total bollocks.  So this is taken care of by the
  second patch.

  I've CCed stable for those two"

* tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  EDAC: Correct workqueue setup path
  EDAC: Poll timeout cannot be zero, p2
parents cbc25256 cb6ef42e
...@@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req) ...@@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req)
* *
* called with the mem_ctls_mutex held * called with the mem_ctls_mutex held
*/ */
static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
bool init)
{ {
edac_dbg(0, "\n"); edac_dbg(0, "\n");
...@@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) ...@@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
if (mci->op_state != OP_RUNNING_POLL) if (mci->op_state != OP_RUNNING_POLL)
return; return;
INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); if (init)
INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
} }
...@@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) ...@@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
* user space has updated our poll period value, need to * user space has updated our poll period value, need to
* reset our workq delays * reset our workq delays
*/ */
void edac_mc_reset_delay_period(int value) void edac_mc_reset_delay_period(unsigned long value)
{ {
struct mem_ctl_info *mci; struct mem_ctl_info *mci;
struct list_head *item; struct list_head *item;
...@@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value) ...@@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value)
list_for_each(item, &mc_devices) { list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link); mci = list_entry(item, struct mem_ctl_info, link);
edac_mc_workq_setup(mci, (unsigned long) value); edac_mc_workq_setup(mci, value, false);
} }
mutex_unlock(&mem_ctls_mutex); mutex_unlock(&mem_ctls_mutex);
...@@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) ...@@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
/* This instance is NOW RUNNING */ /* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL; mci->op_state = OP_RUNNING_POLL;
edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
} else { } else {
mci->op_state = OP_RUNNING_INTERRUPT; mci->op_state = OP_RUNNING_INTERRUPT;
} }
......
...@@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void) ...@@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void)
static int edac_set_poll_msec(const char *val, struct kernel_param *kp) static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
{ {
long l; unsigned long l;
int ret; int ret;
if (!val) if (!val)
return -EINVAL; return -EINVAL;
ret = kstrtol(val, 0, &l); ret = kstrtoul(val, 0, &l);
if (ret) if (ret)
return ret; return ret;
if (!l || ((int)l != l))
if (l < 1000)
return -EINVAL; return -EINVAL;
*((int *)kp->arg) = l;
*((unsigned long *)kp->arg) = l;
/* notify edac_mc engine to reset the poll period */ /* notify edac_mc engine to reset the poll period */
edac_mc_reset_delay_period(l); edac_mc_reset_delay_period(l);
......
...@@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, ...@@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
extern void edac_device_reset_delay_period(struct edac_device_ctl_info extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value); *edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(int value); extern void edac_mc_reset_delay_period(unsigned long value);
extern void *edac_align_ptr(void **p, unsigned size, int n_elems); extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
......
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