There are two parts in this patch. I put them together in order to compile pass.
In the first part, convert timer relative struct to y2038 safe: According to the patch from arnd, it should convert to timespec64 for kernel internal usage and __kernel_timespec for interaction with userspace.
In the second part, convert the timer relative function to y2038 safe. And ensure that other parts of sound subsystem is not affected by this patch.
When arnd's patch[1] is applied and CONFIG_COMPAT_TIME is defined, the 64bit time is used between kernel and userspace. Without arnd's patch[1] or CONFIG_COMPAT_TIME is not defined, timespec will be used between kernel and userspace. That is 64bit time for 64bit application and 32bit time for 32bit application.
[1] y2038: introduce struct __kernel_timespec
Signed-off-by: Bamvor Zhang Jian bamvor.zhangjian@linaro.org --- include/sound/timer.h | 8 +++++++- include/uapi/sound/asound.h | 9 ++++++--- sound/core/timer.c | 49 +++++++++++++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/include/sound/timer.h b/include/sound/timer.h index 7990469..2cfee32 100644 --- a/include/sound/timer.h +++ b/include/sound/timer.h @@ -102,7 +102,7 @@ struct snd_timer_instance { unsigned long ticks, unsigned long resolution); void (*ccallback) (struct snd_timer_instance * timeri, int event, - struct timespec * tstamp, + struct timespec64 * tstamp, unsigned long resolution); void *callback_data; unsigned long ticks; /* auto-load ticks when expired */ @@ -120,6 +120,12 @@ struct snd_timer_instance { struct snd_timer_instance *master; };
+struct snd_timer_tread { + int event; + struct timespec64 tstamp; + unsigned int val; +}; + /* * Registering */ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index a45be6b..f7e3793 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -29,6 +29,9 @@ #include <stdlib.h> #endif
+#ifndef CONFIG_COMPAT_TIME +# define __kernel_timespec timespec +#endif /* * protocol version */ @@ -739,7 +742,7 @@ struct snd_timer_params { };
struct snd_timer_status { - struct timespec tstamp; /* Timestamp - last update */ + struct __kernel_timespec tstamp;/* Timestamp - last update */ unsigned int resolution; /* current period resolution in ns */ unsigned int lost; /* counter of master tick lost */ unsigned int overrun; /* count of read queue overruns */ @@ -787,9 +790,9 @@ enum { SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, };
-struct snd_timer_tread { +struct __kernel_snd_timer_tread { int event; - struct timespec tstamp; + struct __kernel_timespec tstamp; unsigned int val; };
diff --git a/sound/core/timer.c b/sound/core/timer.c index 31f40f0..1b6e1ef 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -70,7 +70,7 @@ struct snd_timer_user { spinlock_t qlock; unsigned long last_resolution; unsigned int filter; - struct timespec tstamp; /* trigger tstamp */ + struct timespec64 tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; struct mutex tread_sem; @@ -387,12 +387,12 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ts; - struct timespec tstamp; + struct timespec64 tstamp;
if (timer_tstamp_monotonic) - ktime_get_ts(&tstamp); + ktime_get_ts64(&tstamp); else - getnstimeofday(&tstamp); + getnstimeofday64(&tstamp); if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || event > SNDRV_TIMER_EVENT_PAUSE)) return; @@ -883,7 +883,8 @@ static int snd_timer_dev_disconnect(struct snd_device *device) return 0; }
-void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) +static void snd_timer_notify64(struct snd_timer *timer, int event, + struct timespec64 *tstamp64) { unsigned long flags; unsigned long resolution = 0; @@ -905,14 +906,23 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam } list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->ccallback) - ti->ccallback(ti, event, tstamp, resolution); + ti->ccallback(ti, event, tstamp64, resolution); list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) - ts->ccallback(ts, event, tstamp, resolution); + ts->ccallback(ts, event, tstamp64, resolution); } spin_unlock_irqrestore(&timer->lock, flags); }
+void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) +{ + struct timespec64 tstamp64; + + tstamp64.tv_sec = tstamp->tv_sec; + tstamp64.tv_nsec = tstamp->tv_nsec; + snd_timer_notify64(timer, event, &tstamp64); +} + /* * exported functions for global timers */ @@ -1159,7 +1169,7 @@ static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, int event, - struct timespec *tstamp, + struct timespec64 *tstamp, unsigned long resolution) { struct snd_timer_user *tu = timeri->callback_data; @@ -1187,7 +1197,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, { struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_tread *r, r1; - struct timespec tstamp; + struct timespec64 tstamp; int prev, append = 0;
memset(&tstamp, 0, sizeof(tstamp)); @@ -1199,9 +1209,9 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, } if (tu->last_resolution != resolution || ticks > 0) { if (timer_tstamp_monotonic) - ktime_get_ts(&tstamp); + ktime_get_ts64(&tstamp); else - getnstimeofday(&tstamp); + getnstimeofday64(&tstamp); } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { @@ -1702,7 +1712,8 @@ static int snd_timer_user_status(struct file *file, if (!tu->timeri) return -EBADFD; memset(&status, 0, sizeof(status)); - status.tstamp = tu->tstamp; + status.tstamp.tv_sec = tu->tstamp.tv_sec; + status.tstamp.tv_nsec = tu->tstamp.tv_nsec; status.resolution = snd_timer_resolution(tu->timeri); status.lost = tu->timeri->lost; status.overrun = tu->overrun; @@ -1843,9 +1854,12 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, struct snd_timer_user *tu; long result = 0, unit; int err = 0; + struct __kernel_snd_timer_tread kttr; + struct snd_timer_tread *ttrp;
tu = file->private_data; - unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); + unit = tu->tread ? sizeof(struct __kernel_snd_timer_tread) : + sizeof(struct snd_timer_read); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { while (!tu->qused) { @@ -1877,8 +1891,13 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, goto _error;
if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], - sizeof(struct snd_timer_tread))) { + ttrp = &tu->tqueue[tu->qhead++]; + kttr.event = ttrp->event; + kttr.tstamp.tv_sec = ttrp->tstamp.tv_sec; + kttr.tstamp.tv_nsec = ttrp->tstamp.tv_nsec; + kttr.val = ttrp->val; + if (copy_to_user(buffer, &kttr, + sizeof(struct __kernel_snd_timer_tread))) { err = -EFAULT; goto _error; }