Skip to content

Commit 0b3bc33

Browse files
t-8chKAGA-KOKO
authored andcommitted
arm64: vdso: Switch to generic storage implementation
The generic storage implementation provides the same features as the custom one. However it can be shared between architectures, making maintenance easier. This switch also moves the random state data out of the time data page. The currently used hardcoded __VDSO_RND_DATA_OFFSET does not take into account changes to the time data page layout. Co-developed-by: Nam Cao <[email protected]> Signed-off-by: Nam Cao <[email protected]> Signed-off-by: Thomas Weißschuh <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 365841e commit 0b3bc33

File tree

9 files changed

+26
-170
lines changed

9 files changed

+26
-170
lines changed

arch/arm64/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ config ARM64
162162
select GENERIC_SMP_IDLE_THREAD
163163
select GENERIC_TIME_VSYSCALL
164164
select GENERIC_GETTIMEOFDAY
165+
select GENERIC_VDSO_DATA_STORE
165166
select GENERIC_VDSO_TIME_NS
166167
select HARDIRQS_SW_RESEND
167168
select HAS_IOPORT

arch/arm64/include/asm/vdso.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#ifndef __ASM_VDSO_H
66
#define __ASM_VDSO_H
77

8-
#define __VVAR_PAGES 2
8+
#define __VDSO_PAGES 4
99

1010
#ifndef __ASSEMBLY__
1111

arch/arm64/include/asm/vdso/compat_gettimeofday.h

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
104104
}
105105

106106
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
107-
const struct vdso_data *vd)
107+
const struct vdso_time_data *vd)
108108
{
109109
u64 res;
110110

@@ -131,43 +131,31 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
131131
return res;
132132
}
133133

134-
static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
134+
static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
135135
{
136-
const struct vdso_data *ret;
136+
const struct vdso_time_data *ret;
137137

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

154154
return ret;
155155
}
156+
#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
156157

157-
#ifdef CONFIG_TIME_NS
158-
static __always_inline
159-
const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
160-
{
161-
const struct vdso_data *ret;
162-
163-
/* See __arch_get_vdso_data(). */
164-
asm volatile("mov %0, %1" : "=r"(ret) : "r"(_timens_data));
165-
166-
return ret;
167-
}
168-
#endif
169-
170-
static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
158+
static inline bool vdso_clocksource_ok(const struct vdso_time_data *vd)
171159
{
172160
return vd->clock_mode == VDSO_CLOCKMODE_ARCHTIMER;
173161
}

arch/arm64/include/asm/vdso/getrandom.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ static __always_inline ssize_t getrandom_syscall(void *_buffer, size_t _len, uns
3333
return ret;
3434
}
3535

36-
static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void)
37-
{
38-
/*
39-
* The RNG data is in the real VVAR data page, but if a task belongs to a time namespace
40-
* then VVAR_DATA_PAGE_OFFSET points to the namespace-specific VVAR page and VVAR_TIMENS_
41-
* PAGE_OFFSET points to the real VVAR page.
42-
*/
43-
if (IS_ENABLED(CONFIG_TIME_NS) && _vdso_data->clock_mode == VDSO_CLOCKMODE_TIMENS)
44-
return (void *)&_vdso_rng_data + VVAR_TIMENS_PAGE_OFFSET * (1UL << CONFIG_PAGE_SHIFT);
45-
return &_vdso_rng_data;
46-
}
47-
4836
#endif /* !__ASSEMBLY__ */
4937

5038
#endif /* __ASM_VDSO_GETRANDOM_H */

arch/arm64/include/asm/vdso/gettimeofday.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
6767
}
6868

6969
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
70-
const struct vdso_data *vd)
70+
const struct vdso_time_data *vd)
7171
{
7272
u64 res;
7373

@@ -99,20 +99,6 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
9999
return res;
100100
}
101101

102-
static __always_inline
103-
const struct vdso_data *__arch_get_vdso_data(void)
104-
{
105-
return _vdso_data;
106-
}
107-
108-
#ifdef CONFIG_TIME_NS
109-
static __always_inline
110-
const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
111-
{
112-
return _timens_data;
113-
}
114-
#endif
115-
116102
#endif /* !__ASSEMBLY__ */
117103

