Expose the auxiliary clocks through the vDSO.
Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
include/vdso/datapage.h | 2 ++
lib/vdso/gettimeofday.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index f4c96d9ce674abb07ccd8703f1a04da7631c1677..02533038640e53c40291c7e09139e0f9b32f502a 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
+#include <uapi/linux/bits.h>
#include <uapi/linux/time.h>
#include <uapi/linux/types.h>
#include <uapi/asm-generic/errno-base.h>
@@ -46,6 +47,7 @@ struct vdso_arch_data {
#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \
BIT(CLOCK_MONOTONIC_COARSE))
#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW))
+#define VDSO_AUX __GENMASK(CLOCK_AUX_LAST, CLOCK_AUX)
#define CS_HRES_COARSE 0
#define CS_RAW 1
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index c383878bb5445a62d8fea6591e8550183852c2e6..3a54dbb8fe32849cd749e71ec2a8be44baf42816 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -2,6 +2,7 @@
/*
* Generic userspace implementations of gettimeofday() and similar.
*/
+#include <vdso/auxclock.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
@@ -74,7 +75,7 @@ static inline bool vdso_cycles_ok(u64 cycles)
static __always_inline bool vdso_clockid_valid(clockid_t clock)
{
/* Check for negative values or invalid clocks */
- return likely((u32) clock < MAX_CLOCKS);
+ return likely((u32) clock < CLOCK_AUX_LAST);
}
/*
@@ -268,6 +269,48 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
return true;
}
+static __always_inline
+bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts)
+{
+ const struct vdso_clock *vc;
+ u64 sec, ns;
+ u32 seq;
+ u8 idx;
+
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return false;
+
+ idx = clock - CLOCK_AUX;
+ vc = &vd->aux_clock_data[idx];
+
+ do {
+ /*
+ * Open coded function vdso_read_begin() to handle
+ * VDSO_CLOCK_TIMENS. See comment in do_hres().
+ */
+ while ((seq = READ_ONCE(vc->seq)) & 1) {
+ if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
+ vd = __arch_get_vdso_u_timens_data(vd);
+ vc = &vd->aux_clock_data[idx];
+ break;
+ }
+ cpu_relax();
+ }
+ smp_rmb();
+
+ /* Auxclock disabled? */
+ if (vc->clock_mode == VDSO_CLOCKMODE_NONE)
+ return false;
+
+ if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns))
+ return false;
+ } while (unlikely(vdso_read_retry(vc, seq)));
+
+ vdso_set_timespec(ts, sec, ns);
+
+ return true;
+}
+
static __always_inline bool
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *ts)
@@ -289,6 +332,8 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
else if (msk & VDSO_RAW)
vc = &vc[CS_RAW];
+ else if (msk & VDSO_AUX)
+ return do_aux(vd, clock, ts);
else
return false;
@@ -433,6 +478,8 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc
* Preserves the behaviour of posix_get_coarse_res().
*/
ns = LOW_RES_NSEC;
+ } else if (msk & VDSO_AUX) {
+ ns = aux_clock_resolution_ns();
} else {
return false;
}
--
2.50.0
On Tue, Jul 1, 2025 at 1:58 AM Thomas Weißschuh <thomas.weissschuh@linutronix.de> wrote: > > Expose the auxiliary clocks through the vDSO. > > Architectures not using the generic vDSO time framework, > namely SPARC64, are not supported. > > Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de> Just as a heads up, I've just been bisecting and this commit seems to be causing problems on arm64 devices, running 32bit versions of kselftest nanosleep or inconsistency-check tests. Running the 64bit versions of the tests are not showing issues. From my initial digging, it looks like clockids that aren't vdso enabled (CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, CLOCK_REALTIME_ALARM, CLOCK_BOOTTIME_ALARM) are somehow getting caught in the vdso logic and are *not* falling back to the syscall (stracing the test I don't see syscalls happen before the failure), and the values returned don't look to be correct. The inconsistency-check output looks like: # 5983032:0 # 5983317:0 # 5983561:0 # 5983846:0 # 5984130:0 # 5984415:0 # -------------------- # 5984659:0 # 2009440:0 # -------------------- # 2009724:0 # 2009969:0 # 2010253:0 # 2010538:0 # 2010782:0 # 2011067:0 Which hints we're returning nanosecond values in the tv_sec field somehow. Reverting just this change gets things back to working. It's pretty late here, so I'm going to try to dig a bit further to understand what's going on tomorrow, but wanted to raise this in case it's more obvious to less tired eyes. :) thanks -john
Hi John, On Wed, Aug 20, 2025 at 01:03:56AM -0700, John Stultz wrote: > On Tue, Jul 1, 2025 at 1:58 AM Thomas Weißschuh > <thomas.weissschuh@linutronix.de> wrote: > > > > Expose the auxiliary clocks through the vDSO. > > > > Architectures not using the generic vDSO time framework, > > namely SPARC64, are not supported. > > > > Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de> > > Just as a heads up, I've just been bisecting and this commit seems to > be causing problems on arm64 devices, running 32bit versions of > kselftest nanosleep or inconsistency-check tests. Running the 64bit > versions of the tests are not showing issues. Thanks for the report, I can reproduce the issue. > From my initial digging, it looks like clockids that aren't vdso > enabled (CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID, > CLOCK_REALTIME_ALARM, CLOCK_BOOTTIME_ALARM) are somehow getting caught > in the vdso logic and are *not* falling back to the syscall (stracing > the test I don't see syscalls happen before the failure), and the > values returned don't look to be correct. The generic vDSO code assumes that it can use the UAPI headers, also in the compat vDSO. This is true for most architectures, as the UAPI headers work correctly in 32-bit and 64-bit mode. On arm64 this is different, as the headers from arm64/ are never used by regular 32-bit userpspace. So arch/arm64/include/uapi/asm/bitsperlong.h defines __BITS_PER_LONG=64 even when used by the 32-bit compat vDSO. The commit you identified uses __GENMASK() which uses __BITS_PER_LONG. Due to the mismatch between __BITS_PER_LONG and the real long datatype we run into an out-of-bounds shift and therefore undefined behaviour. And of course -Wshift-count-overflow is explicitly disabled. There are a few possible fixes, none of which is really great. I'll send some patches. > The inconsistency-check output looks like: (...) > Which hints we're returning nanosecond values in the tv_sec field somehow. That seems to be an artifact of the UB from above, this happens even if do_aux() just returns 'false'. Thomas
On Tue, Jul 01 2025 at 10:58, Thomas Weißschuh wrote: > +static __always_inline > +bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts) > +{ > + const struct vdso_clock *vc; > + u64 sec, ns; > + u32 seq; > + u8 idx; > + > + if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS)) > + return false; > + > + idx = clock - CLOCK_AUX; > + vc = &vd->aux_clock_data[idx]; > + > + do { > + /* > + * Open coded function vdso_read_begin() to handle > + * VDSO_CLOCK_TIMENS. See comment in do_hres(). > + */ > + while ((seq = READ_ONCE(vc->seq)) & 1) { > + if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) { > + vd = __arch_get_vdso_u_timens_data(vd); > + vc = &vd->aux_clock_data[idx]; > + break; This actually wants to be a continue because otherwise @seq contains the stale value from the initial read of the TIMENS page, which is 0x1. That's a pointless extra round through the below. With continue it re-reads, but this time the actual value from the time data page and also takes an eventual odd value into account properly. I fixed it up locally already. Thanks, tglx
The following commit has been merged into the timers/ptp branch of tip:
Commit-ID: cd3557a7618bf5c1935e9f66b58a329f1f1f4b27
Gitweb: https://git.kernel.org/tip/cd3557a7618bf5c1935e9f66b58a329f1f1f4b27
Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
AuthorDate: Tue, 01 Jul 2025 10:58:06 +02:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Fri, 18 Jul 2025 14:09:39 +02:00
vdso/gettimeofday: Add support for auxiliary clocks
Expose the auxiliary clocks through the vDSO.
Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250701-vdso-auxclock-v1-12-df7d9f87b9b8@linutronix.de
---
include/vdso/datapage.h | 2 ++-
lib/vdso/gettimeofday.c | 49 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index f4c96d9..0253303 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
+#include <uapi/linux/bits.h>
#include <uapi/linux/time.h>
#include <uapi/linux/types.h>
#include <uapi/asm-generic/errno-base.h>
@@ -46,6 +47,7 @@ struct vdso_arch_data {
#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \
BIT(CLOCK_MONOTONIC_COARSE))
#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW))
+#define VDSO_AUX __GENMASK(CLOCK_AUX_LAST, CLOCK_AUX)
#define CS_HRES_COARSE 0
#define CS_RAW 1
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index fc0038e..02ea19f 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -2,6 +2,7 @@
/*
* Generic userspace implementations of gettimeofday() and similar.
*/
+#include <vdso/auxclock.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
@@ -74,7 +75,7 @@ static inline bool vdso_cycles_ok(u64 cycles)
static __always_inline bool vdso_clockid_valid(clockid_t clock)
{
/* Check for negative values or invalid clocks */
- return likely((u32) clock < MAX_CLOCKS);
+ return likely((u32) clock <= CLOCK_AUX_LAST);
}
/*
@@ -268,6 +269,48 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
return true;
}
+static __always_inline
+bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts)
+{
+ const struct vdso_clock *vc;
+ u32 seq, idx;
+ u64 sec, ns;
+
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return false;
+
+ idx = clock - CLOCK_AUX;
+ vc = &vd->aux_clock_data[idx];
+
+ do {
+ /*
+ * Open coded function vdso_read_begin() to handle
+ * VDSO_CLOCK_TIMENS. See comment in do_hres().
+ */
+ while ((seq = READ_ONCE(vc->seq)) & 1) {
+ if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
+ vd = __arch_get_vdso_u_timens_data(vd);
+ vc = &vd->aux_clock_data[idx];
+ /* Re-read from the real time data page */
+ continue;
+ }
+ cpu_relax();
+ }
+ smp_rmb();
+
+ /* Auxclock disabled? */
+ if (vc->clock_mode == VDSO_CLOCKMODE_NONE)
+ return false;
+
+ if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns))
+ return false;
+ } while (unlikely(vdso_read_retry(vc, seq)));
+
+ vdso_set_timespec(ts, sec, ns);
+
+ return true;
+}
+
static __always_inline bool
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *ts)
@@ -289,6 +332,8 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
else if (msk & VDSO_RAW)
vc = &vc[CS_RAW];
+ else if (msk & VDSO_AUX)
+ return do_aux(vd, clock, ts);
else
return false;
@@ -433,6 +478,8 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc
* Preserves the behaviour of posix_get_coarse_res().
*/
ns = LOW_RES_NSEC;
+ } else if (msk & VDSO_AUX) {
+ ns = aux_clock_resolution_ns();
} else {
return false;
}
The following commit has been merged into the timers/ptp branch of tip:
Commit-ID: 5b8c75d424fad4d7b295f50021e9fd9c1022e6a8
Gitweb: https://git.kernel.org/tip/5b8c75d424fad4d7b295f50021e9fd9c1022e6a8
Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
AuthorDate: Tue, 01 Jul 2025 10:58:06 +02:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Fri, 18 Jul 2025 13:45:33 +02:00
vdso/gettimeofday: Add support for auxiliary clocks
Expose the auxiliary clocks through the vDSO.
Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250701-vdso-auxclock-v1-12-df7d9f87b9b8@linutronix.de
---
include/vdso/datapage.h | 2 ++-
lib/vdso/gettimeofday.c | 49 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index f4c96d9..0253303 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
+#include <uapi/linux/bits.h>
#include <uapi/linux/time.h>
#include <uapi/linux/types.h>
#include <uapi/asm-generic/errno-base.h>
@@ -46,6 +47,7 @@ struct vdso_arch_data {
#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \
BIT(CLOCK_MONOTONIC_COARSE))
#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW))
+#define VDSO_AUX __GENMASK(CLOCK_AUX_LAST, CLOCK_AUX)
#define CS_HRES_COARSE 0
#define CS_RAW 1
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index fc0038e..487e345 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -2,6 +2,7 @@
/*
* Generic userspace implementations of gettimeofday() and similar.
*/
+#include <vdso/auxclock.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
@@ -74,7 +75,7 @@ static inline bool vdso_cycles_ok(u64 cycles)
static __always_inline bool vdso_clockid_valid(clockid_t clock)
{
/* Check for negative values or invalid clocks */
- return likely((u32) clock < MAX_CLOCKS);
+ return likely((u32) clock < CLOCK_AUX_LAST);
}
/*
@@ -268,6 +269,48 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
return true;
}
+static __always_inline
+bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts)
+{
+ const struct vdso_clock *vc;
+ u32 seq, idx;
+ u64 sec, ns;
+
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return false;
+
+ idx = clock - CLOCK_AUX;
+ vc = &vd->aux_clock_data[idx];
+
+ do {
+ /*
+ * Open coded function vdso_read_begin() to handle
+ * VDSO_CLOCK_TIMENS. See comment in do_hres().
+ */
+ while ((seq = READ_ONCE(vc->seq)) & 1) {
+ if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
+ vd = __arch_get_vdso_u_timens_data(vd);
+ vc = &vd->aux_clock_data[idx];
+ /* Re-read from the real time data page */
+ continue;
+ }
+ cpu_relax();
+ }
+ smp_rmb();
+
+ /* Auxclock disabled? */
+ if (vc->clock_mode == VDSO_CLOCKMODE_NONE)
+ return false;
+
+ if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns))
+ return false;
+ } while (unlikely(vdso_read_retry(vc, seq)));
+
+ vdso_set_timespec(ts, sec, ns);
+
+ return true;
+}
+
static __always_inline bool
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *ts)
@@ -289,6 +332,8 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
else if (msk & VDSO_RAW)
vc = &vc[CS_RAW];
+ else if (msk & VDSO_AUX)
+ return do_aux(vd, clock, ts);
else
return false;
@@ -433,6 +478,8 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc
* Preserves the behaviour of posix_get_coarse_res().
*/
ns = LOW_RES_NSEC;
+ } else if (msk & VDSO_AUX) {
+ ns = aux_clock_resolution_ns();
} else {
return false;
}
The following commit has been merged into the timers/ptp branch of tip:
Commit-ID: dea57842479175fe0914e363b503ccff378ac54d
Gitweb: https://git.kernel.org/tip/dea57842479175fe0914e363b503ccff378ac54d
Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
AuthorDate: Tue, 01 Jul 2025 10:58:06 +02:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 09 Jul 2025 11:52:35 +02:00
vdso/gettimeofday: Add support for auxiliary clocks
Expose the auxiliary clocks through the vDSO.
Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250701-vdso-auxclock-v1-12-df7d9f87b9b8@linutronix.de
---
include/vdso/datapage.h | 2 ++-
lib/vdso/gettimeofday.c | 49 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index f4c96d9..0253303 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
+#include <uapi/linux/bits.h>
#include <uapi/linux/time.h>
#include <uapi/linux/types.h>
#include <uapi/asm-generic/errno-base.h>
@@ -46,6 +47,7 @@ struct vdso_arch_data {
#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \
BIT(CLOCK_MONOTONIC_COARSE))
#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW))
+#define VDSO_AUX __GENMASK(CLOCK_AUX_LAST, CLOCK_AUX)
#define CS_HRES_COARSE 0
#define CS_RAW 1
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index d9cb1d9..97aa905 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -2,6 +2,7 @@
/*
* Generic userspace implementations of gettimeofday() and similar.
*/
+#include <vdso/auxclock.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
@@ -74,7 +75,7 @@ static inline bool vdso_cycles_ok(u64 cycles)
static __always_inline bool vdso_clockid_valid(clockid_t clock)
{
/* Check for negative values or invalid clocks */
- return likely((u32) clock < MAX_CLOCKS);
+ return likely((u32) clock < CLOCK_AUX_LAST);
}
/*
@@ -268,6 +269,48 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
return true;
}
+static __always_inline
+bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts)
+{
+ const struct vdso_clock *vc;
+ u32 seq, idx;
+ u64 sec, ns;
+
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return false;
+
+ idx = clock - CLOCK_AUX;
+ vc = &vd->aux_clock_data[idx];
+
+ do {
+ /*
+ * Open coded function vdso_read_begin() to handle
+ * VDSO_CLOCK_TIMENS. See comment in do_hres().
+ */
+ while ((seq = READ_ONCE(vc->seq)) & 1) {
+ if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
+ vd = __arch_get_vdso_u_timens_data(vd);
+ vc = &vd->aux_clock_data[idx];
+ /* Re-read from the real time data page */
+ continue;
+ }
+ cpu_relax();
+ }
+ smp_rmb();
+
+ /* Auxclock disabled? */
+ if (vc->clock_mode == VDSO_CLOCKMODE_NONE)
+ return false;
+
+ if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns))
+ return false;
+ } while (unlikely(vdso_read_retry(vc, seq)));
+
+ vdso_set_timespec(ts, sec, ns);
+
+ return true;
+}
+
static __always_inline bool
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *ts)
@@ -289,6 +332,8 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
else if (msk & VDSO_RAW)
vc = &vc[CS_RAW];
+ else if (msk & VDSO_AUX)
+ return do_aux(vd, clock, ts);
else
return false;
@@ -433,6 +478,8 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc
* Preserves the behaviour of posix_get_coarse_res().
*/
ns = LOW_RES_NSEC;
+ } else if (msk & VDSO_AUX) {
+ ns = aux_clock_resolution_ns();
} else {
return false;
}
The following commit has been merged into the timers/ptp branch of tip:
Commit-ID: 7893ea1006fcbb876ddf53ad4ebba4a054add4b2
Gitweb: https://git.kernel.org/tip/7893ea1006fcbb876ddf53ad4ebba4a054add4b2
Author: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
AuthorDate: Tue, 01 Jul 2025 10:58:06 +02:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Mon, 07 Jul 2025 08:58:54 +02:00
vdso/gettimeofday: Add support for auxiliary clocks
Expose the auxiliary clocks through the vDSO.
Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250701-vdso-auxclock-v1-12-df7d9f87b9b8@linutronix.de
---
include/vdso/datapage.h | 2 ++-
lib/vdso/gettimeofday.c | 49 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index f4c96d9..0253303 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
+#include <uapi/linux/bits.h>
#include <uapi/linux/time.h>
#include <uapi/linux/types.h>
#include <uapi/asm-generic/errno-base.h>
@@ -46,6 +47,7 @@ struct vdso_arch_data {
#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \
BIT(CLOCK_MONOTONIC_COARSE))
#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW))
+#define VDSO_AUX __GENMASK(CLOCK_AUX_LAST, CLOCK_AUX)
#define CS_HRES_COARSE 0
#define CS_RAW 1
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index c383878..d6743ed 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -2,6 +2,7 @@
/*
* Generic userspace implementations of gettimeofday() and similar.
*/
+#include <vdso/auxclock.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
@@ -74,7 +75,7 @@ static inline bool vdso_cycles_ok(u64 cycles)
static __always_inline bool vdso_clockid_valid(clockid_t clock)
{
/* Check for negative values or invalid clocks */
- return likely((u32) clock < MAX_CLOCKS);
+ return likely((u32) clock < CLOCK_AUX_LAST);
}
/*
@@ -268,6 +269,48 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc,
return true;
}
+static __always_inline
+bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts)
+{
+ const struct vdso_clock *vc;
+ u32 seq, idx;
+ u64 sec, ns;
+
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
+ return false;
+
+ idx = clock - CLOCK_AUX;
+ vc = &vd->aux_clock_data[idx];
+
+ do {
+ /*
+ * Open coded function vdso_read_begin() to handle
+ * VDSO_CLOCK_TIMENS. See comment in do_hres().
+ */
+ while ((seq = READ_ONCE(vc->seq)) & 1) {
+ if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) {
+ vd = __arch_get_vdso_u_timens_data(vd);
+ vc = &vd->aux_clock_data[idx];
+ /* Re-read from the real time data page */
+ continue;
+ }
+ cpu_relax();
+ }
+ smp_rmb();
+
+ /* Auxclock disabled? */
+ if (vc->clock_mode == VDSO_CLOCKMODE_NONE)
+ return false;
+
+ if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns))
+ return false;
+ } while (unlikely(vdso_read_retry(vc, seq)));
+
+ vdso_set_timespec(ts, sec, ns);
+
+ return true;
+}
+
static __always_inline bool
__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *ts)
@@ -289,6 +332,8 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock,
return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts);
else if (msk & VDSO_RAW)
vc = &vc[CS_RAW];
+ else if (msk & VDSO_AUX)
+ return do_aux(vd, clock, ts);
else
return false;
@@ -433,6 +478,8 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc
* Preserves the behaviour of posix_get_coarse_res().
*/
ns = LOW_RES_NSEC;
+ } else if (msk & VDSO_AUX) {
+ ns = aux_clock_resolution_ns();
} else {
return false;
}
© 2016 - 2025 Red Hat, Inc.