aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasamitsu Yamazaki <m-yamazaki@ah.jp.nec.com>2017-11-15 02:33:14 -0500
committerCorey Minyard <cminyard@mvista.com>2017-12-06 08:13:03 -0500
commit4f7f5551a760eb0124267be65763008169db7087 (patch)
tree796491ffe7b284654a9052a782bd66b340dc7d5c
parent6363b3f3ac5be096d08c8c504128befa0c033529 (diff)
ipmi: Stop timers before cleaning up the module
System may crash after unloading ipmi_si.ko module because a timer may remain and fire after the module cleaned up resources. cleanup_one_si() contains the following processing. /* * Make sure that interrupts, the timer and the thread are * stopped and will not run again. */ if (to_clean->irq_cleanup) to_clean->irq_cleanup(to_clean); wait_for_timer_and_thread(to_clean); /* * Timeouts are stopped, now make sure the interrupts are off * in the BMC. Note that timers and CPU interrupts are off, * so no need for locks. */ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); } si_state changes as following in the while loop calling poll(to_clean). SI_GETTING_MESSAGES => SI_CHECKING_ENABLES => SI_SETTING_ENABLES => SI_GETTING_EVENTS => SI_NORMAL As written in the code comments above, timers are expected to stop before the polling loop and not to run again. But the timer is set again in the following process when si_state becomes SI_SETTING_ENABLES. => poll => smi_event_handler => handle_transaction_done // smi_info->si_state == SI_SETTING_ENABLES => start_getting_events => start_new_msg => smi_mod_timer => mod_timer As a result, before the timer set in start_new_msg() expires, the polling loop may see si_state becoming SI_NORMAL and the module clean-up finishes. For example, hard LOCKUP and panic occurred as following. smi_timeout was called after smi_event_handler, kcs_event and hangs at port_inb() trying to access I/O port after release. [exception RIP: port_inb+19] RIP: ffffffffc0473053 RSP: ffff88069fdc3d80 RFLAGS: 00000006 RAX: ffff8806800f8e00 RBX: ffff880682bd9400 RCX: 0000000000000000 RDX: 0000000000000ca3 RSI: 0000000000000ca3 RDI: ffff8806800f8e40 RBP: ffff88069fdc3d80 R8: ffffffff81d86dfc R9: ffffffff81e36426 R10: 00000000000509f0 R11: 0000000000100000 R12: 0000000000]:000000 R13: 0000000000000000 R14: 0000000000000246 R15: ffff8806800f8e00 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0000 --- <NMI exception stack> --- To fix the problem I defined a flag, timer_can_start, as member of struct smi_info. The flag is enabled immediately after initializing the timer and disabled immediately before waiting for timer deletion. Fixes: 0cfec916e86d ("ipmi: Start the timer and thread on internal msgs") Signed-off-by: Yamazaki Masamitsu <m-yamazaki@ah.jp.nec.com> [Adjusted for recent changes in the driver.] Signed-off-by: Corey Minyard <cminyard@mvista.com>
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 71d33a1807e4..99b0513bb55b 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -199,6 +199,9 @@ struct smi_info {
199 /* The timer for this si. */ 199 /* The timer for this si. */
200 struct timer_list si_timer; 200 struct timer_list si_timer;
201 201
202 /* This flag is set, if the timer can be set */
203 bool timer_can_start;
204
202 /* This flag is set, if the timer is running (timer_pending() isn't enough) */ 205 /* This flag is set, if the timer is running (timer_pending() isn't enough) */
203 bool timer_running; 206 bool timer_running;
204 207
@@ -355,6 +358,8 @@ out:
355 358
356static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) 359static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
357{ 360{
361 if (!smi_info->timer_can_start)
362 return;
358 smi_info->last_timeout_jiffies = jiffies; 363 smi_info->last_timeout_jiffies = jiffies;
359 mod_timer(&smi_info->si_timer, new_val); 364 mod_timer(&smi_info->si_timer, new_val);
360 smi_info->timer_running = true; 365 smi_info->timer_running = true;
@@ -374,21 +379,18 @@ static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
374 smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); 379 smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
375} 380}
376 381
377static void start_check_enables(struct smi_info *smi_info, bool start_timer) 382static void start_check_enables(struct smi_info *smi_info)
378{ 383{
379 unsigned char msg[2]; 384 unsigned char msg[2];
380 385
381 msg[0] = (IPMI_NETFN_APP_REQUEST << 2); 386 msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
382 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; 387 msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
383 388
384 if (start_timer) 389 start_new_msg(smi_info, msg, 2);
385 start_new_msg(smi_info, msg, 2);
386 else
387 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
388 smi_info->si_state = SI_CHECKING_ENABLES; 390 smi_info->si_state = SI_CHECKING_ENABLES;
389} 391}
390 392
391static void start_clear_flags(struct smi_info *smi_info, bool start_timer) 393static void start_clear_flags(struct smi_info *smi_info)
392{ 394{
393 unsigned char msg[3]; 395 unsigned char msg[3];
394 396
@@ -397,10 +399,7 @@ static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
397 msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; 399 msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
398 msg[2] = WDT_PRE_TIMEOUT_INT; 400 msg[2] = WDT_PRE_TIMEOUT_INT;
399 401
400 if (start_timer) 402 start_new_msg(smi_info, msg, 3);
401 start_new_msg(smi_info, msg, 3);
402 else
403 smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
404 smi_info->si_state = SI_CLEARING_FLAGS; 403 smi_info->si_state = SI_CLEARING_FLAGS;
405} 404}
406 405
@@ -435,11 +434,11 @@ static void start_getting_events(struct smi_info *smi_info)
435 * Note that we cannot just use disable_irq(), since the interrupt may 434 * Note that we cannot just use disable_irq(), since the interrupt may
436 * be shared. 435 * be shared.
437 */ 436 */
438static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) 437static inline bool disable_si_irq(struct smi_info *smi_info)
439{ 438{
440 if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) { 439 if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
441 smi_info->interrupt_disabled = true; 440 smi_info->interrupt_disabled = true;
442 start_check_enables(smi_info, start_timer); 441 start_check_enables(smi_info);
443 return true; 442 return true;
444 } 443 }
445 return false; 444 return false;
@@ -449,7 +448,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
449{ 448{
450 if ((smi_info->io.irq) && (smi_info->interrupt_disabled)) { 449 if ((smi_info->io.irq) && (smi_info->interrupt_disabled)) {
451 smi_info->interrupt_disabled = false; 450 smi_info->interrupt_disabled = false;
452 start_check_enables(smi_info, true); 451 start_check_enables(smi_info);
453 return true; 452 return true;
454 } 453 }
455 return false; 454 return false;
@@ -467,7 +466,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
467 466
468 msg = ipmi_alloc_smi_msg(); 467 msg = ipmi_alloc_smi_msg();
469 if (!msg) { 468 if (!msg) {
470 if (!disable_si_irq(smi_info, true)) 469 if (!disable_si_irq(smi_info))
471 smi_info->si_state = SI_NORMAL; 470 smi_info->si_state = SI_NORMAL;
472 } else if (enable_si_irq(smi_info)) { 471 } else if (enable_si_irq(smi_info)) {
473 ipmi_free_smi_msg(msg); 472 ipmi_free_smi_msg(msg);
@@ -483,7 +482,7 @@ retry:
483 /* Watchdog pre-timeout */ 482 /* Watchdog pre-timeout */
484 smi_inc_stat(smi_info, watchdog_pretimeouts); 483 smi_inc_stat(smi_info, watchdog_pretimeouts);
485 484
486 start_clear_flags(smi_info, true); 485 start_clear_flags(smi_info);
487 smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; 486 smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
488 if (smi_info->intf) 487 if (smi_info->intf)
489 ipmi_smi_watchdog_pretimeout(smi_info->intf); 488 ipmi_smi_watchdog_pretimeout(smi_info->intf);
@@ -866,7 +865,7 @@ restart:
866 * disable and messages disabled. 865 * disable and messages disabled.
867 */ 866 */
868 if (smi_info->supports_event_msg_buff || smi_info->io.irq) { 867 if (smi_info->supports_event_msg_buff || smi_info->io.irq) {
869 start_check_enables(smi_info, true); 868 start_check_enables(smi_info);
870 } else { 869 } else {
871 smi_info->curr_msg = alloc_msg_handle_irq(smi_info); 870 smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
872 if (!smi_info->curr_msg) 871 if (!smi_info->curr_msg)
@@ -1167,6 +1166,7 @@ static int smi_start_processing(void *send_info,
1167 1166
1168 /* Set up the timer that drives the interface. */ 1167 /* Set up the timer that drives the interface. */
1169 setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); 1168 setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
1169 new_smi->timer_can_start = true;
1170 smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); 1170 smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
1171 1171
1172 /* Try to claim any interrupts. */ 1172 /* Try to claim any interrupts. */
@@ -1936,10 +1936,12 @@ static void check_for_broken_irqs(struct smi_info *smi_info)
1936 check_set_rcv_irq(smi_info); 1936 check_set_rcv_irq(smi_info);
1937} 1937}
1938 1938
1939static inline void wait_for_timer_and_thread(struct smi_info *smi_info) 1939static inline void stop_timer_and_thread(struct smi_info *smi_info)
1940{ 1940{
1941 if (smi_info->thread != NULL) 1941 if (smi_info->thread != NULL)
1942 kthread_stop(smi_info->thread); 1942 kthread_stop(smi_info->thread);
1943
1944 smi_info->timer_can_start = false;
1943 if (smi_info->timer_running) 1945 if (smi_info->timer_running)
1944 del_timer_sync(&smi_info->si_timer); 1946 del_timer_sync(&smi_info->si_timer);
1945} 1947}
@@ -2152,7 +2154,7 @@ static int try_smi_init(struct smi_info *new_smi)
2152 * Start clearing the flags before we enable interrupts or the 2154 * Start clearing the flags before we enable interrupts or the
2153 * timer to avoid racing with the timer. 2155 * timer to avoid racing with the timer.
2154 */ 2156 */
2155 start_clear_flags(new_smi, false); 2157 start_clear_flags(new_smi);
2156 2158
2157 /* 2159 /*
2158 * IRQ is defined to be set when non-zero. req_events will 2160 * IRQ is defined to be set when non-zero. req_events will
@@ -2238,7 +2240,7 @@ out_err_remove_attrs:
2238 dev_set_drvdata(new_smi->io.dev, NULL); 2240 dev_set_drvdata(new_smi->io.dev, NULL);
2239 2241
2240out_err_stop_timer: 2242out_err_stop_timer:
2241 wait_for_timer_and_thread(new_smi); 2243 stop_timer_and_thread(new_smi);
2242 2244
2243out_err: 2245out_err:
2244 new_smi->interrupt_disabled = true; 2246 new_smi->interrupt_disabled = true;
@@ -2388,7 +2390,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
2388 */ 2390 */
2389 if (to_clean->io.irq_cleanup) 2391 if (to_clean->io.irq_cleanup)
2390 to_clean->io.irq_cleanup(&to_clean->io); 2392 to_clean->io.irq_cleanup(&to_clean->io);
2391 wait_for_timer_and_thread(to_clean); 2393 stop_timer_and_thread(to_clean);
2392 2394
2393 /* 2395 /*
2394 * Timeouts are stopped, now make sure the interrupts are off 2396 * Timeouts are stopped, now make sure the interrupts are off
@@ -2400,7 +2402,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
2400 schedule_timeout_uninterruptible(1); 2402 schedule_timeout_uninterruptible(1);
2401 } 2403 }
2402 if (to_clean->handlers) 2404 if (to_clean->handlers)
2403 disable_si_irq(to_clean, false); 2405 disable_si_irq(to_clean);
2404 while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { 2406 while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
2405 poll(to_clean); 2407 poll(to_clean);
2406 schedule_timeout_uninterruptible(1); 2408 schedule_timeout_uninterruptible(1);