Skip to content

Commit

Permalink
Merge tag 'timers-vdso-2025-03-23' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/tip/tip

Pull VDSO infrastructure updates from Thomas Gleixner:

 - Consolidate the VDSO storage

   The VDSO data storage and data layout has been largely architecture
   specific for historical reasons. That increases the maintenance
   effort and causes inconsistencies over and over.

   There is no real technical reason for architecture specific layouts
   and implementations. The architecture specific details can easily be
   integrated into a generic layout, which also reduces the amount of
   duplicated code for managing the mappings.

   Convert all architectures over to a unified layout and common mapping
   infrastructure. This splits the VDSO data layout into subsystem
   specific blocks, timekeeping, random and architecture parts, which
   provides a better structure and allows to improve and update the
   functionalities without conflict and interaction.

 - Rework the timekeeping data storage

   The current implementation is designed for exposing system
   timekeeping accessors, which was good enough at the time when it was
   designed.

   PTP and Time Sensitive Networking (TSN) change that as there are
   requirements to expose independent PTP clocks, which are not related
   to system timekeeping.

   Replace the monolithic data storage by a structured layout, which
   allows to add support for independent PTP clocks on top while reusing
   both the data structures and the time accessor implementations.

* tag 'timers-vdso-2025-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (55 commits)
  sparc/vdso: Always reject undefined references during linking
  x86/vdso: Always reject undefined references during linking
  vdso: Rework struct vdso_time_data and introduce struct vdso_clock
  vdso: Move architecture related data before basetime data
  powerpc/vdso: Prepare introduction of struct vdso_clock
  arm64/vdso: Prepare introduction of struct vdso_clock
  x86/vdso: Prepare introduction of struct vdso_clock
  time/namespace: Prepare introduction of struct vdso_clock
  vdso/namespace: Rename timens_setup_vdso_data() to reflect new vdso_clock struct
  vdso/vsyscall: Prepare introduction of struct vdso_clock
  vdso/gettimeofday: Prepare helper functions for introduction of struct vdso_clock
  vdso/gettimeofday: Prepare do_coarse_timens() for introduction of struct vdso_clock
  vdso/gettimeofday: Prepare do_coarse() for introduction of struct vdso_clock
  vdso/gettimeofday: Prepare do_hres_timens() for introduction of struct vdso_clock
  vdso/gettimeofday: Prepare do_hres() for introduction of struct vdso_clock
  vdso/gettimeofday: Prepare introduction of struct vdso_clock
  vdso/helpers: Prepare introduction of struct vdso_clock
  vdso/datapage: Define vdso_clock to prepare for multiple PTP clocks
  vdso: Make vdso_time_data cacheline aligned
  arm64: Make asm/cache.h compatible with vDSO
  ...
  • Loading branch information
Linus Torvalds committed Mar 25, 2025
2 parents a50b4fe + 6522629 commit 317a76a
Show file tree
Hide file tree
Showing 125 changed files with 1,397 additions and 1,573 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -9792,6 +9792,7 @@ F: include/asm-generic/vdso/vsyscall.h
F: include/vdso/
F: kernel/time/vsyscall.c
F: lib/vdso/
F: tools/testing/selftests/vDSO/

GENWQE (IBM Generic Workqueue Card)
M: Frank Haverkamp <haver@linux.ibm.com>
Expand Down
4 changes: 4 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,10 @@ config HAVE_SPARSE_SYSCALL_NR
entries at 4000, 5000 and 6000 locations. This option turns on syscall
related optimizations for a given architecture.

config ARCH_HAS_VDSO_ARCH_DATA
depends on GENERIC_VDSO_DATA_STORE
bool

config ARCH_HAS_VDSO_TIME_DATA
bool

Expand Down
2 changes: 2 additions & 0 deletions arch/arm/include/asm/vdso.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#ifdef __KERNEL__

#define __VDSO_PAGES 4

#ifndef __ASSEMBLY__

