Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <tglx@linutronix.de>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20200804150124.41692-3-svens@linux.ibm.com

+53 -4
+3
include/vdso/vsyscall.h
··· 6 6 7 7 #include <asm/vdso/vsyscall.h> 8 8 9 + unsigned long vdso_update_begin(void); 10 + void vdso_update_end(unsigned long flags); 11 + 9 12 #endif /* !__ASSEMBLY__ */ 10 13 11 14 #endif /* __VDSO_VSYSCALL_H */
+1 -1
kernel/time/timekeeping.c
··· 50 50 .seq = SEQCNT_ZERO(tk_core.seq), 51 51 }; 52 52 53 - static DEFINE_RAW_SPINLOCK(timekeeper_lock); 53 + DEFINE_RAW_SPINLOCK(timekeeper_lock); 54 54 static struct timekeeper shadow_timekeeper; 55 55 56 56 /**
+8 -3
kernel/time/timekeeping_internal.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 #ifndef _TIMEKEEPING_INTERNAL_H 3 3 #define _TIMEKEEPING_INTERNAL_H 4 + 5 + #include <linux/clocksource.h> 6 + #include <linux/spinlock.h> 7 + #include <linux/time.h> 8 + 4 9 /* 5 10 * timekeeping debug functions 6 11 */ 7 - #include <linux/clocksource.h> 8 - #include <linux/time.h> 9 - 10 12 #ifdef CONFIG_DEBUG_FS 11 13 extern void tk_debug_account_sleep_time(const struct timespec64 *t); 12 14 #else ··· 32 30 return (now - last) & mask; 33 31 } 34 32 #endif 33 + 34 + /* Semi public for serialization of non timekeeper VDSO updates. */ 35 + extern raw_spinlock_t timekeeper_lock; 35 36 36 37 #endif /* _TIMEKEEPING_INTERNAL_H */
+41
kernel/time/vsyscall.c
··· 13 13 #include <vdso/helpers.h> 14 14 #include <vdso/vsyscall.h> 15 15 16 + #include "timekeeping_internal.h" 17 + 16 18 static inline void update_vdso_data(struct vdso_data *vdata, 17 19 struct timekeeper *tk) 18 20 { ··· 128 126 vdata[CS_HRES_COARSE].tz_dsttime = sys_tz.tz_dsttime; 129 127 130 128 __arch_sync_vdso_data(vdata); 129 + } 130 + 131 + /** 132 + * vdso_update_begin - Start of a VDSO update section 133 + * 134 + * Allows architecture code to safely update the architecture specific VDSO 135 + * data. Disables interrupts, acquires timekeeper lock to serialize against 136 + * concurrent updates from timekeeping and invalidates the VDSO data 137 + * sequence counter to prevent concurrent readers from accessing 138 + * inconsistent data. 139 + * 140 + * Returns: Saved interrupt flags which need to be handed in to 141 + * vdso_update_end(). 142 + */ 143 + unsigned long vdso_update_begin(void) 144 + { 145 + struct vdso_data *vdata = __arch_get_k_vdso_data(); 146 + unsigned long flags; 147 + 148 + raw_spin_lock_irqsave(&timekeeper_lock, flags); 149 + vdso_write_begin(vdata); 150 + return flags; 151 + } 152 + 153 + /** 154 + * vdso_update_end - End of a VDSO update section 155 + * @flags: Interrupt flags as returned from vdso_update_begin() 156 + * 157 + * Pairs with vdso_update_begin(). Marks vdso data consistent, invokes data 158 + * synchronization if the architecture requires it, drops timekeeper lock 159 + * and restores interrupt flags. 160 + */ 161 + void vdso_update_end(unsigned long flags) 162 + { 163 + struct vdso_data *vdata = __arch_get_k_vdso_data(); 164 + 165 + vdso_write_end(vdata); 166 + __arch_sync_vdso_data(vdata); 167 + raw_spin_unlock_irqrestore(&timekeeper_lock, flags); 131 168 }