From a5ccec8fd10efa50a3fd4444915a2abff31f2535 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 27 Feb 2026 23:17:11 -0800 Subject: [PATCH 01/51] vdso/datapage: Correct struct member kernel-doc Remove the "[]" array indicators from the struct member descriptions to avoid kernel-doc warnings. Warning: include/vdso/datapage.h:107 struct member 'basetime' not described in 'vdso_clock' Warning: include/vdso/datapage.h:107 struct member 'offset' not described in 'vdso_clock' Signed-off-by: Randy Dunlap Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260228071711.2663851-1-rdunlap@infradead.org --- include/vdso/datapage.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index 23c39b96190f..07c2e086d8f4 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -80,8 +80,8 @@ struct vdso_timestamp { * @mask: clocksource mask * @mult: clocksource multiplier * @shift: clocksource shift - * @basetime[clock_id]: basetime per clock_id - * @offset[clock_id]: time namespace offset per clock_id + * @basetime: basetime per clock_id + * @offset: time namespace offset per clock_id * * See also struct vdso_time_data for basic access and ordering information as * struct vdso_clock is used there. From 56f85f67b3e20b105fa23bf97bfc8b6d5cdbbef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 2 Mar 2026 08:58:37 +0100 Subject: [PATCH 02/51] x86/vdso: Use 32-bit CHECKFLAGS for compat vDSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building the compat vDSO the CHECKFLAGS from the 64-bit kernel are used. These are combined with the 32-bit CFLAGS. This confuses sparse, producing false-positive warnings or potentially missing real issues. Manually override the CHECKFLAGS for the compat vDSO with the correct 32-bit configuration. Reported-by: Sun Jian Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Acked-by: Arnd Bergmann Link: https://patch.msgid.link/20260302-vdso-compat-checkflags-v2-1-78e55baa58ba@linutronix.de Closes: https://lore.kernel.org/lkml/20260114084529.1676356-1-sun.jian.kdev@gmail.com/ Closes: https://lore.kernel.org/lkml/20260117215542.342638347@kernel.org/ Closes: https://lore.kernel.org/r/202602111941.PIhubgrb-lkp@intel.com/ --- arch/x86/entry/vdso/vdso32/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/entry/vdso/vdso32/Makefile b/arch/x86/entry/vdso/vdso32/Makefile index add6afb484ba..ded4fc6a48cd 100644 --- a/arch/x86/entry/vdso/vdso32/Makefile +++ b/arch/x86/entry/vdso/vdso32/Makefile @@ -15,6 +15,10 @@ flags-y := -DBUILD_VDSO32 -m32 -mregparm=0 flags-$(CONFIG_X86_64) += -include $(src)/fake_32bit_build.h flags-remove-y := -m64 +# Checker flags +CHECKFLAGS := $(subst -m64,-m32,$(CHECKFLAGS)) +CHECKFLAGS := $(subst -D__x86_64__,-D__i386__,$(CHECKFLAGS)) + # The location of this include matters! include $(src)/../common/Makefile.include From 273aaa8ef8e347c08865effcd8917e20f049e612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 2 Mar 2026 08:58:38 +0100 Subject: [PATCH 03/51] sparc64: vdso: Use 32-bit CHECKFLAGS for compat vDSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building the compat vDSO the CHECKFLAGS from the 64-bit kernel are used. These are combined with the 32-bit CFLAGS. This confuses sparse, producing false-positive warnings or potentially missing real issues. Manually override the CHECKFLAGS for the compat vDSO with the correct 32-bit configuration. Reported-by: kernel test robot Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Acked-by: Arnd Bergmann Link: https://patch.msgid.link/20260302-vdso-compat-checkflags-v2-2-78e55baa58ba@linutronix.de Closes: https://lore.kernel.org/lkml/202511030021.9v1mIgts-lkp@intel.com/ --- arch/sparc/vdso/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index 683b2d408224..d2811f17af07 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -90,6 +90,9 @@ KBUILD_CFLAGS_32 += -DDISABLE_BRANCH_PROFILING KBUILD_CFLAGS_32 += -mv8plus $(obj)/vdso32.so.dbg: KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) +CHECKFLAGS_32 := $(filter-out -m64 -D__sparc_v9__ -D__arch64__, $(CHECKFLAGS)) -m32 +$(obj)/vdso32.so.dbg: CHECKFLAGS = $(CHECKFLAGS_32) + $(obj)/vdso32.so.dbg: FORCE \ $(obj)/vdso32/vdso32.lds \ $(obj)/vdso32/vclock_gettime.o \ From 08b5dcb6139975f3fd754c27f4943720c3c43ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 2 Mar 2026 08:58:39 +0100 Subject: [PATCH 04/51] s390: Add -m64 to KBUILD_CPPFLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some non-code files, like linkescripts, are preprocessed with the C preprocessor and make use of regular kernel headers. As -m64 is not passed to those preprocessor invocations this leads to an inconsistency between __BITS_PER_LONG and the C type 'long'. An upcoming consistency check will be tripped by this. Make sure -m64 is also defined for those preprocessing steps. As KBUILD_CPPFLAGS is inherited by both KBUILD_AFLAGS and KBUILD_CFLAGS, drop -m64 from these variables. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20260302-vdso-compat-checkflags-v2-3-78e55baa58ba@linutronix.de --- arch/s390/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/s390/Makefile b/arch/s390/Makefile index d78ad6885ca2..02bc948a4a56 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -12,8 +12,7 @@ LD_BFD := elf64-s390 KBUILD_LDFLAGS := -m elf64_s390 KBUILD_AFLAGS_MODULE += -fPIC KBUILD_CFLAGS_MODULE += -fPIC -KBUILD_AFLAGS += -m64 -KBUILD_CFLAGS += -m64 +KBUILD_CPPFLAGS += -m64 KBUILD_CFLAGS += -fPIC LDFLAGS_vmlinux := $(call ld-option,-no-pie) extra_tools := relocs From 9b444349a2e96745fc172e161539594ee1f0239e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 2 Mar 2026 08:58:40 +0100 Subject: [PATCH 05/51] powerpc/audit: Directly include unistd_32.h from compat_audit.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This source file undefines '__powerpc64__' to get the 32-bit system call numbers from asm/unistd.h. However this symbol is also evaluated by other headers, among them is asm/bitsperlong.h. The undefinition leads to an inconsistency between __BITS_PER_LONG and the C type 'long'. An upcoming consistency check will be tripped by this. Directly include asm/unistd_32.h to get access to the 32-bit system call numbers instead. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20260302-vdso-compat-checkflags-v2-4-78e55baa58ba@linutronix.de --- arch/powerpc/kernel/compat_audit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c index 57b38c592b9f..b4d81a57b2d9 100644 --- a/arch/powerpc/kernel/compat_audit.c +++ b/arch/powerpc/kernel/compat_audit.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#undef __powerpc64__ #include -#include +#include #include "audit_32.h" From 62357a5888ea6ef81f718eee20ad962a1101fb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 2 Mar 2026 08:58:41 +0100 Subject: [PATCH 06/51] asm-generic/bitsperlong.h: Add sanity checks for __BITS_PER_LONG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value of __BITS_PER_LONG from architecture-specific logic should always match the generic one if that is available. It should also match the actual C type 'long'. Mismatches can happen for example when building the compat vDSO. Either during the compilation, see commit 9a6d3ff10f7f ("arm64: uapi: Provide correct __BITS_PER_LONG for the compat vDSO"), or when running sparse when mismatched CHECKFLAGS are inherited from the kernel build. Add some consistency checks which detect such issues early and clearly. The kernel-internal BITS_PER_LONG is not checked as it is derived from CONFIG_64BIT and therefore breaks for the compat vDSO. See the similar, deactivated check above. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Acked-by: Arnd Bergmann Link: https://patch.msgid.link/20260302-vdso-compat-checkflags-v2-5-78e55baa58ba@linutronix.de --- include/asm-generic/bitsperlong.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h index 1023e2a4bd37..90e8aeebfd2f 100644 --- a/include/asm-generic/bitsperlong.h +++ b/include/asm-generic/bitsperlong.h @@ -19,6 +19,15 @@ #error Inconsistent word size. Check asm/bitsperlong.h #endif +#if __CHAR_BIT__ * __SIZEOF_LONG__ != __BITS_PER_LONG +#error Inconsistent word size. Check asm/bitsperlong.h +#endif + +#ifndef __ASSEMBLER__ +_Static_assert(sizeof(long) * 8 == __BITS_PER_LONG, + "Inconsistent word size. Check asm/bitsperlong.h"); +#endif + #ifndef BITS_PER_LONG_LONG #define BITS_PER_LONG_LONG 64 #endif From dc432ab7130bb39f5a351281a02d4bc61e85a14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:48:58 +0100 Subject: [PATCH 07/51] vdso/datastore: Reduce scope of some variables in vvar_fault() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These variables are only used inside a single branch. Move their declarations there. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Reviewed-by: Christophe Leroy (CS GROUP) Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-1-d8eb3b0e1410@linutronix.de --- lib/vdso/datastore.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c index a565c30c71a0..2cca4e84e5b5 100644 --- a/lib/vdso/datastore.c +++ b/lib/vdso/datastore.c @@ -41,8 +41,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *timens_page = find_timens_vvar_page(vma); - unsigned long addr, pfn; - vm_fault_t err; + unsigned long pfn; switch (vmf->pgoff) { case VDSO_TIME_PAGE_OFFSET: @@ -54,6 +53,9 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, * Fault in VVAR page too, since it will be accessed * to get clock data anyway. */ + unsigned long addr; + vm_fault_t err; + addr = vmf->address + VDSO_TIMENS_PAGE_OFFSET * PAGE_SIZE; err = vmf_insert_pfn(vma, addr, pfn); if (unlikely(err & VM_FAULT_ERROR)) From c0c9439ba30738104cdf1a50f82c7c189729f3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:48:59 +0100 Subject: [PATCH 08/51] vdso/datastore: Drop inclusion of linux/mmap_lock.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This header is unnecessary and together with some upcoming changes would introduce compiler warnings. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Reviewed-by: Christophe Leroy (CS GROUP) Link: https://lore.kernel.org/lkml/20250916-mm-rcuwait-v1-1-39a3beea6ec3@linutronix.de/ Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-2-d8eb3b0e1410@linutronix.de --- lib/vdso/datastore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c index 2cca4e84e5b5..7377fcb6e1df 100644 --- a/lib/vdso/datastore.c +++ b/lib/vdso/datastore.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include -#include #include #include #include From 05988dba11791ccbb458254484826b32f17f4ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:00 +0100 Subject: [PATCH 09/51] vdso/datastore: Allocate data pages dynamically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocating the data pages as part of the kernel image does not work on SPARC. The MMU will raise a fault when userspace tries to access them. Allocate the data pages through the page allocator instead. Unused pages in the vDSO VMA are still allocated to keep the virtual addresses aligned. Switch the mapping from PFNs to 'struct page' as that is required for dynamically allocated pages. This also aligns the allocation of the datapages with the code pages and is a prerequisite for mlockall() support. VM_MIXEDMAP is necessary for the call to vmf_insert_page() in the timens prefault path to work. The data pages need to be order-0, non-compound pages so that the mapping to userspace and the different orderings work. These pages are also used by the timekeeping, random pool and architecture initialization code. Some of these are running before the page allocator is available. To keep these subsytems working without changes, introduce early, statically data storage which will then replaced by the real one as soon as that is available. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Reviewed-by: Christophe Leroy (CS GROUP) Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-3-d8eb3b0e1410@linutronix.de --- include/linux/vdso_datastore.h | 6 +++ init/main.c | 2 + lib/vdso/datastore.c | 92 ++++++++++++++++++++++------------ 3 files changed, 68 insertions(+), 32 deletions(-) diff --git a/include/linux/vdso_datastore.h b/include/linux/vdso_datastore.h index a91fa24b06e0..0b530428db71 100644 --- a/include/linux/vdso_datastore.h +++ b/include/linux/vdso_datastore.h @@ -2,9 +2,15 @@ #ifndef _LINUX_VDSO_DATASTORE_H #define _LINUX_VDSO_DATASTORE_H +#ifdef CONFIG_HAVE_GENERIC_VDSO #include extern const struct vm_special_mapping vdso_vvar_mapping; struct vm_area_struct *vdso_install_vvar_mapping(struct mm_struct *mm, unsigned long addr); +void __init vdso_setup_data_pages(void); +#else /* !CONFIG_HAVE_GENERIC_VDSO */ +static inline void vdso_setup_data_pages(void) { } +#endif /* CONFIG_HAVE_GENERIC_VDSO */ + #endif /* _LINUX_VDSO_DATASTORE_H */ diff --git a/init/main.c b/init/main.c index 1cb395dd94e4..de867b2693d2 100644 --- a/init/main.c +++ b/init/main.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -1119,6 +1120,7 @@ void start_kernel(void) srcu_init(); hrtimers_init(); softirq_init(); + vdso_setup_data_pages(); timekeeping_init(); time_init(); diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c index 7377fcb6e1df..faebf5b7cd6e 100644 --- a/lib/vdso/datastore.c +++ b/lib/vdso/datastore.c @@ -1,52 +1,79 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include +#include #include #include #include #include #include -/* - * The vDSO data page. - */ +static u8 vdso_initdata[VDSO_NR_PAGES * PAGE_SIZE] __aligned(PAGE_SIZE) __initdata = {}; + #ifdef CONFIG_GENERIC_GETTIMEOFDAY -static union { - struct vdso_time_data data; - u8 page[PAGE_SIZE]; -} vdso_time_data_store __page_aligned_data; -struct vdso_time_data *vdso_k_time_data = &vdso_time_data_store.data; -static_assert(sizeof(vdso_time_data_store) == PAGE_SIZE); +struct vdso_time_data *vdso_k_time_data __refdata = + (void *)&vdso_initdata[VDSO_TIME_PAGE_OFFSET * PAGE_SIZE]; + +static_assert(sizeof(struct vdso_time_data) <= PAGE_SIZE); #endif /* CONFIG_GENERIC_GETTIMEOFDAY */ #ifdef CONFIG_VDSO_GETRANDOM -static union { - struct vdso_rng_data data; - u8 page[PAGE_SIZE]; -} vdso_rng_data_store __page_aligned_data; -struct vdso_rng_data *vdso_k_rng_data = &vdso_rng_data_store.data; -static_assert(sizeof(vdso_rng_data_store) == PAGE_SIZE); +struct vdso_rng_data *vdso_k_rng_data __refdata = + (void *)&vdso_initdata[VDSO_RNG_PAGE_OFFSET * PAGE_SIZE]; + +static_assert(sizeof(struct vdso_rng_data) <= PAGE_SIZE); #endif /* CONFIG_VDSO_GETRANDOM */ #ifdef CONFIG_ARCH_HAS_VDSO_ARCH_DATA -static union { - struct vdso_arch_data data; - u8 page[VDSO_ARCH_DATA_SIZE]; -} vdso_arch_data_store __page_aligned_data; -struct vdso_arch_data *vdso_k_arch_data = &vdso_arch_data_store.data; +struct vdso_arch_data *vdso_k_arch_data __refdata = + (void *)&vdso_initdata[VDSO_ARCH_PAGES_START * PAGE_SIZE]; #endif /* CONFIG_ARCH_HAS_VDSO_ARCH_DATA */ +void __init vdso_setup_data_pages(void) +{ + unsigned int order = get_order(VDSO_NR_PAGES * PAGE_SIZE); + struct page *pages; + + /* + * Allocate the data pages dynamically. SPARC does not support mapping + * static pages to be mapped into userspace. + * It is also a requirement for mlockall() support. + * + * Do not use folios. In time namespaces the pages are mapped in a different order + * to userspace, which is not handled by the folio optimizations in finish_fault(). + */ + pages = alloc_pages(GFP_KERNEL, order); + if (!pages) + panic("Unable to allocate VDSO storage pages"); + + /* The pages are mapped one-by-one into userspace and each one needs to be refcounted. */ + split_page(pages, order); + + /* Move the data already written by other subsystems to the new pages */ + memcpy(page_address(pages), vdso_initdata, VDSO_NR_PAGES * PAGE_SIZE); + + if (IS_ENABLED(CONFIG_GENERIC_GETTIMEOFDAY)) + vdso_k_time_data = page_address(pages + VDSO_TIME_PAGE_OFFSET); + + if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + vdso_k_rng_data = page_address(pages + VDSO_RNG_PAGE_OFFSET); + + if (IS_ENABLED(CONFIG_ARCH_HAS_VDSO_ARCH_DATA)) + vdso_k_arch_data = page_address(pages + VDSO_ARCH_PAGES_START); +} + static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf) { - struct page *timens_page = find_timens_vvar_page(vma); - unsigned long pfn; + struct page *page, *timens_page; + + timens_page = find_timens_vvar_page(vma); switch (vmf->pgoff) { case VDSO_TIME_PAGE_OFFSET: if (!IS_ENABLED(CONFIG_GENERIC_GETTIMEOFDAY)) return VM_FAULT_SIGBUS; - pfn = __phys_to_pfn(__pa_symbol(vdso_k_time_data)); + page = virt_to_page(vdso_k_time_data); if (timens_page) { /* * Fault in VVAR page too, since it will be accessed @@ -56,10 +83,10 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, vm_fault_t err; addr = vmf->address + VDSO_TIMENS_PAGE_OFFSET * PAGE_SIZE; - err = vmf_insert_pfn(vma, addr, pfn); + err = vmf_insert_page(vma, addr, page); if (unlikely(err & VM_FAULT_ERROR)) return err; - pfn = page_to_pfn(timens_page); + page = timens_page; } break; case VDSO_TIMENS_PAGE_OFFSET: @@ -72,24 +99,25 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, */ if (!IS_ENABLED(CONFIG_TIME_NS) || !timens_page) return VM_FAULT_SIGBUS; - pfn = __phys_to_pfn(__pa_symbol(vdso_k_time_data)); + page = virt_to_page(vdso_k_time_data); break; case VDSO_RNG_PAGE_OFFSET: if (!IS_ENABLED(CONFIG_VDSO_GETRANDOM)) return VM_FAULT_SIGBUS; - pfn = __phys_to_pfn(__pa_symbol(vdso_k_rng_data)); + page = virt_to_page(vdso_k_rng_data); break; case VDSO_ARCH_PAGES_START ... VDSO_ARCH_PAGES_END: if (!IS_ENABLED(CONFIG_ARCH_HAS_VDSO_ARCH_DATA)) return VM_FAULT_SIGBUS; - pfn = __phys_to_pfn(__pa_symbol(vdso_k_arch_data)) + - vmf->pgoff - VDSO_ARCH_PAGES_START; + page = virt_to_page(vdso_k_arch_data) + vmf->pgoff - VDSO_ARCH_PAGES_START; break; default: return VM_FAULT_SIGBUS; } - return vmf_insert_pfn(vma, vmf->address, pfn); + get_page(page); + vmf->page = page; + return 0; } const struct vm_special_mapping vdso_vvar_mapping = { @@ -101,7 +129,7 @@ struct vm_area_struct *vdso_install_vvar_mapping(struct mm_struct *mm, unsigned { return _install_special_mapping(mm, addr, VDSO_NR_PAGES * PAGE_SIZE, VM_READ | VM_MAYREAD | VM_IO | VM_DONTDUMP | - VM_PFNMAP | VM_SEALED_SYSMAP, + VM_MIXEDMAP | VM_SEALED_SYSMAP, &vdso_vvar_mapping); } From acc4f131d5d57c2aa89db914aeb6f7bb0ab4eb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:01 +0100 Subject: [PATCH 10/51] sparc64: vdso: Link with -z noexecstack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vDSO stack does not need to be executable. Prevent the linker from creating executable. For more background see commit ffcf9c5700e4 ("x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments"). Also prevent the following warning from the linker: sparc64-linux-ld: warning: arch/sparc/vdso/vdso-note.o: missing .note.GNU-stack section implies executable stack sparc64-linux-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker Fixes: 9a08862a5d2e ("vDSO for sparc") Suggested-by: Arnd Bergmann Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://lore.kernel.org/lkml/20250707144726.4008707-1-arnd@kernel.org/ Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-4-d8eb3b0e1410@linutronix.de --- arch/sparc/vdso/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index d2811f17af07..aaef9174f375 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -107,4 +107,4 @@ quiet_cmd_vdso = VDSO $@ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ -T $(filter %.lds,$^) $(filter %.o,$^) -VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined +VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack From 9fc4fe6e142ae574a494ae4018b3992b7d5b7d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:02 +0100 Subject: [PATCH 11/51] sparc64: vdso: Remove obsolete "fake section table" reservation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the vDSO logic was copied from x86 to SPARC some unused remnants of the fake section handling were copied, too. In x86 the original fake section handling had already been removed incompletely in commit da861e18eccc ("x86, vdso: Get rid of the fake section mechanism"). On x86 the reservation was only cleaned up in commit 24b7c77bbb24 ("x86/vdso: Remove obsolete "fake section table" reservation"). Remove the reservation for SPARC, too. Fixes: 9a08862a5d2e ("vDSO for sparc") Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-5-d8eb3b0e1410@linutronix.de --- arch/sparc/vdso/vdso-layout.lds.S | 21 --------------------- arch/sparc/vdso/vdso2c.c | 8 -------- 2 files changed, 29 deletions(-) diff --git a/arch/sparc/vdso/vdso-layout.lds.S b/arch/sparc/vdso/vdso-layout.lds.S index d31e57e8a3bb..9e0804789d11 100644 --- a/arch/sparc/vdso/vdso-layout.lds.S +++ b/arch/sparc/vdso/vdso-layout.lds.S @@ -4,16 +4,6 @@ * This script controls its layout. */ -#if defined(BUILD_VDSO64) -# define SHDR_SIZE 64 -#elif defined(BUILD_VDSO32) -# define SHDR_SIZE 40 -#else -# error unknown VDSO target -#endif - -#define NUM_FAKE_SHDRS 7 - SECTIONS { /* @@ -47,19 +37,8 @@ SECTIONS *(.bss*) *(.dynbss*) *(.gnu.linkonce.b.*) - - /* - * Ideally this would live in a C file: kept in here for - * compatibility with x86-64. - */ - VDSO_FAKE_SECTION_TABLE_START = .; - . = . + NUM_FAKE_SHDRS * SHDR_SIZE; - VDSO_FAKE_SECTION_TABLE_END = .; } :text - .fake_shstrtab : { *(.fake_shstrtab) } :text - - .note : { *(.note.*) } :text :note .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr diff --git a/arch/sparc/vdso/vdso2c.c b/arch/sparc/vdso/vdso2c.c index dc81240aab6f..b97af5ec9f35 100644 --- a/arch/sparc/vdso/vdso2c.c +++ b/arch/sparc/vdso/vdso2c.c @@ -61,8 +61,6 @@ const char *outfilename; /* Symbols that we need in vdso2c. */ enum { sym_vvar_start, - sym_VDSO_FAKE_SECTION_TABLE_START, - sym_VDSO_FAKE_SECTION_TABLE_END, }; struct vdso_sym { @@ -72,12 +70,6 @@ struct vdso_sym { struct vdso_sym required_syms[] = { [sym_vvar_start] = {"vvar_start", 1}, - [sym_VDSO_FAKE_SECTION_TABLE_START] = { - "VDSO_FAKE_SECTION_TABLE_START", 0 - }, - [sym_VDSO_FAKE_SECTION_TABLE_END] = { - "VDSO_FAKE_SECTION_TABLE_END", 0 - }, }; __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) From 7b4ee085e760cf77993ceca2b7d6a76ab0870d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:03 +0100 Subject: [PATCH 12/51] sparc64: vdso: Replace code patching with runtime conditional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patching logic is unnecessarily complicated and stands in the way of the adoption of the generic vDSO framework. Replace it by a simple runtime switch, similar to other architectures. Suggested-by: Thomas Gleixner Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://lore.kernel.org/lkml/87ecu9tfhw.ffs@tglx/ Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-6-d8eb3b0e1410@linutronix.de --- arch/sparc/vdso/vclock_gettime.c | 112 +-------------- arch/sparc/vdso/vdso.lds.S | 2 - arch/sparc/vdso/vdso32/vdso32.lds.S | 2 - arch/sparc/vdso/vma.c | 204 ---------------------------- 4 files changed, 4 insertions(+), 316 deletions(-) diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index 79607804ea1b..643608bffe13 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -148,17 +148,11 @@ notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) u64 v; u64 cycles; - cycles = vread_tick(); - v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; - return v * vvar->clock.mult; -} + if (likely(vvar->vclock_mode == VCLOCK_STICK)) + cycles = vread_tick_stick(); + else + cycles = vread_tick(); -notrace static __always_inline u64 vgetsns_stick(struct vvar_data *vvar) -{ - u64 v; - u64 cycles; - - cycles = vread_tick_stick(); v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; return v * vvar->clock.mult; } @@ -183,26 +177,6 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar, return 0; } -notrace static __always_inline int do_realtime_stick(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - u64 ns; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->wall_time_sec; - ns = vvar->wall_time_snsec; - ns += vgetsns_stick(vvar); - ns = __shr64(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - notrace static __always_inline int do_monotonic(struct vvar_data *vvar, struct __kernel_old_timespec *ts) { @@ -223,26 +197,6 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar, return 0; } -notrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - u64 ns; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->monotonic_time_sec; - ns = vvar->monotonic_time_snsec; - ns += vgetsns_stick(vvar); - ns = __shr64(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - notrace static int do_realtime_coarse(struct vvar_data *vvar, struct __kernel_old_timespec *ts) { @@ -298,31 +252,6 @@ int clock_gettime(clockid_t, struct __kernel_old_timespec *) __attribute__((weak, alias("__vdso_clock_gettime"))); -notrace int -__vdso_clock_gettime_stick(clockid_t clock, struct __kernel_old_timespec *ts) -{ - struct vvar_data *vvd = get_vvar_data(); - - switch (clock) { - case CLOCK_REALTIME: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_realtime_stick(vvd, ts); - case CLOCK_MONOTONIC: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_monotonic_stick(vvd, ts); - case CLOCK_REALTIME_COARSE: - return do_realtime_coarse(vvd, ts); - case CLOCK_MONOTONIC_COARSE: - return do_monotonic_coarse(vvd, ts); - } - /* - * Unknown clock ID ? Fall back to the syscall. - */ - return vdso_fallback_gettime(clock, ts); -} - notrace int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { @@ -358,36 +287,3 @@ __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) int gettimeofday(struct __kernel_old_timeval *, struct timezone *) __attribute__((weak, alias("__vdso_gettimeofday"))); - -notrace int -__vdso_gettimeofday_stick(struct __kernel_old_timeval *tv, struct timezone *tz) -{ - struct vvar_data *vvd = get_vvar_data(); - - if (likely(vvd->vclock_mode != VCLOCK_NONE)) { - if (likely(tv != NULL)) { - union tstv_t { - struct __kernel_old_timespec ts; - struct __kernel_old_timeval tv; - } *tstv = (union tstv_t *) tv; - do_realtime_stick(vvd, &tstv->ts); - /* - * Assign before dividing to ensure that the division is - * done in the type of tv_usec, not tv_nsec. - * - * There cannot be > 1 billion usec in a second: - * do_realtime() has already distributed such overflow - * into tv_sec. So we can assign it to an int safely. - */ - tstv->tv.tv_usec = tstv->ts.tv_nsec; - tstv->tv.tv_usec /= 1000; - } - if (unlikely(tz != NULL)) { - /* Avoid memcpy. Some old compilers fail to inline it */ - tz->tz_minuteswest = vvd->tz_minuteswest; - tz->tz_dsttime = vvd->tz_dsttime; - } - return 0; - } - return vdso_fallback_gettimeofday(tv, tz); -} diff --git a/arch/sparc/vdso/vdso.lds.S b/arch/sparc/vdso/vdso.lds.S index 629ab6900df7..f3caa29a331c 100644 --- a/arch/sparc/vdso/vdso.lds.S +++ b/arch/sparc/vdso/vdso.lds.S @@ -18,10 +18,8 @@ VERSION { global: clock_gettime; __vdso_clock_gettime; - __vdso_clock_gettime_stick; gettimeofday; __vdso_gettimeofday; - __vdso_gettimeofday_stick; local: *; }; } diff --git a/arch/sparc/vdso/vdso32/vdso32.lds.S b/arch/sparc/vdso/vdso32/vdso32.lds.S index 218930fdff03..53575ee154c4 100644 --- a/arch/sparc/vdso/vdso32/vdso32.lds.S +++ b/arch/sparc/vdso/vdso32/vdso32.lds.S @@ -17,10 +17,8 @@ VERSION { global: clock_gettime; __vdso_clock_gettime; - __vdso_clock_gettime_stick; gettimeofday; __vdso_gettimeofday; - __vdso_gettimeofday_stick; local: *; }; } diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c index c454689ce5fa..1f47d8341e43 100644 --- a/arch/sparc/vdso/vma.c +++ b/arch/sparc/vdso/vma.c @@ -42,203 +42,6 @@ static struct vm_special_mapping vdso_mapping32 = { struct vvar_data *vvar_data; -struct vdso_elfinfo32 { - Elf32_Ehdr *hdr; - Elf32_Sym *dynsym; - unsigned long dynsymsize; - const char *dynstr; - unsigned long text; -}; - -struct vdso_elfinfo64 { - Elf64_Ehdr *hdr; - Elf64_Sym *dynsym; - unsigned long dynsymsize; - const char *dynstr; - unsigned long text; -}; - -struct vdso_elfinfo { - union { - struct vdso_elfinfo32 elf32; - struct vdso_elfinfo64 elf64; - } u; -}; - -static void *one_section64(struct vdso_elfinfo64 *e, const char *name, - unsigned long *size) -{ - const char *snames; - Elf64_Shdr *shdrs; - unsigned int i; - - shdrs = (void *)e->hdr + e->hdr->e_shoff; - snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset; - for (i = 1; i < e->hdr->e_shnum; i++) { - if (!strcmp(snames+shdrs[i].sh_name, name)) { - if (size) - *size = shdrs[i].sh_size; - return (void *)e->hdr + shdrs[i].sh_offset; - } - } - return NULL; -} - -static int find_sections64(const struct vdso_image *image, struct vdso_elfinfo *_e) -{ - struct vdso_elfinfo64 *e = &_e->u.elf64; - - e->hdr = image->data; - e->dynsym = one_section64(e, ".dynsym", &e->dynsymsize); - e->dynstr = one_section64(e, ".dynstr", NULL); - - if (!e->dynsym || !e->dynstr) { - pr_err("VDSO64: Missing symbol sections.\n"); - return -ENODEV; - } - return 0; -} - -static Elf64_Sym *find_sym64(const struct vdso_elfinfo64 *e, const char *name) -{ - unsigned int i; - - for (i = 0; i < (e->dynsymsize / sizeof(Elf64_Sym)); i++) { - Elf64_Sym *s = &e->dynsym[i]; - if (s->st_name == 0) - continue; - if (!strcmp(e->dynstr + s->st_name, name)) - return s; - } - return NULL; -} - -static int patchsym64(struct vdso_elfinfo *_e, const char *orig, - const char *new) -{ - struct vdso_elfinfo64 *e = &_e->u.elf64; - Elf64_Sym *osym = find_sym64(e, orig); - Elf64_Sym *nsym = find_sym64(e, new); - - if (!nsym || !osym) { - pr_err("VDSO64: Missing symbols.\n"); - return -ENODEV; - } - osym->st_value = nsym->st_value; - osym->st_size = nsym->st_size; - osym->st_info = nsym->st_info; - osym->st_other = nsym->st_other; - osym->st_shndx = nsym->st_shndx; - - return 0; -} - -static void *one_section32(struct vdso_elfinfo32 *e, const char *name, - unsigned long *size) -{ - const char *snames; - Elf32_Shdr *shdrs; - unsigned int i; - - shdrs = (void *)e->hdr + e->hdr->e_shoff; - snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset; - for (i = 1; i < e->hdr->e_shnum; i++) { - if (!strcmp(snames+shdrs[i].sh_name, name)) { - if (size) - *size = shdrs[i].sh_size; - return (void *)e->hdr + shdrs[i].sh_offset; - } - } - return NULL; -} - -static int find_sections32(const struct vdso_image *image, struct vdso_elfinfo *_e) -{ - struct vdso_elfinfo32 *e = &_e->u.elf32; - - e->hdr = image->data; - e->dynsym = one_section32(e, ".dynsym", &e->dynsymsize); - e->dynstr = one_section32(e, ".dynstr", NULL); - - if (!e->dynsym || !e->dynstr) { - pr_err("VDSO32: Missing symbol sections.\n"); - return -ENODEV; - } - return 0; -} - -static Elf32_Sym *find_sym32(const struct vdso_elfinfo32 *e, const char *name) -{ - unsigned int i; - - for (i = 0; i < (e->dynsymsize / sizeof(Elf32_Sym)); i++) { - Elf32_Sym *s = &e->dynsym[i]; - if (s->st_name == 0) - continue; - if (!strcmp(e->dynstr + s->st_name, name)) - return s; - } - return NULL; -} - -static int patchsym32(struct vdso_elfinfo *_e, const char *orig, - const char *new) -{ - struct vdso_elfinfo32 *e = &_e->u.elf32; - Elf32_Sym *osym = find_sym32(e, orig); - Elf32_Sym *nsym = find_sym32(e, new); - - if (!nsym || !osym) { - pr_err("VDSO32: Missing symbols.\n"); - return -ENODEV; - } - osym->st_value = nsym->st_value; - osym->st_size = nsym->st_size; - osym->st_info = nsym->st_info; - osym->st_other = nsym->st_other; - osym->st_shndx = nsym->st_shndx; - - return 0; -} - -static int find_sections(const struct vdso_image *image, struct vdso_elfinfo *e, - bool elf64) -{ - if (elf64) - return find_sections64(image, e); - else - return find_sections32(image, e); -} - -static int patch_one_symbol(struct vdso_elfinfo *e, const char *orig, - const char *new_target, bool elf64) -{ - if (elf64) - return patchsym64(e, orig, new_target); - else - return patchsym32(e, orig, new_target); -} - -static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, bool elf64) -{ - int err; - - err = find_sections(image, e, elf64); - if (err) - return err; - - err = patch_one_symbol(e, - "__vdso_gettimeofday", - "__vdso_gettimeofday_stick", elf64); - if (err) - return err; - - return patch_one_symbol(e, - "__vdso_clock_gettime", - "__vdso_clock_gettime_stick", elf64); - return 0; -} - /* * Allocate pages for the vdso and vvar, and copy in the vdso text from the * kernel image. @@ -250,15 +53,8 @@ static int __init init_vdso_image(const struct vdso_image *image, int cnpages = (image->size) / PAGE_SIZE; struct page *dp, **dpp = NULL; struct page *cp, **cpp = NULL; - struct vdso_elfinfo ei; int i, dnpages = 0; - if (tlb_type != spitfire) { - int err = stick_patch(image, &ei, elf64); - if (err) - return err; - } - /* * First, the vdso text. This is initialied data, an integral number of * pages long. From 10fdbd9517e833de31911c29c5ff2494d62a5551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:04 +0100 Subject: [PATCH 13/51] sparc64: vdso: Move hardware counter read into header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic vDSO libraries expected the architecture glue around hardware counter reading in asm/vdso/gettimeofday.h. To prepare the adoption of the generic library, move the existing functions there. While at it, perform some trivial alignment with the generic vDSO library: * Drop 'notrace', as the functions are __always_inline anyways * Use the same parameter types * Use the same function names Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-7-d8eb3b0e1410@linutronix.de --- arch/sparc/include/asm/vdso/gettimeofday.h | 78 ++++++++++++++++++++++ arch/sparc/vdso/vclock_gettime.c | 70 ++----------------- 2 files changed, 82 insertions(+), 66 deletions(-) create mode 100644 arch/sparc/include/asm/vdso/gettimeofday.h diff --git a/arch/sparc/include/asm/vdso/gettimeofday.h b/arch/sparc/include/asm/vdso/gettimeofday.h new file mode 100644 index 000000000000..31f6505d3ab5 --- /dev/null +++ b/arch/sparc/include/asm/vdso/gettimeofday.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2006 Andi Kleen, SUSE Labs. + */ + +#ifndef _ASM_SPARC_VDSO_GETTIMEOFDAY_H +#define _ASM_SPARC_VDSO_GETTIMEOFDAY_H + +#include +#include + +#ifdef CONFIG_SPARC64 +static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) +{ + return val >> amt; +} + +static __always_inline u64 vread_tick(void) +{ + u64 ret; + + __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); + return ret; +} + +static __always_inline u64 vread_tick_stick(void) +{ + u64 ret; + + __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret)); + return ret; +} +#else +static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) +{ + u64 ret; + + __asm__ __volatile__("sllx %H1, 32, %%g1\n\t" + "srl %L1, 0, %L1\n\t" + "or %%g1, %L1, %%g1\n\t" + "srlx %%g1, %2, %L0\n\t" + "srlx %L0, 32, %H0" + : "=r" (ret) + : "r" (val), "r" (amt) + : "g1"); + return ret; +} + +static __always_inline u64 vread_tick(void) +{ + register unsigned long long ret asm("o4"); + + __asm__ __volatile__("rd %%tick, %L0\n\t" + "srlx %L0, 32, %H0" + : "=r" (ret)); + return ret; +} + +static __always_inline u64 vread_tick_stick(void) +{ + register unsigned long long ret asm("o4"); + + __asm__ __volatile__("rd %%asr24, %L0\n\t" + "srlx %L0, 32, %H0" + : "=r" (ret)); + return ret; +} +#endif + +static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) +{ + if (likely(vvar->vclock_mode == VCLOCK_STICK)) + return vread_tick_stick(); + else + return vread_tick(); +} + +#endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index 643608bffe13..16ac80982a00 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #ifdef CONFIG_SPARC64 @@ -85,73 +86,10 @@ notrace static long vdso_fallback_gettimeofday(struct __kernel_old_timeval *tv, return o0; } -#ifdef CONFIG_SPARC64 -notrace static __always_inline u64 __shr64(u64 val, int amt) -{ - return val >> amt; -} - -notrace static __always_inline u64 vread_tick(void) -{ - u64 ret; - - __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); - return ret; -} - -notrace static __always_inline u64 vread_tick_stick(void) -{ - u64 ret; - - __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret)); - return ret; -} -#else -notrace static __always_inline u64 __shr64(u64 val, int amt) -{ - u64 ret; - - __asm__ __volatile__("sllx %H1, 32, %%g1\n\t" - "srl %L1, 0, %L1\n\t" - "or %%g1, %L1, %%g1\n\t" - "srlx %%g1, %2, %L0\n\t" - "srlx %L0, 32, %H0" - : "=r" (ret) - : "r" (val), "r" (amt) - : "g1"); - return ret; -} - -notrace static __always_inline u64 vread_tick(void) -{ - register unsigned long long ret asm("o4"); - - __asm__ __volatile__("rd %%tick, %L0\n\t" - "srlx %L0, 32, %H0" - : "=r" (ret)); - return ret; -} - -notrace static __always_inline u64 vread_tick_stick(void) -{ - register unsigned long long ret asm("o4"); - - __asm__ __volatile__("rd %%asr24, %L0\n\t" - "srlx %L0, 32, %H0" - : "=r" (ret)); - return ret; -} -#endif - notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) { u64 v; - u64 cycles; - - if (likely(vvar->vclock_mode == VCLOCK_STICK)) - cycles = vread_tick_stick(); - else - cycles = vread_tick(); + u64 cycles = __arch_get_hw_counter(vvar); v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; return v * vvar->clock.mult; @@ -168,7 +106,7 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar, ts->tv_sec = vvar->wall_time_sec; ns = vvar->wall_time_snsec; ns += vgetsns(vvar); - ns = __shr64(ns, vvar->clock.shift); + ns = vdso_shift_ns(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); @@ -188,7 +126,7 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar, ts->tv_sec = vvar->monotonic_time_sec; ns = vvar->monotonic_time_snsec; ns += vgetsns(vvar); - ns = __shr64(ns, vvar->clock.shift); + ns = vdso_shift_ns(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); From d60c682bce3dce963d6cf8208ed60d586004ce49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:05 +0100 Subject: [PATCH 14/51] sparc64: vdso: Move syscall fallbacks into header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic vDSO libraries expected the syscall fallbacks in asm/vdso/gettimeofday.h. To prepare the adoption of the generic library, move the existing functions there. While at it, rename them so they match what the generic library expects. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-8-d8eb3b0e1410@linutronix.de --- arch/sparc/include/asm/vdso/gettimeofday.h | 50 +++++++++++++++++++++ arch/sparc/vdso/vclock_gettime.c | 51 +--------------------- 2 files changed, 52 insertions(+), 49 deletions(-) diff --git a/arch/sparc/include/asm/vdso/gettimeofday.h b/arch/sparc/include/asm/vdso/gettimeofday.h index 31f6505d3ab5..429dc080568f 100644 --- a/arch/sparc/include/asm/vdso/gettimeofday.h +++ b/arch/sparc/include/asm/vdso/gettimeofday.h @@ -6,6 +6,9 @@ #ifndef _ASM_SPARC_VDSO_GETTIMEOFDAY_H #define _ASM_SPARC_VDSO_GETTIMEOFDAY_H +#include +#include + #include #include @@ -75,4 +78,51 @@ static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) return vread_tick(); } +#ifdef CONFIG_SPARC64 +#define SYSCALL_STRING \ + "ta 0x6d;" \ + "bcs,a 1f;" \ + " sub %%g0, %%o0, %%o0;" \ + "1:" +#else +#define SYSCALL_STRING \ + "ta 0x10;" \ + "bcs,a 1f;" \ + " sub %%g0, %%o0, %%o0;" \ + "1:" +#endif + +#define SYSCALL_CLOBBERS \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ + "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \ + "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \ + "cc", "memory" + +static __always_inline +long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) +{ + register long num __asm__("g1") = __NR_clock_gettime; + register long o0 __asm__("o0") = clock; + register long o1 __asm__("o1") = (long) ts; + + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); + return o0; +} + +static __always_inline +long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) +{ + register long num __asm__("g1") = __NR_gettimeofday; + register long o0 __asm__("o0") = (long) tv; + register long o1 __asm__("o1") = (long) tz; + + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); + return o0; +} + #endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index 16ac80982a00..e768c0b84b34 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -13,38 +13,13 @@ */ #include -#include #include #include -#include #include #include #include #include -#ifdef CONFIG_SPARC64 -#define SYSCALL_STRING \ - "ta 0x6d;" \ - "bcs,a 1f;" \ - " sub %%g0, %%o0, %%o0;" \ - "1:" -#else -#define SYSCALL_STRING \ - "ta 0x10;" \ - "bcs,a 1f;" \ - " sub %%g0, %%o0, %%o0;" \ - "1:" -#endif - -#define SYSCALL_CLOBBERS \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \ - "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \ - "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \ - "cc", "memory" - /* * Compute the vvar page's address in the process address space, and return it * as a pointer to the vvar_data. @@ -64,28 +39,6 @@ notrace static __always_inline struct vvar_data *get_vvar_data(void) return (struct vvar_data *) ret; } -notrace static long vdso_fallback_gettime(long clock, struct __kernel_old_timespec *ts) -{ - register long num __asm__("g1") = __NR_clock_gettime; - register long o0 __asm__("o0") = clock; - register long o1 __asm__("o1") = (long) ts; - - __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), - "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); - return o0; -} - -notrace static long vdso_fallback_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) -{ - register long num __asm__("g1") = __NR_gettimeofday; - register long o0 __asm__("o0") = (long) tv; - register long o1 __asm__("o1") = (long) tz; - - __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), - "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); - return o0; -} - notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) { u64 v; @@ -184,7 +137,7 @@ __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) /* * Unknown clock ID ? Fall back to the syscall. */ - return vdso_fallback_gettime(clock, ts); + return clock_gettime_fallback(clock, ts); } int clock_gettime(clockid_t, struct __kernel_old_timespec *) @@ -220,7 +173,7 @@ __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) } return 0; } - return vdso_fallback_gettimeofday(tv, tz); + return gettimeofday_fallback(tv, tz); } int gettimeofday(struct __kernel_old_timeval *, struct timezone *) From e13e3059dcc27b0b79603925e68200a148b2ef4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:06 +0100 Subject: [PATCH 15/51] sparc64: vdso: Introduce vdso/processor.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic vDSO library expects a vdso/processor.h with an definition of cpu_relax(). Split out cpu_relax() into this dedicated header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-9-d8eb3b0e1410@linutronix.de --- arch/sparc/include/asm/processor.h | 3 ++ arch/sparc/include/asm/processor_32.h | 2 -- arch/sparc/include/asm/processor_64.h | 25 --------------- arch/sparc/include/asm/vdso/processor.h | 41 +++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 arch/sparc/include/asm/vdso/processor.h diff --git a/arch/sparc/include/asm/processor.h b/arch/sparc/include/asm/processor.h index 18295ea625dd..e34de956519a 100644 --- a/arch/sparc/include/asm/processor.h +++ b/arch/sparc/include/asm/processor.h @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef ___ASM_SPARC_PROCESSOR_H #define ___ASM_SPARC_PROCESSOR_H + +#include + #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index ba8b70ffec08..a074d313f4f8 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h @@ -91,8 +91,6 @@ unsigned long __get_wchan(struct task_struct *); extern struct task_struct *last_task_used_math; int do_mathemu(struct pt_regs *regs, struct task_struct *fpt); -#define cpu_relax() barrier() - extern void (*sparc_idle)(void); #endif diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 321859454ca4..485070495263 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -182,31 +182,6 @@ unsigned long __get_wchan(struct task_struct *task); #define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->u_regs[UREG_FP]) -/* Please see the commentary in asm/backoff.h for a description of - * what these instructions are doing and how they have been chosen. - * To make a long story short, we are trying to yield the current cpu - * strand during busy loops. - */ -#ifdef BUILD_VDSO -#define cpu_relax() asm volatile("\n99:\n\t" \ - "rd %%ccr, %%g0\n\t" \ - "rd %%ccr, %%g0\n\t" \ - "rd %%ccr, %%g0\n\t" \ - ::: "memory") -#else /* ! BUILD_VDSO */ -#define cpu_relax() asm volatile("\n99:\n\t" \ - "rd %%ccr, %%g0\n\t" \ - "rd %%ccr, %%g0\n\t" \ - "rd %%ccr, %%g0\n\t" \ - ".section .pause_3insn_patch,\"ax\"\n\t"\ - ".word 99b\n\t" \ - "wr %%g0, 128, %%asr27\n\t" \ - "nop\n\t" \ - "nop\n\t" \ - ".previous" \ - ::: "memory") -#endif - /* Prefetch support. This is tuned for UltraSPARC-III and later. * UltraSPARC-I will treat these as nops, and UltraSPARC-II has * a shallower prefetch queue than later chips. diff --git a/arch/sparc/include/asm/vdso/processor.h b/arch/sparc/include/asm/vdso/processor.h new file mode 100644 index 000000000000..f7a9adc807f7 --- /dev/null +++ b/arch/sparc/include/asm/vdso/processor.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_SPARC_VDSO_PROCESSOR_H +#define _ASM_SPARC_VDSO_PROCESSOR_H + +#include + +#if defined(__arch64__) + +/* Please see the commentary in asm/backoff.h for a description of + * what these instructions are doing and how they have been chosen. + * To make a long story short, we are trying to yield the current cpu + * strand during busy loops. + */ +#ifdef BUILD_VDSO +#define cpu_relax() asm volatile("\n99:\n\t" \ + "rd %%ccr, %%g0\n\t" \ + "rd %%ccr, %%g0\n\t" \ + "rd %%ccr, %%g0\n\t" \ + ::: "memory") +#else /* ! BUILD_VDSO */ +#define cpu_relax() asm volatile("\n99:\n\t" \ + "rd %%ccr, %%g0\n\t" \ + "rd %%ccr, %%g0\n\t" \ + "rd %%ccr, %%g0\n\t" \ + ".section .pause_3insn_patch,\"ax\"\n\t"\ + ".word 99b\n\t" \ + "wr %%g0, 128, %%asr27\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + ".previous" \ + ::: "memory") +#endif /* BUILD_VDSO */ + +#else /* ! __arch64__ */ + +#define cpu_relax() barrier() + +#endif /* __arch64__ */ + +#endif /* _ASM_SPARC_VDSO_PROCESSOR_H */ From 7c5fc16c7a5699e7706d7847e58a75560251946e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:07 +0100 Subject: [PATCH 16/51] sparc64: vdso: Switch to the generic vDSO library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generic vDSO provides a lot common functionality shared between different architectures. SPARC is the last architecture not using it, preventing some necessary code cleanup. Make use of the generic infrastructure. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-10-d8eb3b0e1410@linutronix.de --- arch/sparc/Kconfig | 3 +- arch/sparc/include/asm/clocksource.h | 9 -- arch/sparc/include/asm/vdso/clocksource.h | 10 ++ arch/sparc/include/asm/vdso/gettimeofday.h | 58 +++++-- arch/sparc/include/asm/vdso/vsyscall.h | 10 ++ arch/sparc/include/asm/vvar.h | 75 --------- arch/sparc/kernel/Makefile | 1 - arch/sparc/kernel/time_64.c | 6 +- arch/sparc/kernel/vdso.c | 69 -------- arch/sparc/vdso/Makefile | 6 +- arch/sparc/vdso/vclock_gettime.c | 179 +++------------------ arch/sparc/vdso/vdso-layout.lds.S | 7 +- arch/sparc/vdso/vma.c | 70 ++------ 13 files changed, 123 insertions(+), 380 deletions(-) create mode 100644 arch/sparc/include/asm/vdso/clocksource.h create mode 100644 arch/sparc/include/asm/vdso/vsyscall.h delete mode 100644 arch/sparc/include/asm/vvar.h delete mode 100644 arch/sparc/kernel/vdso.c diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 8699be91fca9..a6b787efc2c4 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -104,7 +104,6 @@ config SPARC64 select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS select GENERIC_TIME_VSYSCALL - select ARCH_CLOCKSOURCE_DATA select ARCH_HAS_PTE_SPECIAL select PCI_DOMAINS if PCI select ARCH_HAS_GIGANTIC_PAGE @@ -115,6 +114,8 @@ config SPARC64 select ARCH_SUPPORTS_SCHED_SMT if SMP select ARCH_SUPPORTS_SCHED_MC if SMP select ARCH_HAS_LAZY_MMU_MODE + select HAVE_GENERIC_VDSO + select GENERIC_GETTIMEOFDAY config ARCH_PROC_KCORE_TEXT def_bool y diff --git a/arch/sparc/include/asm/clocksource.h b/arch/sparc/include/asm/clocksource.h index d63ef224befe..68303ad26eb2 100644 --- a/arch/sparc/include/asm/clocksource.h +++ b/arch/sparc/include/asm/clocksource.h @@ -5,13 +5,4 @@ #ifndef _ASM_SPARC_CLOCKSOURCE_H #define _ASM_SPARC_CLOCKSOURCE_H -/* VDSO clocksources */ -#define VCLOCK_NONE 0 /* Nothing userspace can do. */ -#define VCLOCK_TICK 1 /* Use %tick. */ -#define VCLOCK_STICK 2 /* Use %stick. */ - -struct arch_clocksource_data { - int vclock_mode; -}; - #endif /* _ASM_SPARC_CLOCKSOURCE_H */ diff --git a/arch/sparc/include/asm/vdso/clocksource.h b/arch/sparc/include/asm/vdso/clocksource.h new file mode 100644 index 000000000000..007aa8ceaf52 --- /dev/null +++ b/arch/sparc/include/asm/vdso/clocksource.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_CLOCKSOURCE_H +#define __ASM_VDSO_CLOCKSOURCE_H + +/* VDSO clocksources */ +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_TICK, \ + VDSO_CLOCKMODE_STICK + +#endif /* __ASM_VDSO_CLOCKSOURCE_H */ diff --git a/arch/sparc/include/asm/vdso/gettimeofday.h b/arch/sparc/include/asm/vdso/gettimeofday.h index 429dc080568f..a35875fba454 100644 --- a/arch/sparc/include/asm/vdso/gettimeofday.h +++ b/arch/sparc/include/asm/vdso/gettimeofday.h @@ -9,15 +9,14 @@ #include #include +#include +#include +#include +#include + #include -#include #ifdef CONFIG_SPARC64 -static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) -{ - return val >> amt; -} - static __always_inline u64 vread_tick(void) { u64 ret; @@ -48,6 +47,7 @@ static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) : "g1"); return ret; } +#define vdso_shift_ns vdso_shift_ns static __always_inline u64 vread_tick(void) { @@ -70,9 +70,9 @@ static __always_inline u64 vread_tick_stick(void) } #endif -static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vdso_time_data *vd) { - if (likely(vvar->vclock_mode == VCLOCK_STICK)) + if (likely(clock_mode == VDSO_CLOCKMODE_STICK)) return vread_tick_stick(); else return vread_tick(); @@ -102,7 +102,7 @@ static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) "cc", "memory" static __always_inline -long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) +long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) { register long num __asm__("g1") = __NR_clock_gettime; register long o0 __asm__("o0") = clock; @@ -113,6 +113,20 @@ long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) return o0; } +#ifndef CONFIG_SPARC64 +static __always_inline +long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts) +{ + register long num __asm__("g1") = __NR_clock_gettime; + register long o0 __asm__("o0") = clock; + register long o1 __asm__("o1") = (long) ts; + + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); + return o0; +} +#endif + static __always_inline long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) { @@ -125,4 +139,30 @@ long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) return o0; } +static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void) +{ + unsigned long ret; + + /* + * SPARC does not support native PC-relative code relocations. + * Calculate the address manually, works for 32 and 64 bit code. + */ + __asm__ __volatile__( + "1:\n" + "call 3f\n" // Jump over the embedded data and set up %o7 + "nop\n" // Delay slot + "2:\n" + ".word vdso_u_time_data - .\n" // Embedded offset to external symbol + "3:\n" + "add %%o7, 2b - 1b, %%o7\n" // Point %o7 to the embedded offset + "ldsw [%%o7], %0\n" // Load the offset + "add %0, %%o7, %0\n" // Calculate the absolute address + : "=r" (ret) + : + : "o7"); + + return (const struct vdso_time_data *)ret; +} +#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data + #endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/sparc/include/asm/vdso/vsyscall.h b/arch/sparc/include/asm/vdso/vsyscall.h new file mode 100644 index 000000000000..8bfe703fedc5 --- /dev/null +++ b/arch/sparc/include/asm/vdso/vsyscall.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_SPARC_VDSO_VSYSCALL_H +#define _ASM_SPARC_VDSO_VSYSCALL_H + +#define __VDSO_PAGES 4 + +#include + +#endif /* _ASM_SPARC_VDSO_VSYSCALL_H */ diff --git a/arch/sparc/include/asm/vvar.h b/arch/sparc/include/asm/vvar.h deleted file mode 100644 index 6eaf5cfcaae1..000000000000 --- a/arch/sparc/include/asm/vvar.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. - */ - -#ifndef _ASM_SPARC_VVAR_DATA_H -#define _ASM_SPARC_VVAR_DATA_H - -#include -#include -#include -#include -#include - -struct vvar_data { - unsigned int seq; - - int vclock_mode; - struct { /* extract of a clocksource struct */ - u64 cycle_last; - u64 mask; - int mult; - int shift; - } clock; - /* open coded 'struct timespec' */ - u64 wall_time_sec; - u64 wall_time_snsec; - u64 monotonic_time_snsec; - u64 monotonic_time_sec; - u64 monotonic_time_coarse_sec; - u64 monotonic_time_coarse_nsec; - u64 wall_time_coarse_sec; - u64 wall_time_coarse_nsec; - - int tz_minuteswest; - int tz_dsttime; -}; - -extern struct vvar_data *vvar_data; -extern int vdso_fix_stick; - -static inline unsigned int vvar_read_begin(const struct vvar_data *s) -{ - unsigned int ret; - -repeat: - ret = READ_ONCE(s->seq); - if (unlikely(ret & 1)) { - cpu_relax(); - goto repeat; - } - smp_rmb(); /* Finish all reads before we return seq */ - return ret; -} - -static inline int vvar_read_retry(const struct vvar_data *s, - unsigned int start) -{ - smp_rmb(); /* Finish all reads before checking the value of seq */ - return unlikely(s->seq != start); -} - -static inline void vvar_write_begin(struct vvar_data *s) -{ - ++s->seq; - smp_wmb(); /* Makes sure that increment of seq is reflected */ -} - -static inline void vvar_write_end(struct vvar_data *s) -{ - smp_wmb(); /* Makes the value of seq current before we increment */ - ++s->seq; -} - - -#endif /* _ASM_SPARC_VVAR_DATA_H */ diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 22170d4f8e06..497b5714fa8f 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_SPARC32) += systbls_32.o obj-y += time_$(BITS).o obj-$(CONFIG_SPARC32) += windows.o obj-y += cpu.o -obj-$(CONFIG_SPARC64) += vdso.o obj-$(CONFIG_SPARC32) += devices.o obj-y += ptrace_$(BITS).o obj-y += unaligned_$(BITS).o diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index b32f27f929d1..87b267043ccd 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -838,14 +838,14 @@ void __init time_init_early(void) if (tlb_type == spitfire) { if (is_hummingbird()) { init_tick_ops(&hbtick_operations); - clocksource_tick.archdata.vclock_mode = VCLOCK_NONE; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_NONE; } else { init_tick_ops(&tick_operations); - clocksource_tick.archdata.vclock_mode = VCLOCK_TICK; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_TICK; } } else { init_tick_ops(&stick_operations); - clocksource_tick.archdata.vclock_mode = VCLOCK_STICK; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_STICK; } } diff --git a/arch/sparc/kernel/vdso.c b/arch/sparc/kernel/vdso.c deleted file mode 100644 index 0e27437eb97b..000000000000 --- a/arch/sparc/kernel/vdso.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2001 Andrea Arcangeli SuSE - * Copyright 2003 Andi Kleen, SuSE Labs. - * - * Thanks to hpa@transmeta.com for some useful hint. - * Special thanks to Ingo Molnar for his early experience with - * a different vsyscall implementation for Linux/IA32 and for the name. - */ - -#include -#include - -#include - -void update_vsyscall_tz(void) -{ - if (unlikely(vvar_data == NULL)) - return; - - vvar_data->tz_minuteswest = sys_tz.tz_minuteswest; - vvar_data->tz_dsttime = sys_tz.tz_dsttime; -} - -void update_vsyscall(struct timekeeper *tk) -{ - struct vvar_data *vdata = vvar_data; - - if (unlikely(vdata == NULL)) - return; - - vvar_write_begin(vdata); - vdata->vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; - vdata->clock.cycle_last = tk->tkr_mono.cycle_last; - vdata->clock.mask = tk->tkr_mono.mask; - vdata->clock.mult = tk->tkr_mono.mult; - vdata->clock.shift = tk->tkr_mono.shift; - - vdata->wall_time_sec = tk->xtime_sec; - vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; - - vdata->monotonic_time_sec = tk->xtime_sec + - tk->wall_to_monotonic.tv_sec; - vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec + - (tk->wall_to_monotonic.tv_nsec << - tk->tkr_mono.shift); - - while (vdata->monotonic_time_snsec >= - (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { - vdata->monotonic_time_snsec -= - ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; - vdata->monotonic_time_sec++; - } - - vdata->wall_time_coarse_sec = tk->xtime_sec; - vdata->wall_time_coarse_nsec = - (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); - - vdata->monotonic_time_coarse_sec = - vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; - vdata->monotonic_time_coarse_nsec = - vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; - - while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { - vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; - vdata->monotonic_time_coarse_sec++; - } - - vvar_write_end(vdata); -} diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index aaef9174f375..83fb2aca59cb 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -3,6 +3,9 @@ # Building vDSO images for sparc. # +# Include the generic Makefile to check the built vDSO: +include $(srctree)/lib/vdso/Makefile.include + # files to link into the vdso vobjs-y := vdso-note.o vclock_gettime.o @@ -105,6 +108,7 @@ $(obj)/vdso32.so.dbg: FORCE \ quiet_cmd_vdso = VDSO $@ cmd_vdso = $(LD) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ - -T $(filter %.lds,$^) $(filter %.o,$^) + -T $(filter %.lds,$^) $(filter %.o,$^); \ + $(cmd_vdso_check) VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index e768c0b84b34..093a7ff4dafc 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -12,169 +12,40 @@ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. */ -#include -#include -#include -#include -#include +#include +#include + +#include + #include -#include -/* - * Compute the vvar page's address in the process address space, and return it - * as a pointer to the vvar_data. - */ -notrace static __always_inline struct vvar_data *get_vvar_data(void) +#include "../../../../lib/vdso/gettimeofday.c" + +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { - unsigned long ret; - - /* - * vdso data page is the first vDSO page so grab the PC - * and move up a page to get to the data page. - */ - __asm__("rd %%pc, %0" : "=r" (ret)); - ret &= ~(8192 - 1); - ret -= 8192; - - return (struct vvar_data *) ret; + return __cvdso_gettimeofday(tv, tz); } -notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) -{ - u64 v; - u64 cycles = __arch_get_hw_counter(vvar); +int gettimeofday(struct __kernel_old_timeval *, struct timezone *) + __weak __alias(__vdso_gettimeofday); - v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; - return v * vvar->clock.mult; +#if defined(CONFIG_SPARC64) +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); } -notrace static __always_inline int do_realtime(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) +int clock_gettime(clockid_t, struct __kernel_timespec *) + __weak __alias(__vdso_clock_gettime); + +#else + +int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { - unsigned long seq; - u64 ns; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->wall_time_sec; - ns = vvar->wall_time_snsec; - ns += vgetsns(vvar); - ns = vdso_shift_ns(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; + return __cvdso_clock_gettime32(clock, ts); } -notrace static __always_inline int do_monotonic(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - u64 ns; +int clock_gettime(clockid_t, struct old_timespec32 *) + __weak __alias(__vdso_clock_gettime); - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->monotonic_time_sec; - ns = vvar->monotonic_time_snsec; - ns += vgetsns(vvar); - ns = vdso_shift_ns(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -notrace static int do_realtime_coarse(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->wall_time_coarse_sec; - ts->tv_nsec = vvar->wall_time_coarse_nsec; - } while (unlikely(vvar_read_retry(vvar, seq))); - return 0; -} - -notrace static int do_monotonic_coarse(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->monotonic_time_coarse_sec; - ts->tv_nsec = vvar->monotonic_time_coarse_nsec; - } while (unlikely(vvar_read_retry(vvar, seq))); - - return 0; -} - -notrace int -__vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) -{ - struct vvar_data *vvd = get_vvar_data(); - - switch (clock) { - case CLOCK_REALTIME: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_realtime(vvd, ts); - case CLOCK_MONOTONIC: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_monotonic(vvd, ts); - case CLOCK_REALTIME_COARSE: - return do_realtime_coarse(vvd, ts); - case CLOCK_MONOTONIC_COARSE: - return do_monotonic_coarse(vvd, ts); - } - /* - * Unknown clock ID ? Fall back to the syscall. - */ - return clock_gettime_fallback(clock, ts); -} -int -clock_gettime(clockid_t, struct __kernel_old_timespec *) - __attribute__((weak, alias("__vdso_clock_gettime"))); - -notrace int -__vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) -{ - struct vvar_data *vvd = get_vvar_data(); - - if (likely(vvd->vclock_mode != VCLOCK_NONE)) { - if (likely(tv != NULL)) { - union tstv_t { - struct __kernel_old_timespec ts; - struct __kernel_old_timeval tv; - } *tstv = (union tstv_t *) tv; - do_realtime(vvd, &tstv->ts); - /* - * Assign before dividing to ensure that the division is - * done in the type of tv_usec, not tv_nsec. - * - * There cannot be > 1 billion usec in a second: - * do_realtime() has already distributed such overflow - * into tv_sec. So we can assign it to an int safely. - */ - tstv->tv.tv_usec = tstv->ts.tv_nsec; - tstv->tv.tv_usec /= 1000; - } - if (unlikely(tz != NULL)) { - /* Avoid memcpy. Some old compilers fail to inline it */ - tz->tz_minuteswest = vvd->tz_minuteswest; - tz->tz_dsttime = vvd->tz_dsttime; - } - return 0; - } - return gettimeofday_fallback(tv, tz); -} -int -gettimeofday(struct __kernel_old_timeval *, struct timezone *) - __attribute__((weak, alias("__vdso_gettimeofday"))); +#endif diff --git a/arch/sparc/vdso/vdso-layout.lds.S b/arch/sparc/vdso/vdso-layout.lds.S index 9e0804789d11..180e5d0ee071 100644 --- a/arch/sparc/vdso/vdso-layout.lds.S +++ b/arch/sparc/vdso/vdso-layout.lds.S @@ -4,6 +4,10 @@ * This script controls its layout. */ +#include +#include +#include + SECTIONS { /* @@ -13,8 +17,7 @@ SECTIONS * segment. Page size is 8192 for both 64-bit and 32-bit vdso binaries */ - vvar_start = . -8192; - vvar_data = vvar_start; + VDSO_VVAR_SYMS . = SIZEOF_HEADERS; diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c index 1f47d8341e43..60029d60f4d3 100644 --- a/arch/sparc/vdso/vma.c +++ b/arch/sparc/vdso/vma.c @@ -16,17 +16,16 @@ #include #include #include +#include #include #include #include -#include #include -unsigned int __read_mostly vdso_enabled = 1; +#include +#include -static struct vm_special_mapping vvar_mapping = { - .name = "[vvar]" -}; +unsigned int __read_mostly vdso_enabled = 1; #ifdef CONFIG_SPARC64 static struct vm_special_mapping vdso_mapping64 = { @@ -40,10 +39,8 @@ static struct vm_special_mapping vdso_mapping32 = { }; #endif -struct vvar_data *vvar_data; - /* - * Allocate pages for the vdso and vvar, and copy in the vdso text from the + * Allocate pages for the vdso and copy in the vdso text from the * kernel image. */ static int __init init_vdso_image(const struct vdso_image *image, @@ -51,9 +48,8 @@ static int __init init_vdso_image(const struct vdso_image *image, bool elf64) { int cnpages = (image->size) / PAGE_SIZE; - struct page *dp, **dpp = NULL; struct page *cp, **cpp = NULL; - int i, dnpages = 0; + int i; /* * First, the vdso text. This is initialied data, an integral number of @@ -76,31 +72,6 @@ static int __init init_vdso_image(const struct vdso_image *image, copy_page(page_address(cp), image->data + i * PAGE_SIZE); } - /* - * Now the vvar page. This is uninitialized data. - */ - - if (vvar_data == NULL) { - dnpages = (sizeof(struct vvar_data) / PAGE_SIZE) + 1; - if (WARN_ON(dnpages != 1)) - goto oom; - dpp = kzalloc_objs(struct page *, dnpages); - vvar_mapping.pages = dpp; - - if (!dpp) - goto oom; - - dp = alloc_page(GFP_KERNEL); - if (!dp) - goto oom; - - dpp[0] = dp; - vvar_data = page_address(dp); - memset(vvar_data, 0, PAGE_SIZE); - - vvar_data->seq = 0; - } - return 0; oom: if (cpp != NULL) { @@ -112,15 +83,6 @@ static int __init init_vdso_image(const struct vdso_image *image, vdso_mapping->pages = NULL; } - if (dpp != NULL) { - for (i = 0; i < dnpages; i++) { - if (dpp[i] != NULL) - __free_page(dpp[i]); - } - kfree(dpp); - vvar_mapping.pages = NULL; - } - pr_warn("Cannot allocate vdso\n"); vdso_enabled = 0; return -ENOMEM; @@ -155,9 +117,12 @@ static unsigned long vdso_addr(unsigned long start, unsigned int len) return start + (offset << PAGE_SHIFT); } +static_assert(VDSO_NR_PAGES == __VDSO_PAGES); + static int map_vdso(const struct vdso_image *image, struct vm_special_mapping *vdso_mapping) { + const size_t area_size = image->size + VDSO_NR_PAGES * PAGE_SIZE; struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned long text_start, addr = 0; @@ -170,23 +135,20 @@ static int map_vdso(const struct vdso_image *image, * region is free. */ if (current->flags & PF_RANDOMIZE) { - addr = get_unmapped_area(NULL, 0, - image->size - image->sym_vvar_start, - 0, 0); + addr = get_unmapped_area(NULL, 0, area_size, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } - addr = vdso_addr(addr, image->size - image->sym_vvar_start); + addr = vdso_addr(addr, area_size); } - addr = get_unmapped_area(NULL, addr, - image->size - image->sym_vvar_start, 0, 0); + addr = get_unmapped_area(NULL, addr, area_size, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } - text_start = addr - image->sym_vvar_start; + text_start = addr + VDSO_NR_PAGES * PAGE_SIZE; current->mm->context.vdso = (void __user *)text_start; /* @@ -204,11 +166,7 @@ static int map_vdso(const struct vdso_image *image, goto up_fail; } - vma = _install_special_mapping(mm, - addr, - -image->sym_vvar_start, - VM_READ|VM_MAYREAD, - &vvar_mapping); + vma = vdso_install_vvar_mapping(mm, addr); if (IS_ERR(vma)) { ret = PTR_ERR(vma); From fb57f3e7d5dc2c9ea195c5a7774412b6ffaf276d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:08 +0100 Subject: [PATCH 17/51] sparc64: vdso2c: Drop sym_vvar_start handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the adoption of the generic vDSO library this symbol does not exist. The alignment invariant is now guaranteed by the generic code. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-11-d8eb3b0e1410@linutronix.de --- arch/sparc/include/asm/vdso.h | 2 -- arch/sparc/vdso/vdso2c.c | 6 ------ arch/sparc/vdso/vdso2c.h | 4 ---- 3 files changed, 12 deletions(-) diff --git a/arch/sparc/include/asm/vdso.h b/arch/sparc/include/asm/vdso.h index 59e79d35cd73..f08562d10215 100644 --- a/arch/sparc/include/asm/vdso.h +++ b/arch/sparc/include/asm/vdso.h @@ -8,8 +8,6 @@ struct vdso_image { void *data; unsigned long size; /* Always a multiple of PAGE_SIZE */ - - long sym_vvar_start; /* Negative offset to the vvar area */ }; #ifdef CONFIG_SPARC64 diff --git a/arch/sparc/vdso/vdso2c.c b/arch/sparc/vdso/vdso2c.c index b97af5ec9f35..70b14a436fe2 100644 --- a/arch/sparc/vdso/vdso2c.c +++ b/arch/sparc/vdso/vdso2c.c @@ -58,18 +58,12 @@ const char *outfilename; -/* Symbols that we need in vdso2c. */ -enum { - sym_vvar_start, -}; - struct vdso_sym { const char *name; int export; }; struct vdso_sym required_syms[] = { - [sym_vvar_start] = {"vvar_start", 1}, }; __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) diff --git a/arch/sparc/vdso/vdso2c.h b/arch/sparc/vdso/vdso2c.h index 60d69acc748f..ba0794659eb5 100644 --- a/arch/sparc/vdso/vdso2c.h +++ b/arch/sparc/vdso/vdso2c.h @@ -104,10 +104,6 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, } } - /* Validate mapping addresses. */ - if (syms[sym_vvar_start] % 8192) - fail("vvar_begin must be a multiple of 8192\n"); - if (!name) { fwrite(stripped_addr, stripped_len, 1, outfile); return; From 168d23e5762b8bad9c7a14b130179dc561c0b13a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:09 +0100 Subject: [PATCH 18/51] sparc64: vdso2c: Remove symbol handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are no handled symbols left. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-12-d8eb3b0e1410@linutronix.de --- arch/sparc/vdso/vdso2c.c | 10 ---------- arch/sparc/vdso/vdso2c.h | 41 +--------------------------------------- 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/arch/sparc/vdso/vdso2c.c b/arch/sparc/vdso/vdso2c.c index 70b14a436fe2..e5c61214a0e2 100644 --- a/arch/sparc/vdso/vdso2c.c +++ b/arch/sparc/vdso/vdso2c.c @@ -58,14 +58,6 @@ const char *outfilename; -struct vdso_sym { - const char *name; - int export; -}; - -struct vdso_sym required_syms[] = { -}; - __attribute__((format(printf, 1, 2))) __attribute__((noreturn)) static void fail(const char *format, ...) { @@ -105,8 +97,6 @@ static void fail(const char *format, ...) #define PUT_BE(x, val) \ PBE(x, val, 64, PBE(x, val, 32, PBE(x, val, 16, LAST_PBE(x, val)))) -#define NSYMS ARRAY_SIZE(required_syms) - #define BITSFUNC3(name, bits, suffix) name##bits##suffix #define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix) #define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, ) diff --git a/arch/sparc/vdso/vdso2c.h b/arch/sparc/vdso/vdso2c.h index ba0794659eb5..bad6a0593f4c 100644 --- a/arch/sparc/vdso/vdso2c.h +++ b/arch/sparc/vdso/vdso2c.h @@ -17,11 +17,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, unsigned long mapping_size; int i; unsigned long j; - ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr; + ELF(Shdr) *symtab_hdr = NULL; ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; ELF(Dyn) *dyn = 0, *dyn_end = 0; - INT_BITS syms[NSYMS] = {}; - ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff)); /* Walk the segment table. */ @@ -72,38 +70,6 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, if (!symtab_hdr) fail("no symbol table\n"); - strtab_hdr = raw_addr + GET_BE(&hdr->e_shoff) + - GET_BE(&hdr->e_shentsize) * GET_BE(&symtab_hdr->sh_link); - - /* Walk the symbol table */ - for (i = 0; - i < GET_BE(&symtab_hdr->sh_size) / GET_BE(&symtab_hdr->sh_entsize); - i++) { - int k; - - ELF(Sym) *sym = raw_addr + GET_BE(&symtab_hdr->sh_offset) + - GET_BE(&symtab_hdr->sh_entsize) * i; - const char *name = raw_addr + GET_BE(&strtab_hdr->sh_offset) + - GET_BE(&sym->st_name); - - for (k = 0; k < NSYMS; k++) { - if (!strcmp(name, required_syms[k].name)) { - if (syms[k]) { - fail("duplicate symbol %s\n", - required_syms[k].name); - } - - /* - * Careful: we use negative addresses, but - * st_value is unsigned, so we rely - * on syms[k] being a signed type of the - * correct width. - */ - syms[k] = GET_BE(&sym->st_value); - } - } - } - if (!name) { fwrite(stripped_addr, stripped_len, 1, outfile); return; @@ -129,10 +95,5 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); fprintf(outfile, "\t.data = raw_data,\n"); fprintf(outfile, "\t.size = %lu,\n", mapping_size); - for (i = 0; i < NSYMS; i++) { - if (required_syms[i].export && syms[i]) - fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n", - required_syms[i].name, (int64_t)syms[i]); - } fprintf(outfile, "};\n"); } From 1628f6a742702071e9d67c47185562e3ab6e6755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Mar 2026 08:49:10 +0100 Subject: [PATCH 19/51] sparc64: vdso: Implement clock_gettime64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be y2038-safe, 32-bit userspace needs to explicitly call the 64-bit safe time APIs. Implement clock_gettime64() in the 32-bit vDSO. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: Andreas Larsson Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-13-d8eb3b0e1410@linutronix.de --- arch/sparc/include/asm/vdso/gettimeofday.h | 20 ++++++++++++++++++-- arch/sparc/vdso/vclock_gettime.c | 8 ++++++++ arch/sparc/vdso/vdso32/vdso32.lds.S | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/sparc/include/asm/vdso/gettimeofday.h b/arch/sparc/include/asm/vdso/gettimeofday.h index a35875fba454..b0c80c8a28bb 100644 --- a/arch/sparc/include/asm/vdso/gettimeofday.h +++ b/arch/sparc/include/asm/vdso/gettimeofday.h @@ -101,6 +101,8 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vd "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \ "cc", "memory" +#ifdef CONFIG_SPARC64 + static __always_inline long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) { @@ -113,7 +115,20 @@ long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) return o0; } -#ifndef CONFIG_SPARC64 +#else /* !CONFIG_SPARC64 */ + +static __always_inline +long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) +{ + register long num __asm__("g1") = __NR_clock_gettime64; + register long o0 __asm__("o0") = clock; + register long o1 __asm__("o1") = (long) ts; + + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); + return o0; +} + static __always_inline long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts) { @@ -125,7 +140,8 @@ long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts) "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); return o0; } -#endif + +#endif /* CONFIG_SPARC64 */ static __always_inline long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index 093a7ff4dafc..1d9859392e4c 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -48,4 +48,12 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) int clock_gettime(clockid_t, struct old_timespec32 *) __weak __alias(__vdso_clock_gettime); +int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} + +int clock_gettime64(clockid_t, struct __kernel_timespec *) + __weak __alias(__vdso_clock_gettime64); + #endif diff --git a/arch/sparc/vdso/vdso32/vdso32.lds.S b/arch/sparc/vdso/vdso32/vdso32.lds.S index 53575ee154c4..a14e4f77e6f2 100644 --- a/arch/sparc/vdso/vdso32/vdso32.lds.S +++ b/arch/sparc/vdso/vdso32/vdso32.lds.S @@ -17,6 +17,8 @@ VERSION { global: clock_gettime; __vdso_clock_gettime; + clock_gettime64; + __vdso_clock_gettime64; gettimeofday; __vdso_gettimeofday; local: *; From c453b9abb4f422461c1493ef74d63af0961a2d30 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Mar 2026 08:49:11 +0100 Subject: [PATCH 20/51] clocksource: Remove ARCH_CLOCKSOURCE_DATA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After sparc64, there are no remaining users of ARCH_CLOCKSOURCE_DATA and it can just be removed. Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Acked-by: John Stultz Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-14-d8eb3b0e1410@linutronix.de [Thomas: drop sparc64 bits from the patch] --- include/linux/clocksource.h | 6 +----- kernel/time/Kconfig | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 65b7c41471c3..12d853b18832 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -25,8 +25,7 @@ struct clocksource_base; struct clocksource; struct module; -#if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \ - defined(CONFIG_GENERIC_GETTIMEOFDAY) +#if defined(CONFIG_GENERIC_GETTIMEOFDAY) #include #endif @@ -106,9 +105,6 @@ struct clocksource { u64 max_idle_ns; u32 maxadj; u32 uncertainty_margin; -#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA - struct arch_clocksource_data archdata; -#endif u64 max_cycles; u64 max_raw_delta; const char *name; diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index 7c6a52f7836c..fe3311877097 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -9,10 +9,6 @@ config CLOCKSOURCE_WATCHDOG bool -# Architecture has extra clocksource data -config ARCH_CLOCKSOURCE_DATA - bool - # Architecture has extra clocksource init called from registration config ARCH_CLOCKSOURCE_INIT bool From 08cd5e1de815842089ca3938c3ad7ac511097d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:43:20 +0100 Subject: [PATCH 21/51] vdso/gettimeofday: Drop a few usages of __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions are used from the very same file, so this annotation is unnecessary. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260227-vdso-cleanups-v1-1-c848b4bc4850@linutronix.de --- lib/vdso/gettimeofday.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 4399e143d43a..4939ee86af65 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -313,7 +313,7 @@ __cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock, return do_hres(vd, vc, clock, ts); } -static __maybe_unused int +static int __cvdso_clock_gettime_data(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts) { @@ -333,7 +333,7 @@ __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) } #ifdef BUILD_VDSO32 -static __maybe_unused int +static int __cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock, struct old_timespec32 *res) { @@ -359,7 +359,7 @@ __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) } #endif /* BUILD_VDSO32 */ -static __maybe_unused int +static int __cvdso_gettimeofday_data(const struct vdso_time_data *vd, struct __kernel_old_timeval *tv, struct timezone *tz) { @@ -394,7 +394,7 @@ __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) } #ifdef VDSO_HAS_TIME -static __maybe_unused __kernel_old_time_t +static __kernel_old_time_t __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time) { const struct vdso_clock *vc = vd->clock_data; @@ -464,7 +464,7 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc return true; } -static __maybe_unused +static int __cvdso_clock_getres_data(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *res) { @@ -484,7 +484,7 @@ int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) } #ifdef BUILD_VDSO32 -static __maybe_unused int +static int __cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t clock, struct old_timespec32 *res) { From ed78b7b2c5ae679960469c0f679539c427e051ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:43:21 +0100 Subject: [PATCH 22/51] vdso/gettimeofday: Add a helper to read the sequence lock of a time namespace aware clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there are three different open-coded variants of a time namespace aware variant of vdso_read_begin(). They make the code hard to read and introduce an inconsistency, as only the first copy uses unlikely(). Split the code into a shared helper function. Move that next to the definition of the regular vdso_read_begin(), so that any future changes can be kept in sync easily. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260227-vdso-cleanups-v1-2-c848b4bc4850@linutronix.de --- include/vdso/helpers.h | 22 ++++++++++++++++++ lib/vdso/gettimeofday.c | 51 ++++++++--------------------------------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/include/vdso/helpers.h b/include/vdso/helpers.h index 1a5ee9d9052c..9ccf6b53ef50 100644 --- a/include/vdso/helpers.h +++ b/include/vdso/helpers.h @@ -18,6 +18,28 @@ static __always_inline u32 vdso_read_begin(const struct vdso_clock *vc) return seq; } +/* + * Variant of vdso_read_begin() to handle VDSO_CLOCKMODE_TIMENS. + * + * Time namespace enabled tasks have a special VVAR page installed which has + * vc->seq set to 1 and vc->clock_mode set to VDSO_CLOCKMODE_TIMENS. For non + * time namespace affected tasks this does not affect performance because if + * vc->seq is odd, i.e. a concurrent update is in progress the extra check for + * vc->clock_mode is just a few extra instructions while spin waiting for + * vc->seq to become even again. + */ +static __always_inline bool vdso_read_begin_timens(const struct vdso_clock *vc, u32 *seq) +{ + while (unlikely((*seq = READ_ONCE(vc->seq)) & 1)) { + if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + return true; + cpu_relax(); + } + smp_rmb(); + + return false; +} + static __always_inline u32 vdso_read_retry(const struct vdso_clock *vc, u32 start) { diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 4939ee86af65..e49369676928 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -158,24 +158,8 @@ bool do_hres(const struct vdso_time_data *vd, const struct vdso_clock *vc, return false; do { - /* - * Open coded function vdso_read_begin() to handle - * VDSO_CLOCKMODE_TIMENS. Time namespace enabled tasks have a - * special VVAR page installed which has vc->seq set to 1 and - * vc->clock_mode set to VDSO_CLOCKMODE_TIMENS. For non time - * namespace affected tasks this does not affect performance - * because if vc->seq is odd, i.e. a concurrent update is in - * progress the extra check for vc->clock_mode is just a few - * extra instructions while spin waiting for vc->seq to become - * even again. - */ - while (unlikely((seq = READ_ONCE(vc->seq)) & 1)) { - if (IS_ENABLED(CONFIG_TIME_NS) && - vc->clock_mode == VDSO_CLOCKMODE_TIMENS) - return do_hres_timens(vd, vc, clk, ts); - cpu_relax(); - } - smp_rmb(); + if (vdso_read_begin_timens(vc, &seq)) + return do_hres_timens(vd, vc, clk, ts); if (!vdso_get_timestamp(vd, vc, clk, &sec, &ns)) return false; @@ -223,17 +207,8 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc, u32 seq; do { - /* - * Open coded function vdso_read_begin() to handle - * VDSO_CLOCK_TIMENS. See comment in do_hres(). - */ - while ((seq = READ_ONCE(vc->seq)) & 1) { - if (IS_ENABLED(CONFIG_TIME_NS) && - vc->clock_mode == VDSO_CLOCKMODE_TIMENS) - return do_coarse_timens(vd, vc, clk, ts); - cpu_relax(); - } - smp_rmb(); + if (vdso_read_begin_timens(vc, &seq)) + return do_coarse_timens(vd, vc, clk, ts); ts->tv_sec = vdso_ts->sec; ts->tv_nsec = vdso_ts->nsec; @@ -256,20 +231,12 @@ bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_ti vc = &vd->aux_clock_data[idx]; do { - /* - * Open coded function vdso_read_begin() to handle - * VDSO_CLOCK_TIMENS. See comment in do_hres(). - */ - while ((seq = READ_ONCE(vc->seq)) & 1) { - if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) { - vd = __arch_get_vdso_u_timens_data(vd); - vc = &vd->aux_clock_data[idx]; - /* Re-read from the real time data page */ - continue; - } - cpu_relax(); + if (vdso_read_begin_timens(vc, &seq)) { + vd = __arch_get_vdso_u_timens_data(vd); + vc = &vd->aux_clock_data[idx]; + /* Re-read from the real time data page */ + continue; } - smp_rmb(); /* Auxclock disabled? */ if (vc->clock_mode == VDSO_CLOCKMODE_NONE) From a657bebd7f02d0ec1ddb08c1d8c572fe1e187f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:43:22 +0100 Subject: [PATCH 23/51] vdso/gettimeofday: Add a helper to test if a clock is namespaced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently this logic is duplicate multiple times. Add a helper for it to make the code more readable. [ bp: Add a missing clocksource.h include, see https://lore.kernel.org/r/20260311113435-f72f81d8-33a6-4a0f-bd80-4997aad068cc@linutronix.de ] Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-cleanups-v1-3-c848b4bc4850@linutronix.de --- include/vdso/helpers.h | 8 +++++++- lib/vdso/gettimeofday.c | 9 +++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/vdso/helpers.h b/include/vdso/helpers.h index 9ccf6b53ef50..4d35877dff5f 100644 --- a/include/vdso/helpers.h +++ b/include/vdso/helpers.h @@ -6,6 +6,12 @@ #include #include +#include + +static __always_inline bool vdso_is_timens_clock(const struct vdso_clock *vc) +{ + return IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS; +} static __always_inline u32 vdso_read_begin(const struct vdso_clock *vc) { @@ -31,7 +37,7 @@ static __always_inline u32 vdso_read_begin(const struct vdso_clock *vc) static __always_inline bool vdso_read_begin_timens(const struct vdso_clock *vc, u32 *seq) { while (unlikely((*seq = READ_ONCE(vc->seq)) & 1)) { - if (IS_ENABLED(CONFIG_TIME_NS) && vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + if (vdso_is_timens_clock(vc)) return true; cpu_relax(); } diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index e49369676928..2faed7851635 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -343,8 +343,7 @@ __cvdso_gettimeofday_data(const struct vdso_time_data *vd, } if (unlikely(tz != NULL)) { - if (IS_ENABLED(CONFIG_TIME_NS) && - vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + if (vdso_is_timens_clock(vc)) vd = __arch_get_vdso_u_timens_data(vd); tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest; @@ -367,8 +366,7 @@ __cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time) const struct vdso_clock *vc = vd->clock_data; __kernel_old_time_t t; - if (IS_ENABLED(CONFIG_TIME_NS) && - vc->clock_mode == VDSO_CLOCKMODE_TIMENS) { + if (vdso_is_timens_clock(vc)) { vd = __arch_get_vdso_u_timens_data(vd); vc = vd->clock_data; } @@ -399,8 +397,7 @@ bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t cloc if (!vdso_clockid_valid(clock)) return false; - if (IS_ENABLED(CONFIG_TIME_NS) && - vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + if (vdso_is_timens_clock(vc)) vd = __arch_get_vdso_u_timens_data(vd); /* From 0c02d6df15d4bf7376a965b66d92ad31b0e458fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:43:23 +0100 Subject: [PATCH 24/51] vdso/gettimeofday: Move the unlikely() into vdso_read_retry() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers of vdso_read_retry() test its return value with unlikely(). Move the unlikely into the helper to make the code easier to read. This is equivalent to the retry function of non-vDSO seqlocks. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-cleanups-v1-4-c848b4bc4850@linutronix.de --- include/vdso/helpers.h | 2 +- lib/vdso/gettimeofday.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/vdso/helpers.h b/include/vdso/helpers.h index 4d35877dff5f..197d233667c2 100644 --- a/include/vdso/helpers.h +++ b/include/vdso/helpers.h @@ -53,7 +53,7 @@ static __always_inline u32 vdso_read_retry(const struct vdso_clock *vc, smp_rmb(); seq = READ_ONCE(vc->seq); - return seq != start; + return unlikely(seq != start); } static __always_inline void vdso_write_seq_begin(struct vdso_clock *vc) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 2faed7851635..efd1b82af614 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -135,7 +135,7 @@ bool do_hres_timens(const struct vdso_time_data *vdns, const struct vdso_clock * if (!vdso_get_timestamp(vd, vc, clk, &sec, &ns)) return false; - } while (unlikely(vdso_read_retry(vc, seq))); + } while (vdso_read_retry(vc, seq)); /* Add the namespace offset */ sec += offs->sec; @@ -163,7 +163,7 @@ bool do_hres(const struct vdso_time_data *vd, const struct vdso_clock *vc, if (!vdso_get_timestamp(vd, vc, clk, &sec, &ns)) return false; - } while (unlikely(vdso_read_retry(vc, seq))); + } while (vdso_read_retry(vc, seq)); vdso_set_timespec(ts, sec, ns); @@ -188,7 +188,7 @@ bool do_coarse_timens(const struct vdso_time_data *vdns, const struct vdso_clock seq = vdso_read_begin(vc); sec = vdso_ts->sec; nsec = vdso_ts->nsec; - } while (unlikely(vdso_read_retry(vc, seq))); + } while (vdso_read_retry(vc, seq)); /* Add the namespace offset */ sec += offs->sec; @@ -212,7 +212,7 @@ bool do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc, ts->tv_sec = vdso_ts->sec; ts->tv_nsec = vdso_ts->nsec; - } while (unlikely(vdso_read_retry(vc, seq))); + } while (vdso_read_retry(vc, seq)); return true; } @@ -244,7 +244,7 @@ bool do_aux(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_ti if (!vdso_get_timestamp(vd, vc, VDSO_BASE_AUX, &sec, &ns)) return false; - } while (unlikely(vdso_read_retry(vc, seq))); + } while (vdso_read_retry(vc, seq)); vdso_set_timespec(ts, sec, ns); From b18ec8b5e0ceb311d860c6521a00056a60cbd5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:27 +0100 Subject: [PATCH 25/51] arm64: vDSO: gettimeofday: Explicitly include vdso/clocksource.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reference to VDSO_CLOCKMODE_NONE requires vdso/clocksource.h. Currently this header is included transitively, but that transitive inclusion is about to go away. Explicitly include the header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Acked-by: Catalin Marinas Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-1-35d60acf7410@linutronix.de --- arch/arm64/include/asm/vdso/gettimeofday.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 3658a757e255..96d2eccd4995 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -9,6 +9,8 @@ #ifndef __ASSEMBLER__ +#include + #include #include #include From 2b8cf39d7e0b4964d27f499e74aed7e5e06dafd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:28 +0100 Subject: [PATCH 26/51] arm64: vDSO: compat_gettimeofday: Add explicit includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reference to VDSO_CLOCKMODE_ARCHTIMER requires vdso/clocksource.h and 'struct old_timespec32' requires vdso/time32.h. Currently these headers are included transitively, but those transitive inclusions are about to go away. Explicitly include the headers. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Acked-by: Catalin Marinas Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-2-35d60acf7410@linutronix.de --- arch/arm64/include/asm/vdso/compat_gettimeofday.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h index 0d513f924321..a03e34b572f1 100644 --- a/arch/arm64/include/asm/vdso/compat_gettimeofday.h +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -7,6 +7,9 @@ #ifndef __ASSEMBLER__ +#include +#include + #include #include #include From 89e6796fa530a90059c63b7c02e54a426d278c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:29 +0100 Subject: [PATCH 27/51] ARM: vdso: gettimeofday: Add explicit includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reference to VDSO_CLOCKMODE_NONE requires vdso/clocksource.h and 'struct old_timespec32' requires vdso/time32.h. Currently these headers are included transitively, but those transitive inclusions are about to go away. Explicitly include the headers. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-3-35d60acf7410@linutronix.de --- arch/arm/include/asm/vdso/gettimeofday.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 1e9f81639c88..26da5d8621cc 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #define VDSO_HAS_CLOCK_GETRES 1 From 3852dd5abc306a64060266a20b64d46a3037b735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:30 +0100 Subject: [PATCH 28/51] powerpc/vdso/gettimeofday: Explicitly include vdso/time32.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usage of 'struct old_timespec32' requires vdso/time32.h. Currently this header is included transitively, but that transitive inclusion is about to go away. Explicitly include the header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Christophe Leroy Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-4-35d60acf7410@linutronix.de --- arch/powerpc/include/asm/vdso/gettimeofday.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h index 8ea397e26ad0..a853f853da6c 100644 --- a/arch/powerpc/include/asm/vdso/gettimeofday.h +++ b/arch/powerpc/include/asm/vdso/gettimeofday.h @@ -8,6 +8,7 @@ #include #include #include +#include #define VDSO_HAS_CLOCK_GETRES 1 From 9c89d8bd64b8c03ad3d5b6fd52550b8773a12669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:31 +0100 Subject: [PATCH 29/51] powerpc/vdso: Explicitly include asm/cputable.h and asm/feature-fixups.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usage of ASM_FTR_IFCLR(CPU_TR_ARCH_31) requires asm/cputable.h and asm/feature-fixups.h. Currently these headers are included transitively, but that transitive inclusion is about to go away. Explicitly include the headers. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Christophe Leroy Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-5-35d60acf7410@linutronix.de --- arch/powerpc/include/asm/vdso/processor.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/vdso/processor.h b/arch/powerpc/include/asm/vdso/processor.h index c1f3d7aaf3ee..4c6802c3a580 100644 --- a/arch/powerpc/include/asm/vdso/processor.h +++ b/arch/powerpc/include/asm/vdso/processor.h @@ -4,6 +4,9 @@ #ifndef __ASSEMBLER__ +#include +#include + /* Macros for adjusting thread priority (hardware multi-threading) */ #ifdef CONFIG_PPC64 #define HMT_very_low() asm volatile("or 31, 31, 31 # very low priority") From 55434071cdcf50f6c2da9a9ecafb32465fb3bf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:32 +0100 Subject: [PATCH 30/51] LoongArch: vDSO: Explicitly include asm/vdso/vdso.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usage of 'struct old_timespec32' requires asm/vdso/vdso.h. Currently this header is included transitively, but that transitive inclusion is about to go away. Explicitly include the header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-6-35d60acf7410@linutronix.de --- arch/loongarch/kernel/process.c | 1 + arch/loongarch/kernel/vdso.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index 4ac1c3086152..ac3a0baa5d00 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef CONFIG_STACKPROTECTOR #include diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c index 0aa10cadb959..8ce8159c10b9 100644 --- a/arch/loongarch/kernel/vdso.c +++ b/arch/loongarch/kernel/vdso.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include From a9d7e1ea5897477d704bd03eaa93d19634e90523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:33 +0100 Subject: [PATCH 31/51] MIPS: vdso: Add include guard to asm/vdso/vdso.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An upcomming patch will lead to the header file being included multiple times from the same source file. Add an include guard so this is possible. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-7-35d60acf7410@linutronix.de --- arch/mips/include/asm/vdso/vdso.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/mips/include/asm/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h index 6889e0f2e5db..ef50d33f3439 100644 --- a/arch/mips/include/asm/vdso/vdso.h +++ b/arch/mips/include/asm/vdso/vdso.h @@ -4,6 +4,9 @@ * Author: Alex Smith */ +#ifndef __ASM_VDSO_VDSO_H +#define __ASM_VDSO_VDSO_H + #include #include @@ -70,3 +73,5 @@ static inline void __iomem *get_gic(const struct vdso_time_data *data) #endif /* CONFIG_CLKSRC_MIPS_GIC */ #endif /* __ASSEMBLER__ */ + +#endif /* __ASM_VDSO_VDSO_H */ From 5dca096e865fbf37febb4dde26d9a52288da6db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:34 +0100 Subject: [PATCH 32/51] MIPS: vdso: Explicitly include asm/vdso/vdso.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usage of __VDSO_PAGES requires asm/vdso/vdso.h. Currently this header is included transitively, but that transitive inclusion is about to go away. Explicitly include the header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-8-35d60acf7410@linutronix.de --- arch/mips/kernel/vdso.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index de096777172f..2fa4df3e46e4 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include From 32bd966050486d3fed6980aa3de3e60b9e383589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:35 +0100 Subject: [PATCH 33/51] random: vDSO: Add explicit includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various used symbols are only visible through transitive includes. These transitive includes are about to go away. Explicitly include the necessary headers. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Acked-by: Jason A. Donenfeld Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-9-35d60acf7410@linutronix.de --- lib/vdso/getrandom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/vdso/getrandom.c b/lib/vdso/getrandom.c index 440f8a6203a6..7e29005aa208 100644 --- a/lib/vdso/getrandom.c +++ b/lib/vdso/getrandom.c @@ -7,8 +7,11 @@ #include #include #include +#include #include +#include #include +#include #include #include From 9fc2232e285bbd3d71c251376255d7fb2ae34f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:36 +0100 Subject: [PATCH 34/51] vdso/gettimeofday: Add explicit includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various used symbols are only visible through transitive includes. These transitive includes are about to go away. Explicitly include the necessary headers. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-10-35d60acf7410@linutronix.de --- lib/vdso/gettimeofday.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index efd1b82af614..ad79642056d5 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -3,8 +3,14 @@ * Generic userspace implementations of gettimeofday() and similar. */ #include +#include #include #include +#include +#include +#include +#include +#include /* Bring in default accessors */ #include From 8bd49acb4e81d2859f66a30e8edfd984f91c6c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:37 +0100 Subject: [PATCH 35/51] vdso/helpers: Explicitly include vdso/processor.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The usage of cpu_relax() requires vdso/processor.h. Currently this header is included transitively, but that transitive inclusion is about to go away. Explicitly include the header. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-11-35d60acf7410@linutronix.de --- include/vdso/helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/vdso/helpers.h b/include/vdso/helpers.h index 197d233667c2..a3bf4f1c0d37 100644 --- a/include/vdso/helpers.h +++ b/include/vdso/helpers.h @@ -6,6 +6,7 @@ #include #include +#include #include static __always_inline bool vdso_is_timens_clock(const struct vdso_clock *vc) From 750d8cc84901757d9e5fe96207f5aa6b3e2acf92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:38 +0100 Subject: [PATCH 36/51] vdso/datapage: Remove inclusion of gettimeofday.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vdso/datapage.h is useful without pulling in the architecture-specific gettimeofday() helpers. Move the include to the only users which needs it. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-12-35d60acf7410@linutronix.de --- include/vdso/datapage.h | 11 ----------- lib/vdso/gettimeofday.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index 07c2e086d8f4..339a34e88c73 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -184,17 +184,6 @@ enum vdso_pages { VDSO_NR_PAGES }; -/* - * The generic vDSO implementation requires that gettimeofday.h - * provides: - * - __arch_get_hw_counter(): to get the hw counter based on the - * clock_mode. - * - gettimeofday_fallback(): fallback for gettimeofday. - * - clock_gettime_fallback(): fallback for clock_gettime. - * - clock_getres_fallback(): fallback for clock_getres. - */ -#include - #else /* !__ASSEMBLY__ */ #ifdef CONFIG_VDSO_GETRANDOM diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index ad79642056d5..a5798bd26d20 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -12,6 +12,17 @@ #include #include +/* + * The generic vDSO implementation requires that gettimeofday.h + * provides: + * - __arch_get_hw_counter(): to get the hw counter based on the + * clock_mode. + * - gettimeofday_fallback(): fallback for gettimeofday. + * - clock_gettime_fallback(): fallback for clock_gettime. + * - clock_getres_fallback(): fallback for clock_getres. + */ +#include + /* Bring in default accessors */ #include From f5e386fe5f1c26b24fb9ffc616f8e857f43cf88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:39 +0100 Subject: [PATCH 37/51] vdso/datapage: Trim down unnecessary includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vdso/datapage.h includes a lot of headers which are not strictly necessary. Some of those headers include architecture-specific vDSO headers which prevent the usage of vdso/datapage.h in kernel code on architectures without an vDSO. This would be useful however to write generic code using IS_ENABLED(), for example in drivers/char/random.c. Remove the unnecessary includes. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-13-35d60acf7410@linutronix.de --- include/vdso/datapage.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index 339a34e88c73..5977723fb3b5 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -4,24 +4,16 @@ #ifndef __ASSEMBLY__ -#include +#include + #include #include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include #include -#include -#include #ifdef CONFIG_ARCH_HAS_VDSO_TIME_DATA #include From fc880ff14acd49202c83b569316bd19c6a037a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:40 +0100 Subject: [PATCH 38/51] random: vDSO: Trim vDSO includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These includes are not used, remove them. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Jason A. Donenfeld Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-14-35d60acf7410@linutronix.de --- drivers/char/random.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 7ff4d29911fd..304cdab939c2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -57,9 +57,7 @@ #include #include #ifdef CONFIG_VDSO_GETRANDOM -#include #include -#include #endif #include #include From 260b98f75b618aa209998557dbd1d13dbc64bc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:44:41 +0100 Subject: [PATCH 39/51] random: vDSO: Remove ifdeffery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent cleanups of the vDSO headers allow the unconditional inclusion of vdso/datapage.h and the declarations it provides. This also means that the declaration of vdso_k_rng_data is always visible and its usage does not need to be guarded by ifdefs anymore. Instead use IS_ENABLED(). Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Jason A. Donenfeld Link: https://patch.msgid.link/20260227-vdso-header-cleanups-v2-15-35d60acf7410@linutronix.de --- drivers/char/random.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 304cdab939c2..b4da1fb976c1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -56,9 +56,7 @@ #include #include #include -#ifdef CONFIG_VDSO_GETRANDOM #include -#endif #include #include #include @@ -267,7 +265,7 @@ static void crng_reseed(struct work_struct *work) if (next_gen == ULONG_MAX) ++next_gen; WRITE_ONCE(base_crng.generation, next_gen); -#ifdef CONFIG_VDSO_GETRANDOM + /* base_crng.generation's invalid value is ULONG_MAX, while * vdso_k_rng_data->generation's invalid value is 0, so add one to the * former to arrive at the latter. Use smp_store_release so that this @@ -281,8 +279,9 @@ static void crng_reseed(struct work_struct *work) * because the vDSO side only checks whether the value changed, without * actually using or interpreting the value. */ - smp_store_release((unsigned long *)&vdso_k_rng_data->generation, next_gen + 1); -#endif + if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + smp_store_release((unsigned long *)&vdso_k_rng_data->generation, next_gen + 1); + if (!static_branch_likely(&crng_is_ready)) crng_init = CRNG_READY; spin_unlock_irqrestore(&base_crng.lock, flags); @@ -732,9 +731,8 @@ static void __cold _credit_init_bits(size_t bits) if (system_dfl_wq) queue_work(system_dfl_wq, &set_ready); atomic_notifier_call_chain(&random_ready_notifier, 0, NULL); -#ifdef CONFIG_VDSO_GETRANDOM - WRITE_ONCE(vdso_k_rng_data->is_ready, true); -#endif + if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + WRITE_ONCE(vdso_k_rng_data->is_ready, true); wake_up_interruptible(&crng_init_wait); kill_fasync(&fasync, SIGIO, POLL_IN); pr_notice("crng init done\n"); From 5abfa0c4da3bdcc53597127be7cd4054812b0383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:45:56 +0100 Subject: [PATCH 40/51] Revert "selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c9fbaa879508 ("selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers") The kernel headers were used to make parse_vdso.c compatible with nolibc. Unfortunately linux/elf.h is incompatible with glibc's sys/auxv.h. When using glibc it is therefore not possible build parse_vdso.c as part of the same compilation unit as its caller as sys/auxv.h is needed for getauxval(). In the meantime nolibc gained its own elf.h, providing compatibility with the documented libc interfaces. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-1-d84830fa8beb@linutronix.de --- tools/testing/selftests/vDSO/Makefile | 2 -- tools/testing/selftests/vDSO/parse_vdso.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile index e361aca22a74..2de5cef311c8 100644 --- a/tools/testing/selftests/vDSO/Makefile +++ b/tools/testing/selftests/vDSO/Makefile @@ -19,8 +19,6 @@ endif include ../lib.mk -CFLAGS += $(TOOLS_INCLUDES) - CFLAGS_NOLIBC := -nostdlib -nostdinc -ffreestanding -fno-asynchronous-unwind-tables \ -fno-stack-protector -include $(top_srcdir)/tools/include/nolibc/nolibc.h \ -I$(top_srcdir)/tools/include/nolibc/ $(KHDR_INCLUDES) diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c index 3ff00fb624a4..c6ff4413ea36 100644 --- a/tools/testing/selftests/vDSO/parse_vdso.c +++ b/tools/testing/selftests/vDSO/parse_vdso.c @@ -19,8 +19,7 @@ #include #include #include -#include -#include +#include #include "parse_vdso.h" From 50692c25ee2e8f9093ec3409ee43b342d9d07775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:45:57 +0100 Subject: [PATCH 41/51] selftests: vDSO: vdso_test_gettimeofday: Remove nolibc checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nolibc now provides these headers, making the check unnecessary. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-2-d84830fa8beb@linutronix.de --- tools/testing/selftests/vDSO/vdso_test_gettimeofday.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c index 912edadad92c..990b29e0e272 100644 --- a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c +++ b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c @@ -11,10 +11,8 @@ */ #include -#ifndef NOLIBC #include #include -#endif #include "kselftest.h" #include "parse_vdso.h" From ad2af7768fac884ede727d2a085bd78b8e13fdef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:45:58 +0100 Subject: [PATCH 42/51] selftests: vDSO: vdso_test_correctness: Drop SYS_getcpu fallbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These fallbacks are only valid on x86 and unused in the first place. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-3-d84830fa8beb@linutronix.de --- tools/testing/selftests/vDSO/vdso_test_correctness.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/testing/selftests/vDSO/vdso_test_correctness.c b/tools/testing/selftests/vDSO/vdso_test_correctness.c index 055af95aa552..2a2d9b01a938 100644 --- a/tools/testing/selftests/vDSO/vdso_test_correctness.c +++ b/tools/testing/selftests/vDSO/vdso_test_correctness.c @@ -25,14 +25,6 @@ static const char **name; -#ifndef SYS_getcpu -# ifdef __x86_64__ -# define SYS_getcpu 309 -# else -# define SYS_getcpu 318 -# endif -#endif - #ifndef __NR_clock_gettime64 #define __NR_clock_gettime64 403 #endif From 38bc16aa47dc89dc3753ee5359c7a7c15f7bf602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:45:59 +0100 Subject: [PATCH 43/51] selftests: vDSO: vdso_test_correctness: Handle different tv_usec types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On SPARC the field tv_usec of 'struct timespec' is not a 'long int', but only a regular int. In this case the format string is incorrect and will trigger compiler warnings. Avoid the warnings by casting to 'long long', similar to how it is done for the tv_sec and what the other similar selftests are doing. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Tested-by: Andreas Larsson Reviewed-by: Andreas Larsson Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-4-d84830fa8beb@linutronix.de --- tools/testing/selftests/vDSO/vdso_test_correctness.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/vDSO/vdso_test_correctness.c b/tools/testing/selftests/vDSO/vdso_test_correctness.c index 2a2d9b01a938..9b564888e74d 100644 --- a/tools/testing/selftests/vDSO/vdso_test_correctness.c +++ b/tools/testing/selftests/vDSO/vdso_test_correctness.c @@ -404,10 +404,10 @@ static void test_gettimeofday(void) return; } - printf("\t%llu.%06ld %llu.%06ld %llu.%06ld\n", - (unsigned long long)start.tv_sec, start.tv_usec, - (unsigned long long)vdso.tv_sec, vdso.tv_usec, - (unsigned long long)end.tv_sec, end.tv_usec); + printf("\t%llu.%06lld %llu.%06lld %llu.%06lld\n", + (unsigned long long)start.tv_sec, (long long)start.tv_usec, + (unsigned long long)vdso.tv_sec, (long long)vdso.tv_usec, + (unsigned long long)end.tv_sec, (long long)end.tv_usec); if (!tv_leq(&start, &vdso) || !tv_leq(&vdso, &end)) { printf("[FAIL]\tTimes are out of sequence\n"); From a8b22a158a47e459d4d353600b1405391bbfb567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:46:00 +0100 Subject: [PATCH 44/51] selftests: vDSO: vdso_test_correctness: Use facilities from parse_vdso.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The soname from the vDSO is not a public API. Furthermore it requires libc to implement dlsym() and friends. Use the facilities from parse_vdso.c instead which uses the official vDSO ABI to find it, aligned with the other vDSO selftests. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-5-d84830fa8beb@linutronix.de --- tools/testing/selftests/vDSO/Makefile | 4 +-- .../selftests/vDSO/vdso_test_correctness.c | 30 ++++++++----------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile index 2de5cef311c8..a61047bdcd57 100644 --- a/tools/testing/selftests/vDSO/Makefile +++ b/tools/testing/selftests/vDSO/Makefile @@ -26,13 +26,11 @@ CFLAGS_NOLIBC := -nostdlib -nostdinc -ffreestanding -fno-asynchronous-unwind-tab $(OUTPUT)/vdso_test_gettimeofday: parse_vdso.c vdso_test_gettimeofday.c $(OUTPUT)/vdso_test_getcpu: parse_vdso.c vdso_test_getcpu.c $(OUTPUT)/vdso_test_abi: parse_vdso.c vdso_test_abi.c +$(OUTPUT)/vdso_test_correctness: parse_vdso.c vdso_test_correctness.c $(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c | headers $(OUTPUT)/vdso_standalone_test_x86: CFLAGS:=$(CFLAGS_NOLIBC) $(CFLAGS) -$(OUTPUT)/vdso_test_correctness: vdso_test_correctness.c -$(OUTPUT)/vdso_test_correctness: LDFLAGS += -ldl - $(OUTPUT)/vdso_test_getrandom: parse_vdso.c $(OUTPUT)/vdso_test_getrandom: CFLAGS += -isystem $(top_srcdir)/tools/include \ $(KHDR_INCLUDES) \ diff --git a/tools/testing/selftests/vDSO/vdso_test_correctness.c b/tools/testing/selftests/vDSO/vdso_test_correctness.c index 9b564888e74d..a94ab4d597b1 100644 --- a/tools/testing/selftests/vDSO/vdso_test_correctness.c +++ b/tools/testing/selftests/vDSO/vdso_test_correctness.c @@ -11,18 +11,20 @@ #include #include #include +#include #include -#include #include #include #include #include #include +#include "parse_vdso.h" #include "vdso_config.h" #include "vdso_call.h" #include "kselftest.h" +static const char *version; static const char **name; #ifndef __NR_clock_gettime64 @@ -102,39 +104,32 @@ static void *vsyscall_getcpu(void) static void fill_function_pointers(void) { - void *vdso = dlopen("linux-vdso.so.1", - RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - if (!vdso) - vdso = dlopen("linux-gate.so.1", - RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - if (!vdso) - vdso = dlopen("linux-vdso32.so.1", - RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - if (!vdso) - vdso = dlopen("linux-vdso64.so.1", - RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); - if (!vdso) { + unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); + + if (!sysinfo_ehdr) { printf("[WARN]\tfailed to find vDSO\n"); return; } - vdso_getcpu = (getcpu_t)dlsym(vdso, name[4]); + vdso_init_from_sysinfo_ehdr(sysinfo_ehdr); + + vdso_getcpu = (getcpu_t)vdso_sym(version, name[4]); if (!vdso_getcpu) printf("Warning: failed to find getcpu in vDSO\n"); vgetcpu = (getcpu_t) vsyscall_getcpu(); - vdso_clock_gettime = (vgettime_t)dlsym(vdso, name[1]); + vdso_clock_gettime = (vgettime_t)vdso_sym(version, name[1]); if (!vdso_clock_gettime) printf("Warning: failed to find clock_gettime in vDSO\n"); #if defined(VDSO_32BIT) - vdso_clock_gettime64 = (vgettime64_t)dlsym(vdso, name[5]); + vdso_clock_gettime64 = (vgettime64_t)vdso_sym(version, name[5]); if (!vdso_clock_gettime64) printf("Warning: failed to find clock_gettime64 in vDSO\n"); #endif - vdso_gettimeofday = (vgtod_t)dlsym(vdso, name[0]); + vdso_gettimeofday = (vgtod_t)vdso_sym(version, name[0]); if (!vdso_gettimeofday) printf("Warning: failed to find gettimeofday in vDSO\n"); @@ -429,6 +424,7 @@ static void test_gettimeofday(void) int main(int argc, char **argv) { + version = versions[VDSO_VERSION]; name = (const char **)&names[VDSO_NAMES]; fill_function_pointers(); From bed0053a6303d908266aaaabf4fa96e2d02a4abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 27 Feb 2026 07:46:01 +0100 Subject: [PATCH 45/51] selftests: vDSO: vdso_test_correctness: Add a test for time() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the test to also cover the time() function. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Signed-off-by: Borislav Petkov (AMD) Link: https://patch.msgid.link/20260227-vdso-selftest-cleanups-v2-6-d84830fa8beb@linutronix.de --- .../selftests/vDSO/vdso_test_correctness.c | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tools/testing/selftests/vDSO/vdso_test_correctness.c b/tools/testing/selftests/vDSO/vdso_test_correctness.c index a94ab4d597b1..5c5a07dd1128 100644 --- a/tools/testing/selftests/vDSO/vdso_test_correctness.c +++ b/tools/testing/selftests/vDSO/vdso_test_correctness.c @@ -55,6 +55,10 @@ typedef long (*vgtod_t)(struct timeval *tv, struct timezone *tz); vgtod_t vdso_gettimeofday; +typedef time_t (*vtime_t)(__kernel_time_t *tloc); + +vtime_t vdso_time; + typedef long (*getcpu_t)(unsigned *, unsigned *, void *); getcpu_t vgetcpu; @@ -133,6 +137,10 @@ static void fill_function_pointers(void) if (!vdso_gettimeofday) printf("Warning: failed to find gettimeofday in vDSO\n"); + vdso_time = (vtime_t)vdso_sym(version, name[2]); + if (!vdso_time) + printf("Warning: failed to find time in vDSO\n"); + } static long sys_getcpu(unsigned * cpu, unsigned * node, @@ -156,6 +164,16 @@ static inline int sys_gettimeofday(struct timeval *tv, struct timezone *tz) return syscall(__NR_gettimeofday, tv, tz); } +static inline __kernel_old_time_t sys_time(__kernel_old_time_t *tloc) +{ +#ifdef __NR_time + return syscall(__NR_time, tloc); +#else + errno = ENOSYS; + return -1; +#endif +} + static void test_getcpu(void) { printf("[RUN]\tTesting getcpu...\n"); @@ -422,6 +440,53 @@ static void test_gettimeofday(void) VDSO_CALL(vdso_gettimeofday, 2, &vdso, NULL); } +static void test_time(void) +{ + __kernel_old_time_t start, end, vdso_ret, vdso_param; + + if (!vdso_time) + return; + + printf("[RUN]\tTesting time...\n"); + + if (sys_time(&start) < 0) { + if (errno == -ENOSYS) { + printf("[SKIP]\tNo time() support\n"); + } else { + printf("[FAIL]\tsys_time failed (%d)\n", errno); + nerrs++; + } + return; + } + + vdso_ret = VDSO_CALL(vdso_time, 1, &vdso_param); + end = sys_time(NULL); + + if (vdso_ret < 0 || end < 0) { + printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n", + (int)vdso_ret, errno); + nerrs++; + return; + } + + printf("\t%lld %lld %lld\n", + (long long)start, + (long long)vdso_ret, + (long long)end); + + if (vdso_ret != vdso_param) { + printf("[FAIL]\tinconsistent return values: %lld %lld\n", + (long long)vdso_ret, (long long)vdso_param); + nerrs++; + return; + } + + if (!(start <= vdso_ret) || !(vdso_ret <= end)) { + printf("[FAIL]\tTimes are out of sequence\n"); + nerrs++; + } +} + int main(int argc, char **argv) { version = versions[VDSO_VERSION]; @@ -432,6 +497,7 @@ int main(int argc, char **argv) test_clock_gettime(); test_clock_gettime64(); test_gettimeofday(); + test_time(); /* * Test getcpu() last so that, if something goes wrong setting affinity, From 5dc9cf835aba73c882348aa4f99be83b6e45ad9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 26 Mar 2026 12:42:30 +0100 Subject: [PATCH 46/51] vdso/timens: Move functions to new file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a preparation of the untangling of time namespaces and the vDSO, move the glue functions between those subsystems into a new file. While at it, switch the mutex lock and mmap_read_lock() in the vDSO namespace code to guard(). Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260326-vdso-timens-decoupling-v2-1-c82693a7775f@linutronix.de --- MAINTAINERS | 2 + include/linux/time_namespace.h | 8 -- kernel/time/Makefile | 2 +- kernel/time/namespace.c | 124 +------------------------- kernel/time/namespace_internal.h | 13 +++ kernel/time/namespace_vdso.c | 146 +++++++++++++++++++++++++++++++ lib/vdso/datastore.c | 25 ------ 7 files changed, 166 insertions(+), 154 deletions(-) create mode 100644 kernel/time/namespace_internal.h create mode 100644 kernel/time/namespace_vdso.c diff --git a/MAINTAINERS b/MAINTAINERS index 77fdfcb55f06..6ad74a5196d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10768,6 +10768,7 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso F: include/asm-generic/vdso/vsyscall.h F: include/vdso/ +F: kernel/time/namespace_vdso.c F: kernel/time/vsyscall.c F: lib/vdso/ F: tools/testing/selftests/vDSO/ @@ -21000,6 +21001,7 @@ F: include/trace/events/timer* F: kernel/time/itimer.c F: kernel/time/posix-* F: kernel/time/namespace.c +F: kernel/time/namespace_vdso.c POWER MANAGEMENT CORE M: "Rafael J. Wysocki" diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h index c514d0e5a45c..0421bf1b13d7 100644 --- a/include/linux/time_namespace.h +++ b/include/linux/time_namespace.h @@ -38,8 +38,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 int vdso_join_timens(struct task_struct *task, - struct time_namespace *ns); extern void timens_commit(struct task_struct *tsk, struct time_namespace *ns); static inline struct time_namespace *get_time_ns(struct time_namespace *ns) @@ -117,12 +115,6 @@ static inline void __init time_ns_init(void) { } -static inline int vdso_join_timens(struct task_struct *task, - struct time_namespace *ns) -{ - return 0; -} - static inline void timens_commit(struct task_struct *tsk, struct time_namespace *ns) { diff --git a/kernel/time/Makefile b/kernel/time/Makefile index f7d52d9543cc..662bccb3b7f9 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -29,6 +29,6 @@ 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 +obj-$(CONFIG_TIME_NS) += namespace.o 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 652744e00eb4..903f55a2dfb2 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -19,7 +19,7 @@ #include #include -#include +#include "namespace_internal.h" ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim, struct timens_offsets *ns_offsets) @@ -138,117 +138,7 @@ struct time_namespace *copy_time_ns(u64 flags, return clone_time_ns(user_ns, old_ns); } -static struct timens_offset offset_from_ts(struct timespec64 off) -{ - struct timens_offset ret; - - ret.sec = off.tv_sec; - ret.nsec = off.tv_nsec; - - return ret; -} - -/* - * A time namespace VVAR page has the same layout as the VVAR page which - * contains the system wide VDSO data. - * - * For a normal task the VVAR pages are installed in the normal ordering: - * VVAR - * PVCLOCK - * HVCLOCK - * TIMENS <- Not really required - * - * Now for a timens task the pages are installed in the following order: - * TIMENS - * PVCLOCK - * HVCLOCK - * VVAR - * - * The check for vdso_clock->clock_mode is in the unlikely path of - * the seq begin magic. So for the non-timens case most of the time - * 'seq' is even, so the branch is not taken. - * - * If 'seq' is odd, i.e. a concurrent update is in progress, the extra check - * for vdso_clock->clock_mode is a non-issue. The task is spin waiting for the - * update to finish and for 'seq' to become even anyway. - * - * Timens page has vdso_clock->clock_mode set to VDSO_CLOCKMODE_TIMENS which - * enforces the time namespace handling path. - */ -static void timens_setup_vdso_clock_data(struct vdso_clock *vc, - struct time_namespace *ns) -{ - struct timens_offset *offset = vc->offset; - struct timens_offset monotonic = offset_from_ts(ns->offsets.monotonic); - struct timens_offset boottime = offset_from_ts(ns->offsets.boottime); - - vc->seq = 1; - vc->clock_mode = VDSO_CLOCKMODE_TIMENS; - offset[CLOCK_MONOTONIC] = monotonic; - offset[CLOCK_MONOTONIC_RAW] = monotonic; - offset[CLOCK_MONOTONIC_COARSE] = monotonic; - offset[CLOCK_BOOTTIME] = boottime; - offset[CLOCK_BOOTTIME_ALARM] = boottime; -} - -struct page *find_timens_vvar_page(struct vm_area_struct *vma) -{ - if (likely(vma->vm_mm == current->mm)) - return current->nsproxy->time_ns->vvar_page; - - /* - * VM_PFNMAP | VM_IO protect .fault() handler from being called - * through interfaces like /proc/$pid/mem or - * process_vm_{readv,writev}() as long as there's no .access() - * in special_mapping_vmops(). - * For more details check_vma_flags() and __access_remote_vm() - */ - - WARN(1, "vvar_page accessed remotely"); - - return NULL; -} - -/* - * Protects possibly multiple offsets writers racing each other - * and tasks entering the namespace. - */ -static DEFINE_MUTEX(offset_lock); - -static void timens_set_vvar_page(struct task_struct *task, - struct time_namespace *ns) -{ - struct vdso_time_data *vdata; - struct vdso_clock *vc; - unsigned int i; - - if (ns == &init_time_ns) - return; - - /* Fast-path, taken by every task in namespace except the first. */ - if (likely(ns->frozen_offsets)) - return; - - mutex_lock(&offset_lock); - /* Nothing to-do: vvar_page has been already initialized. */ - if (ns->frozen_offsets) - goto out; - - ns->frozen_offsets = true; - vdata = page_address(ns->vvar_page); - vc = vdata->clock_data; - - 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); -} +DEFINE_MUTEX(timens_offset_lock); void free_time_ns(struct time_namespace *ns) { @@ -298,12 +188,6 @@ static void timens_put(struct ns_common *ns) put_time_ns(to_time_ns(ns)); } -void timens_commit(struct task_struct *tsk, struct time_namespace *ns) -{ - timens_set_vvar_page(tsk, ns); - vdso_join_timens(tsk, ns); -} - static int timens_install(struct nsset *nsset, struct ns_common *new) { struct nsproxy *nsproxy = nsset->nsproxy; @@ -428,7 +312,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, goto out; } - mutex_lock(&offset_lock); + mutex_lock(&timens_offset_lock); if (time_ns->frozen_offsets) { err = -EACCES; goto out_unlock; @@ -453,7 +337,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, } out_unlock: - mutex_unlock(&offset_lock); + mutex_unlock(&timens_offset_lock); out: put_time_ns(time_ns); diff --git a/kernel/time/namespace_internal.h b/kernel/time/namespace_internal.h new file mode 100644 index 000000000000..e85da11abb4d --- /dev/null +++ b/kernel/time/namespace_internal.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TIME_NAMESPACE_INTERNAL_H +#define _TIME_NAMESPACE_INTERNAL_H + +#include + +/* + * Protects possibly multiple offsets writers racing each other + * and tasks entering the namespace. + */ +extern struct mutex timens_offset_lock; + +#endif /* _TIME_NAMESPACE_INTERNAL_H */ diff --git a/kernel/time/namespace_vdso.c b/kernel/time/namespace_vdso.c new file mode 100644 index 000000000000..0e154f901501 --- /dev/null +++ b/kernel/time/namespace_vdso.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Andrei Vagin + * Author: Dmitry Safonov + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "namespace_internal.h" + +static struct timens_offset offset_from_ts(struct timespec64 off) +{ + struct timens_offset ret; + + ret.sec = off.tv_sec; + ret.nsec = off.tv_nsec; + + return ret; +} + +/* + * A time namespace VVAR page has the same layout as the VVAR page which + * contains the system wide VDSO data. + * + * For a normal task the VVAR pages are installed in the normal ordering: + * VVAR + * PVCLOCK + * HVCLOCK + * TIMENS <- Not really required + * + * Now for a timens task the pages are installed in the following order: + * TIMENS + * PVCLOCK + * HVCLOCK + * VVAR + * + * The check for vdso_clock->clock_mode is in the unlikely path of + * the seq begin magic. So for the non-timens case most of the time + * 'seq' is even, so the branch is not taken. + * + * If 'seq' is odd, i.e. a concurrent update is in progress, the extra check + * for vdso_clock->clock_mode is a non-issue. The task is spin waiting for the + * update to finish and for 'seq' to become even anyway. + * + * Timens page has vdso_clock->clock_mode set to VDSO_CLOCKMODE_TIMENS which + * enforces the time namespace handling path. + */ +static void timens_setup_vdso_clock_data(struct vdso_clock *vc, + struct time_namespace *ns) +{ + struct timens_offset *offset = vc->offset; + struct timens_offset monotonic = offset_from_ts(ns->offsets.monotonic); + struct timens_offset boottime = offset_from_ts(ns->offsets.boottime); + + vc->seq = 1; + vc->clock_mode = VDSO_CLOCKMODE_TIMENS; + offset[CLOCK_MONOTONIC] = monotonic; + offset[CLOCK_MONOTONIC_RAW] = monotonic; + offset[CLOCK_MONOTONIC_COARSE] = monotonic; + offset[CLOCK_BOOTTIME] = boottime; + offset[CLOCK_BOOTTIME_ALARM] = boottime; +} + +struct page *find_timens_vvar_page(struct vm_area_struct *vma) +{ + if (likely(vma->vm_mm == current->mm)) + return current->nsproxy->time_ns->vvar_page; + + /* + * VM_PFNMAP | VM_IO protect .fault() handler from being called + * through interfaces like /proc/$pid/mem or + * process_vm_{readv,writev}() as long as there's no .access() + * in special_mapping_vmops(). + * For more details check_vma_flags() and __access_remote_vm() + */ + + WARN(1, "vvar_page accessed remotely"); + + return NULL; +} + +static void timens_set_vvar_page(struct task_struct *task, + struct time_namespace *ns) +{ + struct vdso_time_data *vdata; + struct vdso_clock *vc; + unsigned int i; + + if (ns == &init_time_ns) + return; + + /* Fast-path, taken by every task in namespace except the first. */ + if (likely(ns->frozen_offsets)) + return; + + guard(mutex)(&timens_offset_lock); + /* Nothing to-do: vvar_page has been already initialized. */ + if (ns->frozen_offsets) + return; + + ns->frozen_offsets = true; + vdata = page_address(ns->vvar_page); + vc = vdata->clock_data; + + 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); + } +} + +/* + * The vvar page layout depends on whether a task belongs to the root or + * non-root time namespace. Whenever a task changes its namespace, the VVAR + * page tables are cleared and then they will be re-faulted with a + * corresponding layout. + * See also the comment near timens_setup_vdso_clock_data() for details. + */ +static int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma; + VMA_ITERATOR(vmi, mm, 0); + + guard(mmap_read_lock)(mm); + for_each_vma(vmi, vma) { + if (vma_is_special_mapping(vma, &vdso_vvar_mapping)) + zap_vma_pages(vma); + } + return 0; +} + +void timens_commit(struct task_struct *tsk, struct time_namespace *ns) +{ + timens_set_vvar_page(tsk, ns); + vdso_join_timens(tsk, ns); +} diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c index faebf5b7cd6e..cf5d784a4a5a 100644 --- a/lib/vdso/datastore.c +++ b/lib/vdso/datastore.c @@ -132,28 +132,3 @@ struct vm_area_struct *vdso_install_vvar_mapping(struct mm_struct *mm, unsigned VM_MIXEDMAP | VM_SEALED_SYSMAP, &vdso_vvar_mapping); } - -#ifdef CONFIG_TIME_NS -/* - * The vvar page layout depends on whether a task belongs to the root or - * non-root time namespace. Whenever a task changes its namespace, the VVAR - * page tables are cleared and then they will be re-faulted with a - * corresponding layout. - * See also the comment near timens_setup_vdso_clock_data() for details. - */ -int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) -{ - struct mm_struct *mm = task->mm; - struct vm_area_struct *vma; - VMA_ITERATOR(vmi, mm, 0); - - mmap_read_lock(mm); - for_each_vma(vmi, vma) { - if (vma_is_special_mapping(vma, &vdso_vvar_mapping)) - zap_vma_pages(vma); - } - mmap_read_unlock(mm); - - return 0; -} -#endif From 1b6c89285d37114d7efe8ab04102a542581cd7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 26 Mar 2026 12:42:31 +0100 Subject: [PATCH 47/51] timens: Remove dependency on the vDSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Thomas Gleixner 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 0421bf1b13d7..c1de21a27c34 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 444ce811ea67..5e710b03a27a 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 662bccb3b7f9..eaf290c972f9 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 903f55a2dfb2..42302cc3f3fb 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 e85da11abb4d..b37ba179f43b 100644 --- a/kernel/time/namespace_internal.h +++ b/kernel/time/namespace_internal.h @@ -4,10 +4,25 @@ #include +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 0e154f901501..88c075cd16a3 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); +} From c2de5a5be4d60af5f928a2dd2b0f73e17358e346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 30 Mar 2026 09:07:55 +0200 Subject: [PATCH 48/51] timens: Add a __free() wrapper for put_time_ns() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrapper will be used to simplify cleanups of 'struct time_namespace'. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260330-timens-cleanup-v1-1-936e91c9dd30@linutronix.de --- include/linux/time_namespace.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/time_namespace.h b/include/linux/time_namespace.h index c1de21a27c34..58bd9728df58 100644 --- a/include/linux/time_namespace.h +++ b/include/linux/time_namespace.h @@ -8,6 +8,7 @@ #include #include #include +#include struct user_namespace; extern struct user_namespace init_user_ns; @@ -171,4 +172,6 @@ static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma) } #endif /* CONFIG_TIME_NS_VDSO */ +DEFINE_FREE(time_ns, struct time_namespace *, if (_T) put_time_ns(_T)) + #endif /* _LINUX_TIMENS_H */ From 3fa3aeb4a5cb19e372680ef8860a0381cd5409e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 30 Mar 2026 09:07:56 +0200 Subject: [PATCH 49/51] timens: Simplify some calls to put_time_ns() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new __free() based cleanup helpers to simplify some functions. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260330-timens-cleanup-v1-2-936e91c9dd30@linutronix.de --- kernel/time/namespace.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 42302cc3f3fb..37495bde92a4 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "namespace_internal.h" @@ -251,36 +252,33 @@ static void show_offset(struct seq_file *m, int clockid, struct timespec64 *ts) void proc_timens_show_offsets(struct task_struct *p, struct seq_file *m) { - struct ns_common *ns; - struct time_namespace *time_ns; + struct time_namespace *time_ns __free(time_ns) = NULL; + struct ns_common *ns = timens_for_children_get(p); - ns = timens_for_children_get(p); if (!ns) return; + time_ns = to_time_ns(ns); show_offset(m, CLOCK_MONOTONIC, &time_ns->offsets.monotonic); show_offset(m, CLOCK_BOOTTIME, &time_ns->offsets.boottime); - put_time_ns(time_ns); } int proc_timens_set_offset(struct file *file, struct task_struct *p, struct proc_timens_offset *offsets, int noffsets) { - struct ns_common *ns; - struct time_namespace *time_ns; + struct time_namespace *time_ns __free(time_ns) = NULL; + struct ns_common *ns = timens_for_children_get(p); struct timespec64 tp; int i, err; - ns = timens_for_children_get(p); if (!ns) return -ESRCH; + time_ns = to_time_ns(ns); - if (!file_ns_capable(file, time_ns->user_ns, CAP_SYS_TIME)) { - put_time_ns(time_ns); + if (!file_ns_capable(file, time_ns->user_ns, CAP_SYS_TIME)) return -EPERM; - } for (i = 0; i < noffsets; i++) { struct proc_timens_offset *off = &offsets[i]; @@ -293,15 +291,12 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, ktime_get_boottime_ts64(&tp); break; default: - err = -EINVAL; - goto out; + return -EINVAL; } - err = -ERANGE; - if (off->val.tv_sec > KTIME_SEC_MAX || off->val.tv_sec < -KTIME_SEC_MAX) - goto out; + return -ERANGE; tp = timespec64_add(tp, off->val); /* @@ -309,7 +304,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, * still unreachable. */ if (tp.tv_sec < 0 || tp.tv_sec > KTIME_SEC_MAX / 2) - goto out; + return -ERANGE; } mutex_lock(&timens_offset_lock); @@ -338,8 +333,6 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, out_unlock: mutex_unlock(&timens_offset_lock); -out: - put_time_ns(time_ns); return err; } From 6d89dc8b1c559ee2662db86f7490ac52cab3030c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 30 Mar 2026 09:07:57 +0200 Subject: [PATCH 50/51] timens: Use mutex guard in proc_timens_set_offset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the logic in proc_timens_set_offset() by converting the mutex usage to a guard(). Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260330-timens-cleanup-v1-3-936e91c9dd30@linutronix.de --- kernel/time/namespace.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 37495bde92a4..084ceec35495 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -270,7 +270,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, struct time_namespace *time_ns __free(time_ns) = NULL; struct ns_common *ns = timens_for_children_get(p); struct timespec64 tp; - int i, err; + int i; if (!ns) return -ESRCH; @@ -307,13 +307,10 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, return -ERANGE; } - mutex_lock(&timens_offset_lock); - if (time_ns->frozen_offsets) { - err = -EACCES; - goto out_unlock; - } + guard(mutex)(&timens_offset_lock); + if (time_ns->frozen_offsets) + return -EACCES; - err = 0; /* Don't report errors after this line */ for (i = 0; i < noffsets; i++) { struct proc_timens_offset *off = &offsets[i]; @@ -331,10 +328,7 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p, *offset = off->val; } -out_unlock: - mutex_unlock(&timens_offset_lock); - - return err; + return 0; } const struct proc_ns_operations timens_operations = { From 7138a8698a39e81eb153e05500823fff76d5b3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 30 Mar 2026 09:07:58 +0200 Subject: [PATCH 51/51] timens: Use task_lock guard in timens_get*() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the logic in timens_get*() by converting the task_lock usage to a guard(). Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260330-timens-cleanup-v1-4-936e91c9dd30@linutronix.de --- kernel/time/namespace.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 084ceec35495..4bca3f78c8ea 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -154,34 +154,32 @@ void free_time_ns(struct time_namespace *ns) static struct ns_common *timens_get(struct task_struct *task) { - struct time_namespace *ns = NULL; + struct time_namespace *ns; struct nsproxy *nsproxy; - task_lock(task); + guard(task_lock)(task); nsproxy = task->nsproxy; - if (nsproxy) { - ns = nsproxy->time_ns; - get_time_ns(ns); - } - task_unlock(task); + if (!nsproxy) + return NULL; - return ns ? &ns->ns : NULL; + ns = nsproxy->time_ns; + get_time_ns(ns); + return &ns->ns; } static struct ns_common *timens_for_children_get(struct task_struct *task) { - struct time_namespace *ns = NULL; + struct time_namespace *ns; struct nsproxy *nsproxy; - task_lock(task); + guard(task_lock)(task); nsproxy = task->nsproxy; - if (nsproxy) { - ns = nsproxy->time_ns_for_children; - get_time_ns(ns); - } - task_unlock(task); + if (!nsproxy) + return NULL; - return ns ? &ns->ns : NULL; + ns = nsproxy->time_ns_for_children; + get_time_ns(ns); + return &ns->ns; } static void timens_put(struct ns_common *ns)