Subject: [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture

From: [email-masked] (Nathan Lynch)
Date: Tue, 28 Jan 2014 15:48:43 -0600

On 01/28/2014 03:22 PM, Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 03:06:53PM -0600, Nathan Lynch wrote:
>> +static union {
>> +	struct vdso_data	data;
>> +	u8			page[PAGE_SIZE];
>> +} vdso_data_store __page_aligned_data;
>> +struct vdso_data *vdso_data = &vdso_data_store.data;
> 
> So this is in the kernel data segment.
> 
>> +void update_vsyscall(struct timekeeper *tk)
>> +{
>> +	struct timespec xtime_coarse;
>> +	struct timespec wall_time = tk_xtime(tk);
>> +	struct timespec *wtm = &tk->wall_to_monotonic;
>> +	u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
>> +
>> +	++vdso_data->tb_seq_count;
>> +	smp_wmb();
>> +
>> +	xtime_coarse = __current_kernel_time();
>> +	vdso_data->use_syscall			= use_syscall;
>> +	vdso_data->xtime_coarse_sec		= xtime_coarse.tv_sec;
>> +	vdso_data->xtime_coarse_nsec		= xtime_coarse.tv_nsec;
>> +
>> +	if (!use_syscall) {
>> +		vdso_data->cs_cycle_last	= tk->clock->cycle_last;
>> +		vdso_data->xtime_clock_sec	= wall_time.tv_sec;
>> +		vdso_data->xtime_clock_nsec	= wall_time.tv_nsec;
>> +		vdso_data->cs_mult		= tk->mult;
>> +		vdso_data->cs_shift		= tk->shift;
>> +		vdso_data->wtm_clock_sec	= wtm->tv_sec;
>> +		vdso_data->wtm_clock_nsec	= wtm->tv_nsec;
>> +	}
>> +
>> +	smp_wmb();
>> +	++vdso_data->tb_seq_count;
>> +}
>> +
>> +void update_vsyscall_tz(void)
>> +{
>> +	vdso_data->tz_minuteswest	= sys_tz.tz_minuteswest;
>> +	vdso_data->tz_dsttime		= sys_tz.tz_dsttime;
>> +}
> 
> which gets written to directly, and read from userspace.  This won't work
> with aliasing caches, of which we have VIVT caches on all ARMv4 and ARMv5
> CPUs, and VIPT caches on some ARMv6.
> 
> Either this needs to be limited to just VIPT nonaliasing caches, or it
> needs cache handling.

Thanks, I will address this.

> 
> The above also looks rather unsafe from the SMP perspective - how does
> vdso_data->tb_seq_count protect this data between CPUs?

It doesn't -- it merely provides a mechanism for signaling the
consistency of the data userspace reads from the page.  It's basically a
seqlock.

Looks like timekeeper_lock in kernel/time/timekeeping.c prevents
concurrent calls to update_vsyscall.  I could document that dependency...