b/arch/arm/include/asm/vdso_datapage.h
@@ -27,7 +27,7 @@
* 32 bytes.
*/
struct vdso_data {
- u32 seq_count; /* sequence count - odd during updates */
+ unsigned long seq; /* sequence counter */
u16 use_syscall; /* whether to fall back to syscalls */
u16 cs_shift; /* clocksource shift */
u32 xtime_coarse_sec; /* coarse time */
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/seqlock.h>
#include <linux/slab.h>
#include <linux/timekeeper_internal.h>
#include <linux/vmalloc.h>
@@ -109,18 +110,8 @@ void arm_install_vdso(struct mm_struct *mm)
/**
* update_vsyscall - update the vdso data page
*
- * Increment the sequence counter, making it odd, indicating to
- * userspace that an update is in progress. Update the fields used
- * for coarse clocks and, if the architected system timer is in use,
- * the fields used for high precision clocks. Increment the sequence
- * counter again, making it even, indicating to userspace that the
- * update is finished.
- *
- * Userspace is expected to sample seq_count before reading any other
- * fields from the data page. If seq_count is odd, userspace is
- * expected to wait until it becomes even. After copying data from
- * the page, userspace must sample seq_count again; if it has changed
- * from its previous value, userspace must retry the whole sequence.
+ * Update the fields used for coarse clocks and, if the architected
+ * system timer is in use, the fields used for high precision clocks.
*
* Calls to update_vsyscall are serialized by the timekeeping core.
*/
@@ -130,8 +121,11 @@ void update_vsyscall(struct timekeeper *tk)
struct timespec *wtm = &tk->wall_to_monotonic;
bool use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
- ++vdso_data->seq_count;
- smp_wmb();
+ BUILD_BUG_ON(offsetof(struct seqcount, sequence) != 0);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct vdso_data, seq) !=
+ FIELD_SIZEOF(struct seqcount, sequence));
+
+ raw_write_seqcount_begin((seqcount_t *)&vdso_data->seq);
xtime_coarse = __current_kernel_time();
vdso_data->use_syscall = use_syscall;
@@ -149,8 +143,7 @@ void update_vsyscall(struct timekeeper *tk)
vdso_data->cs_mask = tk->clock->mask;
}
- smp_wmb();
- ++vdso_data->seq_count;
+ raw_write_seqcount_end((seqcount_t *)&vdso_data->seq);
flush_dcache_page(virt_to_page(vdso_data));
}
b/arch/arm/kernel/vdso/vgettimeofday.c
@@ -10,6 +10,7 @@
#include <linux/compiler.h>
#include <linux/hrtimer.h>
+#include <linux/seqlock.h>
#include <linux/time.h>
#include <asm/arch_timer.h>
#include <asm/barrier.h>
@@ -23,28 +24,6 @@
extern struct vdso_data *__get_datapage(void);
-static u32 seqcnt_acquire(struct vdso_data *vdata)
-{
- u32 seq;
-
- do {
- seq = vdata->seq_count;
-
- /* Force gcc to reload from memory when spinning. */
- asm volatile("" : : : "memory");
- } while (seq & 1);
-
- dmb(ish);
- return seq;
-}
-
-static u32 seqcnt_read(struct vdso_data *vdata)
-{
- dmb(ish);
-
- return ACCESS_ONCE(vdata->seq_count);
-}
-
static long clock_gettime_fallback(clockid_t _clkid, struct timespec *_ts)
{
register struct timespec *ts asm("r1") = _ts;
@@ -63,15 +42,15 @@ static long clock_gettime_fallback(clockid_t _clkid,
struct timespec *_ts)
static int do_realtime_coarse(struct timespec *ts, struct vdso_data *vdata)
{
- u32 seq;
+ unsigned long seq;
do {
- seq = seqcnt_acquire(vdata);
+ seq = raw_read_seqcount_begin((seqcount_t *)&vdata->seq);
ts->tv_sec = vdata->xtime_coarse_sec;
ts->tv_nsec = vdata->xtime_coarse_nsec;
- } while (seq != seqcnt_read(vdata));
+ } while (read_seqcount_retry((seqcount_t *)&vdata->seq, seq));
return 0;