[tip: timers/vdso] timens: Remove dependency on the vDSO

tip-bot2 for Thomas Weißschuh posted 1 patch 1 week ago
include/linux/time_namespace.h   | 28 ++++++++++++++++------------
init/Kconfig                     |  4 +++-
kernel/time/Makefile             |  3 ++-
kernel/time/namespace.c          |  8 ++++----
kernel/time/namespace_internal.h | 15 +++++++++++++++
kernel/time/namespace_vdso.c     | 14 ++++++++++++++
6 files changed, 54 insertions(+), 18 deletions(-)
[tip: timers/vdso] timens: Remove dependency on the vDSO
Posted by tip-bot2 for Thomas Weißschuh 1 week ago
The following commit has been merged into the timers/vdso branch of tip:

Commit-ID:     1b6c89285d37114d7efe8ab04102a542581cd7da
Gitweb:        https://git.kernel.org/tip/1b6c89285d37114d7efe8ab04102a542581cd7da
Author:        Thomas Weißschuh <thomas.weissschuh@linutronix.de>
AuthorDate:    Thu, 26 Mar 2026 12:42:31 +01:00
Committer:     Thomas Gleixner <tglx@kernel.org>
CommitterDate: Thu, 26 Mar 2026 15:44:23 +01:00

timens: Remove dependency on the vDSO

Previously, missing time namespace support in the vDSO meant that time
namespaces needed to be disabled globally. This was expressed in a hard
dependency on the generic vDSO library. This also meant that architectures
without any vDSO or only a stub vDSO could not enable time namespaces.
Now that all architectures using a real vDSO are using the generic library,
that dependency is not necessary anymore.

Remove the dependency and let all architectures enable time namespaces.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260326-vdso-timens-decoupling-v2-2-c82693a7775f@linutronix.de
---
 include/linux/time_namespace.h   | 28 ++++++++++++++++------------
 init/Kconfig                     |  4 +++-
 kernel/time/Makefile             |  3 ++-
 kernel/time/namespace.c          |  8 ++++----
 kernel/time/namespace_internal.h | 15 +++++++++++++++
 kernel/time/namespace_vdso.c     | 14 ++++++++++++++
 6 files changed, 54 insertions(+), 18 deletions(-)

diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h
index 0421bf1..c1de21a 100644
--- a/include/linux/time_namespace.h
+++ b/include/linux/time_namespace.h
@@ -25,7 +25,9 @@ struct time_namespace {
 	struct ucounts		*ucounts;
 	struct ns_common	ns;
 	struct timens_offsets	offsets;
+#ifdef CONFIG_TIME_NS_VDSO
 	struct page		*vvar_page;
+#endif
 	/* If set prevents changing offsets after any task joined namespace. */
 	bool			frozen_offsets;
 } __randomize_layout;
@@ -38,7 +40,6 @@ static inline struct time_namespace *to_time_ns(struct ns_common *ns)
 	return container_of(ns, struct time_namespace, ns);
 }
 void __init time_ns_init(void);
-extern void timens_commit(struct task_struct *tsk, struct time_namespace *ns);
 
 static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
 {
@@ -51,7 +52,6 @@ struct time_namespace *copy_time_ns(u64 flags,
 				    struct time_namespace *old_ns);
 void free_time_ns(struct time_namespace *ns);
 void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk);