118104
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */

arch/arm64/include/asm/vdso/vsyscall.h

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,18 @@
22
#ifndef __ASM_VDSO_VSYSCALL_H
33
#define __ASM_VDSO_VSYSCALL_H
44

5-
#define __VDSO_RND_DATA_OFFSET 480
6-
75
#ifndef __ASSEMBLY__
86

97
#include <vdso/datapage.h>
108

11-
enum vvar_pages {
12-
VVAR_DATA_PAGE_OFFSET,
13-
VVAR_TIMENS_PAGE_OFFSET,
14-
VVAR_NR_PAGES,
15-
};
16-
179
#define VDSO_PRECISION_MASK ~(0xFF00ULL<<48)
1810

19-
extern struct vdso_data *vdso_data;
2011

2112
/*
2213
* Update the vDSO data page to keep in sync with kernel timekeeping.
2314
*/
2415
static __always_inline
25-
struct vdso_data *__arm64_get_k_vdso_data(void)
26-
{
27-
return vdso_data;
28-
}
29-
#define __arch_get_k_vdso_data __arm64_get_k_vdso_data
30-
31-
static __always_inline
32-
struct vdso_rng_data *__arm64_get_k_vdso_rnd_data(void)
33-
{
34-
return (void *)vdso_data + __VDSO_RND_DATA_OFFSET;
35-
}
36-
#define __arch_get_k_vdso_rng_data __arm64_get_k_vdso_rnd_data
37-
38-
static __always_inline
39-
void __arm64_update_vsyscall(struct vdso_data *vdata)
16+
void __arm64_update_vsyscall(struct vdso_time_data *vdata)
4017
{
4118
vdata[CS_HRES_COARSE].mask = VDSO_PRECISION_MASK;
4219
vdata[CS_RAW].mask = VDSO_PRECISION_MASK;

arch/arm64/kernel/vdso.c

Lines changed: 5 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <linux/sched.h>
1919
#include <linux/signal.h>
2020
#include <linux/slab.h>
21-
#include <linux/time_namespace.h>
21+
#include <linux/vdso_datastore.h>
2222
#include <linux/vmalloc.h>
2323
#include <vdso/datapage.h>
2424
#include <vdso/helpers.h>
@@ -57,12 +57,6 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
5757
#endif /* CONFIG_COMPAT_VDSO */
5858
};
5959

60-
/*
61-
* The vDSO data page.
62-
*/
63-
static union vdso_data_store vdso_data_store __page_aligned_data;
64-
struct vdso_data *vdso_data = vdso_data_store.data;
65-
6660
static int vdso_mremap(const struct vm_special_mapping *sm,
6761
struct vm_area_struct *new_vma)
6862
{
@@ -104,78 +98,6 @@ static int __init __vdso_init(enum vdso_abi abi)
10498
return 0;
10599
}
106100