struct mm_struct;
Expand Down
7 changes: 1 addition & 6 deletions arch/arm/include/asm/vdso/gettimeofday.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static inline bool arm_vdso_hres_capable(void)
#define __arch_vdso_hres_capable arm_vdso_hres_capable

static __always_inline u64 __arch_get_hw_counter(int clock_mode,
const struct vdso_data *vd)
const struct vdso_time_data *vd)
{
#ifdef CONFIG_ARM_ARCH_TIMER
u64 cycle_now;
Expand All @@ -135,11 +135,6 @@ static __always_inline u64 __arch_get_hw_counter(int clock_mode,
#endif
}

static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
{
return _vdso_data;
}

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
12 changes: 2 additions & 10 deletions arch/arm/include/asm/vdso/vsyscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,14 @@
#include <vdso/datapage.h>
#include <asm/cacheflush.h>

extern struct vdso_data *vdso_data;
extern bool cntvct_ok;

static __always_inline
struct vdso_data *__arm_get_k_vdso_data(void)
{
return vdso_data;
}
#define __arch_get_k_vdso_data __arm_get_k_vdso_data

static __always_inline
void __arm_sync_vdso_data(struct vdso_data *vdata)
void __arch_sync_vdso_time_data(struct vdso_time_data *vdata)
{
flush_dcache_page(virt_to_page(vdata));
}
#define __arch_sync_vdso_data __arm_sync_vdso_data
#define __arch_sync_vdso_time_data __arch_sync_vdso_time_data

/* The asm-generic header needs to be included after the definitions above */
#include <asm-generic/vdso/vsyscall.h>
Expand Down
4 changes: 0 additions & 4 deletions arch/arm/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,6 @@ int main(void)
DEFINE(CACHE_WRITEBACK_ORDER, __CACHE_WRITEBACK_ORDER);
DEFINE(CACHE_WRITEBACK_GRANULE, __CACHE_WRITEBACK_GRANULE);
BLANK();
#ifdef CONFIG_VDSO
DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
#endif
BLANK();
#ifdef CONFIG_ARM_MPU
DEFINE(MPU_RNG_INFO_RNGS, offsetof(struct mpu_rgn_info, rgns));
DEFINE(MPU_RNG_INFO_USED, offsetof(struct mpu_rgn_info, used));
Expand Down
34 changes: 7 additions & 27 deletions arch/arm/kernel/vdso.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <linux/cache.h>
#include <linux/vdso_datastore.h>
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/kernel.h>
Expand All @@ -33,15 +34,6 @@ extern char vdso_start[], vdso_end[];
/* Total number of pages needed for the data and text portions of the VDSO. */
unsigned int vdso_total_pages __ro_after_init;

static union vdso_data_store vdso_data_store __page_aligned_data;
struct vdso_data *vdso_data = vdso_data_store.data;

static struct page *vdso_data_page __ro_after_init;
static const struct vm_special_mapping vdso_data_mapping = {
.name = "[vvar]",
.pages = &vdso_data_page,
};

static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
Expand Down Expand Up @@ -192,9 +184,6 @@ static int __init vdso_init(void)
if (vdso_text_pagelist == NULL)
return -ENOMEM;

/* Grab the VDSO data page. */
vdso_data_page = virt_to_page(vdso_data);

/* Grab the VDSO text pages. */
for (i = 0; i < text_pages; i++) {
struct page *page;
Expand All @@ -205,7 +194,7 @@ static int __init vdso_init(void)

vdso_text_mapping.pages = vdso_text_pagelist;

vdso_total_pages = 1; /* for the data/vvar page */
vdso_total_pages = VDSO_NR_PAGES; /* for the data/vvar pages */
vdso_total_pages += text_pages;

cntvct_ok = cntvct_functional();
Expand All @@ -216,16 +205,7 @@ static int __init vdso_init(void)
}
arch_initcall(vdso_init);

static int install_vvar(struct mm_struct *mm, unsigned long addr)
{
struct vm_area_struct *vma;

vma = _install_special_mapping(mm, addr, PAGE_SIZE,
VM_READ | VM_MAYREAD,
&vdso_data_mapping);

return PTR_ERR_OR_ZERO(vma);
}
static_assert(__VDSO_PAGES == VDSO_NR_PAGES);

/* assumes mmap_lock is write-locked */
void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
Expand All @@ -238,12 +218,12 @@ void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
if (vdso_text_pagelist == NULL)
return;

if (install_vvar(mm, addr))
if (IS_ERR(vdso_install_vvar_mapping(mm, addr)))
return;

/* Account for vvar page. */
addr += PAGE_SIZE;
len = (vdso_total_pages - 1) << PAGE_SHIFT;
/* Account for vvar pages. */
addr += VDSO_NR_PAGES * PAGE_SIZE;
len = (vdso_total_pages - VDSO_NR_PAGES) << PAGE_SHIFT;

vma = _install_special_mapping(mm, addr, len,
VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,7 @@ config VDSO
select GENERIC_TIME_VSYSCALL
select GENERIC_VDSO_32
select GENERIC_GETTIMEOFDAY
select GENERIC_VDSO_DATA_STORE
help
Place in the process address space an ELF shared object
providing fast implementations of gettimeofday and
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/vdso/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0

# Include the generic Makefile to check the built vdso.
include $(srctree)/lib/vdso/Makefile
include $(srctree)/lib/vdso/Makefile.include

hostprogs := vdsomunge

Expand Down
4 changes: 2 additions & 2 deletions arch/arm/vdso/vdso.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@
*/

#include <linux/const.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/vdso.h>
#include <vdso/datapage.h>

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)

SECTIONS
{
PROVIDE(_vdso_data = . - VDSO_DATA_SIZE);
VDSO_VVAR_SYMS

. = SIZEOF_HEADERS;

Expand Down
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ config ARM64
select GENERIC_SMP_IDLE_THREAD
select GENERIC_TIME_VSYSCALL
select GENERIC_GETTIMEOFDAY
select GENERIC_VDSO_DATA_STORE
select GENERIC_VDSO_TIME_NS
select HARDIRQS_SW_RESEND
select HAS_IOPORT
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/include/asm/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#define ARCH_DMA_MINALIGN (128)
#define ARCH_KMALLOC_MINALIGN (8)

#ifndef __ASSEMBLY__
#if !defined(__ASSEMBLY__) && !defined(BUILD_VDSO)

#include <linux/bitops.h>
#include <linux/kasan-enabled.h>
Expand Down Expand Up @@ -118,6 +118,6 @@ static inline u32 __attribute_const__ read_cpuid_effective_cachetype(void)
return ctr;
}

#endif /* __ASSEMBLY__ */
#endif /* !defined(__ASSEMBLY__) && !defined(BUILD_VDSO) */

#endif
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/vdso.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#ifndef __ASM_VDSO_H
#define __ASM_VDSO_H

#define __VVAR_PAGES 2
#define __VDSO_PAGES 4

#ifndef __ASSEMBLY__

Expand Down
38 changes: 13 additions & 25 deletions arch/arm64/include/asm/vdso/compat_gettimeofday.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
}

