Expose the auxiliary clock data so it can be read from the vDSO.

Architectures not using the generic vDSO time framework,
namely SPARC64, are not supported.

Signed-off-by: Thomas Weißschuh <thomas.weisssc...@linutronix.de>
---
 include/linux/timekeeper_internal.h | 13 ++++++++++++
 include/vdso/datapage.h             |  3 +++
 kernel/time/namespace.c             |  5 +++++
 kernel/time/timekeeping.c           | 12 +++++++++++
 kernel/time/vsyscall.c              | 40 +++++++++++++++++++++++++++++++++++++
 5 files changed, 73 insertions(+)

diff --git a/include/linux/timekeeper_internal.h 
b/include/linux/timekeeper_internal.h
index 
ca79938b62f396afd503e0cf06bbecf6f95cfce4..5de2e019399c72246f7d7dfad561c8b3d479dbd1
 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -190,4 +190,17 @@ static inline void update_vsyscall_tz(void)
 }
 #endif
 
+#if defined(CONFIG_GENERIC_TIME_VSYSCALL) && 
defined(CONFIG_GENERIC_GETTIMEOFDAY) && \
+       defined(CONFIG_POSIX_AUX_CLOCKS)
+
+extern void vdso_time_update_aux(struct timekeeper *tk);
+
+#else
+
+static inline void vdso_time_update_aux(struct timekeeper *tk)
+{
+}
+
+#endif /* CONFIG_GENERIC_TIME_VSYSCALL && CONFIG_POSIX_AUX_CLOCKS */
+
 #endif /* _LINUX_TIMEKEEPER_INTERNAL_H */
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h
index 
1864e76e8f691bab10813543880f71bc59afa9c0..f4c96d9ce674abb07ccd8703f1a04da7631c1677
 100644
--- a/include/vdso/datapage.h
+++ b/include/vdso/datapage.h
@@ -38,6 +38,7 @@ struct vdso_arch_data {
 #endif
 
 #define VDSO_BASES     (CLOCK_TAI + 1)
+#define VDSO_BASE_AUX  0
 #define VDSO_HRES      (BIT(CLOCK_REALTIME)            | \
                         BIT(CLOCK_MONOTONIC)           | \
                         BIT(CLOCK_BOOTTIME)            | \
@@ -117,6 +118,7 @@ struct vdso_clock {
  * @arch_data:         architecture specific data (optional, defaults
  *                     to an empty struct)
  * @clock_data:                clocksource related data (array)
+ * @aux_clock_data:    auxiliary clocksource related data (array)
  * @tz_minuteswest:    minutes west of Greenwich
  * @tz_dsttime:                type of DST correction
  * @hrtimer_res:       hrtimer resolution
@@ -133,6 +135,7 @@ struct vdso_time_data {
        struct arch_vdso_time_data      arch_data;
 
        struct vdso_clock               clock_data[CS_BASES];
+       struct vdso_clock               aux_clock_data[MAX_AUX_CLOCKS];
 
        s32                             tz_minuteswest;
        s32                             tz_dsttime;
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index 
e3642278df433c41654ffb6a8043c3fcecc2994a..667452768ed3b50e48e3cfb70f8ef68e4bed9e0b
 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -242,6 +242,11 @@ static void timens_set_vvar_page(struct task_struct *task,
        for (i = 0; i < CS_BASES; i++)
                timens_setup_vdso_clock_data(&vc[i], ns);
 
+       if (IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS)) {
+               for (i = 0; i < ARRAY_SIZE(vdata->aux_clock_data); i++)
+                       timens_setup_vdso_clock_data(&vdata->aux_clock_data[i], 
ns);
+       }
+
 out:
        mutex_unlock(&offset_lock);
 }
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 
6a088378df54d561ecfeafb45a8b54333e11a9a7..928b8e0773f9e1b8fd700f130a700c5908fe6c27
 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -66,11 +66,21 @@ static inline bool tk_get_aux_ts64(unsigned int tkid, 
struct timespec64 *ts)
 {
        return ktime_get_aux_ts64(CLOCK_AUX + tkid - TIMEKEEPER_AUX_FIRST, ts);
 }
+
+static inline bool tk_is_aux(const struct timekeeper *tk)
+{
+       return tk->id >= TIMEKEEPER_AUX_FIRST && tk->id <= TIMEKEEPER_AUX_LAST;
+}
 #else
 static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)
 {
        return false;
 }
+
+static inline bool tk_is_aux(const struct timekeeper *tk)
+{
+       return false;
+}
 #endif
 
 /* flag for if timekeeping is suspended */
@@ -719,6 +729,8 @@ static void timekeeping_update_from_shadow(struct tk_data 
*tkd, unsigned int act
 
                update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono);
                update_fast_timekeeper(&tk->tkr_raw,  &tk_fast_raw);
+       } else if (tk_is_aux(tk)) {
+               vdso_time_update_aux(tk);
        }
 
        if (action & TK_CLOCK_WAS_SET)
diff --git a/kernel/time/vsyscall.c b/kernel/time/vsyscall.c
index 
df6bada2d58ed9a03e5dd3cb4b218983089a2877..62d9701db9135ba4ef377f3f534a9279d7922d2d
 100644
--- a/kernel/time/vsyscall.c
+++ b/kernel/time/vsyscall.c
@@ -136,6 +136,46 @@ void update_vsyscall_tz(void)
        __arch_sync_vdso_time_data(vdata);
 }
 
+#ifdef CONFIG_POSIX_AUX_CLOCKS
+void vdso_time_update_aux(struct timekeeper *tk)
+{
+       struct vdso_time_data *vdata = vdso_k_time_data;
+       struct vdso_timestamp *vdso_ts;
+       struct vdso_clock *vc;
+       s32 clock_mode;
+       u64 nsec;
+
+       vc = &vdata->aux_clock_data[tk->id - TIMEKEEPER_AUX_FIRST];
+       vdso_ts = &vc->basetime[VDSO_BASE_AUX];
+       clock_mode = tk->tkr_mono.clock->vdso_clock_mode;
+       if (!tk->clock_valid)
+               clock_mode = VDSO_CLOCKMODE_NONE;
+
+       /* copy vsyscall data */
+       vdso_write_begin_clock(vc, true);
+
+       vc->clock_mode = clock_mode;
+
+       if (clock_mode != VDSO_CLOCKMODE_NONE) {
+               fill_clock_configuration(vc, &tk->tkr_mono);
+
+               vdso_ts->sec    = tk->xtime_sec;
+
+               nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
+               nsec += tk->offs_aux;
+               vdso_ts->sec += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec);
+               nsec = nsec << tk->tkr_mono.shift;
+               vdso_ts->nsec = nsec;
+       }
+
+       __arch_update_vdso_clock(vc);
+
+       vdso_write_end_clock(vc, true);
+
+       __arch_sync_vdso_time_data(vdata);
+}
+#endif
+
 /**
  * vdso_update_begin - Start of a VDSO update section
  *

-- 
2.50.0


Reply via email to