We want to remove uses of do_gettimeofday() from the kernel since the
resulting timeval structure overflows in 2038. This is not a problem for
this particular use, but do_gettimeofday() is also not an appropriate
method for measuring time intervals, since it requires a conversion into
microseconds and is complicated to work with.
ktime_get() is a better replacement, as it works with the monontonic
kernel timebase and requires a minimum of computation.
I'm slightly changing the output from microseconds to nanoseconds here,
to avoid introducing a new division operation. This should be fine
since the value is only used for debugging.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
drivers/gpu/drm/via/via_drv.h | 4 ++--
drivers/gpu/drm/via/via_irq.c | 21 +++++++--------------
2 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h
index 9873942ca8f4..6d1ae834484c 100644
--- a/drivers/gpu/drm/via/via_drv.h
+++ b/drivers/gpu/drm/via/via_drv.h
@@ -74,9 +74,9 @@ typedef struct drm_via_private {
volatile uint32_t *last_pause_ptr;
volatile uint32_t *hw_addr_ptr;
drm_via_ring_buffer_t ring;
- struct timeval last_vblank;
+ ktime_t last_vblank;
int last_vblank_valid;
- unsigned usec_per_vblank;
+ ktime_t nsec_per_vblank;
atomic_t vbl_received;
drm_via_state_t hc_state;
char pci_buf[VIA_PCI_BUF_SIZE];
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index ea8172c747a2..24e71578af4d 100644
--- a/drivers/gpu/drm/via/via_irq.c
+++ b/drivers/gpu/drm/via/via_irq.c
@@ -88,13 +88,6 @@ static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
-static unsigned time_diff(struct timeval *now, struct timeval *then)
-{
- return (now->tv_usec >= then->tv_usec) ?
- now->tv_usec - then->tv_usec :
- 1000000 - (then->tv_usec - now->tv_usec);
-}
-
u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
drm_via_private_t *dev_priv = dev->dev_private;
@@ -111,7 +104,7 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg)
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
int handled = 0;
- struct timeval cur_vblank;
+ ktime_t cur_vblank;
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
int i;
@@ -119,18 +112,18 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg)
if (status & VIA_IRQ_VBLANK_PENDING) {
atomic_inc(&dev_priv->vbl_received);
if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
- do_gettimeofday(&cur_vblank);
+ cur_vblank = ktime_get();
if (dev_priv->last_vblank_valid) {
- dev_priv->usec_per_vblank =
- time_diff(&cur_vblank,
- &dev_priv->last_vblank) >> 4;
+ dev_priv->nsec_per_vblank =
+ ktime_sub(cur_vblank,
+ dev_priv->last_vblank) >> 4;
}
dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1;
}
if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
- DRM_DEBUG("US per vblank is: %u\n",
- dev_priv->usec_per_vblank);
+ DRM_DEBUG("nsec per vblank is: %llu\n",
+ ktime_to_ns(dev_priv->nsec_per_vblank));
}
drm_handle_vblank(dev, 0);
handled = 1;
--
2.9.0
isofs uses a 'char' variable to load the number of years since
1900 for an inode timestamp. On architectures that use a signed
char type by default, this results in an invalid date for
anything beyond 2027.
This changes the function argument to a 'u8' array, which
is defined the same way on all architectures, and unambiguously
lets us use years until 2155.
This should be backported to all kernels that might still be
in use by that date.
Cc: stable(a)vger.kernel.org
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
v2: change function prototype instead of adding a cast
---
fs/isofs/isofs.h | 2 +-
fs/isofs/rock.h | 2 +-
fs/isofs/util.c | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index 133a456b0425..bd4047585431 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -106,7 +106,7 @@ static inline unsigned int isonum_733(char *p)
/* Ignore bigendian datum due to broken mastering programs */
return get_unaligned_le32(p);
}
-extern int iso_date(char *, int);
+extern int iso_date(u8 *, int);
struct inode; /* To make gcc happy */
diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h
index ed09e2b08637..f835976ce033 100644
--- a/fs/isofs/rock.h
+++ b/fs/isofs/rock.h
@@ -65,7 +65,7 @@ struct RR_PL_s {
};
struct stamp {
- char time[7];
+ __u8 time[7]; /* actually 6 unsigned, 1 signed */
} __attribute__ ((packed));
struct RR_TF_s {
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index 005a15cfd30a..335f62db0b53 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -15,12 +15,12 @@
* to GMT. Thus we should always be correct.
*/
-int iso_date(char * p, int flag)
+int iso_date(u8 *p, int flag)
{
int year, month, day, hour, minute, second, tz;
int crtime;
- year = p[0];
+ year = (int)(u8)p[0];
month = p[1];
day = p[2];
hour = p[3];
--
2.9.0
do_gettimeofday() is deprecated and we should generally use time64_t
based functions instead.
In case of nfsd, all three users of nfssvc_boot only use the initial
time as a unique token, and are not affected by it overflowing, so they
are not affected by the y2038 overflow.
This converts the structure to timespec64 anyway and adds comments
to all uses, to document that we have thought about it and avoid
having to look at it again.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
fs/nfsd/netns.h | 2 +-
fs/nfsd/nfs3xdr.c | 10 ++++++----
fs/nfsd/nfs4proc.c | 5 +++--
fs/nfsd/nfssvc.c | 2 +-
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 3714231a9d0f..1c91391f4805 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -107,7 +107,7 @@ struct nfsd_net {
bool lockd_up;
/* Time of server startup */
- struct timeval nfssvc_boot;
+ struct timespec64 nfssvc_boot;
/*
* Max number of connections this nfsd container will allow. Defaults
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index bf444b664011..3579e0ae1131 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -747,8 +747,9 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
if (resp->status == 0) {
*p++ = htonl(resp->count);
*p++ = htonl(resp->committed);
- *p++ = htonl(nn->nfssvc_boot.tv_sec);
- *p++ = htonl(nn->nfssvc_boot.tv_usec);
+ /* unique identifier, y2038 overflow can be ignored */
+ *p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
+ *p++ = htonl(nn->nfssvc_boot.tv_nsec);
}
return xdr_ressize_check(rqstp, p);
}
@@ -1118,8 +1119,9 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
p = encode_wcc_data(rqstp, p, &resp->fh);
/* Write verifier */
if (resp->status == 0) {
- *p++ = htonl(nn->nfssvc_boot.tv_sec);
- *p++ = htonl(nn->nfssvc_boot.tv_usec);
+ /* unique identifier, y2038 overflow can be ignored */
+ *p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
+ *p++ = htonl(nn->nfssvc_boot.tv_nsec);
}
return xdr_ressize_check(rqstp, p);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7896f841482e..008ea0b627d0 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -564,10 +564,11 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
/*
* This is opaque to client, so no need to byte-swap. Use
- * __force to keep sparse happy
+ * __force to keep sparse happy. y2038 time_t overflow is
+ * irrelevant in this usage.
*/
verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
- verf[1] = (__force __be32)nn->nfssvc_boot.tv_usec;
+ verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec;
memcpy(verifier->data, verf, sizeof(verifier->data));
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 6bbc717f40f2..28ff3e078af6 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -516,7 +516,7 @@ int nfsd_create_serv(struct net *net)
register_inet6addr_notifier(&nfsd_inet6addr_notifier);
#endif
}
- do_gettimeofday(&nn->nfssvc_boot); /* record boot time */
+ ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */
return 0;
}
--
2.9.0
The dmar driver can be used on both x86 and itanium, but only
the former uses the x86_init structure. The only reference to
that structure is enclosed in an #ifdef, but the header inclusion
I added is not.
Adds another #ifdef to get ia64 to build again.
Fixes: 0f5a0f4f062c ("x86: don't include asm/x86_init.h in asm/setup.h")
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
The broken commit is in x86/timers, please add this one on top
---
drivers/iommu/dmar.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index e9304d6247e1..ed1dd13e03ac 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -41,7 +41,9 @@
#include <linux/iommu.h>
#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>
+#ifdef CONFIG_X86
#include <asm/x86_init.h>
+#endif
#include "irq_remapping.h"
--
2.9.0
This is a preparation to allow using 'struct timespec64' in the
asm/x86_init.h. Unfortunately, we can't use a forward declaration
for timespec64 since it is defined as a macro on 64-bit architectures,
and including linux/time64.h breaks compilation of arch/x86/boot/,
which runs in realmode and can't use many of the regular kernel
headers.
As a workaround, I stop including asm/x86_init.h. This works fine
for the realmode boot code since it does not require any of the
x86_init.h contents, and setup.h doesn't either. However, a couple
of other files that do need x86_init.h used to rely on it being
included indirectly, so I have to put an explicit include in there
now.
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
arch/x86/include/asm/setup.h | 1 -
arch/x86/kernel/platform-quirks.c | 1 +
arch/x86/platform/ce4100/ce4100.c | 1 +
arch/x86/platform/intel-mid/intel-mid.c | 1 +
arch/x86/platform/olpc/olpc.c | 1 +
drivers/iommu/dmar.c | 1 +
6 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index a65cf544686a..deed84119a22 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -27,7 +27,6 @@
#ifndef __ASSEMBLY__
#include <asm/bootparam.h>
-#include <asm/x86_init.h>
extern u64 relocated_ramdisk;
diff --git a/arch/x86/kernel/platform-quirks.c b/arch/x86/kernel/platform-quirks.c
index 502a77d0adb0..d900c7b176f0 100644
--- a/arch/x86/kernel/platform-quirks.c
+++ b/arch/x86/kernel/platform-quirks.c
@@ -3,6 +3,7 @@
#include <asm/setup.h>
#include <asm/bios_ebda.h>
+#include <asm/x86_init.h>
void __init x86_early_init_platform_quirks(void)
{
diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c
index ce4b06733c09..885196300927 100644
--- a/arch/x86/platform/ce4100/ce4100.c
+++ b/arch/x86/platform/ce4100/ce4100.c
@@ -22,6 +22,7 @@
#include <asm/io.h>
#include <asm/io_apic.h>
#include <asm/emergency-restart.h>
+#include <asm/x86_init.h>
/*
* The CE4100 platform has an internal 8051 Microcontroller which is
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
index 86676cec99a1..c6322263610a 100644
--- a/arch/x86/platform/intel-mid/intel-mid.c
+++ b/arch/x86/platform/intel-mid/intel-mid.c
@@ -35,6 +35,7 @@
#include <asm/intel_scu_ipc.h>
#include <asm/apb_timer.h>
#include <asm/reboot.h>
+#include <asm/x86_init.h>
#include "intel_mid_weak_decls.h"
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index 7c3077e58fa0..11a54f386911 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -26,6 +26,7 @@
#include <asm/setup.h>
#include <asm/olpc.h>
#include <asm/olpc_ofw.h>
+#include <asm/x86_init.h>
struct olpc_platform_t olpc_platform_info;
EXPORT_SYMBOL_GPL(olpc_platform_info);
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 1ea7cd537873..e9304d6247e1 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -41,6 +41,7 @@
#include <linux/iommu.h>
#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>
+#include <asm/x86_init.h>
#include "irq_remapping.h"
--
2.9.0