Skip to content

Commit 3503d56

Browse files
avaginctmarinas
authored andcommitted
arm64/vdso: Add time namespace page
Allocate the time namespace page among VVAR pages. Provide __arch_get_timens_vdso_data() helper for VDSO code to get the code-relative position of VVARs on that special page. If a task belongs to a time namespace then the VVAR page which contains the system wide VDSO data is replaced with a namespace specific page which has the same layout as the VVAR page. That page has vdso_data->seq set to 1 to enforce the slow path and vdso_data->clock_mode set to VCLOCK_TIMENS to enforce the time namespace handling path. The extra check in the case that vdso_data->seq is odd, e.g. a concurrent update of the VDSO data is in progress, is not really affecting regular tasks which are not part of a time namespace as the task is spin waiting for the update to finish and vdso_data->seq to become even again. If a time namespace task hits that code path, it invokes the corresponding time getter function which retrieves the real VVAR page, reads host time and then adds the offset for the requested clock which is stored in the special VVAR page. The time-namespace page isn't allocated on !CONFIG_TIME_NAMESPACE, but vma is the same size, which simplifies criu/vdso migration between different kernel configs. Signed-off-by: Andrei Vagin <[email protected]> Reviewed-by: Vincenzo Frascino <[email protected]> Reviewed-by: Dmitry Safonov <[email protected]> Cc: Mark Rutland <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 1b6867d commit 3503d56

File tree

7 files changed

+47
-5
lines changed

7 files changed

+47
-5
lines changed

arch/arm64/include/asm/vdso.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*/
1313
#define VDSO_LBASE 0x0
1414

15+
#define __VVAR_PAGES 2
16+
1517
#ifndef __ASSEMBLY__
1618

1719
#include <generated/vdso-offsets.h>

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
152152
return ret;
153153
}
154154

155+
#ifdef CONFIG_TIME_NS
156+
static __always_inline const struct vdso_data *__arch_get_timens_vdso_data(void)
157+
{
158+
const struct vdso_data *ret;
159+
160+
/* See __arch_get_vdso_data(). */
161+
asm volatile("mov %0, %1" : "=r"(ret) : "r"(_timens_data));
162+
163+
return ret;
164+
}
165+
#endif
166+
155167
#endif /* !__ASSEMBLY__ */
156168

157169
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ const struct vdso_data *__arch_get_vdso_data(void)
9696
return _vdso_data;
9797
}
9898

99+
#ifdef CONFIG_TIME_NS
100+
static __always_inline
101+
const struct vdso_data *__arch_get_timens_vdso_data(void)
102+
{
103+
return _timens_data;
104+
}
105+
#endif
106+
99107
#endif /* !__ASSEMBLY__ */
100108

101109
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */

arch/arm64/kernel/vdso.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ enum vdso_abi {
4040
#endif /* CONFIG_COMPAT_VDSO */
4141
};
4242

43+
enum vvar_pages {
44+
VVAR_DATA_PAGE_OFFSET,
45+
VVAR_TIMENS_PAGE_OFFSET,
46+
VVAR_NR_PAGES,
47+
};
48+
4349
struct vdso_abi_info {
4450
const char *name;
4551
const char *vdso_code_start;
@@ -125,6 +131,11 @@ static int __vdso_init(enum vdso_abi abi)
125131
}
126132

127133
#ifdef CONFIG_TIME_NS
134+
struct vdso_data *arch_get_vdso_data(void *vvar_page)
135+
{
136+
return (struct vdso_data *)(vvar_page);
137+
}
138+
128139
/*
129140
* The vvar mapping contains data for a specific time namespace, so when a task
130141
* changes namespace we must unmap its vvar data for the old namespace.
@@ -173,17 +184,19 @@ static int __setup_additional_pages(enum vdso_abi abi,
173184
unsigned long gp_flags = 0;
174185
void *ret;
175186

187+
BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES);
188+
176189
vdso_text_len = vdso_info[abi].vdso_pages << PAGE_SHIFT;
177190
/* Be sure to map the data page */
178-
vdso_mapping_len = vdso_text_len + PAGE_SIZE;
191+
vdso_mapping_len = vdso_text_len + VVAR_NR_PAGES * PAGE_SIZE;
179192

180193
vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
181194
if (IS_ERR_VALUE(vdso_base)) {
182195
ret = ERR_PTR(vdso_base);
183196
goto up_fail;
184197
}
185198

186-
ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
199+
ret = _install_special_mapping(mm, vdso_base, VVAR_NR_PAGES * PAGE_SIZE,
187200
VM_READ|VM_MAYREAD|VM_PFNMAP,
188201
vdso_info[abi].dm);
189202
if (IS_ERR(ret))
@@ -192,7 +205,7 @@ static int __setup_additional_pages(enum vdso_abi abi,
192205
if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) && system_supports_bti())
193206
gp_flags = VM_ARM64_BTI;
194207

195-
vdso_base += PAGE_SIZE;
208+
vdso_base += VVAR_NR_PAGES * PAGE_SIZE;
196209
mm->context.vdso = (void *)vdso_base;
197210
ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
198211
VM_READ|VM_EXEC|gp_flags|

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ OUTPUT_ARCH(aarch64)
1717

1818
SECTIONS
1919
{
20-
PROVIDE(_vdso_data = . - PAGE_SIZE);
20+
PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
21+
#ifdef CONFIG_TIME_NS
22+
PROVIDE(_timens_data = _vdso_data + PAGE_SIZE);
23+
#endif
2124
. = VDSO_LBASE + SIZEOF_HEADERS;
2225

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

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ OUTPUT_ARCH(arm)
1717

1818
SECTIONS
1919
{
20-
PROVIDE_HIDDEN(_vdso_data = . - PAGE_SIZE);
20+
PROVIDE_HIDDEN(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
21+
#ifdef CONFIG_TIME_NS
22+
PROVIDE_HIDDEN(_timens_data = _vdso_data + PAGE_SIZE);
23+
#endif
2124
. = VDSO_LBASE + SIZEOF_HEADERS;
2225

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

include/vdso/datapage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ struct vdso_data {
109109
* relocation, and this is what we need.
110110
*/
111111
extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")));
112+
extern struct vdso_data _timens_data[CS_BASES] __attribute__((visibility("hidden")));
112113

113114
/*
114115
* The generic vDSO implementation requires that gettimeofday.h

0 commit comments

Comments
 (0)