107-
#ifdef CONFIG_TIME_NS
108-
struct vdso_data *arch_get_vdso_data(void *vvar_page)
109-
{
110-
return (struct vdso_data *)(vvar_page);
111-
}
112-
113-
static const struct vm_special_mapping vvar_map;
114-
115-
/*
116-
* The vvar mapping contains data for a specific time namespace, so when a task
117-
* changes namespace we must unmap its vvar data for the old namespace.
118-
* Subsequent faults will map in data for the new namespace.
119-
*
120-
* For more details see timens_setup_vdso_data().
121-
*/
122-
int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
123-
{
124-
struct mm_struct *mm = task->mm;
125-
struct vm_area_struct *vma;
126-
VMA_ITERATOR(vmi, mm, 0);
127-
128-
mmap_read_lock(mm);
129-
130-
for_each_vma(vmi, vma) {
131-
if (vma_is_special_mapping(vma, &vvar_map))
132-
zap_vma_pages(vma);
133-
}
134-
135-
mmap_read_unlock(mm);
136-
return 0;
137-
}
138-
#endif
139-
140-
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
141-
struct vm_area_struct *vma, struct vm_fault *vmf)
142-
{
143-
struct page *timens_page = find_timens_vvar_page(vma);
144-
unsigned long pfn;
145-
146-
switch (vmf->pgoff) {
147-
case VVAR_DATA_PAGE_OFFSET:
148-
if (timens_page)
149-
pfn = page_to_pfn(timens_page);
150-
else
151-
pfn = sym_to_pfn(vdso_data);
152-
break;
153-
#ifdef CONFIG_TIME_NS
154-
case VVAR_TIMENS_PAGE_OFFSET:
155-
/*
156-
* If a task belongs to a time namespace then a namespace
157-
* specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and
158-
* the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET
159-
* offset.
160-
* See also the comment near timens_setup_vdso_data().
161-
*/
162-
if (!timens_page)
163-
return VM_FAULT_SIGBUS;
164-
pfn = sym_to_pfn(vdso_data);
165-
break;
166-
#endif /* CONFIG_TIME_NS */
167-
default:
168-
return VM_FAULT_SIGBUS;
169-
}
170-
171-
return vmf_insert_pfn(vma, vmf->address, pfn);
172-
}
173-
174-
static const struct vm_special_mapping vvar_map = {
175-
.name = "[vvar]",
176-
.fault = vvar_fault,
177-
};
178-
179101
static int __setup_additional_pages(enum vdso_abi abi,
180102
struct mm_struct *mm,
181103
struct linux_binprm *bprm,
@@ -185,28 +107,26 @@ static int __setup_additional_pages(enum vdso_abi abi,
185107
unsigned long gp_flags = 0;
186108
void *ret;
187109

188-
BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES);
110+
BUILD_BUG_ON(VDSO_NR_PAGES != __VDSO_PAGES);
189111

190112
vdso_text_len = vdso_info[abi].vdso_pages << PAGE_SHIFT;
191113
/* Be sure to map the data page */
192-
vdso_mapping_len = vdso_text_len + VVAR_NR_PAGES * PAGE_SIZE;
114+
vdso_mapping_len = vdso_text_len + VDSO_NR_PAGES * PAGE_SIZE;
193115

194116
vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
195117
if (IS_ERR_VALUE(vdso_base)) {
196118
ret = ERR_PTR(vdso_base);
197119
goto up_fail;
198120
}
199121

200-
ret = _install_special_mapping(mm, vdso_base, VVAR_NR_PAGES * PAGE_SIZE,
201-
VM_READ|VM_MAYREAD|VM_PFNMAP,
202-
&vvar_map);
122+
ret = vdso_install_vvar_mapping(mm, vdso_base);
203123
if (IS_ERR(ret))
204124
goto up_fail;
205125

206126
if (system_supports_bti_kernel())
207127
gp_flags = VM_ARM64_BTI;
208128

209-
vdso_base += VVAR_NR_PAGES * PAGE_SIZE;
129+
vdso_base += VDSO_NR_PAGES * PAGE_SIZE;
210130
mm->context.vdso = (void *)vdso_base;
211131
ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
212132
VM_READ|VM_EXEC|gp_flags|

arch/arm64/kernel/vdso/vdso.lds.S

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@ OUTPUT_ARCH(aarch64)
2020

2121
SECTIONS
2222
{
23-
PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
24-
PROVIDE(_vdso_rng_data = _vdso_data + __VDSO_RND_DATA_OFFSET);
25-
#ifdef CONFIG_TIME_NS
26-
PROVIDE(_timens_data = _vdso_data + PAGE_SIZE);
27-
#endif
23+
VDSO_VVAR_SYMS
24+
2825
. = SIZEOF_HEADERS;
2926

3027
.hash : { *(.hash) } :text

arch/arm64/kernel/vdso32/vdso.lds.S

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@
1212
#include <asm/page.h>
1313
#include <asm/vdso.h>
1414
#include <asm-generic/vmlinux.lds.h>
15+
#include <vdso/datapage.h>
1516

1617
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
1718
OUTPUT_ARCH(arm)
1819

1920
SECTIONS
2021
{
21-
PROVIDE_HIDDEN(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
22-
#ifdef CONFIG_TIME_NS
23-
PROVIDE_HIDDEN(_timens_data = _vdso_data + PAGE_SIZE);
24-
#endif
22+
VDSO_VVAR_SYMS
23+
2524
. = SIZEOF_HEADERS;
2625

2726
.hash : { *(.hash) } :text

0 commit comments

Comments
 (0)