[PATCH] hrtimers: fix posix-timer requeue race
From: Steven Rostedtrostedt@goodmis.org <rostedt@goodmis.org> CPU0 expires a posix-timer and runs the callback function. The signal is queued. After releasing the posix-timer lock and before returning to hrtimer_run_queue CPU0 gets interrupted. CPU1 delivers the queued signal and rearms the timer. CPU0 comes back to hrtimer_run_queue and sets the timer state to expired. The next modification of the timer can result in an oops, because the state information is wrong. Keep track of state = RUNNING and check if the state has been in the return path of hrtimer_run_queue. In case the state has been changed, ignore a restart request and do not touch the state variable. Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
a16a1c095a
commit
ff60a5dc4f
2 changed files with 6 additions and 0 deletions
|
@ -40,6 +40,7 @@ enum hrtimer_restart {
|
||||||
enum hrtimer_state {
|
enum hrtimer_state {
|
||||||
HRTIMER_INACTIVE, /* Timer is inactive */
|
HRTIMER_INACTIVE, /* Timer is inactive */
|
||||||
HRTIMER_EXPIRED, /* Timer is expired */
|
HRTIMER_EXPIRED, /* Timer is expired */
|
||||||
|
HRTIMER_RUNNING, /* Timer is running the callback function */
|
||||||
HRTIMER_PENDING, /* Timer is pending */
|
HRTIMER_PENDING, /* Timer is pending */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -550,6 +550,7 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base)
|
||||||
fn = timer->function;
|
fn = timer->function;
|
||||||
data = timer->data;
|
data = timer->data;
|
||||||
set_curr_timer(base, timer);
|
set_curr_timer(base, timer);
|
||||||
|
timer->state = HRTIMER_RUNNING;
|
||||||
__remove_hrtimer(timer, base);
|
__remove_hrtimer(timer, base);
|
||||||
spin_unlock_irq(&base->lock);
|
spin_unlock_irq(&base->lock);
|
||||||
|
|
||||||
|
@ -565,6 +566,10 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base)
|
||||||
|
|
||||||
spin_lock_irq(&base->lock);
|
spin_lock_irq(&base->lock);
|
||||||
|
|
||||||
|
/* Another CPU has added back the timer */
|
||||||
|
if (timer->state != HRTIMER_RUNNING)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (restart == HRTIMER_RESTART)
|
if (restart == HRTIMER_RESTART)
|
||||||
enqueue_hrtimer(timer, base);
|
enqueue_hrtimer(timer, base);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue