Commit 12e9bd16 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'timers-urgent-2021-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Thomas Gleixner:
 "A small set of timer related fixes:

   - Plug a race between rearm and process tick in the posix CPU timers
     code

   - Make the optimization to avoid recalculation of the next timer
     interrupt work correctly when there are no timers pending"

* tag 'timers-urgent-2021-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  timers: Fix get_next_timer_interrupt() with no timers pending
  posix-cpu-timers: Fix rearm racing against process tick
parents d1b17825 ff5a6a35
...@@ -991,6 +991,11 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer) ...@@ -991,6 +991,11 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
if (!p) if (!p)
goto out; goto out;
/* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL))
goto out;
/* /*
* Fetch the current sample and update the timer's expiry time. * Fetch the current sample and update the timer's expiry time.
*/ */
...@@ -1001,11 +1006,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer) ...@@ -1001,11 +1006,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
bump_cpu_timer(timer, now); bump_cpu_timer(timer, now);
/* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL))
goto out;
/* /*
* Now re-arm for the new expiry time. * Now re-arm for the new expiry time.
*/ */
......
...@@ -207,6 +207,7 @@ struct timer_base { ...@@ -207,6 +207,7 @@ struct timer_base {
unsigned int cpu; unsigned int cpu;
bool next_expiry_recalc; bool next_expiry_recalc;
bool is_idle; bool is_idle;
bool timers_pending;
DECLARE_BITMAP(pending_map, WHEEL_SIZE); DECLARE_BITMAP(pending_map, WHEEL_SIZE);
struct hlist_head vectors[WHEEL_SIZE]; struct hlist_head vectors[WHEEL_SIZE];
} ____cacheline_aligned; } ____cacheline_aligned;
...@@ -595,6 +596,7 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer, ...@@ -595,6 +596,7 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
* can reevaluate the wheel: * can reevaluate the wheel:
*/ */
base->next_expiry = bucket_expiry; base->next_expiry = bucket_expiry;
base->timers_pending = true;
base->next_expiry_recalc = false; base->next_expiry_recalc = false;
trigger_dyntick_cpu(base, timer); trigger_dyntick_cpu(base, timer);
} }
...@@ -1582,6 +1584,7 @@ static unsigned long __next_timer_interrupt(struct timer_base *base) ...@@ -1582,6 +1584,7 @@ static unsigned long __next_timer_interrupt(struct timer_base *base)
} }
base->next_expiry_recalc = false; base->next_expiry_recalc = false;
base->timers_pending = !(next == base->clk + NEXT_TIMER_MAX_DELTA);
return next; return next;
} }
...@@ -1633,7 +1636,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1633,7 +1636,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
u64 expires = KTIME_MAX; u64 expires = KTIME_MAX;
unsigned long nextevt; unsigned long nextevt;
bool is_max_delta;
/* /*
* Pretend that there is no timer pending if the cpu is offline. * Pretend that there is no timer pending if the cpu is offline.
...@@ -1646,7 +1648,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1646,7 +1648,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
if (base->next_expiry_recalc) if (base->next_expiry_recalc)
base->next_expiry = __next_timer_interrupt(base); base->next_expiry = __next_timer_interrupt(base);
nextevt = base->next_expiry; nextevt = base->next_expiry;
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
/* /*
* We have a fresh next event. Check whether we can forward the * We have a fresh next event. Check whether we can forward the
...@@ -1664,7 +1665,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) ...@@ -1664,7 +1665,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
expires = basem; expires = basem;
base->is_idle = false; base->is_idle = false;
} else { } else {
if (!is_max_delta) if (base->timers_pending)
expires = basem + (u64)(nextevt - basej) * TICK_NSEC; expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
/* /*
* If we expect to sleep more than a tick, mark the base idle. * If we expect to sleep more than a tick, mark the base idle.
...@@ -1947,6 +1948,7 @@ int timers_prepare_cpu(unsigned int cpu) ...@@ -1947,6 +1948,7 @@ int timers_prepare_cpu(unsigned int cpu)
base = per_cpu_ptr(&timer_bases[b], cpu); base = per_cpu_ptr(&timer_bases[b], cpu);
base->clk = jiffies; base->clk = jiffies;
base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA; base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
base->timers_pending = false;
base->is_idle = false; base->is_idle = false;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment