From b205656daf932c06aff424de5d6d01faf60faa5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:12 +0100 Subject: [PATCH 01/18] vdso: Add prototype for __vdso_clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. The generic vDSO library already provides nearly all necessary building blocks for architectures to provide this function. Only a prototype is missing. Add the prototype to the generic header so architectures can start providing this function. Suggested-by: Arnd Bergmann Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-1-97ea7a06a543@linutronix.de --- include/vdso/gettime.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/vdso/gettime.h b/include/vdso/gettime.h index 9ac161866653..16a0a0556b86 100644 --- a/include/vdso/gettime.h +++ b/include/vdso/gettime.h @@ -20,5 +20,6 @@ int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); __kernel_old_time_t __vdso_time(__kernel_old_time_t *t); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); +int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts); #endif From 609e359ab904698f1e5aa0ab2fee2f4c29ee0886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:13 +0100 Subject: [PATCH 02/18] selftests: vDSO: vdso_config: Add configurations for clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some architectures will start to implement this function. Make sure that tests can be written for it. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-2-97ea7a06a543@linutronix.de --- tools/testing/selftests/vDSO/vdso_config.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/vDSO/vdso_config.h b/tools/testing/selftests/vDSO/vdso_config.h index 50c261005111..5da223731b81 100644 --- a/tools/testing/selftests/vDSO/vdso_config.h +++ b/tools/testing/selftests/vDSO/vdso_config.h @@ -66,7 +66,7 @@ static const char *versions[7] = { }; __attribute__((unused)) -static const char *names[2][7] = { +static const char *names[2][8] = { { "__kernel_gettimeofday", "__kernel_clock_gettime", @@ -75,6 +75,7 @@ static const char *names[2][7] = { "__kernel_getcpu", "__kernel_clock_gettime64", "__kernel_getrandom", + "__kernel_clock_getres_time64", }, { "__vdso_gettimeofday", @@ -84,6 +85,7 @@ static const char *names[2][7] = { "__vdso_getcpu", "__vdso_clock_gettime64", "__vdso_getrandom", + "__vdso_clock_getres_time64", }, }; From 1dcd1273add368c2b7c65135e22b416e1b374781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:14 +0100 Subject: [PATCH 03/18] selftests: vDSO: vdso_test_abi: Use UAPI system call numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SYS_clock_getres might have been redirected by libc to some other system call than the actual clock_getres. For testing it is required to use exactly this system call. Use the system call number exported by the UAPI headers which is always correct. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-3-97ea7a06a543@linutronix.de --- tools/testing/selftests/vDSO/vdso_test_abi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c index c620317eaeea..a75c12dcb0f1 100644 --- a/tools/testing/selftests/vDSO/vdso_test_abi.c +++ b/tools/testing/selftests/vDSO/vdso_test_abi.c @@ -179,7 +179,7 @@ static void vdso_test_clock_getres(clockid_t clk_id) clock_getres_fail++; } - ret = syscall(SYS_clock_getres, clk_id, &sys_ts); + ret = syscall(__NR_clock_getres, clk_id, &sys_ts); ksft_print_msg("The syscall resolution is %lld %lld\n", (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); From 4e6a2312986d437cc22805b9e08f86b15fee0318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:15 +0100 Subject: [PATCH 04/18] selftests: vDSO: vdso_test_abi: Add test for clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some architectures will start to implement this function. Make sure it works correctly. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-4-97ea7a06a543@linutronix.de --- tools/testing/selftests/vDSO/vdso_test_abi.c | 53 +++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c index a75c12dcb0f1..b162a4ba9c4f 100644 --- a/tools/testing/selftests/vDSO/vdso_test_abi.c +++ b/tools/testing/selftests/vDSO/vdso_test_abi.c @@ -36,6 +36,7 @@ typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); typedef long (*vdso_clock_gettime64_t)(clockid_t clk_id, struct vdso_timespec64 *ts); typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); +typedef long (*vdso_clock_getres_time64_t)(clockid_t clk_id, struct vdso_timespec64 *ts); typedef time_t (*vdso_time_t)(time_t *t); static const char * const vdso_clock_name[] = { @@ -196,6 +197,55 @@ static void vdso_test_clock_getres(clockid_t clk_id) } } +#ifdef __NR_clock_getres_time64 +static void vdso_test_clock_getres_time64(clockid_t clk_id) +{ + int clock_getres_fail = 0; + + /* Find clock_getres. */ + vdso_clock_getres_time64_t vdso_clock_getres_time64 = + (vdso_clock_getres_time64_t)vdso_sym(version, name[7]); + + if (!vdso_clock_getres_time64) { + ksft_print_msg("Couldn't find %s\n", name[7]); + ksft_test_result_skip("%s %s\n", name[7], + vdso_clock_name[clk_id]); + return; + } + + struct vdso_timespec64 ts, sys_ts; + long ret = VDSO_CALL(vdso_clock_getres_time64, 2, clk_id, &ts); + + if (ret == 0) { + ksft_print_msg("The vdso resolution is %lld %lld\n", + (long long)ts.tv_sec, (long long)ts.tv_nsec); + } else { + clock_getres_fail++; + } + + ret = syscall(__NR_clock_getres_time64, clk_id, &sys_ts); + + ksft_print_msg("The syscall resolution is %lld %lld\n", + (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec); + + if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) + clock_getres_fail++; + + if (clock_getres_fail > 0) { + ksft_test_result_fail("%s %s\n", name[7], + vdso_clock_name[clk_id]); + } else { + ksft_test_result_pass("%s %s\n", name[7], + vdso_clock_name[clk_id]); + } +} +#else /* !__NR_clock_getres_time64 */ +static void vdso_test_clock_getres_time64(clockid_t clk_id) +{ + ksft_test_result_skip("%s %s\n", name[7], vdso_clock_name[clk_id]); +} +#endif /* __NR_clock_getres_time64 */ + /* * This function calls vdso_test_clock_gettime and vdso_test_clock_getres * with different values for clock_id. @@ -208,9 +258,10 @@ static inline void vdso_test_clock(clockid_t clock_id) vdso_test_clock_gettime64(clock_id); vdso_test_clock_getres(clock_id); + vdso_test_clock_getres_time64(clock_id); } -#define VDSO_TEST_PLAN 29 +#define VDSO_TEST_PLAN 38 int main(int argc, char **argv) { From 21bbfd74044f77a98bbc27ea9e6cb04f4dfd8ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:16 +0100 Subject: [PATCH 05/18] x86/vdso: Provide clock_getres_time64() for x86-32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-5-97ea7a06a543@linutronix.de --- arch/x86/entry/vdso/vclock_gettime.c | 8 ++++++++ arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 + 2 files changed, 9 insertions(+) diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 0debc194bd78..027b7e88d753 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -74,4 +74,12 @@ int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res) int clock_getres(clockid_t, struct old_timespec32 *) __attribute__((weak, alias("__vdso_clock_getres"))); + +int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_getres(clock, ts); +} + +int clock_getres_time64(clockid_t, struct __kernel_timespec *) + __attribute__((weak, alias("__vdso_clock_getres_time64"))); #endif diff --git a/arch/x86/entry/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S index 8a3be07006bb..6f977c103584 100644 --- a/arch/x86/entry/vdso/vdso32/vdso32.lds.S +++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S @@ -28,6 +28,7 @@ VERSION __vdso_time; __vdso_clock_getres; __vdso_clock_gettime64; + __vdso_clock_getres_time64; __vdso_getcpu; }; From b9fecf0dddfc55cd7d02b0011494da3c613f7cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:17 +0100 Subject: [PATCH 06/18] ARM: VDSO: Patch out __vdso_clock_getres() if unavailable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vDSO code hides symbols which are non-functional. __vdso_clock_getres() was not added to this list when it got introduced. Fixes: 052e76a31b4a ("ARM: 8931/1: Add clock_getres entry point") Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-6-97ea7a06a543@linutronix.de --- arch/arm/kernel/vdso.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index e38a30477f3d..566c40f0f7c7 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -161,6 +161,7 @@ static void __init patch_vdso(void *ehdr) vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); + vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); } } From 1149dcdfc9ef4b3fa90b431a5752da53dcadb0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:18 +0100 Subject: [PATCH 07/18] ARM: VDSO: Provide clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-7-97ea7a06a543@linutronix.de --- arch/arm/kernel/vdso.c | 1 + arch/arm/vdso/vdso.lds.S | 1 + arch/arm/vdso/vgettimeofday.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index 566c40f0f7c7..0108f33d6bed 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -162,6 +162,7 @@ static void __init patch_vdso(void *ehdr) vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); vdso_nullpatch_one(&einfo, "__vdso_clock_getres"); + vdso_nullpatch_one(&einfo, "__vdso_clock_getres_time64"); } } diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S index 7c08371f4400..74d8d8bc8a40 100644 --- a/arch/arm/vdso/vdso.lds.S +++ b/arch/arm/vdso/vdso.lds.S @@ -74,6 +74,7 @@ VERSION __vdso_gettimeofday; __vdso_clock_getres; __vdso_clock_gettime64; + __vdso_clock_getres_time64; local: *; }; } diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index 3554aa35f1ba..f7a2f5dc2fdc 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -34,6 +34,11 @@ int __vdso_clock_getres(clockid_t clock_id, return __cvdso_clock_getres_time32(clock_id, res); } +int __vdso_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res) +{ + return __cvdso_clock_getres(clock_id, res); +} + /* Avoid unresolved references emitted by GCC */ void __aeabi_unwind_cpp_pr0(void) From f10c2e72b5dea0bc7485a05da8e21781b69d5508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:19 +0100 Subject: [PATCH 08/18] arm64: vdso32: Provide clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Acked-by: Will Deacon Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-8-97ea7a06a543@linutronix.de --- arch/arm64/kernel/vdso32/vdso.lds.S | 1 + arch/arm64/kernel/vdso32/vgettimeofday.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S index e02b27487ce8..c374fb0146f3 100644 --- a/arch/arm64/kernel/vdso32/vdso.lds.S +++ b/arch/arm64/kernel/vdso32/vdso.lds.S @@ -86,6 +86,7 @@ VERSION __vdso_gettimeofday; __vdso_clock_getres; __vdso_clock_gettime64; + __vdso_clock_getres_time64; local: *; }; } diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index 29b4d8f61e39..0c6998ebe491 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -32,6 +32,11 @@ int __vdso_clock_getres(clockid_t clock_id, return __cvdso_clock_getres_time32(clock_id, res); } +int __vdso_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res) +{ + return __cvdso_clock_getres(clock_id, res); +} + /* Avoid unresolved references emitted by GCC */ void __aeabi_unwind_cpp_pr0(void) From bec06cd6a140ceb62ee4634c9550212f5f05bcfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 23 Dec 2025 07:59:20 +0100 Subject: [PATCH 09/18] MIPS: vdso: Provide getres_time64() for 32-bit ABIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223-vdso-compat-time32-v1-9-97ea7a06a543@linutronix.de --- arch/mips/vdso/vdso.lds.S | 1 + arch/mips/vdso/vgettimeofday.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S index c8bbe56d89cb..5d08be3a6b85 100644 --- a/arch/mips/vdso/vdso.lds.S +++ b/arch/mips/vdso/vdso.lds.S @@ -103,6 +103,7 @@ VERSION __vdso_clock_getres; #if _MIPS_SIM != _MIPS_SIM_ABI64 __vdso_clock_gettime64; + __vdso_clock_getres_time64; #endif #endif local: *; diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c index 604afea3f336..1d236215e8f6 100644 --- a/arch/mips/vdso/vgettimeofday.c +++ b/arch/mips/vdso/vgettimeofday.c @@ -46,6 +46,11 @@ int __vdso_clock_gettime64(clockid_t clock, return __cvdso_clock_gettime(clock, ts); } +int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_getres(clock, ts); +} + #else int __vdso_clock_gettime(clockid_t clock, From 7158fc54b2c6f124eec0d7cd13bff69da0172e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 30 Dec 2025 08:08:44 +0100 Subject: [PATCH 10/18] vdso: Remove struct getcpu_cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cache parameter of getcpu() is useless nowadays for various reasons. * It is never passed by userspace for either the vDSO or syscalls. * It is never used by the kernel. * It could not be made to work on the current vDSO architecture. * The structure definition is not part of the UAPI headers. * vdso_getcpu() is superseded by restartable sequences in any case. Remove the struct and its header. As a side-effect this gets rid of an unwanted inclusion of the linux/ header namespace from vDSO code. [ tglx: Adapt to s390 upstream changes */ Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Acked-by: Arnd Bergmann Acked-by: Heiko Carstens # s390 Link: https://patch.msgid.link/20251230-getcpu_cache-v3-1-fb9c5f880ebe@linutronix.de --- arch/loongarch/vdso/vgetcpu.c | 5 ++--- arch/s390/kernel/vdso/getcpu.c | 3 +-- arch/s390/kernel/vdso/vdso.h | 4 +--- arch/x86/entry/vdso/vgetcpu.c | 5 ++--- arch/x86/include/asm/vdso/processor.h | 4 +--- include/linux/getcpu.h | 19 ------------------- include/linux/syscalls.h | 3 +-- kernel/sys.c | 4 +--- .../testing/selftests/vDSO/vdso_test_getcpu.c | 4 +--- 9 files changed, 10 insertions(+), 41 deletions(-) delete mode 100644 include/linux/getcpu.h diff --git a/arch/loongarch/vdso/vgetcpu.c b/arch/loongarch/vdso/vgetcpu.c index 73af49242ecd..6f054ec898c7 100644 --- a/arch/loongarch/vdso/vgetcpu.c +++ b/arch/loongarch/vdso/vgetcpu.c @@ -4,7 +4,6 @@ */ #include -#include static __always_inline int read_cpu_id(void) { @@ -28,8 +27,8 @@ static __always_inline int read_cpu_id(void) } extern -int __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused); -int __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused) +int __vdso_getcpu(unsigned int *cpu, unsigned int *node, void *unused); +int __vdso_getcpu(unsigned int *cpu, unsigned int *node, void *unused) { int cpu_id; diff --git a/arch/s390/kernel/vdso/getcpu.c b/arch/s390/kernel/vdso/getcpu.c index 5c5d4a848b76..1e17665616c5 100644 --- a/arch/s390/kernel/vdso/getcpu.c +++ b/arch/s390/kernel/vdso/getcpu.c @@ -2,11 +2,10 @@ /* Copyright IBM Corp. 2020 */ #include -#include #include #include "vdso.h" -int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) +int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, void *unused) { union tod_clock clk; diff --git a/arch/s390/kernel/vdso/vdso.h b/arch/s390/kernel/vdso/vdso.h index 8cff033dd854..1fe52a6f5a56 100644 --- a/arch/s390/kernel/vdso/vdso.h +++ b/arch/s390/kernel/vdso/vdso.h @@ -4,9 +4,7 @@ #include -struct getcpu_cache; - -int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused); +int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, void *unused); int __s390_vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __s390_vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); int __s390_vdso_clock_getres(clockid_t clock, struct __kernel_timespec *ts); diff --git a/arch/x86/entry/vdso/vgetcpu.c b/arch/x86/entry/vdso/vgetcpu.c index e4640306b2e3..6381b472b7c5 100644 --- a/arch/x86/entry/vdso/vgetcpu.c +++ b/arch/x86/entry/vdso/vgetcpu.c @@ -6,17 +6,16 @@ */ #include -#include #include #include notrace long -__vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) +__vdso_getcpu(unsigned *cpu, unsigned *node, void *unused) { vdso_read_cpunode(cpu, node); return 0; } -long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) +long getcpu(unsigned *cpu, unsigned *node, void *tcache) __attribute__((weak, alias("__vdso_getcpu"))); diff --git a/arch/x86/include/asm/vdso/processor.h b/arch/x86/include/asm/vdso/processor.h index 7000aeb59aa2..93e0e24e5cb4 100644 --- a/arch/x86/include/asm/vdso/processor.h +++ b/arch/x86/include/asm/vdso/processor.h @@ -18,9 +18,7 @@ static __always_inline void cpu_relax(void) native_pause(); } -struct getcpu_cache; - -notrace long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused); +notrace long __vdso_getcpu(unsigned *cpu, unsigned *node, void *unused); #endif /* __ASSEMBLER__ */ diff --git a/include/linux/getcpu.h b/include/linux/getcpu.h deleted file mode 100644 index c304dcdb4eac..000000000000 --- a/include/linux/getcpu.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_GETCPU_H -#define _LINUX_GETCPU_H 1 - -/* Cache for getcpu() to speed it up. Results might be a short time - out of date, but will be faster. - - User programs should not refer to the contents of this structure. - I repeat they should not refer to it. If they do they will break - in future kernels. - - It is only a private cache for vgetcpu(). It will change in future kernels. - The user program must store this information per thread (__thread) - If you want 100% accurate information pass NULL instead. */ -struct getcpu_cache { - unsigned long blob[128 / sizeof(long)]; -}; - -#endif diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index cf84d98964b2..23704e006afd 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -59,7 +59,6 @@ struct compat_stat; struct old_timeval32; struct robust_list_head; struct futex_waitv; -struct getcpu_cache; struct old_linux_dirent; struct perf_event_attr; struct file_handle; @@ -718,7 +717,7 @@ asmlinkage long sys_getrusage(int who, struct rusage __user *ru); asmlinkage long sys_umask(int mask); asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); +asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, void __user *cache); asmlinkage long sys_gettimeofday(struct __kernel_old_timeval __user *tv, struct timezone __user *tz); asmlinkage long sys_settimeofday(struct __kernel_old_timeval __user *tv, diff --git a/kernel/sys.c b/kernel/sys.c index 8b58eece4e58..f1780ab132a3 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -2876,8 +2875,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return error; } -SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, - struct getcpu_cache __user *, unused) +SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, void __user *, unused) { int err = 0; int cpu = raw_smp_processor_id(); diff --git a/tools/testing/selftests/vDSO/vdso_test_getcpu.c b/tools/testing/selftests/vDSO/vdso_test_getcpu.c index bea8ad54da11..3fe49cbdae98 100644 --- a/tools/testing/selftests/vDSO/vdso_test_getcpu.c +++ b/tools/testing/selftests/vDSO/vdso_test_getcpu.c @@ -16,9 +16,7 @@ #include "vdso_config.h" #include "vdso_call.h" -struct getcpu_cache; -typedef long (*getcpu_t)(unsigned int *, unsigned int *, - struct getcpu_cache *); +typedef long (*getcpu_t)(unsigned int *, unsigned int *, void *); int main(int argc, char **argv) { From df0f9a664be55a8529362a1ada847a19a91e4807 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Oct 2025 13:51:23 -0700 Subject: [PATCH 11/18] parisc: Inline a type punning version of get_unaligned_le32() Reading the byte/char output_len with get_unaligned_le32() can trigger compiler warnings due to the size read. Avoid these warnings by using type punning. This avoids issues when switching get_unaligned_t() to __builtin_memcpy(). Signed-off-by: Ian Rogers Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251016205126.2882625-2-irogers@google.com --- arch/parisc/boot/compressed/misc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c index 9c83bd06ef15..111f267230a1 100644 --- a/arch/parisc/boot/compressed/misc.c +++ b/arch/parisc/boot/compressed/misc.c @@ -278,6 +278,19 @@ static void parse_elf(void *output) free(phdrs); } +/* + * The regular get_unaligned_le32 uses __builtin_memcpy which can trigger + * warnings when reading a byte/char output_len as an integer, as the size of a + * char is less than that of an integer. Use type punning and the packed + * attribute, which requires -fno-strict-aliasing, to work around the problem. + */ +static u32 punned_get_unaligned_le32(const void *p) +{ + const struct { __le32 x; } __packed * __get_pptr = p; + + return le32_to_cpu(__get_pptr->x); +} + asmlinkage unsigned long __visible decompress_kernel(unsigned int started_wide, unsigned int command_line, const unsigned int rd_start, @@ -309,7 +322,7 @@ asmlinkage unsigned long __visible decompress_kernel(unsigned int started_wide, * leave 2 MB for the stack. */ vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024; - vmlinux_len = get_unaligned_le32(&output_len); + vmlinux_len = punned_get_unaligned_le32(&output_len); output = (char *) vmlinux_addr; /* From a339671db64b12bb02492557d2b0658811286277 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Oct 2025 13:51:24 -0700 Subject: [PATCH 12/18] vdso: Switch get/put_unaligned() from packed struct to memcpy() Type punning is necessary for get/put_unaligned() but the use of a packed struct violates strict aliasing rules, requiring -fno-strict-aliasing to be passed to the C compiler. Switch to using memcpy() so that -fno-strict-aliasing isn't necessary. Signed-off-by: Ian Rogers Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251016205126.2882625-3-irogers@google.com --- include/vdso/unaligned.h | 41 ++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/include/vdso/unaligned.h b/include/vdso/unaligned.h index ff0c06b6513e..9076483c9fbb 100644 --- a/include/vdso/unaligned.h +++ b/include/vdso/unaligned.h @@ -2,14 +2,43 @@ #ifndef __VDSO_UNALIGNED_H #define __VDSO_UNALIGNED_H -#define __get_unaligned_t(type, ptr) ({ \ - const struct { type x; } __packed * __get_pptr = (typeof(__get_pptr))(ptr); \ - __get_pptr->x; \ +#include + +/** + * __get_unaligned_t - read an unaligned value from memory. + * @type: the type to load from the pointer. + * @ptr: the pointer to load from. + * + * Use memcpy to affect an unaligned type sized load avoiding undefined behavior + * from approaches like type punning that require -fno-strict-aliasing in order + * to be correct. As type may be const, use __unqual_scalar_typeof to map to a + * non-const type - you can't memcpy into a const type. The + * __get_unaligned_ctrl_type gives __unqual_scalar_typeof its required + * expression rather than type, a pointer is used to avoid warnings about mixing + * the use of 0 and NULL. The void* cast silences ubsan warnings. + */ +#define __get_unaligned_t(type, ptr) ({ \ + type *__get_unaligned_ctrl_type __always_unused = NULL; \ + __unqual_scalar_typeof(*__get_unaligned_ctrl_type) __get_unaligned_val; \ + __builtin_memcpy(&__get_unaligned_val, (void *)(ptr), \ + sizeof(__get_unaligned_val)); \ + __get_unaligned_val; \ }) -#define __put_unaligned_t(type, val, ptr) do { \ - struct { type x; } __packed * __put_pptr = (typeof(__put_pptr))(ptr); \ - __put_pptr->x = (val); \ +/** + * __put_unaligned_t - write an unaligned value to memory. + * @type: the type of the value to store. + * @val: the value to store. + * @ptr: the pointer to store to. + * + * Use memcpy to affect an unaligned type sized store avoiding undefined + * behavior from approaches like type punning that require -fno-strict-aliasing + * in order to be correct. The void* cast silences ubsan warnings. + */ +#define __put_unaligned_t(type, val, ptr) do { \ + type __put_unaligned_val = (val); \ + __builtin_memcpy((void *)(ptr), &__put_unaligned_val, \ + sizeof(__put_unaligned_val)); \ } while (0) #endif /* __VDSO_UNALIGNED_H */ From 1d7cf255eefbb479d0eea9aa3b6372a1e52f8c62 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Oct 2025 13:51:25 -0700 Subject: [PATCH 13/18] tools headers: Update the linux/unaligned.h copy with the kernel sources To pick up the changes in: vdso: Switch get/put_unaligned() from packed struct to memcpy As the code is dependent on __unqual_scalar_typeof, update also the tools version of compiler_types.h to include this. Signed-off-by: Ian Rogers Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251016205126.2882625-4-irogers@google.com --- tools/include/linux/compiler_types.h | 22 +++++++++++++++ tools/include/vdso/unaligned.h | 41 ++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/compiler_types.h index d09f9dc172a4..890982283a5e 100644 --- a/tools/include/linux/compiler_types.h +++ b/tools/include/linux/compiler_types.h @@ -40,4 +40,26 @@ #define asm_goto_output(x...) asm goto(x) #endif +/* + * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving + * non-scalar types unchanged. + */ +/* + * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' + * is not type-compatible with 'signed char', and we define a separate case. + */ +#define __scalar_type_to_expr_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unqual_scalar_typeof(x) typeof( \ + _Generic((x), \ + char: (char)0, \ + __scalar_type_to_expr_cases(char), \ + __scalar_type_to_expr_cases(short), \ + __scalar_type_to_expr_cases(int), \ + __scalar_type_to_expr_cases(long), \ + __scalar_type_to_expr_cases(long long), \ + default: (x))) + #endif /* __LINUX_COMPILER_TYPES_H */ diff --git a/tools/include/vdso/unaligned.h b/tools/include/vdso/unaligned.h index ff0c06b6513e..9076483c9fbb 100644 --- a/tools/include/vdso/unaligned.h +++ b/tools/include/vdso/unaligned.h @@ -2,14 +2,43 @@ #ifndef __VDSO_UNALIGNED_H #define __VDSO_UNALIGNED_H -#define __get_unaligned_t(type, ptr) ({ \ - const struct { type x; } __packed * __get_pptr = (typeof(__get_pptr))(ptr); \ - __get_pptr->x; \ +#include + +/** + * __get_unaligned_t - read an unaligned value from memory. + * @type: the type to load from the pointer. + * @ptr: the pointer to load from. + * + * Use memcpy to affect an unaligned type sized load avoiding undefined behavior + * from approaches like type punning that require -fno-strict-aliasing in order + * to be correct. As type may be const, use __unqual_scalar_typeof to map to a + * non-const type - you can't memcpy into a const type. The + * __get_unaligned_ctrl_type gives __unqual_scalar_typeof its required + * expression rather than type, a pointer is used to avoid warnings about mixing + * the use of 0 and NULL. The void* cast silences ubsan warnings. + */ +#define __get_unaligned_t(type, ptr) ({ \ + type *__get_unaligned_ctrl_type __always_unused = NULL; \ + __unqual_scalar_typeof(*__get_unaligned_ctrl_type) __get_unaligned_val; \ + __builtin_memcpy(&__get_unaligned_val, (void *)(ptr), \ + sizeof(__get_unaligned_val)); \ + __get_unaligned_val; \ }) -#define __put_unaligned_t(type, val, ptr) do { \ - struct { type x; } __packed * __put_pptr = (typeof(__put_pptr))(ptr); \ - __put_pptr->x = (val); \ +/** + * __put_unaligned_t - write an unaligned value to memory. + * @type: the type of the value to store. + * @val: the value to store. + * @ptr: the pointer to store to. + * + * Use memcpy to affect an unaligned type sized store avoiding undefined + * behavior from approaches like type punning that require -fno-strict-aliasing + * in order to be correct. The void* cast silences ubsan warnings. + */ +#define __put_unaligned_t(type, val, ptr) do { \ + type __put_unaligned_val = (val); \ + __builtin_memcpy((void *)(ptr), &__put_unaligned_val, \ + sizeof(__put_unaligned_val)); \ } while (0) #endif /* __VDSO_UNALIGNED_H */ From 10a62a0611f5544d209446acfde5beb7b27773c7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 16 Oct 2025 13:51:26 -0700 Subject: [PATCH 14/18] tools headers: Remove unneeded ignoring of warnings in unaligned.h Now that get/put_unaligned() use memcpy() the -Wpacked and -Wattributes warnings don't need disabling anymore. Signed-off-by: Ian Rogers Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251016205126.2882625-5-irogers@google.com --- tools/include/linux/unaligned.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/include/linux/unaligned.h b/tools/include/linux/unaligned.h index 395a4464fe73..d51ddafed138 100644 --- a/tools/include/linux/unaligned.h +++ b/tools/include/linux/unaligned.h @@ -6,9 +6,6 @@ * This is the most generic implementation of unaligned accesses * and should work almost anywhere. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpacked" -#pragma GCC diagnostic ignored "-Wattributes" #include #define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr)) @@ -143,6 +140,5 @@ static inline u64 get_unaligned_be48(const void *p) { return __get_unaligned_be48(p); } -#pragma GCC diagnostic pop #endif /* __LINUX_UNALIGNED_H */ From 759a1f97373f25770cf438d9fb5f2bddf4d77a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 14 Jan 2026 08:26:05 +0100 Subject: [PATCH 15/18] powerpc/vdso: Provide clock_getres_time64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with __vdso_clock_gettime64() there should also be a 64-bit variant of clock_getres(). This will allow the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and finally the removal of 32-bit time types from the kernel and UAPI. Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Reviewed-by: Christophe Leroy (CS GROUP) Link: https://patch.msgid.link/20260114-vdso-powerpc-align-v1-1-acf09373d568@linutronix.de --- arch/powerpc/include/asm/vdso/gettimeofday.h | 2 ++ arch/powerpc/kernel/vdso/gettimeofday.S | 12 ++++++++++++ arch/powerpc/kernel/vdso/vdso32.lds.S | 1 + arch/powerpc/kernel/vdso/vgettimeofday.c | 6 ++++++ 4 files changed, 21 insertions(+) diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h index ab3df12c8d94..8ea397e26ad0 100644 --- a/arch/powerpc/include/asm/vdso/gettimeofday.h +++ b/arch/powerpc/include/asm/vdso/gettimeofday.h @@ -135,6 +135,8 @@ int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts, const struct vdso_time_data *vd); int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res, const struct vdso_time_data *vd); +int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res, + const struct vdso_time_data *vd); #endif int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz, const struct vdso_time_data *vd); diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S index 79c967212444..1c8e51691bf8 100644 --- a/arch/powerpc/kernel/vdso/gettimeofday.S +++ b/arch/powerpc/kernel/vdso/gettimeofday.S @@ -103,6 +103,18 @@ V_FUNCTION_BEGIN(__kernel_clock_getres) cvdso_call __c_kernel_clock_getres V_FUNCTION_END(__kernel_clock_getres) +/* + * Exact prototype of clock_getres_time64() + * + * int __kernel_clock_getres(clockid_t clock_id, struct __timespec64 *res); + * + */ +#ifndef __powerpc64__ +V_FUNCTION_BEGIN(__kernel_clock_getres_time64) + cvdso_call __c_kernel_clock_getres_time64 +V_FUNCTION_END(__kernel_clock_getres_time64) +#endif + /* * Exact prototype of time() diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S index 72a1012b8a20..3f384a2526ae 100644 --- a/arch/powerpc/kernel/vdso/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso/vdso32.lds.S @@ -124,6 +124,7 @@ VERSION __kernel_clock_gettime; __kernel_clock_gettime64; __kernel_clock_getres; + __kernel_clock_getres_time64; __kernel_time; __kernel_get_tbfreq; __kernel_sync_dicache; diff --git a/arch/powerpc/kernel/vdso/vgettimeofday.c b/arch/powerpc/kernel/vdso/vgettimeofday.c index 6f5167d81af5..3c194e1ab562 100644 --- a/arch/powerpc/kernel/vdso/vgettimeofday.c +++ b/arch/powerpc/kernel/vdso/vgettimeofday.c @@ -35,6 +35,12 @@ int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res, { return __cvdso_clock_getres_time32_data(vd, clock_id, res); } + +int __c_kernel_clock_getres_time64(clockid_t clock_id, struct __kernel_timespec *res, + const struct vdso_time_data *vd) +{ + return __cvdso_clock_getres_data(vd, clock_id, res); +} #endif int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz, From fd69b2f7d5f4e1d89cea4cdfa6f15e7fa53d8358 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 16 Jan 2026 19:18:16 +0100 Subject: [PATCH 16/18] compiler: Use __typeof_unqual__() for __unqual_scalar_typeof() The recent changes to get_unaligned() resulted in a new sparse warning: net/rds/ib_cm.c:96:35: sparse: sparse: incorrect type in argument 1 (different modifiers) @@ expected void * @@ got restricted __be64 const * @@ net/rds/ib_cm.c:96:35: sparse: expected void * net/rds/ib_cm.c:96:35: sparse: got restricted __be64 const * The updated get_unaligned_t() uses __unqual_scalar_typeof() to get an unqualified type. This works correctly for the compilers, but fails for sparse when the data type is __be64 (or any other __beNN variant). On sparse runs (C=[12]) __beNN types are annotated with __attribute__((bitwise)). That annotation allows sparse to detect incompatible operations on __beNN variables, but it also prevents sparse from evaluating the _Generic() in __unqual_scalar_typeof() and map __beNN to a unqualified scalar type, so it ends up with the default, i.e. the original qualified type of a 'const __beNN' pointer. That then ends up as the first pointer argument to builtin_memcpy(), which obviously causes the above sparse warnings. The sparse git tree supports typeof_unqual() now, which allows to use it instead of the _Generic() based __unqual_scalar_typeof(). With that sparse correctly evaluates the unqualified type and keeps the __beNN logic intact. The downside is that this requires a top of tree sparse build and an old sparse version will emit a metric ton of incomprehensible error messages before it dies with a segfault. Therefore implement a sanity check which validates that the checker is available and capable of handling typeof_unqual(). Emit a warning if not so the user can take informed action. [ tglx: Move the evaluation of USE_TYPEOF_UNQUAL to compiler_types.h so it is set before use and implement the sanity checker ] Reported-by: kernel test robot Signed-off-by: Peter Zijlstra Signed-off-by: Thomas Gleixner Acked-by: Ian Rogers Link: https://patch.msgid.link/87ecnp2zh3.ffs@tglx Closes: https://lore.kernel.org/oe-kbuild-all/202601150001.sKSN644a-lkp@intel.com/ --- Makefile | 8 ++++++++ include/linux/compiler.h | 10 ---------- include/linux/compiler_types.h | 13 +++++++++++++ scripts/checker-valid.sh | 19 +++++++++++++++++++ 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100755 scripts/checker-valid.sh diff --git a/Makefile b/Makefile index 9d38125263fb..179c9d9a56dd 100644 --- a/Makefile +++ b/Makefile @@ -1187,6 +1187,14 @@ CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian) # the checker needs the correct machine size CHECKFLAGS += $(if $(CONFIG_64BIT),-m64,-m32) +# Validate the checker is available and functional +ifneq ($(KBUILD_CHECKSRC), 0) + ifneq ($(shell $(srctree)/scripts/checker-valid.sh $(CHECK) $(CHECKFLAGS)), 1) + $(warning C=$(KBUILD_CHECKSRC) specified, but $(CHECK) is not available or not up to date) + KBUILD_CHECKSRC = 0 + endif +endif + # Default kernel image to build when no specific target is given. # KBUILD_IMAGE may be overruled on the command line or # set in the environment diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 04487c9bd751..c601222b495a 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -230,16 +230,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, __BUILD_BUG_ON_ZERO_MSG(!__is_noncstr(p), \ "must be non-C-string (not NUL-terminated)") -/* - * Use __typeof_unqual__() when available. - * - * XXX: Remove test for __CHECKER__ once - * sparse learns about __typeof_unqual__(). - */ -#if CC_HAS_TYPEOF_UNQUAL && !defined(__CHECKER__) -# define USE_TYPEOF_UNQUAL 1 -#endif - /* * Define TYPEOF_UNQUAL() to use __typeof_unqual__() as typeof * operator when available, to return an unqualified type of the exp. diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index d3318a3c2577..377df1e64096 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -562,6 +562,14 @@ struct ftrace_likely_data { #define asm_inline asm #endif +#ifndef __ASSEMBLY__ +/* + * Use __typeof_unqual__() when available. + */ +#if CC_HAS_TYPEOF_UNQUAL || defined(__CHECKER__) +# define USE_TYPEOF_UNQUAL 1 +#endif + /* Are two types/vars the same type (ignoring qualifiers)? */ #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) @@ -569,6 +577,7 @@ struct ftrace_likely_data { * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving * non-scalar types unchanged. */ +#ifndef USE_TYPEOF_UNQUAL /* * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' * is not type-compatible with 'signed char', and we define a separate case. @@ -586,6 +595,10 @@ struct ftrace_likely_data { __scalar_type_to_expr_cases(long), \ __scalar_type_to_expr_cases(long long), \ default: (x))) +#else +#define __unqual_scalar_typeof(x) __typeof_unqual__(x) +#endif +#endif /* !__ASSEMBLY__ */ /* Is this type a native word size -- useful for atomic operations */ #define __native_word(t) \ diff --git a/scripts/checker-valid.sh b/scripts/checker-valid.sh new file mode 100755 index 000000000000..625a789ed1c8 --- /dev/null +++ b/scripts/checker-valid.sh @@ -0,0 +1,19 @@ +#!/bin/sh -eu +# SPDX-License-Identifier: GPL-2.0 + +[ ! -x "$(command -v "$1")" ] && exit 1 + +tmp_file=$(mktemp) +trap "rm -f $tmp_file" EXIT + +cat << EOF >$tmp_file +static inline int u(const int *q) +{ + __typeof_unqual__(*q) v = *q; + return v; +} +EOF + +# sparse happily exits with 0 on error so validate +# there is none on stderr. Use awk as grep is a pain with sh -e +$@ $tmp_file 2>&1 | awk -v c=1 '/error/{c=0}END{print c}' From bbef8e2c29c32f048fac8e07f884f827d028f1da Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 18 Jan 2026 15:45:40 +0100 Subject: [PATCH 17/18] x86/percpu: Make CONFIG_USE_X86_SEG_SUPPORT work with sparse Now that sparse builds enforce the usage of typeof_unqual() the casts in __raw_cpu_read/write() cause sparse to emit tons of false postive warnings: warning: cast removes address space '__percpu' of expression Address this by annotating the casts with __force. Reported-by: kernel test robot Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/87v7gz0yjv.ffs@tglx Closes: https://lore.kernel.org/oe-kbuild-all/202601181733.YZOf9XU3-lkp@intel.com/ --- arch/x86/include/asm/percpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 725d0eff7acd..c55058f3d75e 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -137,12 +137,12 @@ #define __raw_cpu_read(size, qual, pcp) \ ({ \ - *(qual __my_cpu_type(pcp) *)__my_cpu_ptr(&(pcp)); \ + *(qual __my_cpu_type(pcp) * __force)__my_cpu_ptr(&(pcp)); \ }) -#define __raw_cpu_write(size, qual, pcp, val) \ -do { \ - *(qual __my_cpu_type(pcp) *)__my_cpu_ptr(&(pcp)) = (val); \ +#define __raw_cpu_write(size, qual, pcp, val) \ +do { \ + *(qual __my_cpu_type(pcp) * __force)__my_cpu_ptr(&(pcp)) = (val); \ } while (0) #define __raw_cpu_read_const(pcp) __raw_cpu_read(, , pcp) From 546e9289c74f606423ef72075b34cc38eda3bb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 23 Jan 2026 08:35:41 +0100 Subject: [PATCH 18/18] vdso/gettimeofday: Force inlining of __cvdso_clock_getres_common() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_CC_OPTIMIZE_FOR_SIZE=y, GCC may decide not to inline __cvdso_clock_getres_common(). This introduces spurious internal function calls in the vDSO fastpath. Furthermore, with automatic stack variable initialization (CONFIG_INIT_STACK_ALL_ZERO or CONFIG_INIT_STACK_ALL_PATTERN) GCC can emit a call to memset() which is not valid in the vDSO. Mark __cvdso_clock_getres_common() as __always_inline to avoid both issues. Paradoxically the inlining even reduces the size of the code: $ ./scripts/bloat-o-meter arch/powerpc/kernel/vdso/vgettimeofday-32.o.before arch/powerpc/kernel/vdso/vgettimeofday-32.o.after add/remove: 0/1 grow/shrink: 1/1 up/down: 52/-148 (-96) Function old new delta __c_kernel_clock_getres_time64 92 144 +52 __c_kernel_clock_getres 136 132 -4 __cvdso_clock_getres_common 144 - -144 Total: Before=2788, After=2692, chg -3.44% With CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y the functions are always inlined and therefore the behaviour stays the same. See also the equivalent change for clock_gettime() in commit b91c8c42ffdd ("lib/vdso: Force inlining of __cvdso_clock_gettime_common()"). Fixes: 21bbfd74044f ("x86/vdso: Provide clock_getres_time64() for x86-32") Fixes: 1149dcdfc9ef ("ARM: VDSO: Provide clock_getres_time64()") Fixes: f10c2e72b5de ("arm64: vdso32: Provide clock_getres_time64()") Fixes: bec06cd6a140 ("MIPS: vdso: Provide getres_time64() for 32-bit ABIs") Fixes: 759a1f97373f ("powerpc/vdso: Provide clock_getres_time64()") Reported-by: Sverdlin, Alexander Suggested-by: Christophe Leroy (CS GROUP) Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/lkml/230c749f-ebd6-4829-93ee-601d88000a45@kernel.org/ Link: https://patch.msgid.link/20260123-vdso-clock_getres-inline-v1-1-4d6203b90cd3@linutronix.de Closes: https://lore.kernel.org/lkml/f45316f65a46da638b3c6aa69effd8980e6677b9.camel@siemens.com/ --- lib/vdso/gettimeofday.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 95df0153f05a..4399e143d43a 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -421,7 +421,7 @@ static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time #endif /* VDSO_HAS_TIME */ #ifdef VDSO_HAS_CLOCK_GETRES -static __maybe_unused +static __always_inline bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *res) {