From: Andrei Vagin <ava...@openvz.org> Introduce offsets for time namespace. They will contain an adjustment needed to convert clocks to/from host's.
Allocate one page for each time namespace that will be premapped into userspace among vvar pages. A new namespace is created with the same offsets as the time namespace of the current process. Signed-off-by: Andrei Vagin <ava...@openvz.org> Co-developed-by: Dmitry Safonov <d...@arista.com> Signed-off-by: Dmitry Safonov <d...@arista.com> --- MAINTAINERS | 1 + include/linux/time_namespace.h | 18 ++++++++++++++++++ include/linux/timens_offsets.h | 10 ++++++++++ kernel/time_namespace.c | 16 ++++++++++++++-- 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 include/linux/timens_offsets.h diff --git a/MAINTAINERS b/MAINTAINERS index 97b7737f5aba..527aee1e616f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12899,6 +12899,7 @@ S: Maintained F: fs/timerfd.c F: include/linux/timer* F: include/linux/time_namespace.h +F: include/linux/timens_offsets.h F: kernel/time_namespace.c F: kernel/time/*timer* diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h index 9507ed7072fe..334c1a1c6607 100644 --- a/include/linux/time_namespace.h +++ b/include/linux/time_namespace.h @@ -8,6 +8,7 @@ #include <linux/nsproxy.h> #include <linux/ns_common.h> #include <linux/err.h> +#include <linux/timens_offsets.h> struct user_namespace; extern struct user_namespace init_user_ns; @@ -39,6 +40,21 @@ 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); +} + +static inline void timens_add_boottime(struct timespec64 *ts) +{ + struct timens_offsets *ns_offsets = current->nsproxy->time_ns->offsets; + + if (ns_offsets) + *ts = timespec64_add(*ts, ns_offsets->boottime); +} #else static inline struct time_namespace *get_time_ns(struct time_namespace *ns) @@ -64,6 +80,8 @@ static inline int timens_on_fork(struct nsproxy *nsproxy, struct task_struct *ts return 0; } +static inline void timens_add_monotonic(struct timespec64 *ts) {} +static inline void timens_add_boottime(struct timespec64 *ts) {} #endif #endif /* _LINUX_TIMENS_H */ diff --git a/include/linux/timens_offsets.h b/include/linux/timens_offsets.h new file mode 100644 index 000000000000..e93aabaa5e45 --- /dev/null +++ b/include/linux/timens_offsets.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_TIME_OFFSETS_H +#define _LINUX_TIME_OFFSETS_H + +struct timens_offsets { + struct timespec64 monotonic; + struct timespec64 boottime; +}; + +#endif diff --git a/kernel/time_namespace.c b/kernel/time_namespace.c index 8fd8384b7261..394a9e168e7c 100644 --- a/kernel/time_namespace.c +++ b/kernel/time_namespace.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/cred.h> #include <linux/err.h> +#include <linux/mm.h> static struct ucounts *inc_time_namespaces(struct user_namespace *ns) { @@ -47,6 +48,7 @@ static struct time_namespace *clone_time_ns(struct user_namespace *user_ns, { struct time_namespace *ns; struct ucounts *ucounts; + struct page *page; int err; err = -ENOSPC; @@ -59,15 +61,24 @@ static struct time_namespace *clone_time_ns(struct user_namespace *user_ns, if (!ns) goto fail_dec; + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) + goto fail_free; + ns->offsets = page_address(page); + if (old_ns->offsets) + memcpy(ns->offsets, old_ns->offsets, sizeof(struct timens_offsets)); + BUILD_BUG_ON(sizeof(*ns->offsets) > PAGE_SIZE); + err = ns_alloc_inum(&ns->ns); if (err) - goto fail_free; + goto fail_page; ns->ucounts = ucounts; ns->ns.ops = &timens_operations; ns->user_ns = get_user_ns(user_ns); return ns; - +fail_page: + free_page((unsigned long)ns->offsets); fail_free: kfree(ns); fail_dec: @@ -95,6 +106,7 @@ void free_time_ns(struct kref *kref) struct time_namespace *ns; ns = container_of(kref, struct time_namespace, kref); + free_page((unsigned long)ns->offsets); dec_time_namespaces(ns->ucounts); put_user_ns(ns->user_ns); ns_free_inum(&ns->ns); -- 2.22.0