Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull RAS fixes from Thomas Gleixner:
"Two small fixes for RAS:

- Use a proper search algorithm to find the correct element in the
CEC array. The replacement was a better choice than fixing the
crash causes by the original search function with horrible duct
tape.

- Move the timer based decay function into thread context so it can
actually acquire the mutex which protects the CEC array to prevent
corruption"

* 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
RAS/CEC: Convert the timer callback to a workqueue
RAS/CEC: Fix binary search function

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