2
2
#include <linux/mm.h>
3
3
#include <linux/gfp.h>
4
4
#include <linux/kernel.h>
5
+ #include <linux/workqueue.h>
5
6
6
7
#include <asm/mce.h>
7
8
@@ -123,16 +124,12 @@ static u64 dfs_pfn;
123
124
/* Amount of errors after which we offline */
124
125
static unsigned int count_threshold = COUNT_MASK ;
125
126
126
- /*
127
- * The timer "decays" element count each timer_interval which is 24hrs by
128
- * default.
129
- */
130
-
131
- #define CEC_TIMER_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
132
- #define CEC_TIMER_MIN_INTERVAL 1 * 60 * 60 /* 1h */
133
- #define CEC_TIMER_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
134
- static struct timer_list cec_timer ;
135
- static u64 timer_interval = CEC_TIMER_DEFAULT_INTERVAL ;
127
+ /* Each element "decays" each decay_interval which is 24hrs by default. */
128
+ #define CEC_DECAY_DEFAULT_INTERVAL 24 * 60 * 60 /* 24 hrs */
129
+ #define CEC_DECAY_MIN_INTERVAL 1 * 60 * 60 /* 1h */
130
+ #define CEC_DECAY_MAX_INTERVAL 30 * 24 * 60 * 60 /* one month */
131
+ static struct delayed_work cec_work ;
132
+ static u64 decay_interval = CEC_DECAY_DEFAULT_INTERVAL ;
136
133
137
134
/*
138
135
* Decrement decay value. We're using DECAY_BITS bits to denote decay of an
@@ -160,20 +157,21 @@ static void do_spring_cleaning(struct ce_array *ca)
160
157
/*
161
158
* @interval in seconds
162
159
*/
163
- static void cec_mod_timer ( struct timer_list * t , unsigned long interval )
160
+ static void cec_mod_work ( unsigned long interval )
164
161
{
165
162
unsigned long iv ;
166
163
167
- iv = interval * HZ + jiffies ;
168
-
169
- mod_timer (t , round_jiffies (iv ));
164
+ iv = interval * HZ ;
165
+ mod_delayed_work (system_wq , & cec_work , round_jiffies (iv ));
170
166
}
171
167
172
- static void cec_timer_fn (struct timer_list * unused )
168
+ static void cec_work_fn (struct work_struct * work )
173
169
{
170
+ mutex_lock (& ce_mutex );
174
171
do_spring_cleaning (& ce_arr );
172
+ mutex_unlock (& ce_mutex );
175
173
176
- cec_mod_timer ( & cec_timer , timer_interval );
174
+ cec_mod_work ( decay_interval );
177
175
}
178
176
179
177
/*
@@ -183,32 +181,38 @@ static void cec_timer_fn(struct timer_list *unused)
183
181
*/
184
182
static int __find_elem (struct ce_array * ca , u64 pfn , unsigned int * to )
185
183
{
184
+ int min = 0 , max = ca -> n - 1 ;
186
185
u64 this_pfn ;
187
- int min = 0 , max = ca -> n ;
188
186
189
- while (min < max ) {
190
- int tmp = (max + min ) >> 1 ;
187
+ while (min <= max ) {
188
+ int i = (min + max ) >> 1 ;
191
189
192
- this_pfn = PFN (ca -> array [tmp ]);
190
+ this_pfn = PFN (ca -> array [i ]);
193
191
194
192
if (this_pfn < pfn )
195
- min = tmp + 1 ;
193
+ min = i + 1 ;
196
194
else if (this_pfn > pfn )
197
- max = tmp ;
198
- else {
199
- min = tmp ;
200
- break ;
195
+ max = i - 1 ;
196
+ else if (this_pfn == pfn ) {
197
+ if (to )
198
+ * to = i ;
199
+
200
+ return i ;
201
201
}
202
202
}
203
203
204
+ /*
205
+ * When the loop terminates without finding @pfn, min has the index of
206
+ * the element slot where the new @pfn should be inserted. The loop
207
+ * terminates when min > max, which means the min index points to the
208
+ * bigger element while the max index to the smaller element, in-between
209
+ * which the new @pfn belongs to.
210
+ *
211
+ * For more details, see exercise 1, Section 6.2.1 in TAOCP, vol. 3.
212
+ */
204
213
if (to )
205
214
* to = min ;
206
215
207
- this_pfn = PFN (ca -> array [min ]);
208
-
209
- if (this_pfn == pfn )
210
- return min ;
211
-
212
216
return - ENOKEY ;
213
217
}
214
218
@@ -374,15 +378,15 @@ static int decay_interval_set(void *data, u64 val)
374
378
{
375
379
* (u64 * )data = val ;
376
380
377
- if (val < CEC_TIMER_MIN_INTERVAL )
381
+ if (val < CEC_DECAY_MIN_INTERVAL )
378
382
return - EINVAL ;
379
383
380
- if (val > CEC_TIMER_MAX_INTERVAL )
384
+ if (val > CEC_DECAY_MAX_INTERVAL )
381
385
return - EINVAL ;
382
386
383
- timer_interval = val ;
387
+ decay_interval = val ;
384
388
385
- cec_mod_timer ( & cec_timer , timer_interval );
389
+ cec_mod_work ( decay_interval );
386
390
return 0 ;
387
391
}
388
392
DEFINE_DEBUGFS_ATTRIBUTE (decay_interval_ops , u64_get , decay_interval_set , "%lld\n" );
@@ -426,7 +430,7 @@ static int array_dump(struct seq_file *m, void *v)
426
430
427
431
seq_printf (m , "Flags: 0x%x\n" , ca -> flags );
428
432
429
- seq_printf (m , "Timer interval: %lld seconds\n" , timer_interval );
433
+ seq_printf (m , "Decay interval: %lld seconds\n" , decay_interval );
430
434
seq_printf (m , "Decays: %lld\n" , ca -> decays_done );
431
435
432
436
seq_printf (m , "Action threshold: %d\n" , count_threshold );
@@ -472,7 +476,7 @@ static int __init create_debugfs_nodes(void)
472
476
}
473
477
474
478
decay = debugfs_create_file ("decay_interval" , S_IRUSR | S_IWUSR , d ,
475
- & timer_interval , & decay_interval_ops );
479
+ & decay_interval , & decay_interval_ops );
476
480
if (!decay ) {
477
481
pr_warn ("Error creating decay_interval debugfs node!\n" );
478
482
goto err ;
@@ -508,8 +512,8 @@ void __init cec_init(void)
508
512
if (create_debugfs_nodes ())
509
513
return ;
510
514
511
- timer_setup ( & cec_timer , cec_timer_fn , 0 );
512
- cec_mod_timer ( & cec_timer , CEC_TIMER_DEFAULT_INTERVAL );
515
+ INIT_DELAYED_WORK ( & cec_work , cec_work_fn );
516
+ schedule_delayed_work ( & cec_work , CEC_DECAY_DEFAULT_INTERVAL );
513
517
514
518
pr_info ("Correctable Errors collector initialized.\n" );
515
519
}
0 commit comments