1769071acSAndrei Vagin /* SPDX-License-Identifier: GPL-2.0 */
2769071acSAndrei Vagin #ifndef _LINUX_TIMENS_H
3769071acSAndrei Vagin #define _LINUX_TIMENS_H
4769071acSAndrei Vagin
5769071acSAndrei Vagin
6769071acSAndrei Vagin #include <linux/sched.h>
7769071acSAndrei Vagin #include <linux/nsproxy.h>
8769071acSAndrei Vagin #include <linux/ns_common.h>
9769071acSAndrei Vagin #include <linux/err.h>
10058e0529SKent Overstreet #include <linux/time64.h>
11769071acSAndrei Vagin
12769071acSAndrei Vagin struct user_namespace;
13769071acSAndrei Vagin extern struct user_namespace init_user_ns;
14769071acSAndrei Vagin
15*6060ef31SKent Overstreet struct vm_area_struct;
16*6060ef31SKent Overstreet
17af993f58SAndrei Vagin struct timens_offsets {
18af993f58SAndrei Vagin struct timespec64 monotonic;
19af993f58SAndrei Vagin struct timespec64 boottime;
20af993f58SAndrei Vagin };
21af993f58SAndrei Vagin
22769071acSAndrei Vagin struct time_namespace {
23769071acSAndrei Vagin struct user_namespace *user_ns;
24769071acSAndrei Vagin struct ucounts *ucounts;
25769071acSAndrei Vagin struct ns_common ns;
26af993f58SAndrei Vagin struct timens_offsets offsets;
27afaa7b5aSDmitry Safonov struct page *vvar_page;
28afaa7b5aSDmitry Safonov /* If set prevents changing offsets after any task joined namespace. */
29afaa7b5aSDmitry Safonov bool frozen_offsets;
30769071acSAndrei Vagin } __randomize_layout;
31769071acSAndrei Vagin
32769071acSAndrei Vagin extern struct time_namespace init_time_ns;
33769071acSAndrei Vagin
34769071acSAndrei Vagin #ifdef CONFIG_TIME_NS
3570ddf651SDmitry Safonov extern int vdso_join_timens(struct task_struct *task,
3670ddf651SDmitry Safonov struct time_namespace *ns);
3776c12881SChristian Brauner extern void timens_commit(struct task_struct *tsk, struct time_namespace *ns);
3870ddf651SDmitry Safonov
get_time_ns(struct time_namespace * ns)39769071acSAndrei Vagin static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
40769071acSAndrei Vagin {
4128c41efdSKirill Tkhai refcount_inc(&ns->ns.count);
42769071acSAndrei Vagin return ns;
43769071acSAndrei Vagin }
44769071acSAndrei Vagin
45769071acSAndrei Vagin struct time_namespace *copy_time_ns(unsigned long flags,
46769071acSAndrei Vagin struct user_namespace *user_ns,
47769071acSAndrei Vagin struct time_namespace *old_ns);
4828c41efdSKirill Tkhai void free_time_ns(struct time_namespace *ns);
495c62634fSHui Su void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk);
50d6c494e8SJann Horn struct page *find_timens_vvar_page(struct vm_area_struct *vma);
51769071acSAndrei Vagin
put_time_ns(struct time_namespace * ns)52769071acSAndrei Vagin static inline void put_time_ns(struct time_namespace *ns)
53769071acSAndrei Vagin {
5428c41efdSKirill Tkhai if (refcount_dec_and_test(&ns->ns.count))
5528c41efdSKirill Tkhai free_time_ns(ns);
56769071acSAndrei Vagin }
57769071acSAndrei Vagin
5804a8682aSAndrei Vagin void proc_timens_show_offsets(struct task_struct *p, struct seq_file *m);
5904a8682aSAndrei Vagin
6004a8682aSAndrei Vagin struct proc_timens_offset {
6104a8682aSAndrei Vagin int clockid;
6204a8682aSAndrei Vagin struct timespec64 val;
6304a8682aSAndrei Vagin };
6404a8682aSAndrei Vagin
6504a8682aSAndrei Vagin int proc_timens_set_offset(struct file *file, struct task_struct *p,
6604a8682aSAndrei Vagin struct proc_timens_offset *offsets, int n);
6704a8682aSAndrei Vagin
timens_add_monotonic(struct timespec64 * ts)68af993f58SAndrei Vagin static inline void timens_add_monotonic(struct timespec64 *ts)
69af993f58SAndrei Vagin {
70af993f58SAndrei Vagin struct timens_offsets *ns_offsets = ¤t->nsproxy->time_ns->offsets;
71af993f58SAndrei Vagin
72af993f58SAndrei Vagin *ts = timespec64_add(*ts, ns_offsets->monotonic);
73af993f58SAndrei Vagin }
74af993f58SAndrei Vagin
timens_add_boottime(struct timespec64 * ts)75af993f58SAndrei Vagin static inline void timens_add_boottime(struct timespec64 *ts)
76af993f58SAndrei Vagin {
77af993f58SAndrei Vagin struct timens_offsets *ns_offsets = ¤t->nsproxy->time_ns->offsets;
78af993f58SAndrei Vagin
79af993f58SAndrei Vagin *ts = timespec64_add(*ts, ns_offsets->boottime);
80af993f58SAndrei Vagin }
81af993f58SAndrei Vagin
timens_add_boottime_ns(u64 nsec)8231909e33SMichael Weiß static inline u64 timens_add_boottime_ns(u64 nsec)
8331909e33SMichael Weiß {
8431909e33SMichael Weiß struct timens_offsets *ns_offsets = ¤t->nsproxy->time_ns->offsets;
8531909e33SMichael Weiß
8631909e33SMichael Weiß return nsec + timespec64_to_ns(&ns_offsets->boottime);
8731909e33SMichael Weiß }
8831909e33SMichael Weiß
timens_sub_boottime(struct timespec64 * ts)8931909e33SMichael Weiß static inline void timens_sub_boottime(struct timespec64 *ts)
9031909e33SMichael Weiß {
9131909e33SMichael Weiß struct timens_offsets *ns_offsets = ¤t->nsproxy->time_ns->offsets;
9231909e33SMichael Weiß
9331909e33SMichael Weiß *ts = timespec64_sub(*ts, ns_offsets->boottime);
9431909e33SMichael Weiß }
9531909e33SMichael Weiß
9689dd8eecSAndrei Vagin ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim,
9789dd8eecSAndrei Vagin struct timens_offsets *offsets);
9889dd8eecSAndrei Vagin
timens_ktime_to_host(clockid_t clockid,ktime_t tim)9989dd8eecSAndrei Vagin static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
10089dd8eecSAndrei Vagin {
10189dd8eecSAndrei Vagin struct time_namespace *ns = current->nsproxy->time_ns;
10289dd8eecSAndrei Vagin
10389dd8eecSAndrei Vagin if (likely(ns == &init_time_ns))
10489dd8eecSAndrei Vagin return tim;
10589dd8eecSAndrei Vagin
10689dd8eecSAndrei Vagin return do_timens_ktime_to_host(clockid, tim, &ns->offsets);
10789dd8eecSAndrei Vagin }
10889dd8eecSAndrei Vagin
109769071acSAndrei Vagin #else
vdso_join_timens(struct task_struct * task,struct time_namespace * ns)11070ddf651SDmitry Safonov static inline int vdso_join_timens(struct task_struct *task,
11170ddf651SDmitry Safonov struct time_namespace *ns)
11270ddf651SDmitry Safonov {
11370ddf651SDmitry Safonov return 0;
11470ddf651SDmitry Safonov }
11570ddf651SDmitry Safonov
timens_commit(struct task_struct * tsk,struct time_namespace * ns)11676c12881SChristian Brauner static inline void timens_commit(struct task_struct *tsk,
11776c12881SChristian Brauner struct time_namespace *ns)
11876c12881SChristian Brauner {
11976c12881SChristian Brauner }
12076c12881SChristian Brauner
get_time_ns(struct time_namespace * ns)121769071acSAndrei Vagin static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
122769071acSAndrei Vagin {
123769071acSAndrei Vagin return NULL;
124769071acSAndrei Vagin }
125769071acSAndrei Vagin
put_time_ns(struct time_namespace * ns)126769071acSAndrei Vagin static inline void put_time_ns(struct time_namespace *ns)
127769071acSAndrei Vagin {
128769071acSAndrei Vagin }
129769071acSAndrei Vagin
130769071acSAndrei Vagin static inline
copy_time_ns(unsigned long flags,struct user_namespace * user_ns,struct time_namespace * old_ns)131769071acSAndrei Vagin struct time_namespace *copy_time_ns(unsigned long flags,
132769071acSAndrei Vagin struct user_namespace *user_ns,
133769071acSAndrei Vagin struct time_namespace *old_ns)
134769071acSAndrei Vagin {
135769071acSAndrei Vagin if (flags & CLONE_NEWTIME)
136769071acSAndrei Vagin return ERR_PTR(-EINVAL);
137769071acSAndrei Vagin
138769071acSAndrei Vagin return old_ns;
139769071acSAndrei Vagin }
140769071acSAndrei Vagin
timens_on_fork(struct nsproxy * nsproxy,struct task_struct * tsk)1415c62634fSHui Su static inline void timens_on_fork(struct nsproxy *nsproxy,
142769071acSAndrei Vagin struct task_struct *tsk)
143769071acSAndrei Vagin {
1445c62634fSHui Su return;
145769071acSAndrei Vagin }
146769071acSAndrei Vagin
find_timens_vvar_page(struct vm_area_struct * vma)147d6c494e8SJann Horn static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
148d6c494e8SJann Horn {
149d6c494e8SJann Horn return NULL;
150d6c494e8SJann Horn }
151d6c494e8SJann Horn
timens_add_monotonic(struct timespec64 * ts)152af993f58SAndrei Vagin static inline void timens_add_monotonic(struct timespec64 *ts) { }
timens_add_boottime(struct timespec64 * ts)153af993f58SAndrei Vagin static inline void timens_add_boottime(struct timespec64 *ts) { }
15431909e33SMichael Weiß
timens_add_boottime_ns(u64 nsec)15531909e33SMichael Weiß static inline u64 timens_add_boottime_ns(u64 nsec)
15631909e33SMichael Weiß {
15731909e33SMichael Weiß return nsec;
15831909e33SMichael Weiß }
15931909e33SMichael Weiß
timens_sub_boottime(struct timespec64 * ts)16031909e33SMichael Weiß static inline void timens_sub_boottime(struct timespec64 *ts) { }
16131909e33SMichael Weiß
timens_ktime_to_host(clockid_t clockid,ktime_t tim)16289dd8eecSAndrei Vagin static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
16389dd8eecSAndrei Vagin {
16489dd8eecSAndrei Vagin return tim;
16589dd8eecSAndrei Vagin }
166769071acSAndrei Vagin #endif
167769071acSAndrei Vagin
168769071acSAndrei Vagin #endif /* _LINUX_TIMENS_H */
169