timekeeping: Fix bogus clock_was_set() invocation in do_adjtimex()
Subsystems (4)
PATCH 1/1 timekeeping: Fix bogus clock_was_set() invocation in do_adjtimex()
The addition of the bases argument to clock_was_set() fixed up all call sites correctly except for do_adjtimex(). This uses CLOCK_REALTIME instead of CLOCK_SET_WALL as argument. CLOCK_REALTIME is 0.
As a result the effect of that clock_was_set() notification is incomplete and might result in timers expiring late because the hrtimer code does not re-evaluate the affected clock bases.
Use CLOCK_SET_WALL instead of CLOCK_REALTIME to tell the hrtimers code which clock bases need to be re-evaluated.
--- kernel/time/timekeeping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/timekeeping.c +1 -1
@@ -2606,7 +2606,7 @@ int do_adjtimex(struct __kernel_timex *t clock_set |=timekeeping_advance (TK_ADV_FREQ );if (clock_set) -clock_was_set (CLOCK_REALTIME ); +clock_was_set (CLOCK_SET_WALL );ntp_notify_cmos_timer ();
The following commit has been merged into the timers/urgent branch of tip:
The following commit has been merged into the timers/urgent branch of tip:
Commit-ID: 5916be8a53de6401871bdd953f6c60237b47d6d3 Gitweb: https://git.kernel.org/tip/5916be8a53de6401871bdd953f6c60237b47d6d3 Author: Thomas Gleixner <[email protected]> AuthorDate: Sat, 03 Aug 2024 17:07:51 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Aug 2024 16:14:14 +02:00
timekeeping: Fix bogus clock_was_set() invocation in do_adjtimex()
The addition of the bases argument to clock_was_set() fixed up all call sites correctly except for do_adjtimex(). This uses CLOCK_REALTIME instead of CLOCK_SET_WALL as argument. CLOCK_REALTIME is 0.
As a result the effect of that clock_was_set() notification is incomplete and might result in timers expiring late because the hrtimer code does not re-evaluate the affected clock bases.
Use CLOCK_SET_WALL instead of CLOCK_REALTIME to tell the hrtimers code which clock bases need to be re-evaluated.
--- kernel/time/timekeeping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/timekeeping.c +1 -1
@@ -2606,7 +2606,7 @@ int do_adjtimex(struct __kernel_timex *txc) clock_set |=timekeeping_advance (TK_ADV_FREQ );if (clock_set) -clock_was_set (CLOCK_REALTIME ); +clock_was_set (CLOCK_SET_WALL );ntp_notify_cmos_timer ();
Quoted 11 lines · Thomas Gleixner
The addition of the bases argument to
clock_was_set()fixed up all call sites correctly except fordo_adjtimex(). This usesCLOCK_REALTIMEinstead ofCLOCK_SET_WALLas argument.CLOCK_REALTIMEis 0.As a result the effect of that
clock_was_set()notification is incomplete and might result in timers expiring late because the hrtimer code does not re-evaluate the affected clock bases.Use
CLOCK_SET_WALLinstead ofCLOCK_REALTIMEto tell the hrtimers code which clock bases need to be re-evaluated.
My only thought here is maybe renaming CLOCK_SET_WALL and CLOCK_SET_BOOT to something like:
BASEMASK_WALL_CLOCK_SET and BASEMASK_BOOT_CLOCK_SET
Just to avoid future naming mixups or confusion with clockids?
thanks
-john
Quoted 13 lines · John Stultz
Quoted 11 lines · Thomas Gleixner
The addition of the bases argument to
clock_was_set()fixed up all call sites correctly except fordo_adjtimex(). This usesCLOCK_REALTIMEinstead ofCLOCK_SET_WALLas argument.CLOCK_REALTIMEis 0.As a result the effect of that
clock_was_set()notification is incomplete and might result in timers expiring late because the hrtimer code does not re-evaluate the affected clock bases.Use
CLOCK_SET_WALLinstead ofCLOCK_REALTIMEto tell the hrtimers code which clock bases need to be re-evaluated.
Quoted 7 lines
Acked-by John Stultz <[email protected]>My only thought here is maybe renaming
CLOCK_SET_WALLandCLOCK_SET_BOOTto something like:
BASEMASK_WALL_CLOCK_SETandBASEMASK_BOOT_CLOCK_SETJust to avoid future naming mixups or confusion with clockids?
Makes sense. Care to whip up a patch?
Thanks,
tglx
John Stultz
maintainerPATCH 1/1 time: Rename CLOCK_SET_* as BASEMASK_*_CLOCK_SET
In commit 5916be8a53de ("timekeeping: Fix bogus clock_was_set() invocation in do_adjtimex()"), Thomas fixed a bug where instead of passing one of the CLOCK_SET_* values to clock_was_set(),a conceptually related clockid (CLOCK_REALTIME) was incorrectly passed.
Just to make this type of accident less likely, lets rename the base masks used by clock_was_set() to something that doesn't resemble a clockid.
Thus:CLOCK_SET_WALL -> BASEMASK_WALL_CLOCK_SETCLOCK_SET_BOOT -> BASEMASK_BOOT_CLOCK_SET
--- kernel/time/hrtimer.c | 2 +- kernel/time/tick-internal.h | 4 ++-- kernel/time/timekeeping.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-)
kernel/time/hrtimer.c +1 -1
@@ -980,7 +980,7 @@ void clock_was_set(unsigned int bases)static void clock_was_set_work (struct work_struct *work) { -clock_was_set (CLOCK_SET_WALL ); +clock_was_set (BASEMASK_WALL_CLOCK_SET ); } static DECLARE_WORK(hrtimer_work, clock_was_set_work);
kernel/time/tick-internal.h +2 -2
@@ -181,11 +181,11 @@ extern u64 get_next_timer_interrupt(unsigned long basej, u64 basem);u64 timer_base_try_to_set_idle (unsigned long basej,u64 basem,bool *idle);void timer_clear_idle (void ); -#define CLOCK_SET_WALL \ +#define BASEMASK_WALL_CLOCK_SET \ (BIT(HRTIMER_BASE_REALTIME) | BIT(HRTIMER_BASE_REALTIME_SOFT) | \ BIT(HRTIMER_BASE_TAI) | BIT(HRTIMER_BASE_TAI_SOFT)) -#define CLOCK_SET_BOOT \ +#define BASEMASK_BOOT_CLOCK_SET \ (BIT(HRTIMER_BASE_BOOTTIME) | BIT(HRTIMER_BASE_BOOTTIME_SOFT))void clock_was_set (unsigned int bases);
kernel/time/timekeeping.c +4 -4
@@ -1471,7 +1471,7 @@ int do_settimeofday64(const struct timespec64 *ts)raw_spin_unlock_irqrestore (&timekeeper_lock, flags);/* Signal hrtimers about time change */ -clock_was_set (CLOCK_SET_WALL ); +clock_was_set (BASEMASK_WALL_CLOCK_SET );if (!ret) {audit_tk_injoffset (ts_delta);
@@ -1521,7 +1521,7 @@ static int timekeeping_inject_offset(const struct timespec64 *ts)raw_spin_unlock_irqrestore (&timekeeper_lock, flags);/* Signal hrtimers about time change */ -clock_was_set (CLOCK_SET_WALL ); +clock_was_set (BASEMASK_WALL_CLOCK_SET );return ret; }
@@ -1896,7 +1896,7 @@ void timekeeping_inject_sleeptime64(const struct timespec64 *delta)raw_spin_unlock_irqrestore (&timekeeper_lock, flags);/* Signal hrtimers about time change */ - clock_was_set(CLOCK_SET_WALL | CLOCK_SET_BOOT); + clock_was_set(BASEMASK_WALL_CLOCK_SET | BASEMASK_BOOT_CLOCK_SET); }#endif
@@ -2606,7 +2606,7 @@ int do_adjtimex(struct __kernel_timex *txc) clock_set |=timekeeping_advance (TK_ADV_FREQ );if (clock_set) -clock_was_set (CLOCK_SET_WALL ); +clock_was_set (BASEMASK_WALL_CLOCK_SET );ntp_notify_cmos_timer ();
Signature · 1 line
2.46.0.184.g6999bdac58-goog
Re: [PATCH] time: Rename CLOCK_SET_* as BASEMASK_*_CLOCK_SET
Quoted 7 lines · John Stultz
In commit
5916be8a53de("timekeeping: Fix bogusclock_was_set()invocation indo_adjtimex()"), Thomas fixed a bug where instead of passing one of the CLOCK_SET_* values to clock_was_set(),a conceptually related clockid (CLOCK_REALTIME) was incorrectly passed.Just to make this type of accident less likely, lets rename the
s/lets//
Quoted 6 lines
base masks used by
clock_was_set()to something that doesn't resemble a clockid.Thus:
CLOCK_SET_WALL->BASEMASK_WALL_CLOCK_SETCLOCK_SET_BOOT->BASEMASK_BOOT_CLOCK_SET
I don't think that's the actual problem. What's the confusing part is the function name itself clock_was_set().
Renaming that to at the same time to something unambiguous would be helpful.
hrtimer_refresh_bases() or something like that should be descriptive enough.
Thanks,
tglx