1 From 0ade0b6240c4853cf9725924c46c10f4251639d7 Mon Sep 17 00:00:00 2001
2 From: Cong Wang <xiyou.wangcong@gmail.com>
3 Date: Tue, 16 Apr 2019 14:33:51 -0700
4 Subject: RAS/CEC: Convert the timer callback to a workqueue
6 From: Cong Wang <xiyou.wangcong@gmail.com>
8 commit 0ade0b6240c4853cf9725924c46c10f4251639d7 upstream.
10 cec_timer_fn() is a timer callback which reads ce_arr.array[] and
11 updates its decay values. However, it runs in interrupt context and the
12 mutex protection the CEC uses for that array, is inadequate. Convert the
13 used timer to a workqueue to keep the tasks the CEC performs preemptible
16 [ bp: Rewrite commit message.
17 s/timer/decay/gi to make it agnostic as to what facility is used. ]
19 Fixes: 011d82611172 ("RAS: Add a Corrected Errors Collector")
20 Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
21 Signed-off-by: Borislav Petkov <bp@suse.de>
22 Cc: Thomas Gleixner <tglx@linutronix.de>
23 Cc: Tony Luck <tony.luck@intel.com>
24 Cc: linux-edac <linux-edac@vger.kernel.org>
25 Cc: <stable@vger.kernel.org>
26 Link: https://lkml.kernel.org/r/20190416213351.28999-2-xiyou.wangcong@gmail.com
27 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30 drivers/ras/cec.c | 46 ++++++++++++++++++++++------------------------
31 1 file changed, 22 insertions(+), 24 deletions(-)
33 --- a/drivers/ras/cec.c
34 +++ b/drivers/ras/cec.c
37 #include <linux/gfp.h>
38 #include <linux/kernel.h>
39 +#include <linux/workqueue.h>
43 @@ -123,16 +124,12 @@ static u64 dfs_pfn;
44 /* Amount of errors after which we offline */
45 static unsigned int count_threshold = COUNT_MASK;
48 - * The timer "decays" element count each timer_interval which is 24hrs by
52 -#define CEC_TIMER_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
53 -#define CEC_TIMER_MIN_INTERVAL 1 * 60 * 60 /* 1h */
54 -#define CEC_TIMER_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
55 -static struct timer_list cec_timer;
56 -static u64 timer_interval = CEC_TIMER_DEFAULT_INTERVAL;
57 +/* Each element "decays" each decay_interval which is 24hrs by default. */
58 +#define CEC_DECAY_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
59 +#define CEC_DECAY_MIN_INTERVAL 1 * 60 * 60 /* 1h */
60 +#define CEC_DECAY_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
61 +static struct delayed_work cec_work;
62 +static u64 decay_interval = CEC_DECAY_DEFAULT_INTERVAL;
65 * Decrement decay value. We're using DECAY_BITS bits to denote decay of an
66 @@ -160,20 +157,21 @@ static void do_spring_cleaning(struct ce
68 * @interval in seconds
70 -static void cec_mod_timer(struct timer_list *t, unsigned long interval)
71 +static void cec_mod_work(unsigned long interval)
75 - iv = interval * HZ + jiffies;
77 - mod_timer(t, round_jiffies(iv));
79 + mod_delayed_work(system_wq, &cec_work, round_jiffies(iv));
82 -static void cec_timer_fn(struct timer_list *unused)
83 +static void cec_work_fn(struct work_struct *work)
85 + mutex_lock(&ce_mutex);
86 do_spring_cleaning(&ce_arr);
87 + mutex_unlock(&ce_mutex);
89 - cec_mod_timer(&cec_timer, timer_interval);
90 + cec_mod_work(decay_interval);
94 @@ -374,15 +372,15 @@ static int decay_interval_set(void *data
98 - if (val < CEC_TIMER_MIN_INTERVAL)
99 + if (val < CEC_DECAY_MIN_INTERVAL)
102 - if (val > CEC_TIMER_MAX_INTERVAL)
103 + if (val > CEC_DECAY_MAX_INTERVAL)
106 - timer_interval = val;
107 + decay_interval = val;
109 - cec_mod_timer(&cec_timer, timer_interval);
110 + cec_mod_work(decay_interval);
113 DEFINE_DEBUGFS_ATTRIBUTE(decay_interval_ops, u64_get, decay_interval_set, "%lld\n");
114 @@ -426,7 +424,7 @@ static int array_dump(struct seq_file *m
116 seq_printf(m, "Flags: 0x%x\n", ca->flags);
118 - seq_printf(m, "Timer interval: %lld seconds\n", timer_interval);
119 + seq_printf(m, "Decay interval: %lld seconds\n", decay_interval);
120 seq_printf(m, "Decays: %lld\n", ca->decays_done);
122 seq_printf(m, "Action threshold: %d\n", count_threshold);
123 @@ -472,7 +470,7 @@ static int __init create_debugfs_nodes(v
126 decay = debugfs_create_file("decay_interval", S_IRUSR | S_IWUSR, d,
127 - &timer_interval, &decay_interval_ops);
128 + &decay_interval, &decay_interval_ops);
130 pr_warn("Error creating decay_interval debugfs node!\n");
132 @@ -508,8 +506,8 @@ void __init cec_init(void)
133 if (create_debugfs_nodes())
136 - timer_setup(&cec_timer, cec_timer_fn, 0);
137 - cec_mod_timer(&cec_timer, CEC_TIMER_DEFAULT_INTERVAL);
138 + INIT_DELAYED_WORK(&cec_work, cec_work_fn);
139 + schedule_delayed_work(&cec_work, CEC_DECAY_DEFAULT_INTERVAL);
141 pr_info("Correctable Errors collector initialized.\n");