-struct page *find_timens_vvar_page(struct vm_area_struct *vma);
 
 static inline void put_time_ns(struct time_namespace *ns)
 {
@@ -115,11 +115,6 @@ static inline void __init time_ns_init(void)
 {
 }
 
-static inline void timens_commit(struct task_struct *tsk,
-				 struct time_namespace *ns)
-{
-}
-
 static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
 {
 	return NULL;
@@ -146,11 +141,6 @@ static inline void timens_on_fork(struct nsproxy *nsproxy,
 	return;
 }
 
-static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
-{
-	return NULL;
-}
-
 static inline void timens_add_monotonic(struct timespec64 *ts) { }
 static inline void timens_add_boottime(struct timespec64 *ts) { }
 
@@ -167,4 +157,18 @@ static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
 }
 #endif
 
+#ifdef CONFIG_TIME_NS_VDSO
+extern void timens_commit(struct task_struct *tsk, struct time_namespace *ns);
+struct page *find_timens_vvar_page(struct vm_area_struct *vma);
+#else /* !CONFIG_TIME_NS_VDSO */
+static inline void timens_commit(struct task_struct *tsk, struct time_namespace *ns)
+{
+}
+
+static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
+{
+	return NULL;
+}
+#endif /* CONFIG_TIME_NS_VDSO */
+
 #endif /* _LINUX_TIMENS_H */
diff --git a/init/Kconfig b/init/Kconfig
index 444ce81..5e710b0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1386,12 +1386,14 @@ config UTS_NS
 
 config TIME_NS
 	bool "TIME namespace"
-	depends on GENERIC_GETTIMEOFDAY
 	default y
 	help
 	  In this namespace boottime and monotonic clocks can be set.
 	  The time will keep going with the same pace.
 
+config TIME_NS_VDSO
+	def_bool TIME_NS && GENERIC_GETTIMEOFDAY
+
 config IPC_NS
 	bool "IPC namespace"
 	depends on (SYSVIPC || POSIX_MQUEUE)
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 662bccb..eaf290c 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -29,6 +29,7 @@ endif
 obj-$(CONFIG_GENERIC_GETTIMEOFDAY)		+= vsyscall.o
 obj-$(CONFIG_DEBUG_FS)				+= timekeeping_debug.o
 obj-$(CONFIG_TEST_UDELAY)			+= test_udelay.o
-obj-$(CONFIG_TIME_NS)				+= namespace.o namespace_vdso.o
+obj-$(CONFIG_TIME_NS)				+= namespace.o
+obj-$(CONFIG_TIME_NS_VDSO)			+= namespace_vdso.o
 obj-$(CONFIG_TEST_CLOCKSOURCE_WATCHDOG)		+= clocksource-wdtest.o
 obj-$(CONFIG_TIME_KUNIT_TEST)			+= time_test.o
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index 903f55a..42302cc 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -93,8 +93,8 @@ static struct time_namespace *clone_time_ns(struct user_namespace *user_ns,
 	if (!ns)
 		goto fail_dec;
 
-	ns->vvar_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
-	if (!ns->vvar_page)
+	err = timens_vdso_alloc_vvar_page(ns);
+	if (err)
 		goto fail_free;
 
 	err = ns_common_init(ns);
@@ -109,7 +109,7 @@ static struct time_namespace *clone_time_ns(struct user_namespace *user_ns,
 	return ns;
 
 fail_free_page:
-	__free_page(ns->vvar_page);
+	timens_vdso_free_vvar_page(ns);
 fail_free:
 	kfree(ns);
 fail_dec:
@@ -146,7 +146,7 @@ void free_time_ns(struct time_namespace *ns)
 	dec_time_namespaces(ns->ucounts);
 	put_user_ns(ns->user_ns);
 	ns_common_free(ns);
-	__free_page(ns->vvar_page);
+	timens_vdso_free_vvar_page(ns);
 	/* Concurrent nstree traversal depends on a grace period. */
 	kfree_rcu(ns, ns.ns_rcu);
 }
diff --git a/kernel/time/namespace_internal.h b/kernel/time/namespace_internal.h
index e85da11..b37ba17 100644
--- a/kernel/time/namespace_internal.h
+++ b/kernel/time/namespace_internal.h
@@ -4,10 +4,25 @@
 
 #include <linux/mutex.h>
 
+struct time_namespace;
+
 /*
  * Protects possibly multiple offsets writers racing each other
  * and tasks entering the namespace.
  */
 extern struct mutex timens_offset_lock;
 
+#ifdef CONFIG_TIME_NS_VDSO
+int timens_vdso_alloc_vvar_page(struct time_namespace *ns);
+void timens_vdso_free_vvar_page(struct time_namespace *ns);
+#else /* !CONFIG_TIME_NS_VDSO */
+static inline int timens_vdso_alloc_vvar_page(struct time_namespace *ns)
+{
+	return 0;
+}
+static inline void timens_vdso_free_vvar_page(struct time_namespace *ns)
+{
+}
+#endif /* CONFIG_TIME_NS_VDSO */
+
 #endif /* _TIME_NAMESPACE_INTERNAL_H */
diff --git a/kernel/time/namespace_vdso.c b/kernel/time/namespace_vdso.c
index 0e154f9..88c075c 100644
--- a/kernel/time/namespace_vdso.c
+++ b/kernel/time/namespace_vdso.c
@@ -144,3 +144,17 @@ void timens_commit(struct task_struct *tsk, struct time_namespace *ns)
 	timens_set_vvar_page(tsk, ns);
 	vdso_join_timens(tsk, ns);
 }
+
+int timens_vdso_alloc_vvar_page(struct time_namespace *ns)
+{
+	ns->vvar_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+	if (!ns->vvar_page)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void timens_vdso_free_vvar_page(struct time_namespace *ns)
+{
+	__free_page(ns->vvar_page);
+}