Hi Anna-Maria, Nice change, it indeed makes more sense that way. Just a few details below:
On Fri, Jul 10, 2020 at 05:46:22PM +0200, Anna-Maria Behnsen wrote: > The bucket expiry time is the effective expriy time of timers and is > greater than or equal to the requested timer expiry time. This is due > to the guarantee that timers never expire early and the reduced expiry > granularity in the secondary wheel levels. > > When a timer is enqueued, trigger_dyntick_cpu() checks whether the > timer is the new first timer. This check compares next_expiry with > the requested timer expiry value and not with the effective expiry > value of the bucket into which the timer was queued. > > Storing the requested timer expiry value in base->next_expiry can lead > to base->clk going backwards if the requested timer expiry value is > smaller than base->clk. Commit 30c66fc30ee7 ("timer: Prevent base->clk > from moving backward") worked around this by preventing the store when > timer->expiry is before base->clk, but did not fix the underlying > problem. > > Use the expiry value of the bucket into which the timer is queued to > do the new first timer check. This fixes the base->clk going backward > problem and also prevents unnecessary softirq invocations when the > timer->expiry is not equal to the bucket expiry time in case of a new > first timer which is queued in a secondary wheel level. I think there shouldn't be such unecessary softirq invocations. Either they fire at the bucket expiry time or the timer expiry time, it doesn't make much difference. More important below: > -static int calc_wheel_index(unsigned long expires, unsigned long clk) > +static int calc_wheel_index(unsigned long expires, unsigned long clk, > + unsigned long *bucket_expiry) > { > unsigned long delta = expires - clk; > unsigned int idx; > > if (delta < LVL_START(1)) { > - idx = calc_index(expires, 0); > + idx = calc_index(expires, 0, bucket_expiry); > } else if (delta < LVL_START(2)) { > - idx = calc_index(expires, 1); > + idx = calc_index(expires, 1, bucket_expiry); > } else if (delta < LVL_START(3)) { > - idx = calc_index(expires, 2); > + idx = calc_index(expires, 2, bucket_expiry); > } else if (delta < LVL_START(4)) { > - idx = calc_index(expires, 3); > + idx = calc_index(expires, 3, bucket_expiry); > } else if (delta < LVL_START(5)) { > - idx = calc_index(expires, 4); > + idx = calc_index(expires, 4, bucket_expiry); > } else if (delta < LVL_START(6)) { > - idx = calc_index(expires, 5); > + idx = calc_index(expires, 5, bucket_expiry); > } else if (delta < LVL_START(7)) { > - idx = calc_index(expires, 6); > + idx = calc_index(expires, 6, bucket_expiry); > } else if (LVL_DEPTH > 8 && delta < LVL_START(8)) { > - idx = calc_index(expires, 7); > + idx = calc_index(expires, 7, bucket_expiry); > } else if ((long) delta < 0) { > idx = clk & LVL_MASK; You also need to handle that part. That's in fact the critical one :) I'll rebase my series on top of that. Thanks!