Commit 48e8ac2979920ffa39117e2d725afa3a749bfe8d
Committed by
Linus Torvalds
1 parent
a94cdd1f4d
Exists in
master
and in
13 other branches
ipmi: Fix a race restarting the timer
With recent changes it is possible for the timer handler to detect an idle interface and not start the timer, but the thread to start an operation at the same time. The thread will not start the timer in that instance, resulting in the timer not running. Instead, move all timer operations under the lock and start the timer in the thread if it detect non-idle and the timer is not already running. Moving under locks allows the last timeout to be set in both the thread and the timer. 'Timer is not running' means that the timer is not pending and smi_timeout() is not running. So we need a flag to detect this correctly. Also fix a few other timeout bugs: setting the last timeout when the interrupt has to be disabled and the timer started, and setting the last timeout in check_start_timer_thread possibly racing with the timer Signed-off-by: Corey Minyard <cminyard@mvista.com> Signed-off-by: Bodo Stroesser <bstroesser@ts.fujitsu.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 28 additions and 18 deletions Side-by-side Diff
drivers/char/ipmi/ipmi_si_intf.c
... | ... | @@ -248,6 +248,9 @@ |
248 | 248 | /* The timer for this si. */ |
249 | 249 | struct timer_list si_timer; |
250 | 250 | |
251 | + /* This flag is set, if the timer is running (timer_pending() isn't enough) */ | |
252 | + bool timer_running; | |
253 | + | |
251 | 254 | /* The time (in jiffies) the last timeout occurred at. */ |
252 | 255 | unsigned long last_timeout_jiffies; |
253 | 256 | |
... | ... | @@ -434,6 +437,13 @@ |
434 | 437 | smi_info->si_state = SI_CLEARING_FLAGS; |
435 | 438 | } |
436 | 439 | |
440 | +static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) | |
441 | +{ | |
442 | + smi_info->last_timeout_jiffies = jiffies; | |
443 | + mod_timer(&smi_info->si_timer, new_val); | |
444 | + smi_info->timer_running = true; | |
445 | +} | |
446 | + | |
437 | 447 | /* |
438 | 448 | * When we have a situtaion where we run out of memory and cannot |
439 | 449 | * allocate messages, we just leave them in the BMC and run the system |
... | ... | @@ -446,8 +456,7 @@ |
446 | 456 | start_disable_irq(smi_info); |
447 | 457 | smi_info->interrupt_disabled = 1; |
448 | 458 | if (!atomic_read(&smi_info->stop_operation)) |
449 | - mod_timer(&smi_info->si_timer, | |
450 | - jiffies + SI_TIMEOUT_JIFFIES); | |
459 | + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); | |
451 | 460 | } |
452 | 461 | } |
453 | 462 | |
454 | 463 | |
... | ... | @@ -907,16 +916,8 @@ |
907 | 916 | list_add_tail(&msg->link, &smi_info->xmit_msgs); |
908 | 917 | |
909 | 918 | if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) { |
910 | - /* | |
911 | - * last_timeout_jiffies is updated here to avoid | |
912 | - * smi_timeout() handler passing very large time_diff | |
913 | - * value to smi_event_handler() that causes | |
914 | - * the send command to abort. | |
915 | - */ | |
916 | - smi_info->last_timeout_jiffies = jiffies; | |
919 | + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); | |
917 | 920 | |
918 | - mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES); | |
919 | - | |
920 | 921 | if (smi_info->thread) |
921 | 922 | wake_up_process(smi_info->thread); |
922 | 923 | |
... | ... | @@ -1004,6 +1005,17 @@ |
1004 | 1005 | |
1005 | 1006 | spin_lock_irqsave(&(smi_info->si_lock), flags); |
1006 | 1007 | smi_result = smi_event_handler(smi_info, 0); |
1008 | + | |
1009 | + /* | |
1010 | + * If the driver is doing something, there is a possible | |
1011 | + * race with the timer. If the timer handler see idle, | |
1012 | + * and the thread here sees something else, the timer | |
1013 | + * handler won't restart the timer even though it is | |
1014 | + * required. So start it here if necessary. | |
1015 | + */ | |
1016 | + if (smi_result != SI_SM_IDLE && !smi_info->timer_running) | |
1017 | + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); | |
1018 | + | |
1007 | 1019 | spin_unlock_irqrestore(&(smi_info->si_lock), flags); |
1008 | 1020 | busy_wait = ipmi_thread_busy_wait(smi_result, smi_info, |
1009 | 1021 | &busy_until); |
... | ... | @@ -1073,10 +1085,6 @@ |
1073 | 1085 | * SI_USEC_PER_JIFFY); |
1074 | 1086 | smi_result = smi_event_handler(smi_info, time_diff); |
1075 | 1087 | |
1076 | - spin_unlock_irqrestore(&(smi_info->si_lock), flags); | |
1077 | - | |
1078 | - smi_info->last_timeout_jiffies = jiffies_now; | |
1079 | - | |
1080 | 1088 | if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { |
1081 | 1089 | /* Running with interrupts, only do long timeouts. */ |
1082 | 1090 | timeout = jiffies + SI_TIMEOUT_JIFFIES; |
... | ... | @@ -1098,7 +1106,10 @@ |
1098 | 1106 | |
1099 | 1107 | do_mod_timer: |
1100 | 1108 | if (smi_result != SI_SM_IDLE) |
1101 | - mod_timer(&(smi_info->si_timer), timeout); | |
1109 | + smi_mod_timer(smi_info, timeout); | |
1110 | + else | |
1111 | + smi_info->timer_running = false; | |
1112 | + spin_unlock_irqrestore(&(smi_info->si_lock), flags); | |
1102 | 1113 | } |
1103 | 1114 | |
1104 | 1115 | static irqreturn_t si_irq_handler(int irq, void *data) |
... | ... | @@ -1146,8 +1157,7 @@ |
1146 | 1157 | |
1147 | 1158 | /* Set up the timer that drives the interface. */ |
1148 | 1159 | setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); |
1149 | - new_smi->last_timeout_jiffies = jiffies; | |
1150 | - mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES); | |
1160 | + smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); | |
1151 | 1161 | |
1152 | 1162 | /* |
1153 | 1163 | * Check if the user forcefully enabled the daemon. |