diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-14 14:05:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-14 14:05:41 -0500 |
| commit | 3bd354abe17f2c8aa426ef84b78f14e505f0a920 (patch) | |
| tree | bdaed9ba35a7b6fdce76ae4086309b644f1afd37 /drivers | |
| parent | cbc252566c09ad4ab14a40813d4feac4228571cb (diff) | |
| parent | cb6ef42e516cb8948f15e4b70dc03af8020050a2 (diff) | |
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 79040cad3f82 ("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
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/edac/edac_mc.c | 13 | ||||
| -rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 10 | ||||
| -rw-r--r-- | drivers/edac/edac_module.h | 2 |
3 files changed, 15 insertions, 10 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index e8c9ef03495b..33edd6766344 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
| @@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req) | |||
| 559 | * | 559 | * |
| 560 | * called with the mem_ctls_mutex held | 560 | * called with the mem_ctls_mutex held |
| 561 | */ | 561 | */ |
| 562 | static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) | 562 | static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, |
| 563 | bool init) | ||
| 563 | { | 564 | { |
| 564 | edac_dbg(0, "\n"); | 565 | edac_dbg(0, "\n"); |
| 565 | 566 | ||
| @@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) | |||
| 567 | if (mci->op_state != OP_RUNNING_POLL) | 568 | if (mci->op_state != OP_RUNNING_POLL) |
| 568 | return; | 569 | return; |
| 569 | 570 | ||
| 570 | INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); | 571 | if (init) |
| 572 | INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); | ||
| 573 | |||
| 571 | mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); | 574 | mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); |
| 572 | } | 575 | } |
| 573 | 576 | ||
| @@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) | |||
| 601 | * user space has updated our poll period value, need to | 604 | * user space has updated our poll period value, need to |
| 602 | * reset our workq delays | 605 | * reset our workq delays |
| 603 | */ | 606 | */ |
| 604 | void edac_mc_reset_delay_period(int value) | 607 | void edac_mc_reset_delay_period(unsigned long value) |
| 605 | { | 608 | { |
| 606 | struct mem_ctl_info *mci; | 609 | struct mem_ctl_info *mci; |
| 607 | struct list_head *item; | 610 | struct list_head *item; |
| @@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value) | |||
| 611 | list_for_each(item, &mc_devices) { | 614 | list_for_each(item, &mc_devices) { |
| 612 | mci = list_entry(item, struct mem_ctl_info, link); | 615 | mci = list_entry(item, struct mem_ctl_info, link); |
| 613 | 616 | ||
| 614 | edac_mc_workq_setup(mci, (unsigned long) value); | 617 | edac_mc_workq_setup(mci, value, false); |
| 615 | } | 618 | } |
| 616 | 619 | ||
| 617 | mutex_unlock(&mem_ctls_mutex); | 620 | mutex_unlock(&mem_ctls_mutex); |
| @@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) | |||
| 782 | /* This instance is NOW RUNNING */ | 785 | /* This instance is NOW RUNNING */ |
| 783 | mci->op_state = OP_RUNNING_POLL; | 786 | mci->op_state = OP_RUNNING_POLL; |
| 784 | 787 | ||
| 785 | edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); | 788 | edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true); |
| 786 | } else { | 789 | } else { |
| 787 | mci->op_state = OP_RUNNING_INTERRUPT; | 790 | mci->op_state = OP_RUNNING_INTERRUPT; |
| 788 | } | 791 | } |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 8ec1747b1c39..b335c6ab5efe 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
| @@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void) | |||
| 52 | 52 | ||
| 53 | static int edac_set_poll_msec(const char *val, struct kernel_param *kp) | 53 | static int edac_set_poll_msec(const char *val, struct kernel_param *kp) |
| 54 | { | 54 | { |
| 55 | long l; | 55 | unsigned long l; |
| 56 | int ret; | 56 | int ret; |
| 57 | 57 | ||
| 58 | if (!val) | 58 | if (!val) |
| 59 | return -EINVAL; | 59 | return -EINVAL; |
| 60 | 60 | ||
| 61 | ret = kstrtol(val, 0, &l); | 61 | ret = kstrtoul(val, 0, &l); |
| 62 | if (ret) | 62 | if (ret) |
| 63 | return ret; | 63 | return ret; |
| 64 | if (!l || ((int)l != l)) | 64 | |
| 65 | if (l < 1000) | ||
| 65 | return -EINVAL; | 66 | return -EINVAL; |
| 66 | *((int *)kp->arg) = l; | 67 | |
| 68 | *((unsigned long *)kp->arg) = l; | ||
| 67 | 69 | ||
| 68 | /* notify edac_mc engine to reset the poll period */ | 70 | /* notify edac_mc engine to reset the poll period */ |
| 69 | edac_mc_reset_delay_period(l); | 71 | edac_mc_reset_delay_period(l); |
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 3d139c6e7fe3..f2118bfcf8df 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
| @@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | |||
| 52 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); | 52 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); |
| 53 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info | 53 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info |
| 54 | *edac_dev, unsigned long value); | 54 | *edac_dev, unsigned long value); |
| 55 | extern void edac_mc_reset_delay_period(int value); | 55 | extern void edac_mc_reset_delay_period(unsigned long value); |
| 56 | 56 | ||
| 57 | extern void *edac_align_ptr(void **p, unsigned size, int n_elems); | 57 | extern void *edac_align_ptr(void **p, unsigned size, int n_elems); |
| 58 | 58 | ||
