The sequencer client manager reports timestamps in units of unsigned
32-bit seconds/nanoseconds, but that does not suffer from the y2038
overflow because it stores only the delta since the 'last_update'
time was recorded.
However, the use of the do_gettimeofday() function is problematic
and we have to replace it to avoid the overflow on on 32-bit
architectures.
This uses 'struct timespec64' to record 'last_update', and changes
the code to use monotonic timestamps that do not suffer from leap
seconds and settimeofday updates.
As a side-effect, the code can now use the timespec64_sub() helper
and become more readable and also avoid a multiplication to convert
from microseconds to nanoseconds.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
sound/core/seq/seq_timer.c | 23 +++++++++--------------
sound/core/seq/seq_timer.h | 2 +-
2 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 293104926098..dcc102813aef 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -165,7 +165,7 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
snd_seq_timer_update_tick(&tmr->tick, resolution);
/* register actual time of this timer update */
- do_gettimeofday(&tmr->last_update);
+ ktime_get_ts64(&tmr->last_update);
spin_unlock_irqrestore(&tmr->lock, flags);
@@ -392,7 +392,7 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
return -EINVAL;
snd_timer_start(tmr->timeri, tmr->ticks);
tmr->running = 1;
- do_gettimeofday(&tmr->last_update);
+ ktime_get_ts64(&tmr->last_update);
return 0;
}
@@ -420,7 +420,7 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
}
snd_timer_start(tmr->timeri, tmr->ticks);
tmr->running = 1;
- do_gettimeofday(&tmr->last_update);
+ ktime_get_ts64(&tmr->last_update);
return 0;
}
@@ -444,17 +444,12 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
spin_lock_irqsave(&tmr->lock, flags);
cur_time = tmr->cur_time;
if (tmr->running) {
- struct timeval tm;
- int usec;
- do_gettimeofday(&tm);
- usec = (int)(tm.tv_usec - tmr->last_update.tv_usec);
- if (usec < 0) {
- cur_time.tv_nsec += (1000000 + usec) * 1000;
- cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1;
- } else {
- cur_time.tv_nsec += usec * 1000;
- cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec;
- }
+ struct timespec64 tm;
+
+ ktime_get_ts64(&tm);
+ tm = timespec64_sub(tm, tmr->last_update);
+ cur_time.tv_nsec = tm.tv_nsec;
+ cur_time.tv_sec = tm.tv_sec;
snd_seq_sanity_real_time(&cur_time);
}
spin_unlock_irqrestore(&tmr->lock, flags);
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
index 88dfb71805ae..9506b661fe5b 100644
--- a/sound/core/seq/seq_timer.h
+++ b/sound/core/seq/seq_timer.h
@@ -52,7 +52,7 @@ struct snd_seq_timer {
unsigned int skew;
unsigned int skew_base;
- struct timeval last_update; /* time of last clock update, used for interpolation */
+ struct timespec64 last_update; /* time of last clock update, used for interpolation */
spinlock_t lock;
};
--
2.9.0
/proc/stat shows (among lots of other things) the current boottime
(i.e. number of seconds since boot). While a 32-bit number is sufficient
for this particular case, we want to get rid of the 'struct timespec'
suffers from a 32-bit overflow in 2038.
This changes the code to use a struct timespec64, which is known to
be safe in all cases.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
fs/proc/stat.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 510413eb25b8..7907e456ac4f 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -80,19 +80,17 @@ static u64 get_iowait_time(int cpu)
static int show_stat(struct seq_file *p, void *v)
{
int i, j;
- unsigned long jif;
u64 user, nice, system, idle, iowait, irq, softirq, steal;
u64 guest, guest_nice;
u64 sum = 0;
u64 sum_softirq = 0;
unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
- struct timespec boottime;
+ struct timespec64 boottime;
user = nice = system = idle = iowait =
irq = softirq = steal = 0;
guest = guest_nice = 0;
- getboottime(&boottime);
- jif = boottime.tv_sec;
+ getboottime64(&boottime);
for_each_possible_cpu(i) {
user += kcpustat_cpu(i).cpustat[CPUTIME_USER];
@@ -163,12 +161,12 @@ static int show_stat(struct seq_file *p, void *v)
seq_printf(p,
"\nctxt %llu\n"
- "btime %lu\n"
+ "btime %llu\n"
"processes %lu\n"
"procs_running %lu\n"
"procs_blocked %lu\n",
nr_context_switches(),
- (unsigned long)jif,
+ (unsigned long long)boottime.tv_sec,
total_forks,
nr_running(),
nr_iowait());
--
2.9.0
sys_newlstat is a system call implementation that is meant for user
space, and that copies kernel-internal data structure to the user
format, which is not needed for in-kernel users.
Further, as we rearrange the system call implementation so we can
extend it with 64-bit time_t, the prototype for sys_newlstat changes.
This changes the initramfs code to use vfs_lstat directly, to get
it out of the way of the time_t changes, and make it slightly more
efficient in the process. Along the same lines we also replace
sys_stat and sys_stat64 with vfs_stat.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
init/do_mounts.h | 22 ++++------------------
init/initramfs.c | 12 ++++++------
2 files changed, 10 insertions(+), 24 deletions(-)
diff --git a/init/do_mounts.h b/init/do_mounts.h
index 067af1d9e8b6..282d65bfd674 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -19,29 +19,15 @@ static inline int create_dev(char *name, dev_t dev)
return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
}
-#if BITS_PER_LONG == 32
static inline u32 bstat(char *name)
{
- struct stat64 stat;
- if (sys_stat64(name, &stat) != 0)
+ struct kstat stat;
+ if (vfs_stat(name, &stat) != 0)
return 0;
- if (!S_ISBLK(stat.st_mode))
+ if (!S_ISBLK(stat.mode))
return 0;
- if (stat.st_rdev != (u32)stat.st_rdev)
- return 0;
- return stat.st_rdev;
-}
-#else
-static inline u32 bstat(char *name)
-{
- struct stat stat;
- if (sys_newstat(name, &stat) != 0)
- return 0;
- if (!S_ISBLK(stat.st_mode))
- return 0;
- return stat.st_rdev;
+ return stat.rdev;
}
-#endif
#ifdef CONFIG_BLK_DEV_RAM
diff --git a/init/initramfs.c b/init/initramfs.c
index b32ad7d97ac9..ce7a04435996 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -311,10 +311,10 @@ static int __init maybe_link(void)
static void __init clean_path(char *path, umode_t fmode)
{
- struct stat st;
+ struct kstat st;
- if (!sys_newlstat(path, &st) && (st.st_mode ^ fmode) & S_IFMT) {
- if (S_ISDIR(st.st_mode))
+ if (!vfs_lstat(path, &st) && (st.mode ^ fmode) & S_IFMT) {
+ if (S_ISDIR(st.mode))
sys_rmdir(path);
else
sys_unlink(path);
@@ -580,13 +580,13 @@ static void __init clean_rootfs(void)
num = sys_getdents64(fd, dirp, BUF_SIZE);
while (num > 0) {
while (num > 0) {
- struct stat st;
+ struct kstat st;
int ret;
- ret = sys_newlstat(dirp->d_name, &st);
+ ret = vfs_lstat(dirp->d_name, &st);
WARN_ON_ONCE(ret);
if (!ret) {
- if (S_ISDIR(st.st_mode))
+ if (S_ISDIR(st.mode))
sys_rmdir(dirp->d_name);
else
sys_unlink(dirp->d_name);
--
2.9.0
Comedi uses 32-bit seconds for its timestamps, on both 32-bit and
64-bit machines. For all I can tell, this was originally meant as
a 'timespec', which would overflow in 2038 because of the use of
a signed 'long' on 32-bit machines, but it is now used as an
array of two unsigned 'lsampl_t' values in comedilib, which will
only overflow in 2106, on both 32-bit and 64-bit machines.
In an effort to get rid of all uses of 'struct timeval' in the kernel,
this replaces the internal code with a call to ktime_get_real_ts64()
and a comment at the location of the conversion.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
drivers/staging/comedi/comedi_fops.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 629080f39db0..10a8a9245925 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1256,16 +1256,17 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
switch (insn->insn) {
case INSN_GTOD:
{
- struct timeval tv;
+ struct timespec64 tv;
if (insn->n != 2) {
ret = -EINVAL;
break;
}
- do_gettimeofday(&tv);
- data[0] = tv.tv_sec;
- data[1] = tv.tv_usec;
+ ktime_get_real_ts64(&tv);
+ /* unsigned data safe until 2106 */
+ data[0] = (unsigned int)tv.tv_sec;
+ data[1] = tv.tv_nsec / NSEC_PER_USEC;
ret = 2;
break;
--
2.9.0
The sysfs file for the libata error handling has multiple issues
in the way it prints time stamps:
* it prints a 9-digit nanosecond value using a %06lu format string,
which drops some leading zeroes
* it converts a 64-bit jiffes value to a timespec using
jiffies_to_timespec(), which takes a 'long' argument, so the
result is wrong after a jiffies overflow (49 days).
* we try to avoid using timespec because that generally overflows
in 2038, although this particular usage is ok.
This replaces the jiffies_to_timespec call with an open-coded
implementation that gets it right.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
drivers/ata/libata-transport.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index e2d94972962d..7ef16c085058 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -495,12 +495,13 @@ struct ata_show_ering_arg {
static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
{
struct ata_show_ering_arg* arg = void_arg;
- struct timespec time;
+ u64 seconds;
+ u32 rem;
- jiffies_to_timespec(ent->timestamp,&time);
+ seconds = div_u64_rem(ent->timestamp, HZ, &rem);
arg->written += sprintf(arg->buf + arg->written,
- "[%5lu.%06lu]",
- time.tv_sec, time.tv_nsec);
+ "[%5llu.%09lu]", seconds,
+ rem * NSEC_PER_SEC / HZ);
arg->written += get_ata_err_names(ent->err_mask,
arg->buf + arg->written);
return 0;
--
2.9.0
It depends on user space whether this is safe or not: if programs
interpret the data as a signed time_t value, they will be broken
in y2038, and we have to redesign the entire interface.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
drivers/staging/comedi/comedi_fops.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 629080f39db0..fe50d1f823c6 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1256,16 +1256,17 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
switch (insn->insn) {
case INSN_GTOD:
{
- struct timeval tv;
+ struct timespec64 tv;
if (insn->n != 2) {
ret = -EINVAL;
break;
}
- do_gettimeofday(&tv);
+ ktime_get_real_ts64(&tv);
data[0] = tv.tv_sec;
- data[1] = tv.tv_usec;
+ /* unsigned data safe until 2106 */
+ data[1] = tv.tv_nsec / NSEC_PER_USEC;
ret = 2;
break;
--
2.9.0