Skip to contentSkip to conversation

timekeeping: Fix bogus clock_was_set() invocation in do_adjtimex()

PATCH Applied Thomas Gleixner 3 participants 6 messages Aug 3, 2024 – Sep 2, 2024

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

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.

Fixes 17a1b8826b45 ("hrtimer: Add bases argument to clock_was_set()")
Cc John Stultz <[email protected]>
Cc Stephen Boyd <[email protected]>
---
 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();
 
#1 lore raw
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.

Fixes 17a1b8826b45 ("hrtimer: Add bases argument to clock_was_set()")
---
 kernel/time/timekeeping.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/timekeeping.c +1 -1
index 2fa87dc..5391e41 100644
@@ -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();
 
maintainer Acked-by on v1 1/1
#2 lore raw
In reply to Thomas Gleixner
Quoted 11 lines · Thomas Gleixner

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.

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

#3 lore raw
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 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.

Quoted 7 lines

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?

Makes sense. Care to whip up a patch?

Thanks,

tglx

maintainer
#4 lore raw

PATCH 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_SET
CLOCK_SET_BOOT -> BASEMASK_BOOT_CLOCK_SET

Cc Thomas Gleixner <[email protected]>
Cc Stephen Boyd <[email protected]>
Cc Anna-Maria Behnsen <[email protected]>
Cc Frederic Weisbecker <[email protected]>
---
 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
index b8ee320208d41..ca18a2a344294 100644
@@ -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
index 5f2105e637bdf..59a6e50734f40 100644
@@ -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
index 5391e4167d602..c8108345438aa 100644
@@ -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
#5 lore raw

Re: [PATCH] time: Rename CLOCK_SET_* as BASEMASK_*_CLOCK_SET

Quoted 7 lines · John Stultz

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

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_SET
CLOCK_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