static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
const struct vdso_data *vd)
const struct vdso_time_data *vd)
{
u64 res;

Expand All @@ -131,45 +131,33 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
return res;
}

static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
{
const struct vdso_data *ret;
const struct vdso_time_data *ret;

/*
* This simply puts &_vdso_data into ret. The reason why we don't use
* `ret = _vdso_data` is that the compiler tends to optimise this in a
* very suboptimal way: instead of keeping &_vdso_data in a register,
* it goes through a relocation almost every time _vdso_data must be
* This simply puts &_vdso_time_data into ret. The reason why we don't use
* `ret = _vdso_time_data` is that the compiler tends to optimise this in a
* very suboptimal way: instead of keeping &_vdso_time_data in a register,
* it goes through a relocation almost every time _vdso_time_data must be
* accessed (even in subfunctions). This is both time and space
* consuming: each relocation uses a word in the code section, and it
* has to be loaded at runtime.
*
* This trick hides the assignment from the compiler. Since it cannot
* track where the pointer comes from, it will only use one relocation
* where __arch_get_vdso_data() is called, and then keep the result in
* a register.
* where __aarch64_get_vdso_u_time_data() is called, and then keep the
* result in a register.
*/
asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data));
asm volatile("mov %0, %1" : "=r"(ret) : "r"(&vdso_u_time_data));

