Skip to content

Commit 19d0070

Browse files
committed
timekeeping/vsyscall: Provide vdso_update_begin/end()
Architectures can have the requirement to add additional architecture specific data to the VDSO data page which needs to be updated independent of the timekeeper updates. To protect these updates vs. concurrent readers and a conflicting update through timekeeping, provide helper functions to make such updates safe. vdso_update_begin() takes the timekeeper_lock to protect against a potential update from timekeeper code and increments the VDSO sequence count to signal data inconsistency to concurrent readers. vdso_update_end() makes the sequence count even again to signal data consistency and drops the timekeeper lock. [ Sven: Add interrupt disable handling to the functions ] Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Sven Schnelle <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 4c5a116 commit 19d0070

File tree

4 files changed

+53
-4
lines changed

4 files changed

+53
-4
lines changed

include/vdso/vsyscall.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include <asm/vdso/vsyscall.h>
88

9+
unsigned long vdso_update_begin(void);
10+
void vdso_update_end(unsigned long flags);
11+
912
#endif /* !__ASSEMBLY__ */
1013

1114
#endif /* __VDSO_VSYSCALL_H */

kernel/time/timekeeping.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static struct {
5050
.seq = SEQCNT_ZERO(tk_core.seq),
5151
};
5252

53-
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
53+
DEFINE_RAW_SPINLOCK(timekeeper_lock);
5454
static struct timekeeper shadow_timekeeper;
5555

5656
/**

kernel/time/timekeeping_internal.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
#ifndef _TIMEKEEPING_INTERNAL_H
33
#define _TIMEKEEPING_INTERNAL_H
4-
/*
5-
* timekeeping debug functions
6-
*/
4+
75
#include <linux/clocksource.h>
6+
#include <linux/spinlock.h>
87
#include <linux/time.h>
98

9+
/*
10+
* timekeeping debug functions
11+
*/
1012
#ifdef CONFIG_DEBUG_FS
1113
extern void tk_debug_account_sleep_time(const struct timespec64 *t);
1214
#else
@@ -31,4 +33,7 @@ static inline u64 clocksource_delta(u64 now, u64 last, u64 mask)
3133
}
3234
#endif
3335

36+
/* Semi public for serialization of non timekeeper VDSO updates. */
37+
extern raw_spinlock_t timekeeper_lock;
38+
3439
#endif /* _TIMEKEEPING_INTERNAL_H */

kernel/time/vsyscall.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <vdso/helpers.h>
1414
#include <vdso/vsyscall.h>
1515

16+
#include "timekeeping_internal.h"
17+
1618
static inline void update_vdso_data(struct vdso_data *vdata,
1719
struct timekeeper *tk)
1820
{
@@ -127,3 +129,42 @@ void update_vsyscall_tz(void)
127129

128130
__arch_sync_vdso_data(vdata);
129131
}
132+
133+
/**
134+
* vdso_update_begin - Start of a VDSO update section
135+
*
136+
* Allows architecture code to safely update the architecture specific VDSO
137+
* data. Disables interrupts, acquires timekeeper lock to serialize against
138+
* concurrent updates from timekeeping and invalidates the VDSO data
139+
* sequence counter to prevent concurrent readers from accessing
140+
* inconsistent data.
141+
*
142+
* Returns: Saved interrupt flags which need to be handed in to
143+
* vdso_update_end().
144+
*/
145+
unsigned long vdso_update_begin(void)
146+
{
147+
struct vdso_data *vdata = __arch_get_k_vdso_data();
148+
unsigned long flags;
149+
150+
raw_spin_lock_irqsave(&timekeeper_lock, flags);
151+
vdso_write_begin(vdata);
152+
return flags;
153+
}
154+
155+
/**
156+
* vdso_update_end - End of a VDSO update section
157+
* @flags: Interrupt flags as returned from vdso_update_begin()
158+
*
159+
* Pairs with vdso_update_begin(). Marks vdso data consistent, invokes data
160+
* synchronization if the architecture requires it, drops timekeeper lock
161+
* and restores interrupt flags.
162+
*/
163+
void vdso_update_end(unsigned long flags)
164+
{
165+
struct vdso_data *vdata = __arch_get_k_vdso_data();
166+
167+
vdso_write_end(vdata);
168+
__arch_sync_vdso_data(vdata);
169+
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
170+
}

0 commit comments

Comments
 (0)