On Wed, 2023-10-25 at 22:45 +0200, Johannes Berg wrote: > From: Johannes Berg <johannes.b...@intel.com> > > In 'basic' time-travel mode (without =inf-cpu or =ext), we > still get timer interrupts. These can happen at arbitrary > points in time, i.e. while in timer_read(), which pushes > time forward just a little bit. Then, if we happen to get > the interrupt after calculating the new time to push to, > but before actually finishing that, the interrupt will set > the time to a value that's incompatible with the forward, > and we'll crash because time goes backwards when we do the > forwarding. > > Fix this by reading the time_travel_time, calculating the > adjustment, and doing the adjustment all with interrupts > disabled. > > Reported-by: Vincent Whitchurch <vincent.whitchu...@axis.com> > Signed-off-by: Johannes Berg <johannes.b...@intel.com>
Thanks, this works for me too. However, one question below. > --- > v2: remove stray debug code > --- > arch/um/kernel/time.c | 32 +++++++++++++++++++++++++++----- > 1 file changed, 27 insertions(+), 5 deletions(-) > > diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c > index 8ff46bc86d09..0c01674e14d5 100644 > --- a/arch/um/kernel/time.c > +++ b/arch/um/kernel/time.c > @@ -551,9 +551,29 @@ static void time_travel_update_time(unsigned long long > next, bool idle) > time_travel_del_event(&ne); > } > > > +static void time_travel_update_time_rel(unsigned long long offs) > +{ > + unsigned long flags; > + > + /* > + * Disable interrupts before calculating the new time so > + * that a real timer interrupt (signal) can't happen at > + * a bad time e.g. after we read time_travel_time but > + * before we've completed updating the time. > + */ > + local_irq_save(flags); > + time_travel_update_time(time_travel_time + offs, false); > + local_irq_restore(flags); > +} > + > void time_travel_ndelay(unsigned long nsec) > { > - time_travel_update_time(time_travel_time + nsec, false); > + /* > + * Not strictly needed to use _rel() version since this is > + * only used in INFCPU/EXT modes, but it doesn't hurt and > + * is more readable too. > + */ > + time_travel_update_time_rel(nsec); > } > EXPORT_SYMBOL(time_travel_ndelay); > > > @@ -687,7 +707,11 @@ static void time_travel_set_start(void) > #define time_travel_time 0 > #define time_travel_ext_waiting 0 > > > -static inline void time_travel_update_time(unsigned long long ns, bool > retearly) > +static inline void time_travel_update_time(unsigned long long ns, bool idle) > +{ > +} > + > +static inline void time_travel_update_time_rel(unsigned long long offs) > { > } > > > @@ -839,9 +863,7 @@ static u64 timer_read(struct clocksource *cs) > */ > if (!irqs_disabled() && !in_interrupt() && !in_softirq() && > !time_travel_ext_waiting) > - time_travel_update_time(time_travel_time + > - TIMER_MULTIPLIER, > - false); > + time_travel_update_time_rel(TIMER_MULTIPLIER); > return time_travel_time / TIMER_MULTIPLIER; > } The reason I hesitated with putting the whole of time_travel_update_time() under local_irq_save() in my attempt was because I didn't quite understand the reason for the !irqs_disabled() condition here and the comment just above it about recursion and things getting messed up. If it's OK to disable interrupts as this patch does, is the !irqs_disabled() condition valid? _______________________________________________ linux-um mailing list linux-um@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-um