return ret;
}
#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data

#ifdef CONFIG_TIME_NS
static __always_inline
const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
{
const struct vdso_data *ret;

/* See __arch_get_vdso_data(). */
asm volatile("mov %0, %1" : "=r"(ret) : "r"(_timens_data));

return ret;
}
#endif

static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
static inline bool vdso_clocksource_ok(const struct vdso_clock *vc)
{
return vd->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
return vc->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
}
#define vdso_clocksource_ok vdso_clocksource_ok

Expand Down
12 changes: 0 additions & 12 deletions arch/arm64/include/asm/vdso/getrandom.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,6 @@ static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, uns
return ret;
}

static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void)
{
/*
* The RNG data is in the real VVAR data page, but if a task belongs to a time namespace
* then VVAR_DATA_PAGE_OFFSET points to the namespace-specific VVAR page and VVAR_TIMENS_
* PAGE_OFFSET points to the real VVAR page.
*/
if (IS_ENABLED(CONFIG_TIME_NS) && _vdso_data->clock_mode == VDSO_CLOCKMODE_TIMENS)
return (void *)&_vdso_rng_data + VVAR_TIMENS_PAGE_OFFSET * (1UL << CONFIG_PAGE_SHIFT);
return &_vdso_rng_data;
}

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_VDSO_GETRANDOM_H */
16 changes: 1 addition & 15 deletions arch/arm64/include/asm/vdso/gettimeofday.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
}

static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
const struct vdso_data *vd)
const struct vdso_time_data *vd)
{
u64 res;

Expand Down Expand Up @@ -99,20 +99,6 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
return res;
}

static __always_inline
const struct vdso_data *__arch_get_vdso_data(void)
{
return _vdso_data;
}

#ifdef CONFIG_TIME_NS
static __always_inline
const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
{
return _timens_data;
}
#endif

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
29 changes: 3 additions & 26 deletions arch/arm64/include/asm/vdso/vsyscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,21 @@
#ifndef __ASM_VDSO_VSYSCALL_H
#define __ASM_VDSO_VSYSCALL_H

#define __VDSO_RND_DATA_OFFSET 480

#ifndef __ASSEMBLY__

#include <vdso/datapage.h>

enum vvar_pages {
VVAR_DATA_PAGE_OFFSET,
VVAR_TIMENS_PAGE_OFFSET,
VVAR_NR_PAGES,
};

#define VDSO_PRECISION_MASK ~(0xFF00ULL<<48)

extern struct vdso_data *vdso_data;

/*
* Update the vDSO data page to keep in sync with kernel timekeeping.
*/
static __always_inline
struct vdso_data *__arm64_get_k_vdso_data(void)
{
return vdso_data;
}
#define __arch_get_k_vdso_data __arm64_get_k_vdso_data

static __always_inline
struct vdso_rng_data *__arm64_get_k_vdso_rnd_data(void)
{
return (void *)vdso_data + __VDSO_RND_DATA_OFFSET;
}
#define __arch_get_k_vdso_rng_data __arm64_get_k_vdso_rnd_data

static __always_inline
void __arm64_update_vsyscall(struct vdso_data *vdata)
void __arm64_update_vsyscall(struct vdso_time_data *vdata)
{
vdata[CS_HRES_COARSE].mask = VDSO_PRECISION_MASK;
vdata[CS_RAW].mask = VDSO_PRECISION_MASK;
vdata->clock_data[CS_HRES_COARSE].mask = VDSO_PRECISION_MASK;
vdata->clock_data[CS_RAW].mask = VDSO_PRECISION_MASK;
}
#define __arch_update_vsyscall __arm64_update_vsyscall

Expand Down
Loading

0 comments on commit 317a76a

Please sign in to comment.