Makefile | 8 ++++ arch/arm/kernel/vdso.c | 2 + arch/arm/vdso/vdso.lds.S | 1 + arch/arm/vdso/vgettimeofday.c | 5 +++ arch/arm64/kernel/vdso32/vdso.lds.S | 1 + arch/arm64/kernel/vdso32/vgettimeofday.c | 5 +++ arch/loongarch/vdso/vgetcpu.c | 5 +-- arch/mips/vdso/vdso.lds.S | 1 + arch/mips/vdso/vgettimeofday.c | 5 +++ arch/parisc/boot/compressed/misc.c | 15 ++++++- 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 +++ arch/s390/kernel/vdso/getcpu.c | 3 +- arch/s390/kernel/vdso/vdso.h | 4 +- arch/x86/entry/vdso/vclock_gettime.c | 8 ++++ arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 + arch/x86/entry/vdso/vgetcpu.c | 5 +-- arch/x86/include/asm/percpu.h | 8 ++-- arch/x86/include/asm/vdso/processor.h | 4 +- include/linux/compiler.h | 10 ----- include/linux/compiler_types.h | 13 ++++++ include/linux/getcpu.h | 19 --------- include/linux/syscalls.h | 3 +- include/vdso/gettime.h | 1 + include/vdso/unaligned.h | 41 +++++++++++++++--- kernel/sys.c | 4 +- lib/vdso/gettimeofday.c | 2 +- scripts/checker-valid.sh | 19 +++++++++ tools/include/linux/compiler_types.h | 22 ++++++++++ tools/include/linux/unaligned.h | 4 -- tools/include/vdso/unaligned.h | 41 +++++++++++++++--- tools/testing/selftests/vDSO/vdso_config.h | 4 +- tools/testing/selftests/vDSO/vdso_test_abi.c | 55 ++++++++++++++++++++++++- tools/testing/selftests/vDSO/vdso_test_getcpu.c | 4 +- 36 files changed, 268 insertions(+), 76 deletions(-) delete mode 100644 include/linux/getcpu.h create mode 100755 scripts/checker-valid.sh
Linus,
please pull the latest timers/vdso branch from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers-vdso-2026-02-09
up to: 546e9289c74f: vdso/gettimeofday: Force inlining of __cvdso_clock_getres_common()
Updates for the VDSO subsystem:
- Provide the missing 64-bit variant of clock_getres()
This allows the extension of CONFIG_COMPAT_32BIT_TIME to the vDSO and
finally the removal of 32-bit time types from the kernel and UAPI.
- Remove the useless and broken getcpu_cache from the VDSO
The intention was to provide a trivial way to retrieve the CPU number from
the VDSO, but as the VDSO data is per process there is no way to make it
work.
- Switch get/put_unaligned() from packed struct to memcpy()
The packed struct violates strict aliasing rules which requires to pass
-fno-strict-aliasing to the compiler. As this are scalar values
__builtin_memcpy() turns them into simple loads and stores
- Use __typeof_unqual__() for __unqual_scalar_typeof()
The get/put_unaligned() changes triggered a new sparse warning when __beNN
types are used with get/put_unaligned() as sparse builds add a special
'bitwise' attribute to them which prevents sparse to evaluate the Generic
in __unqual_scalar_typeof().
Newer sparse versions support __typeof_unqual__() which avoids the problem,
but requires a recent sparse install. So this adds a sanity check to sparse
builds, which validates that sparse is available and capable of handling it.
- Force inline __cvdso_clock_getres_common()
Compilers sometimes un-inline agressively, which results in function call
overhead and problems with automatic stack variable initialization.
Interestingly enough the force inlining results in smaller code than the
un-inlined variant produced by GCC when optimizing for size.
Thanks,
tglx
------------------>
Ian Rogers (4):
parisc: Inline a type punning version of get_unaligned_le32()
vdso: Switch get/put_unaligned() from packed struct to memcpy()
tools headers: Update the linux/unaligned.h copy with the kernel sources
tools headers: Remove unneeded ignoring of warnings in unaligned.h
Peter Zijlstra (1):
compiler: Use __typeof_unqual__() for __unqual_scalar_typeof()
Thomas Gleixner (1):
x86/percpu: Make CONFIG_USE_X86_SEG_SUPPORT work with sparse
Thomas Weißschuh (12):
vdso: Add prototype for __vdso_clock_getres_time64()
selftests: vDSO: vdso_config: Add configurations for clock_getres_time64()
selftests: vDSO: vdso_test_abi: Use UAPI system call numbers
selftests: vDSO: vdso_test_abi: Add test for clock_getres_time64()
x86/vdso: Provide clock_getres_time64() for x86-32
ARM: VDSO: Patch out __vdso_clock_getres() if unavailable
ARM: VDSO: Provide clock_getres_time64()
arm64: vdso32: Provide clock_getres_time64()
MIPS: vdso: Provide getres_time64() for 32-bit ABIs
vdso: Remove struct getcpu_cache
powerpc/vdso: Provide clock_getres_time64()
vdso/gettimeofday: Force inlining of __cvdso_clock_getres_common()
Makefile | 8 ++++
arch/arm/kernel/vdso.c | 2 +
arch/arm/vdso/vdso.lds.S | 1 +
arch/arm/vdso/vgettimeofday.c | 5 +++
arch/arm64/kernel/vdso32/vdso.lds.S | 1 +
arch/arm64/kernel/vdso32/vgettimeofday.c | 5 +++
arch/loongarch/vdso/vgetcpu.c | 5 +--
arch/mips/vdso/vdso.lds.S | 1 +
arch/mips/vdso/vgettimeofday.c | 5 +++
arch/parisc/boot/compressed/misc.c | 15 ++++++-
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 +++
arch/s390/kernel/vdso/getcpu.c | 3 +-
arch/s390/kernel/vdso/vdso.h | 4 +-
arch/x86/entry/vdso/vclock_gettime.c | 8 ++++
arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 +
arch/x86/entry/vdso/vgetcpu.c | 5 +--
arch/x86/include/asm/percpu.h | 8 ++--
arch/x86/include/asm/vdso/processor.h | 4 +-
include/linux/compiler.h | 10 -----
include/linux/compiler_types.h | 13 ++++++
include/linux/getcpu.h | 19 ---------
include/linux/syscalls.h | 3 +-
include/vdso/gettime.h | 1 +
include/vdso/unaligned.h | 41 +++++++++++++++---
kernel/sys.c | 4 +-
lib/vdso/gettimeofday.c | 2 +-
scripts/checker-valid.sh | 19 +++++++++
tools/include/linux/compiler_types.h | 22 ++++++++++
tools/include/linux/unaligned.h | 4 --
tools/include/vdso/unaligned.h | 41 +++++++++++++++---
tools/testing/selftests/vDSO/vdso_config.h | 4 +-
tools/testing/selftests/vDSO/vdso_test_abi.c | 55 ++++++++++++++++++++++++-
tools/testing/selftests/vDSO/vdso_test_getcpu.c | 4 +-
36 files changed, 268 insertions(+), 76 deletions(-)
delete mode 100644 include/linux/getcpu.h
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/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
index e38a30477f3d..0108f33d6bed 100644
--- a/arch/arm/kernel/vdso.c
+++ b/arch/arm/kernel/vdso.c
@@ -161,6 +161,8 @@ 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");
+ 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)
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)
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 <asm/vdso.h>
-#include <linux/getcpu.h>
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/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,
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;
/*
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,
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 <linux/compiler.h>
-#include <linux/getcpu.h>
#include <asm/timex.h>
#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 <vdso/datapage.h>
-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/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;
};
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 <linux/kernel.h>
-#include <linux/getcpu.h>
#include <asm/segment.h>
#include <vdso/processor.h>
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/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)
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/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/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/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
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 <linux/compiler_types.h>
+
+/**
+ * __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 */
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 <linux/tty.h>
#include <linux/signal.h>
#include <linux/cn_proc.h>
-#include <linux/getcpu.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/seccomp.h>
#include <linux/cpu.h>
@@ -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/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)
{
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}'
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/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 <vdso/unaligned.h>
#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 */
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 <linux/compiler_types.h>
+
+/**
+ * __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 */
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",
},
};
diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c
index c620317eaeea..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[] = {
@@ -179,7 +180,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);
@@ -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)
{
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)
{
© 2016 - 2026 Red Hat, Inc.