From: Andrei Vagin <avagin@xxxxxxxxxx> Add monotonic time virtualisation for time namespace. Introduce timespec for monotionic clock into timens offsets and wire clock_gettime() syscall. Signed-off-by: Andrei Vagin <avagin@xxxxxxxxxx> Co-developed-by: Dmitry Safonov <dima@xxxxxxxxxx> Signed-off-by: Dmitry Safonov <dima@xxxxxxxxxx> --- include/linux/time_namespace.h | 8 ++++++++ include/linux/timens_offsets.h | 1 + include/uapi/linux/time.h | 2 ++ kernel/time/posix-stubs.c | 2 ++ kernel/time/posix-timers.c | 11 +++++++++-- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h index b6985aa87479..8f75d34cf34a 100644 --- a/include/linux/time_namespace.h +++ b/include/linux/time_namespace.h @@ -40,6 +40,13 @@ static inline void put_time_ns(struct time_namespace *ns) kref_put(&ns->kref, free_time_ns); } +static inline void timens_add_monotonic(struct timespec64 *ts) +{ + struct timens_offsets *ns_offsets = current->nsproxy->time_ns->offsets; + + if (ns_offsets) + *ts = timespec64_add(*ts, ns_offsets->monotonic_time_offset); +} #else static inline struct time_namespace *get_time_ns(struct time_namespace *ns) @@ -65,6 +72,7 @@ static inline int timens_on_fork(struct nsproxy *nsproxy, struct task_struct *ts return 0; } +static inline void timens_add_monotonic(struct timespec64 *ts) {} #endif #endif /* _LINUX_TIMENS_H */ diff --git a/include/linux/timens_offsets.h b/include/linux/timens_offsets.h index 7d7cb68ea778..248b0c0bb92a 100644 --- a/include/linux/timens_offsets.h +++ b/include/linux/timens_offsets.h @@ -3,6 +3,7 @@ #define _LINUX_TIME_OFFSETS_H struct timens_offsets { + struct timespec64 monotonic_time_offset; }; #endif diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h index 958932effc5e..32abadc68f72 100644 --- a/include/uapi/linux/time.h +++ b/include/uapi/linux/time.h @@ -65,6 +65,8 @@ struct itimerval { #define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC) #define CLOCKS_MONO CLOCK_MONOTONIC +#define CLOCK_TIMENS 1024 + /* * The various flags for setting POSIX.1b interval timers: */ diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c index 67df65f887ac..17c67e0aecd8 100644 --- a/kernel/time/posix-stubs.c +++ b/kernel/time/posix-stubs.c @@ -14,6 +14,7 @@ #include <linux/ktime.h> #include <linux/timekeeping.h> #include <linux/posix-timers.h> +#include <linux/time_namespace.h> #include <linux/compat.h> #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER @@ -77,6 +78,7 @@ int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp) break; case CLOCK_MONOTONIC: ktime_get_ts64(tp); + timens_add_monotonic(tp); break; case CLOCK_BOOTTIME: ktime_get_boottime_ts64(tp); diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 29176635991f..a047d6b7c768 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -30,6 +30,7 @@ #include <linux/hashtable.h> #include <linux/compat.h> #include <linux/nospec.h> +#include <linux/time_namespace.h> #include "timekeeping.h" #include "posix-timers.h" @@ -190,6 +191,8 @@ static int posix_clock_realtime_adj(const clockid_t which_clock, static int posix_ktime_get_ts(clockid_t which_clock, struct timespec64 *tp) { ktime_get_ts64(tp); + if (which_clock & CLOCK_TIMENS) + timens_add_monotonic(tp); return 0; } @@ -199,6 +202,8 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec64 *tp) static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec64 *tp) { ktime_get_raw_ts64(tp); + if (which_clock & CLOCK_TIMENS) + timens_add_monotonic(tp); return 0; } @@ -213,6 +218,8 @@ static int posix_get_monotonic_coarse(clockid_t which_clock, struct timespec64 *tp) { ktime_get_coarse_ts64(tp); + if (which_clock & CLOCK_TIMENS) + timens_add_monotonic(tp); return 0; } @@ -1039,7 +1046,7 @@ SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, if (!kc) return -EINVAL; - error = kc->clock_get(which_clock, &kernel_tp); + error = kc->clock_get(which_clock | CLOCK_TIMENS, &kernel_tp); if (!error && put_timespec64(&kernel_tp, tp)) error = -EFAULT; @@ -1121,7 +1128,7 @@ SYSCALL_DEFINE2(clock_gettime32, clockid_t, which_clock, if (!kc) return -EINVAL; - err = kc->clock_get(which_clock, &ts); + err = kc->clock_get(which_clock | CLOCK_TIMENS, &ts); if (!err && put_old_timespec32(&ts, tp)) err = -EFAULT; -- 2.21.0